npm package: @mehdashti/tables
Description: Enterprise-grade data table components for Smart Platform
Author: mehdashti
Latest version: 1.2.0

# @mehdashti/tables

Enterprise-grade data tables with TanStack Table v8 for Smart Platform.

## Features

### Core Table Features
- **Powerful Sorting**: Multi-column sorting with custom sort functions
- **Advanced Filtering**: Filter Builder with complex AND/OR conditions
- **Pagination**: Both client-side and server-side pagination support
- **Row Selection**: Single and multi-row selection with bulk actions
- **Column Management**: Dynamic show/hide with mobile-responsive defaults
- **Type Safe**: Full TypeScript support with strict types
- **Customizable**: Custom cell renderers and formatters
- **Loading States**: Built-in loading and empty state handling

### Enterprise Features (Phase 2)
- **Bulk Actions**: Toolbar with actions for selected rows (delete, export, archive, etc.)
- **Data Export**: Export to CSV or Excel with customizable columns
- **Aggregations**: Summary row with sum, average, min, max calculations
- **Inline Editing**: Edit cells directly with validation and auto-save
- **Row Actions**: Edit/Cancel/Save actions for row-level editing

### Advanced Features (Phase 5)
- **Filter Builder**: Visual query builder with multiple operators and conditions
- **Filter Chips**: Display active filters as removable chips
- **Saved Filters**: Save and manage filter presets with defaults
- **Mobile Card View**: Responsive card layout for mobile devices
- **Adaptive Columns**: Auto-hide columns on mobile with visibility toggle

## Installation

```bash
pnpm add @mehdashti/tables
```

## Usage

### Basic Table

```tsx
import { DataTable } from '@mehdashti/tables'
import { ColumnDef } from '@tanstack/react-table'

interface User {
  id: string
  name: string
  email: string
  role: string
}

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: 'Name',
  },
  {
    accessorKey: 'email',
    header: 'Email',
  },
  {
    accessorKey: 'role',
    header: 'Role',
  },
]

function UserTable() {
  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' },
  ]

  return (
    <DataTable
      columns={columns}
      data={data}
      pagination
      sorting
    />
  )
}
```

### With Filtering

```tsx
<DataTable
  columns={columns}
  data={data}
  filtering
  globalFilter
  placeholder="Search users..."
/>
```

### With Row Selection

```tsx
function UserTable() {
  const [rowSelection, setRowSelection] = useState({})

  return (
    <DataTable
      columns={columns}
      data={data}
      rowSelection
      onRowSelectionChange={setRowSelection}
    />
  )
}
```

### Server-Side Pagination

```tsx
function UserTable() {
  const [pagination, setPagination] = useState({
    pageIndex: 0,
    pageSize: 10,
  })

  const { data, isLoading } = useQuery({
    queryKey: ['users', pagination],
    queryFn: () => fetchUsers(pagination),
  })

  return (
    <DataTable
      columns={columns}
      data={data?.items ?? []}
      pagination
      pageCount={data?.totalPages}
      onPaginationChange={setPagination}
      isLoading={isLoading}
      manualPagination
    />
  )
}
```

## Column Helpers

Utility functions for common column types:

### Sortable Header

```tsx
import { createSortableHeader } from '@mehdashti/tables'

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: ({ column }) => createSortableHeader(column, 'Name'),
  },
]
```

### Selection Column

```tsx
import { createSelectionColumn } from '@mehdashti/tables'

const columns = [
  createSelectionColumn<User>(),
  // ... other columns
]
```

### Date Column

```tsx
import { createDateColumn } from '@mehdashti/tables'

const columns = [
  createDateColumn<User>('createdAt', 'Created', {
    format: 'MMM dd, yyyy',
  }),
]
```

### Badge Column

```tsx
import { createBadgeColumn } from '@mehdashti/tables'

const columns = [
  createBadgeColumn<User>('status', 'Status', {
    active: 'success',
    inactive: 'secondary',
    pending: 'warning',
  }),
]
```

### Actions Column

```tsx
import { createActionsColumn } from '@mehdashti/tables'

const columns = [
  createActionsColumn<User>({
    onEdit: (user) => console.log('Edit', user),
    onDelete: (user) => console.log('Delete', user),
    onView: (user) => console.log('View', user),
  }),
]
```

## API

### DataTable Props

