UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

126 lines (125 loc) 4.05 kB
"use client"; import { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { useSharedState } from "../../../shared/helpers/useSharedState.js"; import { debounceAsync } from "../../../shared/helpers/debounce.js"; import { FilterContext } from "../FilterContext.js"; const emptyState = { search: '', filters: {} }; export function useFilter(id) { const { data, get, extend } = useSharedState(id, emptyState); const state = data !== null && data !== void 0 ? data : emptyState; const resetFilters = useCallback(() => { extend({ search: '', filters: {} }); }, [extend]); const removeFilter = useCallback(filterKey => { var _get; const latest = (_get = get()) !== null && _get !== void 0 ? _get : emptyState; const next = { ...latest.filters }; delete next[filterKey]; extend({ filters: next }); }, [extend, get]); return { filters: state.filters, search: state.search, hasActiveFilters: state.search.length > 0 || Object.keys(state.filters).length > 0, resetFilters, removeFilter }; } export function useFilterContext() { const context = useContext(FilterContext); if (!context) { throw new Error('Filter.useFilterContext() must be used inside a Filter.Root.'); } return { setFilter: context.setFilter, getFilter: context.getFilter, removeFilter: context.removeFilter, resetFilters: context.resetFilters, commitFilters: context.commitFilters, revertFilters: context.revertFilters, filters: context.state.filters, search: context.state.search, hasActiveFilters: context.hasActiveFilters }; } export function useFilterAsync(id, fetcher, options) { var _options$debounce, _state$resultLoading; const { data: filterData, extend } = useSharedState(id, emptyState); const state = filterData !== null && filterData !== void 0 ? filterData : emptyState; const [result, setResult] = useState(options?.initialData); const [error, setError] = useState(undefined); const requestRef = useRef(0); const fetcherRef = useRef(fetcher); fetcherRef.current = fetcher; const initialDataRef = useRef(options?.initialData); initialDataRef.current = options?.initialData; const debounceMs = (_options$debounce = options?.debounce) !== null && _options$debounce !== void 0 ? _options$debounce : 0; const debouncedFetcherRef = useRef(undefined); if (debounceMs > 0 && !debouncedFetcherRef.current) { debouncedFetcherRef.current = debounceAsync(params => fetcherRef.current(params), debounceMs); } const filtersKey = JSON.stringify(state.filters); const search = state.search; useEffect(() => { const filters = JSON.parse(filtersKey); const requestId = ++requestRef.current; const isFirstRun = requestId === 1; let cancelled = false; if (!isFirstRun || !initialDataRef.current) { extend({ resultLoading: true }); } setError(undefined); const shouldDebounce = debounceMs > 0 && !isFirstRun; const fetchFn = shouldDebounce ? debouncedFetcherRef.current : fetcherRef.current; fetchFn({ filters, search }).then(data => { if (!cancelled && requestId === requestRef.current) { setResult(data); extend({ resultLoading: false, resultCount: Array.isArray(data) ? data.length : undefined }); } }).catch(err => { if (!cancelled && requestId === requestRef.current) { setError(err instanceof Error ? err : new Error(String(err))); extend({ resultLoading: false }); } }); return () => { cancelled = true; if (shouldDebounce) { debouncedFetcherRef.current?.cancel(); } }; }, [filtersKey, search, extend, debounceMs]); return { data: result, loading: (_state$resultLoading = state.resultLoading) !== null && _state$resultLoading !== void 0 ? _state$resultLoading : false, error }; } //# sourceMappingURL=useFilter.js.map