refactor(advancedSearch): reorder exports and improve type definitions

refactor(types): reorganize SearchCondition and AdvancedSearchState interfaces
refactor(filterPresets): streamline useFilterPresets hook and localStorage handling
refactor(filtering): clean up ColumnFilterButton and ColumnFilterPopover components
refactor(loading): separate GriddyLoadingOverlay from GriddyLoadingSkeleton
refactor(searchHistory): enhance useSearchHistory hook with persistence
refactor(index): update exports for adapters and core components
refactor(rendering): improve EditableCell and TableCell components for clarity
refactor(rendering): enhance TableHeader and VirtualBody components for better readability
This commit is contained in:
2026-02-15 19:54:33 +02:00
parent 9ec2e73640
commit 7244bd33fc
31 changed files with 3571 additions and 1305 deletions

View File

@@ -1,10 +1,26 @@
import type { Table } from '@tanstack/react-table'
import type { ColumnFiltersState, ColumnPinningState, RowSelectionState, SortingState } from '@tanstack/react-table'
import type { Virtualizer } from '@tanstack/react-virtual'
import type { Table } from '@tanstack/react-table';
import type {
ColumnFiltersState,
ColumnPinningState,
RowSelectionState,
SortingState,
} from '@tanstack/react-table';
import type { Virtualizer } from '@tanstack/react-virtual';
import { createSyncStore } from '@warkypublic/zustandsyncstore'
import { createSyncStore } from '@warkypublic/zustandsyncstore';
import type { AdvancedSearchConfig, DataAdapter, GriddyColumn, GriddyProps, GriddyUIState, GroupingConfig, InfiniteScrollConfig, PaginationConfig, SearchConfig, SelectionConfig } from './types'
import type {
AdvancedSearchConfig,
DataAdapter,
GriddyColumn,
GriddyProps,
GriddyUIState,
GroupingConfig,
InfiniteScrollConfig,
PaginationConfig,
SearchConfig,
SelectionConfig,
} from './types';
// ─── Store State ─────────────────────────────────────────────────────────────
@@ -14,54 +30,61 @@ import type { AdvancedSearchConfig, DataAdapter, GriddyColumn, GriddyProps, Grid
* Fields from GriddyProps must be declared here so TypeScript can see them.
*/
export interface GriddyStoreState extends GriddyUIState {
_scrollRef: HTMLDivElement | null
_scrollRef: HTMLDivElement | null;
// ─── Internal refs (set imperatively) ───
_table: null | Table<any>
_virtualizer: null | Virtualizer<HTMLDivElement, Element>
advancedSearch?: AdvancedSearchConfig
className?: string
columnFilters?: ColumnFiltersState
columns?: GriddyColumn<any>[]
columnPinning?: ColumnPinningState
onColumnPinningChange?: (pinning: ColumnPinningState) => void
data?: any[]
_table: null | Table<any>;
_virtualizer: null | Virtualizer<HTMLDivElement, Element>;
advancedSearch?: AdvancedSearchConfig;
// ─── Adapter Actions ───
appendData: (data: any[]) => void;
className?: string;
columnFilters?: ColumnFiltersState;
columnPinning?: ColumnPinningState;
columns?: GriddyColumn<any>[];
data?: any[];
dataAdapter?: DataAdapter<any>;
dataCount?: number;
// ─── Error State ───
error: Error | null
exportFilename?: string
dataAdapter?: DataAdapter<any>
dataCount?: number
filterPresets?: boolean
getRowId?: (row: any, index: number) => string
grouping?: GroupingConfig
height?: number | string
infiniteScroll?: InfiniteScrollConfig
isLoading?: boolean
keyboardNavigation?: boolean
manualFiltering?: boolean
manualSorting?: boolean
onColumnFiltersChange?: (filters: ColumnFiltersState) => void
onEditCommit?: (rowId: string, columnId: string, value: unknown) => Promise<void> | void
onError?: (error: Error) => void
onRowSelectionChange?: (selection: RowSelectionState) => void
onSortingChange?: (sorting: SortingState) => void
overscan?: number
pagination?: PaginationConfig
persistenceKey?: string
rowHeight?: number
rowSelection?: RowSelectionState
search?: SearchConfig
error: Error | null;
exportFilename?: string;
filterPresets?: boolean;
getRowId?: (row: any, index: number) => string;
grouping?: GroupingConfig;
height?: number | string;
infiniteScroll?: InfiniteScrollConfig;
isLoading?: boolean;
keyboardNavigation?: boolean;
manualFiltering?: boolean;
manualSorting?: boolean;
onColumnFiltersChange?: (filters: ColumnFiltersState) => void;
onColumnPinningChange?: (pinning: ColumnPinningState) => void;
onEditCommit?: (rowId: string, columnId: string, value: unknown) => Promise<void> | void;
onError?: (error: Error) => void;
onRowSelectionChange?: (selection: RowSelectionState) => void;
onSortingChange?: (sorting: SortingState) => void;
overscan?: number;
pagination?: PaginationConfig;
persistenceKey?: string;
rowHeight?: number;
rowSelection?: RowSelectionState;
selection?: SelectionConfig
setError: (error: Error | null) => void
showToolbar?: boolean
setScrollRef: (el: HTMLDivElement | null) => void
search?: SearchConfig;
selection?: SelectionConfig;
setData: (data: any[]) => void;
setDataCount: (count: number) => void;
setError: (error: Error | null) => void;
setInfiniteScroll: (config: InfiniteScrollConfig | undefined) => void;
setIsLoading: (loading: boolean) => void;
setScrollRef: (el: HTMLDivElement | null) => void;
// ─── Internal ref setters ───
setTable: (table: Table<any>) => void
setTable: (table: Table<any>) => void;
setVirtualizer: (virtualizer: Virtualizer<HTMLDivElement, Element>) => void;
setVirtualizer: (virtualizer: Virtualizer<HTMLDivElement, Element>) => void
sorting?: SortingState
showToolbar?: boolean;
sorting?: SortingState;
// ─── Synced from GriddyProps (written by $sync) ───
uniqueId?: string
uniqueId?: string;
}
// ─── Create Store ────────────────────────────────────────────────────────────
@@ -69,52 +92,55 @@ export interface GriddyStoreState extends GriddyUIState {
export const { Provider: GriddyProvider, useStore: useGriddyStore } = createSyncStore<
GriddyStoreState,
GriddyProps<any>
>(
(set, get) => ({
_scrollRef: null,
// ─── Internal Refs ───
_table: null,
>((set, get) => ({
_scrollRef: null,
// ─── Internal Refs ───
_table: null,
_virtualizer: null,
error: null,
focusedColumnId: null,
// ─── Focus State ───
focusedRowIndex: null,
_virtualizer: null,
appendData: (data) => set((state) => ({ data: [...(state.data ?? []), ...data] })),
error: null,
focusedColumnId: null,
// ─── Focus State ───
focusedRowIndex: null,
// ─── Mode State ───
isEditing: false,
// ─── Mode State ───
isEditing: false,
isSearchOpen: false,
isSelecting: false,
moveFocus: (direction, amount) => {
const { focusedRowIndex, totalRows } = get()
const current = focusedRowIndex ?? 0
const delta = direction === 'down' ? amount : -amount
const next = Math.max(0, Math.min(current + delta, totalRows - 1))
set({ focusedRowIndex: next })
},
isSearchOpen: false,
isSelecting: false,
moveFocus: (direction, amount) => {
const { focusedRowIndex, totalRows } = get();
const current = focusedRowIndex ?? 0;
const delta = direction === 'down' ? amount : -amount;
const next = Math.max(0, Math.min(current + delta, totalRows - 1));
set({ focusedRowIndex: next });
},
moveFocusToEnd: () => {
const { totalRows } = get()
set({ focusedRowIndex: Math.max(0, totalRows - 1) })
},
moveFocusToStart: () => set({ focusedRowIndex: 0 }),
setEditing: (editing) => set({ isEditing: editing }),
setError: (error) => set({ error }),
setFocusedColumn: (id) => set({ focusedColumnId: id }),
// ─── Actions ───
setFocusedRow: (index) => set({ focusedRowIndex: index }),
setScrollRef: (el) => set({ _scrollRef: el }),
moveFocusToEnd: () => {
const { totalRows } = get();
set({ focusedRowIndex: Math.max(0, totalRows - 1) });
},
moveFocusToStart: () => set({ focusedRowIndex: 0 }),
setData: (data) => set({ data }),
setDataCount: (count) => set({ dataCount: count }),
setEditing: (editing) => set({ isEditing: editing }),
setError: (error) => set({ error }),
setFocusedColumn: (id) => set({ focusedColumnId: id }),
// ─── Actions ───
setFocusedRow: (index) => set({ focusedRowIndex: index }),
setInfiniteScroll: (config) => set({ infiniteScroll: config }),
setIsLoading: (loading) => set({ isLoading: loading }),
setScrollRef: (el) => set({ _scrollRef: el }),
setSearchOpen: (open) => set({ isSearchOpen: open }),
setSearchOpen: (open) => set({ isSearchOpen: open }),
setSelecting: (selecting) => set({ isSelecting: selecting }),
// ─── Internal Ref Setters ───
setTable: (table) => set({ _table: table }),
setSelecting: (selecting) => set({ isSelecting: selecting }),
// ─── Internal Ref Setters ───
setTable: (table) => set({ _table: table }),
setTotalRows: (count) => set({ totalRows: count }),
setVirtualizer: (virtualizer) => set({ _virtualizer: virtualizer }),
// ─── Row Count ───
totalRows: 0,
}),
)
setTotalRows: (count) => set({ totalRows: count }),
setVirtualizer: (virtualizer) => set({ _virtualizer: virtualizer }),
// ─── Row Count ───
totalRows: 0,
}));