```typescript
interface DataTableProps<TData> {
  columns: ColumnDef<TData>[]
  data: TData[]

  // Features
  pagination?: boolean
  sorting?: boolean
  filtering?: boolean
  rowSelection?: boolean
  globalFilter?: boolean

  // Pagination
  pageSize?: number
  pageCount?: number
  onPaginationChange?: (updater: Updater<PaginationState>) => void
  manualPagination?: boolean

  // Sorting
  onSortingChange?: (updater: Updater<SortingState>) => void
  manualSorting?: boolean

  // Filtering
  onFilteringChange?: (updater: Updater<ColumnFiltersState>) => void
  onGlobalFilterChange?: (value: string) => void
  manualFiltering?: boolean

  // Selection
  onRowSelectionChange?: (updater: Updater<RowSelectionState>) => void

  // UI
  isLoading?: boolean
  emptyMessage?: string
  placeholder?: string
  showColumnVisibility?: boolean

  // Styling
  className?: string
}
```

## Enterprise Features

### Bulk Actions

Handle multiple rows with bulk action toolbar.

```tsx
import { DataTable, BulkActionsToolbar } from '@mehdashti/tables'

function UserTable() {
  const [rowSelection, setRowSelection] = useState({})

  const handleDelete = (selectedRows: User[]) => {
    console.log('Delete', selectedRows)
  }

  const handleExport = (selectedRows: User[]) => {
    console.log('Export', selectedRows)
  }

  return (
    <>
      <BulkActionsToolbar
        selectedCount={Object.keys(rowSelection).length}
        onDelete={handleDelete}
        onExport={handleExport}
        actions={[
          { label: 'Archive', onClick: handleArchive },
          { label: 'Tag', onClick: handleTag },
        ]}
      />
      <DataTable
        columns={columns}
        data={data}
        rowSelection
        onRowSelectionChange={setRowSelection}
      />
    </>
  )
}
```

### Data Export

Export table data to CSV or Excel.

```tsx
import { ExportButton } from '@mehdashti/tables'

<ExportButton
  data={data}
  filename="users"
  format="csv"
  columns={['name', 'email', 'role']}
/>

// Or export to Excel
<ExportButton
  data={data}
  filename="users"
  format="xlsx"
/>
```

### Aggregation Row

Show summary calculations at the bottom of the table.

```tsx
import { AggregationRow } from '@mehdashti/tables'

<AggregationRow
  columns={[
    { field: 'revenue', type: 'sum', label: 'Total Revenue' },
    { field: 'orders', type: 'count', label: 'Total Orders' },
    { field: 'rating', type: 'avg', label: 'Avg Rating' },
  ]}
  data={data}
/>
```

### Inline Editing

Edit cells directly with validation.

```tsx
import { EditableCell, RowEditActions } from '@mehdashti/tables'

const columns = [
  {
    accessorKey: 'name',
    header: 'Name',
    cell: ({ row, getValue }) => (
      <EditableCell
        value={getValue()}
        onSave={(value) => handleSave(row.id, 'name', value)}
        isEditing={row.getIsEditing()}
      />
    ),
  },
  {
    id: 'actions',
    cell: ({ row }) => (
      <RowEditActions
        isEditing={row.getIsEditing()}
        onEdit={() => row.toggleEditing()}
        onSave={() => handleRowSave(row)}
        onCancel={() => row.toggleEditing()}
      />
    ),
  },
]
```

## Advanced Features

### Filter Builder

Build complex filter queries with AND/OR logic.

```tsx
import { FilterBuilder, type FilterGroup } from '@mehdashti/tables'

function TableWithFilters() {
  const [filter, setFilter] = useState<FilterGroup>({
    id: '1',
    logic: 'AND',
    conditions: [],
  })

  return (
    <FilterBuilder
      fields={[
        { name: 'name', label: 'Name', type: 'string' },
        { name: 'age', label: 'Age', type: 'number' },
        { name: 'status', label: 'Status', type: 'string' },
      ]}
      value={filter}
      onChange={setFilter}
    />
  )
}
```

### Filter Chips

Display and manage active filters.

```tsx
import { FilterChips } from '@mehdashti/tables'

<FilterChips
  filter={currentFilter}
  onRemove={(conditionId) => handleRemoveFilter(conditionId)}
  onClear={() => setFilter({ id: '1', logic: 'AND', conditions: [] })}
  fieldLabels={{
    name: 'Full Name',
    email: 'Email Address',
    status: 'Account Status',
  }}
/>
```

### Saved Filters

Save and reuse filter presets.

