UNPKG

@veebisepad/vue-query-filters

Version:

Reactive utility for managing URL query parameters in Vue 3.

225 lines (218 loc) 8.13 kB
import { Reactive } from 'vue'; /** * Base interface for all filter types * @template T The type of value this filter handles */ interface AllowedFilter<T> { /** Default value when filter is not specified */ defaultValue: T; /** * Converts a URL parameter string to filter value * @param value The string value from URL query parameter * @param delimiter Character used to split multiple values * @returns Properly typed filter value */ parseQueryParam(value: string | null, delimiter: string): T; /** * Converts filter value to URL parameter string * @param value The filter value to convert * @param delimiter Character used to join multiple values * @returns String representation for URL or null if empty/default */ serializeQueryParam(value: T, delimiter: string): string | null; /** * Checks if a specific value exists in the filter * @param filterValue Current filter value * @param value Value to check for * @returns True if value exists in filter */ hasValue(filterValue: T, value: string | number): boolean; /** * Transforms filter keys for query parameter names * @param key Original filter key from the application * @returns Transformed key suitable for URL parameters */ transformKey: (key: string) => string; } /** Map of filter keys to their filter implementation */ type Filters = Record<string, AllowedFilter<any>>; /** Map of filter keys to their string representation for URL */ type QueryObject = Record<string, string>; /** * Maps filter types to their value types using the defaultValue property * @template T Input type with defaultValue property */ type FilterValueMap<T> = T extends { defaultValue: infer V; } ? V : never; /** * Complete filter object with values and methods * @template T Filter configuration type */ type QueryFilters<T extends Filters> = Reactive<{ [K in keyof T]: FilterValueMap<T[K]>; } & FilterMethods<T>>; type FilterState<T extends Filters> = { [K in keyof T]: FilterValueMap<T[K]>; } & FilterMethods<T>; /** * Configuration options for filters */ interface Options { /** Character used to separate multiple values in URL parameters */ delimiter: string; /** * Callback triggered when filters are applied * @param filters The query object with current filter values */ onApply?(filters: QueryObject): void; /** * When true, preserves the order of query parameters as they appear in the URL * @default true */ preserveQueryOrder?: boolean; /** * Optional Location object to use instead of window.location (for SSR) */ location?: LocationLike; } /** * Methods available on the filter object * @template T Type of the filters configuration */ interface FilterMethods<T extends Filters> { /** * Converts current filter values to URLSearchParams * @returns URLSearchParams object for use in fetch or URL construction */ toSearchParams(): URLSearchParams; /** * Triggers the onApply callback with current filter values */ get(): void; /** * Creates an object with filter keys and their string representations * @param transformKeys Whether to transform keys using the keyTransformer function * @returns Object mapping filter keys to query string values */ toQueryObject(transformKeys?: boolean): Record<string, string>; /** * Creates an object with filter keys and their string representations, * preserving the order of parameters from the current URL * @param transformKeys Whether to transform keys using the keyTransformer function * @returns Object mapping filter keys to query string values in URL order */ toOrderedQueryObject(transformKeys?: boolean): Record<string, string>; /** * Checks if a value exists in the specified filter * @param filter The filter key to check * @param value The value to look for * @returns True if the value exists in the filter */ has<K extends keyof T>(filter: K, value: string | number): boolean; /** * Resets one or more filters to their default values * @param filterKey Single key or array of keys to reset * @param shouldGet Whether to trigger the onApply callback after clearing */ clear<K extends keyof T>(filterKey: K | K[], shouldGet?: boolean): void; /** * Resets all filters to their default values */ clearAll(): void; /** * Updates filter options * @param newOptions New options to merge with existing ones */ setOptions(newOptions: Partial<Options>): void; /** * Filters data object * @returns Object with filter keys and their values */ data(): { [K in keyof T]: FilterValueMap<T[K]>; }; } interface SingleFilter<T> extends AllowedFilter<T> { defaultValue: T; } interface MultipleFilter<T> extends AllowedFilter<T[]> { defaultValue: T[]; } interface RangeFilter<T> extends AllowedFilter<{ from: T; to: T; }> { defaultValue: { from: T; to: T; }; } type FilterFactoryOptions = { keyTransformer?: (key: string) => string; }; type LocationLike = Pick<Location, 'search'> | URL; /** * Creates a collection of filter factory functions * @returns Object containing filter factory methods */ declare const createFilterFactory: (options?: FilterFactoryOptions) => { /** * Creates a filter for a single value * @template SingleType Type of the filter value * @param defaultValue Default value when filter key is not present * @returns A filter object handling single values */ single: <SingleType>(defaultValue?: SingleType) => SingleFilter<SingleType>; /** * Creates a filter for multiple values * @template MultipleType Type of each item in the array * @param defaultValue Default array when filter key is not present * @returns A filter object handling arrays */ multiple: <MultipleType>(defaultValue?: MultipleType[]) => MultipleFilter<MultipleType>; /** * Creates a range filter * @template RangeType Type of the range endpoints * @param defaultValue Default range when filter key is not present * @returns A filter object handling { from: RangeType; to: RangeType } */ range: <RangeType>(defaultValue?: { from: RangeType; to: RangeType; }) => RangeFilter<RangeType>; /** * Allows creating a custom filter * @template CustomType Type of the filter value * @param filter A fully-defined filter object * @returns The same filter, for custom scenarios */ custom: <CustomType>(filter: AllowedFilter<CustomType>) => AllowedFilter<CustomType>; }; /** * Creates a reactive filter object from filter configurations * @param filters Map of filter keys to their configurations * @param initialOptions Initial options for the filters * @returns Reactive filter object with values and methods */ declare function useFilters<T extends Filters>(filters: T, initialOptions?: Partial<Options>): QueryFilters<T>; /** * Pre-configured filter factory for convenience * @example * import { factory } from 'vue-query-filters'; * * const filters = useFilters({ * search: factory.single<string>(), * categories: factory.multiple<string>() * }); */ declare const factory: { single: <SingleType>(defaultValue?: SingleType) => SingleFilter<SingleType>; multiple: <MultipleType>(defaultValue?: MultipleType[]) => MultipleFilter<MultipleType>; range: <RangeType>(defaultValue?: { from: RangeType; to: RangeType; }) => RangeFilter<RangeType>; custom: <CustomType>(filter: AllowedFilter<CustomType>) => AllowedFilter<CustomType>; }; export { type AllowedFilter, type FilterFactoryOptions, type FilterMethods, type FilterState, type FilterValueMap, type Filters, type LocationLike, type MultipleFilter, type Options, type QueryFilters, type QueryObject, type RangeFilter, type SingleFilter, createFilterFactory, factory, useFilters };