@seekora-ai/ui-sdk-react 0.2.25 → 0.2.26
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/Facets.d.ts +2 -0
- package/dist/components/Facets.d.ts.map +1 -1
- package/dist/components/Facets.js +16 -3
- package/dist/hooks/useFilters.d.ts.map +1 -1
- package/dist/hooks/useFilters.js +15 -4
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.esm.js +34 -16
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +34 -16
- package/dist/src/index.js.map +1 -1
- package/dist/utils/responsive.d.ts.map +1 -1
- package/dist/utils/responsive.js +4 -10
- package/package.json +3 -3
|
@@ -111,6 +111,8 @@ export interface FacetsProps {
|
|
|
111
111
|
hideEmptyFacets?: boolean;
|
|
112
112
|
/** Fields that should start collapsed (collapsible variant only). Overrides defaultCollapsed for listed fields. */
|
|
113
113
|
defaultCollapsedFields?: string[];
|
|
114
|
+
/** Callback fired when facet availability changes. Receives true when facets are available, false when empty. */
|
|
115
|
+
onFacetsAvailable?: (available: boolean) => void;
|
|
114
116
|
}
|
|
115
117
|
export declare const Facets: React.FC<FacetsProps>;
|
|
116
118
|
//# sourceMappingURL=Facets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Facets.d.ts","sourceRoot":"","sources":["../../src/components/Facets.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"Facets.d.ts","sourceRoot":"","sources":["../../src/components/Facets.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Displays facet filters for search results with multiple display variants,
|
|
5
5
|
* client-side search, count badges, and color swatch support.
|
|
6
6
|
*/
|
|
7
|
-
import React, { useState, useMemo } from 'react';
|
|
7
|
+
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
|
8
8
|
import { useSearchContext } from './SearchProvider';
|
|
9
9
|
import { useSearchState } from '../hooks/useSearchState';
|
|
10
10
|
import { useFilters } from '../hooks/useFilters';
|
|
@@ -66,7 +66,7 @@ const CSS_VAR_DEFAULTS = {
|
|
|
66
66
|
// ---------------------------------------------------------------------------
|
|
67
67
|
// Component
|
|
68
68
|
// ---------------------------------------------------------------------------
|
|
69
|
-
export const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, renderFacet, renderFacetItem, maxItems = 10, showMore = true, className, style, theme: customTheme, variant = 'checkbox', searchable = false, showCounts = true, colorMap, defaultCollapsed = false, size = 'medium', facetRanges, useFiltersApi = false, disjunctiveFacets, hideEmptyFacets = true, defaultCollapsedFields, }) => {
|
|
69
|
+
export const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, renderFacet, renderFacetItem, maxItems = 10, showMore = true, className, style, theme: customTheme, variant = 'checkbox', searchable = false, showCounts = true, colorMap, defaultCollapsed = false, size = 'medium', facetRanges, useFiltersApi = false, disjunctiveFacets, hideEmptyFacets = true, defaultCollapsedFields, onFacetsAvailable, }) => {
|
|
70
70
|
const { theme } = useSearchContext();
|
|
71
71
|
const { results: stateResults, refinements, addRefinement, removeRefinement } = useSearchState();
|
|
72
72
|
const facetsTheme = customTheme || {};
|
|
@@ -144,9 +144,22 @@ export const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange
|
|
|
144
144
|
return extracted;
|
|
145
145
|
};
|
|
146
146
|
const rawFacetList = extractFacets();
|
|
147
|
+
const hasStats = (stats) => stats != null && (stats.min != null || stats.max != null);
|
|
147
148
|
const facets = hideEmptyFacets
|
|
148
|
-
? rawFacetList.filter(f => f.items.length > 0 || f.stats
|
|
149
|
+
? rawFacetList.filter(f => f.items.length > 0 || hasStats(f.stats))
|
|
149
150
|
: rawFacetList;
|
|
151
|
+
// Notify parent about facet availability
|
|
152
|
+
const facetCount = facets.length;
|
|
153
|
+
const prevFacetAvailableRef = useRef(null);
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
if (!onFacetsAvailable)
|
|
156
|
+
return;
|
|
157
|
+
const available = facetCount > 0;
|
|
158
|
+
if (prevFacetAvailableRef.current !== available) {
|
|
159
|
+
prevFacetAvailableRef.current = available;
|
|
160
|
+
onFacetsAvailable(available);
|
|
161
|
+
}
|
|
162
|
+
}, [facetCount, onFacetsAvailable]);
|
|
150
163
|
// -------------------------------------------------------------------
|
|
151
164
|
// Handlers
|
|
152
165
|
// -------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFilters.d.ts","sourceRoot":"","sources":["../../src/hooks/useFilters.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,wBAAwB,CAAC;AAIhC,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,gGAAgG;IAChG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,qDAAqD;IACrD,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kEAAkE;IAClE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5F,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,UAAU,GAAI,UAAU,iBAAiB,KAAG,
|
|
1
|
+
{"version":3,"file":"useFilters.d.ts","sourceRoot":"","sources":["../../src/hooks/useFilters.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,wBAAwB,CAAC;AAIhC,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,gGAAgG;IAChG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,qDAAqD;IACrD,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kEAAkE;IAClE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5F,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,UAAU,GAAI,UAAU,iBAAiB,KAAG,gBA2FxD,CAAC"}
|
package/dist/hooks/useFilters.js
CHANGED
|
@@ -14,15 +14,22 @@ export const useFilters = (options) => {
|
|
|
14
14
|
const [error, setError] = useState(null);
|
|
15
15
|
const mountedRef = useRef(true);
|
|
16
16
|
const autoFetch = options?.autoFetch !== false;
|
|
17
|
+
// Track whether we've completed the first fetch (to avoid skeleton flash on refetches)
|
|
18
|
+
const hasDataRef = useRef(false);
|
|
17
19
|
// Extract non-autoFetch options to pass to fetchFilters
|
|
18
20
|
const fetchFilters = useCallback(async () => {
|
|
19
|
-
|
|
21
|
+
// Only show loading spinner on the very first fetch; subsequent refetches
|
|
22
|
+
// keep previous data visible to avoid skeleton/flash on facet changes.
|
|
23
|
+
if (!hasDataRef.current) {
|
|
24
|
+
setLoading(true);
|
|
25
|
+
}
|
|
20
26
|
setError(null);
|
|
21
27
|
try {
|
|
22
28
|
const { autoFetch: _, ...filterOptions } = options || {};
|
|
23
29
|
const response = await stateManager.fetchFilters(filterOptions);
|
|
24
30
|
if (mountedRef.current) {
|
|
25
31
|
setFilters(response?.filters || []);
|
|
32
|
+
hasDataRef.current = true;
|
|
26
33
|
setLoading(false);
|
|
27
34
|
}
|
|
28
35
|
}
|
|
@@ -33,14 +40,18 @@ export const useFilters = (options) => {
|
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
}, [stateManager, options?.facetBy, options?.maxFacetValues, options?.disjunctiveFacets?.join(',')]);
|
|
36
|
-
// Track query
|
|
37
|
-
|
|
43
|
+
// Track query to only refetch filters when query actually changes.
|
|
44
|
+
// Sentinel ensures the first subscribe callback always triggers a fetch.
|
|
45
|
+
const prevKeyRef = useRef(null);
|
|
38
46
|
// Refetch when query or refinements change (not on every state update)
|
|
39
47
|
useEffect(() => {
|
|
40
48
|
if (!autoFetch)
|
|
41
49
|
return;
|
|
42
50
|
const unsubscribe = stateManager.subscribe((state) => {
|
|
43
|
-
|
|
51
|
+
// Only track query changes — refinements are NOT passed to the Filters API
|
|
52
|
+
// (facets are generated from search query only, not narrowed by active filters).
|
|
53
|
+
// This prevents redundant filters refetches on every facet toggle.
|
|
54
|
+
const key = state.query;
|
|
44
55
|
if (key === prevKeyRef.current)
|
|
45
56
|
return;
|
|
46
57
|
prevKeyRef.current = key;
|