```tsx
import { SavedFilters, type SavedFilter } from '@mehdashti/tables'

function TableWithSavedFilters() {
  const [savedFilters, setSavedFilters] = useState<SavedFilter[]>([])
  const [currentFilter, setCurrentFilter] = useState<FilterGroup>(...)

  return (
    <SavedFilters
      filters={savedFilters}
      currentFilter={currentFilter}
      onApply={(filter) => setCurrentFilter(filter.filter)}
      onSave={(name) => {
        const newFilter = {
          id: generateId(),
          name,
          filter: currentFilter,
          createdAt: new Date(),
        }
        setSavedFilters([...savedFilters, newFilter])
      }}
      onDelete={(id) => {
        setSavedFilters(savedFilters.filter((f) => f.id !== id))
      }}
      onSetDefault={(id) => {
        setSavedFilters(
          savedFilters.map((f) => ({
            ...f,
            isDefault: f.id === id,
          }))
        )
      }}
    />
  )
}
```

### Mobile Card View

Responsive card layout for mobile devices.

```tsx
import { MobileCardView, type MobileCardField } from '@mehdashti/tables'

const fields: MobileCardField<User>[] = [
  {
    accessorKey: 'name',
    label: 'Name',
    primary: true, // Show as card title
  },
  {
    accessorKey: 'email',
    label: 'Email',
  },
  {
    accessorKey: 'role',
    label: 'Role',
    render: (value) => <Badge>{value}</Badge>,
  },
  {
    accessorKey: 'internalId',
    label: 'Internal ID',
    hideOnMobile: true, // Hide on mobile
  },
]

<MobileCardView
  data={users}
  fields={fields}
  onCardClick={(user) => navigate(`/users/${user.id}`)}
  isLoading={isLoading}
  emptyMessage="No users found"
/>
```

### Column Visibility Toggle

Manage column visibility with mobile defaults.

```tsx
import { ColumnVisibilityToggle, type ColumnConfig } from '@mehdashti/tables'

const columns: ColumnConfig[] = [
  { id: 'name', label: 'Name', enableHiding: false },
  { id: 'email', label: 'Email' },
  { id: 'phone', label: 'Phone', hideOnMobile: true },
  { id: 'address', label: 'Address', hideOnMobile: true },
  { id: 'status', label: 'Status' },
]

<ColumnVisibilityToggle
  columns={columns}
  visibility={columnVisibility}
  onChange={setColumnVisibility}
/>
```

## API Reference

### Components

- `DataTable` - Main table component with all features
- `BulkActionsToolbar` - Toolbar for bulk operations
- `ExportButton` - Export data to CSV/Excel
- `AggregationRow` - Summary calculations row
- `EditableCell` - Inline editable cell
- `EditableSelectCell` - Inline editable select cell
- `RowEditActions` - Edit/Save/Cancel actions for rows
- `FilterBuilder` - Visual query builder
- `FilterChips` - Active filter display
- `SavedFilters` - Filter preset management
- `MobileCardView` - Mobile-optimized card layout
- `ColumnVisibilityToggle` - Column visibility control

### Column Helpers

- `createSortableHeader` - Sortable column header
- `createSelectionColumn` - Checkbox selection column
- `createDateColumn` - Formatted date column
- `createBadgeColumn` - Badge status column
- `createActionsColumn` - Row actions dropdown

### Types

```typescript
export type FilterOperator =
  | "equals" | "notEquals"
  | "contains" | "notContains"
  | "startsWith" | "endsWith"
  | "greaterThan" | "lessThan"
  | "greaterThanOrEqual" | "lessThanOrEqual"
  | "between" | "in" | "notIn"
  | "isEmpty" | "isNotEmpty"

export type FilterCondition = {
  id: string
  field: string
  operator: FilterOperator
  value: any
  type?: "string" | "number" | "date" | "boolean"
}

export type FilterGroup = {
  id: string
  logic: "AND" | "OR"
  conditions: (FilterCondition | FilterGroup)[]
}

export interface MobileCardField<TData> {
  accessorKey: keyof TData
  label: string
  render?: (value: any, row: TData) => React.ReactNode
  primary?: boolean
  hideOnMobile?: boolean
}

export interface ColumnConfig {
  id: string
  label: string
  hideOnMobile?: boolean
  enableHiding?: boolean
}
```

## Examples

See [Storybook stories](./src/components/data-table.stories.tsx) for interactive examples.

## License

MIT