docs(plan): add feature complete implementation plan

This commit is contained in:
Hein
2026-02-12 18:55:15 +02:00
parent 6dadbc9ba6
commit 6d73e83fbf

702
src/Griddy/plan.md Normal file
View File

@@ -0,0 +1,702 @@
# Griddy - Feature Complete Implementation Plan
## Project Overview
Griddy is a native TypeScript HTML table/grid component designed as a lightweight, extensible alternative to both Glide Data Editor and Mantine React Table. It will provide a zero-dependency core with optional plugin architecture, built on TanStack React Virtual for efficient virtualization.
## Architecture & Core Design Principles
### 1. Core Philosophy
- **Independent**: Minimal peer dependencies (React, React DOM only at minimum)
- **Lightweight**: Pure HTML table rendering with CSS styling
- **Virtual-First**: Virtualization from the ground up using TanStack React Virtual
- **Plugin-Based**: All advanced features as pluggable modules
- **State Agnostic**: Works with any state management solution or local state
- **Callback-Driven**: Similar to Glide Data Editor's read-only data principle
### 1.5. Lessons from Gridler
Gridly (existing implementation) provides valuable patterns:
- **Zustand Store Pattern**: Central state management using `createSyncStore` for reactive updates
- **Data Adapter Pattern**: Wrapper components that interface with store (LocalDataAdaptor, FormAdaptor, APIAdaptor)
- **Event System**: Uses CustomEvent for inter-component communication
- **Provider/Context Pattern**: Wraps grid in Provider for configuration and state sharing
- **Column Definition System**: Type-safe, extensible column definitions with custom rendering
- **Ref-based API**: Forward refs for imperative commands (refresh, reload, scrollTo, selectRow)
- **Persistence**: Automatic localStorage persistence for column order and sizing
**Griddy will adopt these proven patterns while building on TanStack React Virtual instead of Glide Data Grid**
### 2. Component Structure
Following Gridler's proven architecture, with improvements:
```
Griddy/
├── core/
│ ├── Griddy.tsx (main component, similar to Gridler.tsx)
│ ├── GriddyStore.ts (zustand store, similar to Gridler's createSyncStore)
│ ├── GriddyProvider.tsx (context provider for configuration)
│ └── types.ts (core type definitions)
├── virtualization/
│ ├── VirtualBody.tsx (uses TanStack React Virtual)
│ ├── VirtualHeader.tsx
│ └── hooks/useVirtualize.ts
├── features/
│ ├── filtering/ (column filtering)
│ ├── sorting/ (multi-column sorting)
│ ├── grouping/ (header grouping & data grouping)
│ ├── search/ (global & column-specific search)
│ ├── selection/ (row/column/range selection)
│ ├── editing/ (in-place cell editors)
│ ├── pagination/ (cursor & offset-based)
│ ├── resizing/ (column width resizing)
│ ├── pinning/ (freeze columns/rows)
│ └── export/ (CSV/data export)
├── editors/
│ ├── TextEditor.tsx
│ ├── NumericEditor.tsx
│ ├── DateEditor.tsx
│ ├── SelectEditor.tsx
│ └── CustomEditor.tsx (extensibility point)
├── renderers/
│ ├── defaultRenderers.ts
│ ├── CustomRenderer.tsx (extensibility point)
│ └── formatters.ts (value formatting)
├── hooks/
│ ├── useGriddy.ts (main hook)
│ ├── useFiltering.ts
│ ├── useSorting.ts
│ ├── useSearch.ts
│ ├── useSelection.ts
│ ├── usePagination.ts
│ ├── useEditing.ts
│ └── useVirtualization.ts
├── adapters/
│ ├── LocalDataAdapter.ts
│ ├── RemoteServerAdapter.ts
│ ├── GraphQLAdapter.ts (optional)
│ └── RESTAdapter.ts (optional)
├── styles/
│ ├── griddy.module.css
│ └── themes.ts (theme system)
└── index.ts (exports)
```
## Feature Specifications
### Core Features
#### 1. Data Handling
- **Local Data**: Direct array-based data binding
- **Remote Server Data**: Async data fetching with loading states
- **Cursor-Based Paging**: Server-side paging with cursor tokens (for performance)
- **Offset-Based Paging**: Traditional offset/limit paging
- **Lazy Loading**: Data loaded as user scrolls (virtual scrolling integration)
- **Data Adapters**: Pluggable adapters for different data sources
API:
```typescript
interface GriddyDataSource {
data: T[]
total?: number
pageInfo?: { hasNextPage: boolean, cursor?: string }
isLoading?: boolean
error?: Error
}
interface GriddyProps<T> {
data: T[]
columns: Column<T>[]
onDataChange?: (data: T[]) => void
dataAdapter?: DataAdapter<T>
// ... other props
}
```
#### 2. Virtualization
- **Row Virtualization**: Only render visible rows using TanStack React Virtual
- **Column Virtualization**: Optionally virtualize columns for wide tables
- **Scrolling Performance**: Smooth scrolling with overscan optimization
- **Height Calculation**: Fixed height container with auto-height option
- **Sticky Headers**: Virtual header stays fixed while scrolling
Implementation:
- Use `@tanstack/react-virtual` for row/column virtualization
- Configurable overscan count for smooth scrolling
- Support both fixed and variable row heights
#### 3. Column Management
- **Column Definition**: Type-safe column definitions with accessors
- **Header Grouping**: Multi-level header groups (similar to Glide)
- **Column Pinning**: Freeze left/right columns
- **Column Resizing**: Drag-to-resize with min/max constraints
- **Column Hiding**: Show/hide columns dynamically
- **Column Reordering**: Drag-and-drop column reordering
- **Header Customization**: Custom header renderers
API:
```typescript
interface Column<T> {
id: string
header: string | ReactNode
accessor: keyof T | ((row: T) => any)
width?: number
minWidth?: number
maxWidth?: number
pinned?: 'left' | 'right'
sortable?: boolean
filterable?: boolean
searchable?: boolean
editable?: boolean
editor?: EditorComponent<T>
renderer?: RendererComponent<T>
headerGroup?: string
hidden?: boolean
}
```
#### 4. Filtering
- **Column Filtering**: Per-column filter UI (text, number, date, select)
- **Filter Modes**: Exact match, contains, starts with, ends with, between (for numbers/dates)
- **Multi-Filter**: Multiple filters per column with AND/OR logic
- **Filter Persistence**: Save/restore filter state
- **Custom Filters**: User-provided filter functions
Implementation:
- Filter dropdown in column header
- Configuration for filter types per column
- Debounced filtering for performance
#### 5. Search
- **Global Search**: Search across all searchable columns
- **Column Search**: Search within specific columns
- **Search Highlighting**: Highlight matching text
- **Search Navigation**: Navigate through search results
- **Fuzzy Search**: Optional fuzzy search capability
API:
```typescript
interface SearchConfig {
enabled: boolean
debounceMs?: number
fuzzy?: boolean
highlightMatches?: boolean
caseSensitive?: boolean
columnsToSearch?: string[] // column IDs
}
```
#### 6. Sorting
- **Single Column Sort**: Sort by one column (default)
- **Multi-Column Sort**: Sort by multiple columns with priority
- **Sort Direction**: Ascending/descending/unsorted
- **Custom Sort Functions**: User-provided sort comparators
- **Sort Persistence**: Save/restore sort state
- **Server-Side Sort**: Offload sorting to server
Implementation:
- Click header to sort (first click = asc, second = desc, third = unsorted)
- Shift+Click for multi-column sort
- Visual indicators in header (arrows/icons)
#### 7. Row/Column Selection
- **Row Selection**: Single or multi-select with checkboxes
- **Column Selection**: Select entire columns
- **Range Selection**: Rectangular range selection (like Glide)
- **Selection Callbacks**: On selection change events
- **Selection Persistence**: Maintain selection across pagination
- **Selection Styling**: Highlight selected rows/columns
API:
```typescript
interface SelectionConfig {
mode: 'none' | 'row' | 'column' | 'range'
multiSelect?: boolean
selectOnClick?: boolean
deselectOnClick?: boolean
onSelectionChange?: (selection: Selection) => void
}
```
#### 8. Grouping
- **Header Grouping**: Multi-level column groups (visual grouping only, no data aggregation initially)
- **Data Grouping**: Group rows by column value with collapsible groups
- **Aggregation**: Show aggregate values (count, sum, avg, etc.) in group headers
- **Group Actions**: Expand/collapse groups, delete groups
#### 9. In-Place Editing
- **Text Editor**: Simple text input with validation
- **Numeric Editor**: Number input with constraints
- **Date Editor**: Date picker or input
- **Select Editor**: Dropdown with predefined options
- **Custom Editors**: User-provided editor components
- **Validation**: Per-cell or per-row validation
- **Undo/Redo**: Optional undo/redo support
- **Batch Edits**: Edit multiple cells and submit together
API:
```typescript
interface EditorProps<T> {
value: any
column: Column<T>
row: T
onCommit: (newValue: any) => void
onCancel: () => void
onBlur?: () => void
}
interface Column<T> {
editor?: EditorComponent<T>
editable?: boolean | ((row: T) => boolean)
onEditCommit?: (newValue: any, row: T) => Promise<void>
validation?: (value: any) => string | null
}
```
#### 10. Pagination
- **Offset Pagination**: Page/limit based (e.g., page 1-10, 20 items per page)
- **Cursor Pagination**: Cursor-based (for infinite scroll or server-side)
- **Page Navigation**: Next/prev buttons, page input, jump to page
- **Items Per Page**: Configurable items per page with preset options
- **Total Count**: Display total items and current range
API:
```typescript
interface PaginationConfig {
enabled: boolean
type: 'offset' | 'cursor'
pageSize: number
pageSizeOptions?: number[]
onPageChange?: (page: number) => void
onPageSizeChange?: (pageSize: number) => void
}
```
#### 11. Extensibility
**Custom Cell Renderers**:
```typescript
interface RendererProps<T> {
value: any
row: T
column: Column<T>
rowIndex: number
columnIndex: number
isEditing?: boolean
}
type CellRenderer<T> = (props: RendererProps<T>) => ReactNode
```
**Custom Features via Hooks**:
- Users can wrap Griddy with custom hooks to add features
- Plugin architecture through context and callbacks
**Custom Editors**:
- Any component can be an editor if it implements EditorProps interface
**Custom Data Adapters**:
```typescript
interface DataAdapter<T> {
fetch: (config: FetchConfig) => Promise<GriddyDataSource<T>>
save: (row: T) => Promise<void>
delete: (row: T) => Promise<void>
}
```
---
## Architectural Patterns from Gridler to Adopt
### 1. Zustand Store Pattern
Gridler's `GridlerStore.tsx` demonstrates effective state management:
```typescript
// Griddy will follow similar pattern
const { Provider, useGriddyStore } = createSyncStore<GriddyState, GriddyProps>(
(set, get) => ({
// State mutations and getters
// Immer integration for immutable updates
// Custom methods for grid operations
})
)
```
**Benefits**: Reactive updates, easy testing, dev tools support, persistence support
### 2. Data Adapter Pattern
Gridler's adapters (LocalDataAdaptor, FormAdaptor, APIAdaptor) show clean separation:
- Adapters are wrapper components that consume store and trigger data operations
- They handle filtering, sorting, searching via store mutations
- Support both local and remote data without core changes
- Each adapter implements `useAPIQuery` pattern for pagination
**Griddy will adopt this for extensibility**:
```typescript
// Location: src/Griddy/adapters/
// - LocalDataAdapter.tsx (array data)
// - RemoteServerAdapter.tsx (API with cursor/offset paging)
// - CustomAdapter pattern for user extensions
```
### 3. Event System
Gridler uses `CustomEvent` for loose coupling between components:
```typescript
state._events.dispatchEvent(new CustomEvent('loadPage', { detail }))
state._events.addEventListener('reload', handler)
```
**Griddy benefit**: Allows features to trigger actions without tight coupling
### 4. Column Definition System
Gridler's `GridlerColumn` interface shows best practices:
- Optional `Cell` renderer for custom cell display
- `disableSort`, `disableFilter`, `disableMove`, `disableResize` flags
- Custom menu items via `getMenuItems`
- Tooltip support (string or function)
- Nested field access via dot notation
**Griddy will enhance this**:
```typescript
interface Column<T> {
id: string
header: string
accessor: keyof T | ((row: T) => any)
renderer?: (props: RendererProps<T>) => ReactNode
editor?: EditorComponent<T>
sortable?: boolean
filterable?: boolean
resizable?: boolean
pinned?: 'left' | 'right'
// ... more options
}
```
### 5. Ref-Based Imperative API
Gridler's `GridlerRef` provides necessary imperative operations:
```typescript
interface GridlerRef {
getState: () => GridlerState
refresh: () => Promise<void>
scrollToRow: (key: string | number) => Promise<void>
selectRow: (key: string | number) => Promise<void>
reloadRow: (key: string | number) => Promise<void>
}
```
**Griddy will provide similar imperative API for parent control**
### 6. Persistence Layer
Gridler uses localStorage for column state:
```typescript
persist={{
name: `Gridler_${props.uniqueid}`,
partialize: (s) => ({ colOrder: s.colOrder, colSize: s.colSize }),
version: 1,
}}
```
**Griddy will support this optional persistence**
---
## Implementation Phases
### Phase 1: Core Foundation (Weeks 1-2)
- [ ] Set up Griddy package structure
- [ ] Create core types and interfaces
- [ ] Implement basic Griddy component with:
- Simple table rendering (HTML `<table>`)
- Column definition system
- Basic props interface
- Initial Zustand store (optional, minimal state)
- [ ] Implement LocalDataAdapter
- [ ] Add Storybook stories for basic table
**Deliverable**: Functional table rendering local data with column definitions
### Phase 2: Virtualization & Performance (Weeks 2-3)
- [ ] Integrate TanStack React Virtual
- [ ] Implement row virtualization
- [ ] Implement sticky header with virtual scroll
- [ ] Add column resizing
- [ ] Performance optimization (memo, useMemo)
- [ ] Test with large datasets (10k+ rows)
**Deliverable**: High-performance virtualized table
### Phase 3: Data Handling (Weeks 3-4)
- [ ] Implement RemoteServerAdapter
- [ ] Add cursor-based pagination
- [ ] Add offset-based pagination
- [ ] Implement loading states
- [ ] Error handling and display
- [ ] Infinite scroll pattern
**Deliverable**: Full data source flexibility (local, remote, paginated)
### Phase 4: Selection & Interaction (Week 4)
- [ ] Row selection (checkbox + keyboard)
- [ ] Column selection
- [ ] Range selection
- [ ] Selection persistence
- [ ] Keyboard navigation (arrows, shift+click, etc.)
**Deliverable**: Full selection capabilities
### Phase 5: Filtering, Sorting, Search (Week 5)
- [ ] Sorting (single & multi-column)
- [ ] Column filtering UI and logic
- [ ] Global search
- [ ] Search highlighting
- [ ] Filter/sort state persistence
**Deliverable**: Data manipulation features
### Phase 6: In-Place Editing (Week 5-6)
- [ ] Text, Numeric, Date editors
- [ ] Select editor
- [ ] Validation system
- [ ] Edit callbacks (onEditCommit, onEditCancel)
- [ ] Undo/redo (optional)
- [ ] Trailing row for new records (optional)
**Deliverable**: Full editing capabilities
### Phase 7: Advanced Features (Week 6-7)
- [ ] Grouping (header groups)
- [ ] Data grouping with aggregation
- [ ] Column pinning/freezing
- [ ] Column reordering
- [ ] Column hiding/showing
- [ ] Export to CSV
**Deliverable**: Advanced features
### Phase 8: Polish & Documentation (Week 7-8)
- [ ] Comprehensive Storybook stories
- [ ] API documentation
- [ ] TypeScript definitions and examples
- [ ] Integration examples
- [ ] Performance benchmarks
- [ ] Accessibility improvements (ARIA, keyboard nav)
- [ ] Theme system documentation
**Deliverable**: Production-ready component
---
## Comparison with Competitors
### vs. Glide Data Editor
**Advantages**:
- No proprietary license needed
- Simpler API, less callback hell
- Smaller bundle size
- Framework agnostic (could be ported to Vue, Svelte, etc.)
- More transparent development
**Disadvantages**:
- Less mature (initially)
- Fewer enterprise features
- No rich text editing (not planned for MVP)
### vs. Mantine React Table
**Advantages**:
- Lighter weight
- Pure virtual rendering (no DOM overhead)
- More flexible CSS styling (pure HTML table)
- Better performance with large datasets
- Simpler core API
**Disadvantages**:
- No built-in Modal editing (only in-line)
- No tree/hierarchical data (initially)
- Requires Mantine knowledge (eventually provide integrations)
---
## Technology Stack
- **React**: 19.x (peer dependency)
- **TypeScript**: 5.9+
- **Virtualization**: @tanstack/react-virtual 3.13+
- **State Management**: Zustand (optional, for advanced features)
- **Styling**: CSS Modules + Mantine theming integration (optional)
- **Testing**: Vitest, React Testing Library
- **Build**: Vite with TypeScript declaration generation
---
## Dependencies
**Peer Dependencies**:
- react >= 19.0.0
- react-dom >= 19.0.0
- @tanstack/react-virtual >= 3.13.0
**Optional Peer Dependencies**:
- @mantine/core (for integrated theming)
- @tanstack/react-query (for server-side data)
**Dev Dependencies**:
- Same as Oranguru project (Vitest, Storybook, etc.)
---
## Testing Strategy
1. **Unit Tests**:
- Editor components
- Filter/Sort logic
- Data adapter functions
- Hook logic
2. **Integration Tests**:
- Column definition system
- Data flow end-to-end
- Selection with filtering
- Editing with validation
3. **Performance Tests**:
- Rendering 10k+ rows
- Filtering/sorting on large datasets
- Memory usage monitoring
4. **Accessibility Tests**:
- Keyboard navigation
- ARIA labels and roles
- Screen reader compatibility
---
## Browser Support
- Chrome/Edge: Latest 2 versions
- Firefox: Latest 2 versions
- Safari: Latest 2 versions
- No IE11 support (modern React requirement)
---
## Success Criteria
1. ✅ Table renders 10k+ rows smoothly (60fps)
2. ✅ Filtering/sorting on 10k rows completes in <500ms
3. ✅ TypeScript types cover 95%+ of code
4. ✅ Bundle size < 50KB (gzipped, excluding Mantine)
5. ✅ Full keyboard accessibility (WCAG AA)
6. ✅ 100+ Storybook stories covering all features
7. ✅ Zero external styling dependencies (works with any CSS)
8. ✅ All features tested with >80% coverage
---
## Known Limitations (Phase 1)
- Tree/hierarchical data: Planned for Phase 2
- Drag-and-drop column reordering: Phase 2
- Copy/paste: Phase 2
- Rich text/HTML content: Not planned
- Master-detail/expandable rows: Phase 2
---
## File Structure (Detailed)
```
src/Griddy/
├── core/
│ ├── Griddy.tsx # Main component
│ ├── GriddyContext.ts # React context
│ ├── GriddyStore.ts # Zustand store (optional)
│ ├── types.ts # Core types
│ ├── defaults.ts # Default config
│ └── constants.ts # Constants
├── virtualization/
│ ├── VirtualBody.tsx # Virtual row rendering
│ ├── VirtualHeader.tsx # Virtual column header
│ ├── hooks/
│ │ ├── useVirtualize.ts # Virtualization logic
│ │ └── useVirtualizeColumns.ts
│ └── utils/
│ └── sizing.ts # Size calculations
├── features/
│ ├── filtering/
│ │ ├── FilterControl.tsx
│ │ ├── useFiltering.ts
│ │ ├── types.ts
│ │ └── operators.ts
│ ├── sorting/
│ │ ├── SortIndicator.tsx
│ │ ├── useSorting.ts
│ │ └── types.ts
│ ├── search/
│ │ ├── SearchBox.tsx
│ │ ├── useSearch.ts
│ │ └── types.ts
│ ├── selection/
│ │ ├── SelectionCheckbox.tsx
│ │ ├── useSelection.ts
│ │ ├── types.ts
│ │ └── keyboard.ts
│ ├── grouping/
│ │ ├── HeaderGroup.tsx
│ │ ├── DataGrouping.tsx
│ │ ├── useGrouping.ts
│ │ └── types.ts
│ ├── editing/
│ │ ├── EditableCell.tsx
│ │ ├── useEditing.ts
│ │ ├── validation.ts
│ │ └── types.ts
│ ├── pagination/
│ │ ├── PaginationControl.tsx
│ │ ├── usePagination.ts
│ │ └── types.ts
│ ├── pinning/
│ │ ├── usePinning.ts
│ │ └── types.ts
│ └── resizing/
│ ├── useColumnResizing.ts
│ └── types.ts
├── editors/
│ ├── TextEditor.tsx
│ ├── NumericEditor.tsx
│ ├── DateEditor.tsx
│ ├── SelectEditor.tsx
│ ├── CheckboxEditor.tsx
│ └── index.ts
├── renderers/
│ ├── defaultRenderers.tsx
│ ├── formatters.ts
│ └── types.ts
├── adapters/
│ ├── LocalDataAdapter.ts
│ ├── RemoteServerAdapter.ts
│ ├── base.ts
│ └── types.ts
├── hooks/
│ ├── useGriddy.ts # Main hook composing all features
│ ├── useMergedRefs.ts
│ ├── useAsync.ts
│ └── index.ts
├── styles/
│ ├── griddy.module.css
│ ├── themes.ts
│ ├── variables.css
│ └── reset.css
├── utils/
│ ├── merge.ts
│ ├── classNames.ts
│ ├── keyboard.ts
│ ├── accessibility.ts
│ └── index.ts
├── index.ts # Main export
├── Griddy.test.tsx
└── README.md
```
---
## Next Steps
1. Review and approve this plan
2. Create project directory structure
3. Set up initial TypeScript types and interfaces
4. Begin Phase 1 implementation
5. Create Storybook stories alongside implementation