feat(search): add search history functionality with dropdown and persistence

- Implement SearchHistoryDropdown component for displaying recent searches
- Add useSearchHistory hook for managing search history in localStorage
- Integrate search history into SearchOverlay for user convenience
- Update GridToolbar to support filter presets
- Enhance SearchOverlay with close button and history display
This commit is contained in:
2026-02-15 13:52:36 +02:00
parent 6226193ab5
commit 9ec2e73640
42 changed files with 2026 additions and 780 deletions

View File

@@ -20,7 +20,10 @@ import React, { forwardRef, type Ref, useEffect, useImperativeHandle, useMemo, u
import type { GriddyProps, GriddyRef } from './types'
import { AdvancedSearchPanel, advancedSearchGlobalFilterFn } from '../features/advancedSearch'
import { GriddyErrorBoundary } from '../features/errorBoundary'
import { useKeyboardNavigation } from '../features/keyboard/useKeyboardNavigation'
import { GriddyLoadingOverlay, GriddyLoadingSkeleton } from '../features/loading'
import { PaginationControl } from '../features/pagination'
import { SearchOverlay } from '../features/search/SearchOverlay'
import { GridToolbar } from '../features/toolbar'
@@ -37,7 +40,9 @@ import { GriddyProvider, useGriddyStore } from './GriddyStore'
function _Griddy<T>(props: GriddyProps<T>, ref: Ref<GriddyRef<T>>) {
return (
<GriddyProvider {...props}>
<GriddyInner tableRef={ref} />
<GriddyErrorBoundary onError={props.onError} onRetry={props.onRetry}>
<GriddyInner tableRef={ref} />
</GriddyErrorBoundary>
{props.children}
</GriddyProvider>
)
@@ -70,6 +75,10 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
const className = useGriddyStore((s) => s.className)
const showToolbar = useGriddyStore((s) => s.showToolbar)
const exportFilename = useGriddyStore((s) => s.exportFilename)
const isLoading = useGriddyStore((s) => s.isLoading)
const filterPresets = useGriddyStore((s) => s.filterPresets)
const advancedSearch = useGriddyStore((s) => s.advancedSearch)
const persistenceKey = useGriddyStore((s) => s.persistenceKey)
const manualSorting = useGriddyStore((s) => s.manualSorting)
const manualFiltering = useGriddyStore((s) => s.manualFiltering)
const dataCount = useGriddyStore((s) => s.dataCount)
@@ -164,6 +173,7 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
enableRowSelection,
enableSorting: true,
getCoreRowModel: getCoreRowModel(),
...(advancedSearch?.enabled ? { globalFilterFn: advancedSearchGlobalFilterFn as any } : {}),
getExpandedRowModel: getExpandedRowModel(),
getFilteredRowModel: manualFiltering ? undefined : getFilteredRowModel(),
getGroupedRowModel: groupingConfig?.enabled ? getGroupedRowModel() : undefined,
@@ -289,9 +299,12 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
role="grid"
>
{search?.enabled && <SearchOverlay />}
{advancedSearch?.enabled && <AdvancedSearchPanel table={table} />}
{showToolbar && (
<GridToolbar
exportFilename={exportFilename}
filterPresets={filterPresets}
persistenceKey={persistenceKey}
table={table}
/>
)}
@@ -302,7 +315,14 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
tabIndex={enableKeyboard ? 0 : undefined}
>
<TableHeader />
<VirtualBody />
{isLoading && (!data || data.length === 0) ? (
<GriddyLoadingSkeleton />
) : (
<>
<VirtualBody />
{isLoading && <GriddyLoadingOverlay />}
</>
)}
</div>
{paginationConfig?.enabled && (
<PaginationControl