@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
package/dist/src/index.js
CHANGED
|
@@ -2711,11 +2711,8 @@ function getCurrentBreakpoint(width) {
|
|
|
2711
2711
|
* Hook to get current breakpoint
|
|
2712
2712
|
*/
|
|
2713
2713
|
function useBreakpoint() {
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
return 'lg';
|
|
2717
|
-
return getCurrentBreakpoint(window.innerWidth);
|
|
2718
|
-
});
|
|
2714
|
+
// Always start with 'lg' to avoid hydration mismatch between server and client
|
|
2715
|
+
const [breakpoint, setBreakpoint] = React.useState('lg');
|
|
2719
2716
|
React.useEffect(() => {
|
|
2720
2717
|
const handleResize = () => {
|
|
2721
2718
|
setBreakpoint(getCurrentBreakpoint(window.innerWidth));
|
|
@@ -2730,11 +2727,8 @@ function useBreakpoint() {
|
|
|
2730
2727
|
* Hook to check if current viewport matches breakpoint
|
|
2731
2728
|
*/
|
|
2732
2729
|
function useMediaQuery(query) {
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
return false;
|
|
2736
|
-
return window.matchMedia(query).matches;
|
|
2737
|
-
});
|
|
2730
|
+
// Always start with false to avoid hydration mismatch between server and client
|
|
2731
|
+
const [matches, setMatches] = React.useState(false);
|
|
2738
2732
|
React.useEffect(() => {
|
|
2739
2733
|
const mediaQuery = window.matchMedia(query);
|
|
2740
2734
|
const handleChange = () => setMatches(mediaQuery.matches);
|
|
@@ -3530,15 +3524,22 @@ const useFilters = (options) => {
|
|
|
3530
3524
|
const [error, setError] = React.useState(null);
|
|
3531
3525
|
const mountedRef = React.useRef(true);
|
|
3532
3526
|
const autoFetch = options?.autoFetch !== false;
|
|
3527
|
+
// Track whether we've completed the first fetch (to avoid skeleton flash on refetches)
|
|
3528
|
+
const hasDataRef = React.useRef(false);
|
|
3533
3529
|
// Extract non-autoFetch options to pass to fetchFilters
|
|
3534
3530
|
const fetchFilters = React.useCallback(async () => {
|
|
3535
|
-
|
|
3531
|
+
// Only show loading spinner on the very first fetch; subsequent refetches
|
|
3532
|
+
// keep previous data visible to avoid skeleton/flash on facet changes.
|
|
3533
|
+
if (!hasDataRef.current) {
|
|
3534
|
+
setLoading(true);
|
|
3535
|
+
}
|
|
3536
3536
|
setError(null);
|
|
3537
3537
|
try {
|
|
3538
3538
|
const { autoFetch: _, ...filterOptions } = options || {};
|
|
3539
3539
|
const response = await stateManager.fetchFilters(filterOptions);
|
|
3540
3540
|
if (mountedRef.current) {
|
|
3541
3541
|
setFilters(response?.filters || []);
|
|
3542
|
+
hasDataRef.current = true;
|
|
3542
3543
|
setLoading(false);
|
|
3543
3544
|
}
|
|
3544
3545
|
}
|
|
@@ -3549,14 +3550,18 @@ const useFilters = (options) => {
|
|
|
3549
3550
|
}
|
|
3550
3551
|
}
|
|
3551
3552
|
}, [stateManager, options?.facetBy, options?.maxFacetValues, options?.disjunctiveFacets?.join(',')]);
|
|
3552
|
-
// Track query
|
|
3553
|
-
|
|
3553
|
+
// Track query to only refetch filters when query actually changes.
|
|
3554
|
+
// Sentinel ensures the first subscribe callback always triggers a fetch.
|
|
3555
|
+
const prevKeyRef = React.useRef(null);
|
|
3554
3556
|
// Refetch when query or refinements change (not on every state update)
|
|
3555
3557
|
React.useEffect(() => {
|
|
3556
3558
|
if (!autoFetch)
|
|
3557
3559
|
return;
|
|
3558
3560
|
const unsubscribe = stateManager.subscribe((state) => {
|
|
3559
|
-
|
|
3561
|
+
// Only track query changes — refinements are NOT passed to the Filters API
|
|
3562
|
+
// (facets are generated from search query only, not narrowed by active filters).
|
|
3563
|
+
// This prevents redundant filters refetches on every facet toggle.
|
|
3564
|
+
const key = state.query;
|
|
3560
3565
|
if (key === prevKeyRef.current)
|
|
3561
3566
|
return;
|
|
3562
3567
|
prevKeyRef.current = key;
|
|
@@ -3906,7 +3911,7 @@ const CSS_VAR_DEFAULTS = {
|
|
|
3906
3911
|
// ---------------------------------------------------------------------------
|
|
3907
3912
|
// Component
|
|
3908
3913
|
// ---------------------------------------------------------------------------
|
|
3909
|
-
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, }) => {
|
|
3914
|
+
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, }) => {
|
|
3910
3915
|
const { theme } = useSearchContext();
|
|
3911
3916
|
const { results: stateResults, refinements, addRefinement, removeRefinement } = useSearchState();
|
|
3912
3917
|
const facetsTheme = customTheme || {};
|
|
@@ -3984,9 +3989,22 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
|
|
|
3984
3989
|
return extracted;
|
|
3985
3990
|
};
|
|
3986
3991
|
const rawFacetList = extractFacets();
|
|
3992
|
+
const hasStats = (stats) => stats != null && (stats.min != null || stats.max != null);
|
|
3987
3993
|
const facets = hideEmptyFacets
|
|
3988
|
-
? rawFacetList.filter(f => f.items.length > 0 || f.stats
|
|
3994
|
+
? rawFacetList.filter(f => f.items.length > 0 || hasStats(f.stats))
|
|
3989
3995
|
: rawFacetList;
|
|
3996
|
+
// Notify parent about facet availability
|
|
3997
|
+
const facetCount = facets.length;
|
|
3998
|
+
const prevFacetAvailableRef = React.useRef(null);
|
|
3999
|
+
React.useEffect(() => {
|
|
4000
|
+
if (!onFacetsAvailable)
|
|
4001
|
+
return;
|
|
4002
|
+
const available = facetCount > 0;
|
|
4003
|
+
if (prevFacetAvailableRef.current !== available) {
|
|
4004
|
+
prevFacetAvailableRef.current = available;
|
|
4005
|
+
onFacetsAvailable(available);
|
|
4006
|
+
}
|
|
4007
|
+
}, [facetCount, onFacetsAvailable]);
|
|
3990
4008
|
// -------------------------------------------------------------------
|
|
3991
4009
|
// Handlers
|
|
3992
4010
|
// -------------------------------------------------------------------
|