npm package: @forgedevstack/grid-table
Description: A powerful, headless grid table component for React with SCSS styling, drag-and-drop columns, filtering, sorting, and responsive mobile support
Author: John Yaghobieh
Latest version: 1.0.8

# @forgedevstack/grid-table

<p align="center">
  <img src="https://github.com/yaghobieh/grid-table/blob/main/docs/logo.svg" alt="Grid Table logo" width="120" />
</p>

**@forgedevstack/grid-table** v1.0.8 — A powerful, feature-rich data grid for React with 30+ features including cell editing, multi-format export, keyboard navigation, context menu, tree data, row reordering, frozen rows, undo/redo, print mode, and **server-driven (manual) pagination**. Zero-config SCSS styling. Part of [ForgeStack](https://forgedevstack.dev).

## Features

### Core
- **Server-driven pagination** — `paginationConfig.manualPagination` + `totalRowCount`: pass one page in `data` and load more in `onPageChange` (see portal **Server-driven** demo).
- **Cell Editing** — Double-click to edit inline with validation (text, number, select, date, boolean)
- **Dark/Light Theme** — Built-in theme support with customizable colors
- **Filtering** — Column-level and global filtering with multiple operators
- **Sorting** — Single and multi-column sorting with custom sort functions
- **Drag & Drop** — Reorder columns by dragging
- **Column Resize** — Adjust column widths by dragging
- **Pagination** — Built-in pagination with customizable page sizes
- **Row Selection** — Single and multi-select support
- **Row Expansion** — Expandable rows with custom content
- **Responsive** — Default **horizontal scroll** table on small screens; optional **`mobileLayout="stacked"`** for card layout. Drawer for filters/sorting. Disable breakpoints with `mobileBreakpoint="none"`.

### v1.0.8

- **Mobile layout** — `mobileLayout="scroll"` (default) shows the full header and columns with swipe scrolling; `mobileLayout="stacked"` uses the stacked card layout.
- **Hover** — Softer row hover when `tableEffects.hover` is enabled.

### v1.0.7
- **Keyboard Navigation** — Arrow keys, Tab, Enter to edit, Escape, Home/End, PageUp/Down
- **Context Menu** — Right-click for copy, filter, pin, hide. Custom actions supported
- **Tree Data** — Hierarchical rows with expand/collapse, indentation, and toggle arrows
- **Status Bar** — Footer with row count, selected count, and column aggregations (sum, avg, min, max)
- **Row Reordering** — Drag-and-drop rows with visual handle
- **Excel Export** — SpreadsheetML XML export, no dependencies
- **PDF Export** — Print-dialog-based PDF with styled table
- **CSV / JSON Export** — One-click export with `enableExport`
- **Copy to Clipboard** — Tab-separated clipboard copy
- **Undo/Redo** — Edit history with Ctrl+Z / Ctrl+Y (Cmd on Mac)
- **Column Pinning** — Runtime pin/unpin columns left or right
- **Column Auto-Fit** — Double-click to auto-size, or global auto-fit
- **Frozen Rows** — Pin rows to top or bottom of viewport
- **Print Mode** — Styled printable view with title and date

### Display
- **Table Effects** — Sort animations, row entry effects, hover highlights
- **Lazy Load** — Infinite scroll with configurable batch size
- **Skeleton Loading** — Beautiful loading states
- **Overflow Tooltip** — Show full cell content on hover when truncated
- **Expandable Sub-cell** — Extra content per cell via double-click or arrow
- **Studio Panel** — Development/prototyping side panel
- **Context API** — No prop drilling, access state from anywhere
- **TypeScript** — Full type safety
- **Accessible** — ARIA attributes and keyboard navigation

## Installation

```bash
npm i @forgedevstack/grid-table
```

### Import CSS (Required)

```tsx
import '@forgedevstack/grid-table/grid-table.css';
```

Bear styles are loaded automatically.

## Quick Start

```tsx
import { GridTable } from '@forgedevstack/grid-table';
import type { ColumnDefinition } from '@forgedevstack/grid-table';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
  [key: string]: unknown;
}

const columns: ColumnDefinition<User>[] = [
  { id: 'name', accessor: 'name', header: 'Name', sortable: true, filterable: true },
  { id: 'email', accessor: 'email', header: 'Email', sortable: true },
  { id: 'role', accessor: 'role', header: 'Role', filterType: 'select', filterOptions: [{ value: 'admin', label: 'Admin' }, { value: 'user', label: 'User' }] },
];

const data: User[] = [
  { id: 1, name: 'John Doe', email: 'john@example.com', role: 'admin' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'user' },
];

function App() {
  return (
    <GridTable
      data={data}
      columns={columns}
      enableRowSelection
      showPagination
      showFilter
      enableExport
      tableEffects={{ hover: true, sort: true, row: true }}
    />
  );
}
```

## Cell Editing

Double-click any editable cell to edit inline. Press Enter to save, Escape to cancel.

```tsx
const columns: ColumnDefinition<User>[] = [
  {
    id: 'name',
    accessor: 'name',
    header: 'Name',
    editable: true,
  },
  {
    id: 'role',
    accessor: 'role',
    header: 'Role',
    editable: {
      enabled: true,
      type: 'select',
      options: [
        { value: 'admin', label: 'Admin' },
        { value: 'editor', label: 'Editor' },
        { value: 'viewer', label: 'Viewer' },
      ],
      validate: (value) => value ? true : 'Role is required',
      onSave: (row, columnId, oldValue, newValue) => {
        console.log('Saved:', { row, columnId, oldValue, newValue });
      },
    },
  },
];

<GridTable
  data={data}
  columns={columns}
  enableCellEdit
  onCellEdit={(row, columnId, oldValue, newValue) => {
    console.log('Cell edited:', { row, columnId, oldValue, newValue });
  }}
/>
```

## Export (CSV, JSON, Excel, PDF)

```tsx
<GridTable
  data={data}
  columns={columns}
  enableExport={['csv', 'json', 'excel', 'pdf']}
  exportFileName="my-data"
  enableCopy
  printConfig={{ enabled: true, title: 'My Report' }}
/>
```

Or use the utilities directly:

```tsx
import { exportToCSV, exportToJSON, exportToExcel, exportToPDF, copyToClipboard, printTable } from '@forgedevstack/grid-table';

exportToCSV(data, columns, 'my-report');
exportToJSON(data, columns, 'my-report');
exportToExcel(data, columns, 'my-report');
exportToPDF(data, columns, 'my-report', 'Report Title');
copyToClipboard(data, columns);
printTable(data, columns, 'Print Title');
```

## Table Effects

Unified `tableEffects` prop controls all animations:

```tsx
<GridTable
  data={data}
  columns={columns}
  tableEffects={{
    hover: true,
    sort: true,
    row: true,
  }}
/>
```

Each effect accepts `true` for defaults or a config object:

```tsx
tableEffects={{
  hover: { enabled: true, bgColor: '#1a1a2e', accentBorder: true, className: 'my-hover' },
  sort: { enabled: true, flash: true, bounce: true },
  row: { enabled: true, staggerMs: 50, className: 'my-row-enter' },
  className: 'effects-active',
}}
```

## Tree Data

Render hierarchical data with expand/collapse:

```tsx
const treeData = [
  { id: 1, name: 'CEO', children: [
    { id: 2, name: 'CTO', children: [
      { id: 3, name: 'Lead Dev' },
    ]},
    { id: 4, name: 'CFO' },
  ]},
];

<GridTable
  data={treeData}
  columns={columns}
  treeData={{ enabled: true, childrenField: 'children', expandAll: false }}
/>
```

## Row Expansion

```tsx
<GridTable
  data={employees}
  columns={columns}
  enableRowExpansion
  defaultExpandedIds={[1, 5]}
  renderRowExpansion={(row) => <EmployeeDetail employee={row} />}
/>
```

## Keyboard Navigation

```tsx
<GridTable
  data={data}
  columns={columns}
  keyboardNavigation={{ enabled: true, enableEditOnEnter: true, wrap: true }}
/>
```

Arrow keys move between cells. Enter starts editing. Tab moves to next cell. Escape cancels editing.

## Context Menu

```tsx
<GridTable
  data={data}
  columns={columns}
  contextMenu={{
    enabled: true,
    showCopy: true,
    showFilter: true,
    showPin: true,
    showHide: true,
    actions: [
      { id: 'custom', label: 'Custom Action', onClick: (ctx) => console.log(ctx.value) },
    ],
  }}
/>
```

## Status Bar

```tsx
<GridTable
  data={data}
  columns={columns}
  statusBar={{
    enabled: true,
    showRowCount: true,
    showSelectedCount: true,
    showFilteredCount: true,
    aggregations: [
      { columnId: 'salary', type: 'sum', label: 'Total Salary', format: (v) => `$${v.toLocaleString()}` },
      { columnId: 'age', type: 'avg', label: 'Avg Age' },
    ],
  }}
/>
```

## Row Reordering

```tsx
<GridTable
  data={data}
  columns={columns}
  rowReorder={{ enabled: true }}
  onRowReorder={(newOrder) => setData(newOrder)}
/>
```

## Undo/Redo

```tsx
<GridTable
  data={data}
  columns={columns}
  enableCellEdit
  undoRedo={{ enabled: true, maxHistory: 50 }}
  onUndo={(rowId, colId, value) => console.log('Undone:', rowId, colId, value)}
  onRedo={(rowId, colId, value) => console.log('Redone:', rowId, colId, value)}
/>
```

## Frozen Rows

```tsx
<GridTable
  data={data}
  columns={columns}
  frozenRows={{
    top: [summaryRow],
    bottom: [totalRow],
  }}
/>
```

## Print Mode

```tsx
<GridTable
  data={data}
  columns={columns}
  printConfig={{
    enabled: true,
    title: 'Sales Report',
    showDate: true,
  }}
/>
```

## Lazy Load / Infinite Scroll

```tsx
<GridTable
  data={data}
  columns={columns}
  lazyLoad={{
    enabled: true,
    initialRows: 10,
    batchSize: 10,
    showLoader: true,
  }}
/>
```

## Theming

```tsx
const customTheme: Partial<Theme> = {
  mode: 'dark',
  colors: {
    background: { primary: '#1a1a2e', secondary: '#16213e', tertiary: '#0f3460', hover: '#1a1a2e' },
    text: { primary: '#eaeaea', secondary: '#a0a0a0', muted: '#707070' },
    accent: { primary: '#22c55e', success: '#4ade80', warning: '#fbbf24', error: '#f87171' },
  },
};

<GridTable data={data} columns={columns} theme={customTheme} />
```

## Bear Integration

Grid-table uses **@forgedevstack/bear** for UI controls. Set `themeMode` and `themeOverride` on GridTable to control Bear components inside:

```tsx
<GridTable
  data={data}
  columns={columns}
  themeMode="dark"
  themeOverride={{
    colors: {
      primary: '#22c55e',
      background: { default: '#0a0a14', paper: '#1a1a2e' },
      text: { primary: '#f8fafc', secondary: '#94a3b8' },
    },
  }}
/>
```

## Translations

```tsx
const customTranslations: Partial<Translations> = {
  empty: 'No records found',
  loading: 'Fetching data...',
  search: 'Search users...',
  rowsPerPage: 'Show',
};

<GridTable data={data} columns={columns} translations={customTranslations} />
```

## Responsive Breakpoints

```tsx
<GridTable
  data={data}
  columns={columns}
  mobileBreakpoint="tablet"
  mobileLayout="scroll"
  showMobileLabels={true}
  dimensions={{
    width: { mobile: '100%', tablet: '100%', desktop: 800 },
    height: { mobile: 400, tablet: 500, desktop: 600 },
  }}
/>
```

Use `mobileLayout="stacked"` for the previous label-per-cell mobile layout.

## Using Hooks

```tsx
import { TableProvider, useTable } from '@forgedevstack/grid-table';

function TableControls() {
  const { filter, sort, selection } = useTable();
  return (
    <div>
      <button onClick={() => filter.clearFilters()}>Clear Filters</button>
      <button onClick={() => sort.clearSorting()}>Clear Sort</button>
      <span>{selection.selectedIds.size} rows selected</span>
    </div>
  );
}
```

## Studio

Development panel for inspecting data, props, and generating sample rows:

```tsx
<GridTable data={data} columns={columns} studio />
```

## API Reference

### GridTable Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `T[]` | Required | Array of data objects |
| `columns` | `ColumnDefinition<T>[]` | Required | Column definitions |
| `loading` | `boolean` | `false` | Show loading skeleton |
| `error` | `Error \| string` | `null` | Error to display |
| `theme` | `Partial<Theme>` | Dark theme | Custom theme colors |
| `translations` | `Partial<Translations>` | English | Custom text labels |
| `themeMode` | `'light' \| 'dark' \| 'system'` | — | Light/dark mode |
| `themeOverride` | `Record<string, unknown>` | — | Bear theme object |
| `enableDragDrop` | `boolean` | `true` | Column reordering |
| `enableColumnResize` | `boolean` | `true` | Column resizing |
| `enableRowSelection` | `boolean` | `false` | Row selection |
| `enableMultiSelect` | `boolean` | `false` | Multi-row selection |
| `enableRowExpansion` | `boolean` | `false` | Row expansion |
| `enableCellEdit` | `boolean` | `false` | Enable inline cell editing |
| `enableExport` | `boolean \| string \| string[]` | `false` | Export buttons: `true`, `'csv'`, `['csv','excel','pdf']` |
| `exportFileName` | `string` | `'grid-table-export'` | Export file name |
| `enableCopy` | `boolean` | `false` | Show copy-to-clipboard button |
| `contextMenu` | `ContextMenuConfig` | — | Right-click context menu |
| `statusBar` | `StatusBarConfig` | — | Footer status bar |
| `frozenRows` | `FrozenRowsConfig` | — | Pin rows to top/bottom |
| `treeData` | `TreeConfig` | — | Hierarchical tree data |
| `keyboardNavigation` | `KeyboardNavConfig` | — | Arrow key navigation |
| `rowReorder` | `RowReorderConfig` | — | Drag-and-drop row reorder |
| `onRowReorder` | `(rows) => void` | — | Row reorder callback |
| `undoRedo` | `UndoRedoConfig` | — | Edit undo/redo |
| `onUndo` | `(rowId, colId, value) => void` | — | Undo callback |
| `onRedo` | `(rowId, colId, value) => void` | — | Redo callback |
| `printConfig` | `PrintConfig` | — | Print mode config |
| `autoFit` | `AutoFitConfig` | — | Column auto-fit |
| `showPagination` | `boolean` | `true` | Pagination controls |
| `showFilter` | `boolean` | `true` | Filter controls |
| `showGlobalFilter` | `boolean` | `true` | Global search |
| `showOverflowTooltip` | `boolean` | `true` | Tooltip on truncated cells |
| `stickyHeader` | `boolean` | `true` | Sticky header |
| `tableEffects` | `TableEffects` | — | Sort/hover/row animations |
| `defaultExpandedIds` | `Array<string \| number>` | — | IDs to expand on mount |
| `lazyLoad` | `LazyLoadConfig` | — | Infinite scroll config |
| `onCellEdit` | `(row, colId, old, new) => void` | — | Cell edit callback |
| `onRowClick` | `(row, index) => void` | — | Row click callback |
| `onRowSelect` | `(selectedRows) => void` | — | Selection callback |
| `onSort` | `(sorting) => void` | — | Sort change callback |
| `onPageChange` | `(page, pageSize) => void` | — | Page change callback |
| `studio` | `boolean` | `false` | Show Studio panel |

### ColumnDefinition

| Property | Type | Description |
|----------|------|-------------|
| `id` | `string` | Unique column identifier |
| `accessor` | `string \| (row) => unknown` | Data accessor |
| `header` | `ReactNode \| () => ReactNode` | Header content |
| `width` | `ResponsiveValue<number \| string>` | Column width |
| `align` | `'left' \| 'center' \| 'right'` | Text alignment |
| `sortable` | `boolean` | Enable sorting |
| `filterable` | `boolean` | Enable filtering |
| `draggable` | `boolean` | Allow drag reorder |
| `resizable` | `boolean` | Allow resize |
| `hidden` | `boolean` | Initially hidden |
| `editable` | `boolean \| CellEditConfig` | Enable inline editing |
| `render` | `(value, row, index) => ReactNode` | Custom cell renderer |
| `filterType` | `'text' \| 'number' \| 'select' \| ...` | Filter input type |
| `showOverflowTooltip` | `boolean` | Tooltip on truncated cell |
| `renderSubCell` | `(row) => ReactNode` | Expandable sub-content |

### TableEffects

| Property | Type | Description |
|----------|------|-------------|
| `hover` | `boolean \| HoverEffectConfig` | Hover highlight effect |
| `sort` | `boolean \| SortEffectConfig` | Sort animation effect |
| `row` | `boolean \| RowEffectConfig` | Row entry animation |
| `className` | `string` | Custom class on root |

### LazyLoadConfig

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `enabled` | `boolean` | Required | Enable lazy loading |
| `initialRows` | `number` | `20` | Rows shown initially |
| `batchSize` | `number` | `10` | Rows per scroll load |
| `showLoader` | `boolean` | `true` | Show loading indicator |
| `loadingContent` | `ReactNode` | — | Custom loader |

### CellEditConfig

| Property | Type | Description |
|----------|------|-------------|
| `enabled` | `boolean` | Enable editing for this column |
| `type` | `'text' \| 'number' \| 'select' \| 'date' \| 'boolean'` | Input type |
| `options` | `Array<{ value, label }>` | Options for select type |
| `validate` | `(value, row) => string \| true` | Validation function |
| `onSave` | `(row, colId, old, new) => void` | Save callback |
| `placeholder` | `string` | Input placeholder |

### Exports

```tsx
import {
  // Components
  GridTable,
  EditableCell,
  GridHeader,
  GridBody,
  GridRow,
  GridCell,
  Pagination,
  Skeleton,
  EmptyState,
  ContextMenu,
  StatusBar,
  // Context
  TableProvider,
  useTableContext,
  // Hooks
  useTable,
  useSort,
  useFilter,
  usePagination,
  useDragDrop,
  useBreakpoint,
  useKeyboardNavigation,
  useRowReorder,
  useUndoRedo,
  useTreeData,
  // Utils
  exportToCSV,
  exportToJSON,
  exportToExcel,
  exportToPDF,
  copyToClipboard,
  printTable,
  computeAggregation,
} from '@forgedevstack/grid-table';
```

## Portal

The grid-table portal is a full documentation + demo website:

- **Home** — Feature showcase, demo mesh, ecosystem banner
- **Demos** — Finance (live data), HR (tree view), Basic (all props)
- **Playground** — Toggle props live, auto-generated code
- **Theme Builder** — Customize colors and export code
- **Docs** — Getting started, API reference, guides
- **Changelog** — Full version history
- **i18n** — English and Spanish
- **Cmd+K** — Quick search across all pages

Run the portal:

```bash
cd portal && npm i && npm run dev
```

## License

MIT