From 6d73e83fbfa1db0606c060dfd39df0e815a20e08 Mon Sep 17 00:00:00 2001 From: Hein Date: Thu, 12 Feb 2026 18:55:15 +0200 Subject: [PATCH] docs(plan): add feature complete implementation plan --- src/Griddy/plan.md | 702 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 src/Griddy/plan.md diff --git a/src/Griddy/plan.md b/src/Griddy/plan.md new file mode 100644 index 0000000..cab8c4f --- /dev/null +++ b/src/Griddy/plan.md @@ -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 { + data: T[] + columns: Column[] + onDataChange?: (data: T[]) => void + dataAdapter?: DataAdapter + // ... 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 { + 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 + renderer?: RendererComponent + 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 { + value: any + column: Column + row: T + onCommit: (newValue: any) => void + onCancel: () => void + onBlur?: () => void +} + +interface Column { + editor?: EditorComponent + editable?: boolean | ((row: T) => boolean) + onEditCommit?: (newValue: any, row: T) => Promise + 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 { + value: any + row: T + column: Column + rowIndex: number + columnIndex: number + isEditing?: boolean +} + +type CellRenderer = (props: RendererProps) => 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 { + fetch: (config: FetchConfig) => Promise> + save: (row: T) => Promise + delete: (row: T) => Promise +} +``` + +--- + +## 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( + (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 { + id: string + header: string + accessor: keyof T | ((row: T) => any) + renderer?: (props: RendererProps) => ReactNode + editor?: EditorComponent + 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 + scrollToRow: (key: string | number) => Promise + selectRow: (key: string | number) => Promise + reloadRow: (key: string | number) => Promise +} +``` +**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 ``) + - 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