@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.
@@ -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":"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"}
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 != null)
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,gBA+ExD,CAAC"}
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"}
@@ -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
- setLoading(true);
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 + refinements to only refetch when they actually change
37
- const prevKeyRef = useRef('');
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
- const key = `${state.query}|${state.refinements.map(r => `${r.field}:${r.value}`).sort().join(',')}`;
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;