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:
@@ -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,
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user