UNPKG

@jungle-commerce/typesense-react

Version:

React hooks and components for building search interfaces with Typesense

557 lines 15.4 kB
/** * @fileoverview Core TypeScript type definitions for the Typesense search handler. * These types define the complete structure of search requests, responses, and state management. */ import type { SearchResponse, SearchResponseHit, DocumentSchema, SearchResponseFacetCountSchema } from 'typesense/lib/Typesense/Documents'; import type { CollectionSchema } from 'typesense/lib/Typesense/Collection'; /** * Configuration for initializing the Typesense client */ export interface TypesenseConfig { nodes: Array<{ host: string; port: number; protocol: string; }>; apiKey: string; connectionTimeoutSeconds?: number; numRetries?: number; retryIntervalSeconds?: number; cacheSearchResultsForSeconds?: number; } /** * Extended search request parameters for Typesense */ export interface SearchRequest { q: string; query_by: string; filter_by?: string; facet_by?: string; sort_by?: string; max_facet_values?: number; facet_query?: string; page?: number; per_page?: number; group_by?: string; group_limit?: number; include_fields?: string; exclude_fields?: string; highlight_fields?: string; highlight_full_fields?: string; highlight_affix_num_tokens?: number; highlight_start_tag?: string; highlight_end_tag?: string; snippet_threshold?: number; num_typos?: number; min_len_1typo?: number; min_len_2typo?: number; typo_tokens_threshold?: number; drop_tokens_threshold?: number; prefix?: boolean | string; infix?: 'off' | 'always' | 'fallback'; pre_segmented_query?: boolean; query_by_weights?: string; limit_hits?: number; search_cutoff_ms?: number; use_cache?: boolean; cache_ttl?: number; prioritize_exact_match?: boolean; exhaustive_search?: boolean; pinned_hits?: string; hidden_hits?: string; preset?: string; } /** * Individual search hit with document data */ export interface SearchHit<T extends DocumentSchema = Record<string, any>> extends Omit<SearchResponseHit<T>, 'text_match'> { document: T; text_match?: number; } /** * Complete search response from Typesense */ export interface TypesenseSearchResponse<T extends DocumentSchema = Record<string, any>> extends Omit<SearchResponse<T>, 'request_params' | 'hits'> { facet_counts?: SearchResponseFacetCountSchema<T>[]; hits?: SearchHit<T>[]; found: number; search_time_ms: number; page: number; request_params: SearchRequest; search_cutoff?: boolean; } /** * Facet configuration for UI rendering */ export interface FacetConfig { /** Field name in the document */ field: string; /** Display label for the facet */ label: string; /** Type of facet rendering */ type: 'checkbox' | 'select' | 'numeric' | 'date' | 'custom'; /** Whether this facet uses disjunctive (OR) logic */ disjunctive?: boolean; /** Maximum number of values to display */ maxValues?: number; /** Whether to show search box for values */ searchable?: boolean; /** Whether facet is initially expanded */ expanded?: boolean; /** Sort order for facet values */ sortBy?: 'count' | 'value' | 'alpha'; /** For numeric facets, the step size */ step?: number; /** For date facets, the date format */ dateFormat?: string; /** Custom render function */ renderLabel?: (value: string) => string; /** For numeric facets, how to display them */ numericDisplay?: 'checkbox' | 'range' | 'both'; /** For range sliders, the step granularity */ rangeStep?: number; } /** * Facet result from Typesense API */ export interface FacetResult { field_name: string; counts: FacetValue[]; stats?: { avg?: number; max?: number; min?: number; sum?: number; }; } /** * Individual facet value with count */ export interface FacetValue { value: string; count: number; highlighted?: string; } /** * State for disjunctive (OR) facets */ export interface DisjunctiveFacetState { [field: string]: string[]; } /** * State for numeric range filters */ export interface NumericFilterState { [field: string]: { min?: number; max?: number; }; } /** * State for date range filters */ export interface DateFilterState { [field: string]: { start?: Date | string; end?: Date | string; }; } /** * State for selective (single-value) filters */ export interface SelectiveFilterState { [field: string]: string; } /** * State for custom attribute filters */ export interface CustomFilterState { [field: string]: string[]; } /** * Column configuration for table displays */ export interface ColumnConfig { field: string; label: string; visible: boolean; width?: number; minWidth?: number; maxWidth?: number; sortable?: boolean; filterable?: boolean; render?: (value: any, row: any) => React.ReactNode; } /** * Saved filter configuration */ export interface SavedFilter { id: string; name: string; description?: string; filters: { query?: string; disjunctiveFacets?: DisjunctiveFacetState; numericFilters?: NumericFilterState; dateFilters?: DateFilterState; selectiveFilters?: SelectiveFilterState; customFilters?: CustomFilterState; }; createdAt: Date; updatedAt?: Date; } /** * Numeric facet range configuration */ export interface NumericFacetRange { /** Whether this facet is in range mode or individual selection mode */ mode: 'individual' | 'range'; /** Available bounds from all values */ bounds: { min: number; max: number; }; /** Currently selected range (when in range mode) */ currentRange?: { min: number; max: number; }; } /** * Numeric facet ranges state */ export interface NumericFacetRangesState { [field: string]: NumericFacetRange; } /** * Accumulated facet values across searches */ export interface AccumulatedFacetValues { [field: string]: { values: Set<string>; /** Array to maintain insertion order */ orderedValues: string[]; /** Numeric bounds for numeric fields */ numericBounds?: { min: number; max: number; }; lastUpdated: number; }; } /** * Complete search state managed by the provider */ export interface SearchState { /** Current search query */ query: string; /** Search results from Typesense */ results: TypesenseSearchResponse | null; /** Loading state */ loading: boolean; /** Error state */ error: Error | null; /** Available facets configuration */ facets: FacetConfig[]; /** Disjunctive facet selections */ disjunctiveFacets: DisjunctiveFacetState; /** Numeric range filters */ numericFilters: NumericFilterState; /** Date range filters */ dateFilters: DateFilterState; /** Selective (single-value) filters */ selectiveFilters: SelectiveFilterState; /** Custom attribute filters */ customFilters: CustomFilterState; /** Current page number (1-indexed) */ page: number; /** Results per page */ perPage: number; /** Sort field and order */ sortBy: string; /** Multiple sort fields with order (e.g., [{field: 'price', order: 'desc'}, {field: 'name', order: 'asc'}]) */ multiSortBy?: Array<{ field: string; order: 'asc' | 'desc'; }>; /** Additional raw filter string that will be AND-ed with other filters */ additionalFilters?: string; /** Collection schema */ schema: CollectionSchema | null; /** Whether search has been performed */ searchPerformed: boolean; /** Last search timestamp */ lastSearchAt?: number; /** Accumulated facet values across all searches */ accumulatedFacetValues: AccumulatedFacetValues; /** Whether to accumulate facet values */ accumulateFacets: boolean; /** Whether to move selected facet values to the top */ moveSelectedToTop: boolean; /** Whether to reorder facet values by count (vs keeping insertion order) */ reorderByCount: boolean; /** Whether to use numeric ranges for numeric facets */ useNumericRanges: boolean; /** Numeric facet range configurations */ numericFacetRanges: NumericFacetRangesState; /** Limit for facet options - facets exceeding this become single-select */ facetOptionLimit: number; /** Whether to hide zero-count options for single-select facets */ hideZeroCountsForSingleSelect: boolean; /** Whether to allow numeric facets to use range behavior when over the limit */ allowNumericRangeForSingleSelect: boolean; } /** * Actions for updating search state */ export type SearchAction = { type: 'SET_QUERY'; payload: string; } | { type: 'SET_RESULTS'; payload: TypesenseSearchResponse; } | { type: 'SET_LOADING'; payload: boolean; } | { type: 'SET_ERROR'; payload: Error | null; } | { type: 'SET_FACETS'; payload: FacetConfig[]; } | { type: 'SET_DISJUNCTIVE_FACETS'; payload: DisjunctiveFacetState; } | { type: 'TOGGLE_DISJUNCTIVE_FACET'; payload: { field: string; value: string; }; } | { type: 'SET_NUMERIC_FILTER'; payload: { field: string; min?: number; max?: number; }; } | { type: 'SET_DATE_FILTER'; payload: { field: string; start?: Date | string; end?: Date | string; }; } | { type: 'SET_SELECTIVE_FILTER'; payload: { field: string; value: string; }; } | { type: 'SET_CUSTOM_FILTER'; payload: { field: string; values: string[]; }; } | { type: 'CLEAR_FILTER'; payload: { field: string; filterType: 'disjunctive' | 'numeric' | 'date' | 'selective' | 'custom'; }; } | { type: 'CLEAR_ALL_FILTERS'; } | { type: 'SET_PAGE'; payload: number; } | { type: 'SET_PER_PAGE'; payload: number; } | { type: 'SET_SORT_BY'; payload: string; } | { type: 'SET_SCHEMA'; payload: CollectionSchema; } | { type: 'RESET_SEARCH'; } | { type: 'BATCH_UPDATE'; payload: Partial<SearchState>; } | { type: 'SET_ACCUMULATE_FACETS'; payload: boolean; } | { type: 'UPDATE_ACCUMULATED_FACETS'; payload: { field: string; values: string[]; }; } | { type: 'CLEAR_ACCUMULATED_FACETS'; payload?: string; } | { type: 'SET_MOVE_SELECTED_TO_TOP'; payload: boolean; } | { type: 'SET_REORDER_BY_COUNT'; payload: boolean; } | { type: 'SET_USE_NUMERIC_RANGES'; payload: boolean; } | { type: 'SET_NUMERIC_FACET_MODE'; payload: { field: string; mode: 'individual' | 'range'; }; } | { type: 'SET_NUMERIC_FACET_RANGE'; payload: { field: string; min: number; max: number; }; } | { type: 'UPDATE_NUMERIC_FACET_BOUNDS'; payload: { field: string; min: number; max: number; }; } | { type: 'CLEAR_NUMERIC_FACET_RANGE'; payload: string; } | { type: 'SET_FACET_OPTION_LIMIT'; payload: number; } | { type: 'SET_HIDE_ZERO_COUNTS_FOR_SINGLE_SELECT'; payload: boolean; } | { type: 'SET_ALLOW_NUMERIC_RANGE_FOR_SINGLE_SELECT'; payload: boolean; } | { type: 'SET_ADDITIONAL_FILTERS'; payload: string; } | { type: 'SET_MULTI_SORT_BY'; payload: Array<{ field: string; order: 'asc' | 'desc'; }>; } | { type: 'ADD_SORT_FIELD'; payload: { field: string; order: 'asc' | 'desc'; }; } | { type: 'REMOVE_SORT_FIELD'; payload: string; } | { type: 'CLEAR_MULTI_SORT'; }; /** * Search provider configuration options */ export interface SearchProviderProps { /** Typesense configuration */ config: TypesenseConfig; /** Collection name to search */ collection: string; /** Initial search parameters */ initialSearchParams?: Partial<SearchRequest>; /** Initial state values */ initialState?: Partial<SearchState>; /** Facet configurations */ facets?: FacetConfig[]; /** Whether to search on mount */ searchOnMount?: boolean; /** Callback when state changes */ onStateChange?: (state: SearchState) => void; /** Children components */ children: React.ReactNode; /** Performance mode - disables some features for better performance */ performanceMode?: boolean; /** Enable disjunctive facet queries */ enableDisjunctiveFacetQueries?: boolean; /** Enable accumulation of facet values across searches */ accumulateFacets?: boolean; } /** * Context value provided by SearchProvider */ export interface SearchContextValue { /** Current search state */ state: SearchState; /** Dispatch function for state updates */ dispatch: React.Dispatch<SearchAction>; /** Typesense client instance */ client: any; /** Collection name */ collection: string; /** Initial search parameters */ initialSearchParams?: Partial<SearchRequest>; /** Search configuration */ config: { searchOnMount: boolean; performanceMode: boolean; enableDisjunctiveFacetQueries: boolean; }; } /** * Hook return types */ export interface UseSearchReturn { /** Current search state */ state: SearchState; /** Search actions */ actions: { search: (query?: string) => Promise<void>; setQuery: (query: string) => void; setPage: (page: number) => void; setPerPage: (perPage: number) => void; setSortBy: (sortBy: string) => void; clearAllFilters: () => void; reset: () => void; setAdditionalFilters: (filters: string) => void; setMultiSortBy: (sorts: Array<{ field: string; order: 'asc' | 'desc'; }>) => void; addSortField: (field: string, order?: 'asc' | 'desc') => void; removeSortField: (field: string) => void; clearMultiSort: () => void; }; /** Loading state */ loading: boolean; /** Error state */ error: Error | null; } export interface UseAdvancedFacetsReturn { /** Active disjunctive facets */ disjunctiveFacets: DisjunctiveFacetState; /** Active numeric filters */ numericFilters: NumericFilterState; /** Active date filters */ dateFilters: DateFilterState; /** Active selective filters */ selectiveFilters: SelectiveFilterState; /** Active custom filters */ customFilters: CustomFilterState; /** Total active filter count */ activeFilterCount: number; /** Actions for managing facets */ actions: { toggleFacetValue: (field: string, value: string) => void; setNumericFilter: (field: string, min?: number, max?: number) => void; setDateFilter: (field: string, start?: Date | string, end?: Date | string) => void; setSelectiveFilter: (field: string, value: string) => void; setCustomFilter: (field: string, values: string[]) => void; clearFilter: (field: string, filterType: 'disjunctive' | 'numeric' | 'date' | 'selective' | 'custom') => void; clearAllFilters: () => void; }; } //# sourceMappingURL=index.d.ts.map