A Griddy AI prototype
This commit is contained in:
103
src/Griddy/core/GriddyStore.ts
Normal file
103
src/Griddy/core/GriddyStore.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { Table } from '@tanstack/react-table'
|
||||
import type { ColumnFiltersState, RowSelectionState, SortingState } from '@tanstack/react-table'
|
||||
import type { Virtualizer } from '@tanstack/react-virtual'
|
||||
|
||||
import { createSyncStore } from '@warkypublic/zustandsyncstore'
|
||||
|
||||
import type { DataAdapter, GriddyColumn, GriddyProps, GriddyUIState, GroupingConfig, PaginationConfig, SearchConfig, SelectionConfig } from './types'
|
||||
|
||||
// ─── Store State ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Full store state: UI state + synced props + internal references.
|
||||
* Props from GriddyProps are synced automatically via createSyncStore's $sync.
|
||||
* Fields from GriddyProps must be declared here so TypeScript can see them.
|
||||
*/
|
||||
export interface GriddyStoreState extends GriddyUIState {
|
||||
_scrollRef: HTMLDivElement | null
|
||||
// ─── Internal refs (set imperatively) ───
|
||||
_table: null | Table<any>
|
||||
_virtualizer: null | Virtualizer<HTMLDivElement, Element>
|
||||
className?: string
|
||||
columnFilters?: ColumnFiltersState
|
||||
columns?: GriddyColumn<any>[]
|
||||
data?: any[]
|
||||
dataAdapter?: DataAdapter<any>
|
||||
getRowId?: (row: any, index: number) => string
|
||||
grouping?: GroupingConfig
|
||||
height?: number | string
|
||||
keyboardNavigation?: boolean
|
||||
onColumnFiltersChange?: (filters: ColumnFiltersState) => void
|
||||
onEditCommit?: (rowId: string, columnId: string, value: unknown) => Promise<void> | void
|
||||
onRowSelectionChange?: (selection: RowSelectionState) => void
|
||||
onSortingChange?: (sorting: SortingState) => void
|
||||
overscan?: number
|
||||
pagination?: PaginationConfig
|
||||
persistenceKey?: string
|
||||
rowHeight?: number
|
||||
rowSelection?: RowSelectionState
|
||||
search?: SearchConfig
|
||||
|
||||
selection?: SelectionConfig
|
||||
setScrollRef: (el: HTMLDivElement | null) => void
|
||||
// ─── Internal ref setters ───
|
||||
setTable: (table: Table<any>) => void
|
||||
|
||||
setVirtualizer: (virtualizer: Virtualizer<HTMLDivElement, Element>) => void
|
||||
sorting?: SortingState
|
||||
// ─── Synced from GriddyProps (written by $sync) ───
|
||||
uniqueId?: string
|
||||
}
|
||||
|
||||
// ─── Create Store ────────────────────────────────────────────────────────────
|
||||
|
||||
export const { Provider: GriddyProvider, useStore: useGriddyStore } = createSyncStore<
|
||||
GriddyStoreState,
|
||||
GriddyProps<any>
|
||||
>(
|
||||
(set, get) => ({
|
||||
_scrollRef: null,
|
||||
// ─── Internal Refs ───
|
||||
_table: null,
|
||||
|
||||
_virtualizer: null,
|
||||
focusedColumnId: null,
|
||||
// ─── Focus State ───
|
||||
focusedRowIndex: null,
|
||||
|
||||
// ─── 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 })
|
||||
},
|
||||
|
||||
moveFocusToEnd: () => {
|
||||
const { totalRows } = get()
|
||||
set({ focusedRowIndex: Math.max(0, totalRows - 1) })
|
||||
},
|
||||
moveFocusToStart: () => set({ focusedRowIndex: 0 }),
|
||||
setEditing: (editing) => set({ isEditing: editing }),
|
||||
setFocusedColumn: (id) => set({ focusedColumnId: id }),
|
||||
// ─── Actions ───
|
||||
setFocusedRow: (index) => set({ focusedRowIndex: index }),
|
||||
setScrollRef: (el) => set({ _scrollRef: el }),
|
||||
|
||||
setSearchOpen: (open) => set({ isSearchOpen: open }),
|
||||
|
||||
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,
|
||||
}),
|
||||
)
|
||||
Reference in New Issue
Block a user