Skip to content

Latest commit

 

History

History

README.md

@object-ui/plugin-grid

Grid plugin for Object UI - Advanced data grid with sorting, filtering, and pagination.

Features

  • Data Grid - Enterprise-grade data grid component
  • Sorting - Multi-column sorting support
  • Filtering - Column-level filtering
  • Pagination - Built-in pagination controls
  • Row Selection - Single and multi-row selection
  • Customizable - Tailwind CSS styling support

Installation

pnpm add @object-ui/plugin-grid

Usage

Automatic Registration (Side-Effect Import)

// In your app entry point (e.g., App.tsx or main.tsx)
import '@object-ui/plugin-grid';

// Now you can use grid types in your schemas
const schema = {
  type: 'grid',
  columns: [
    { header: 'Name', accessorKey: 'name' },
    { header: 'Email', accessorKey: 'email' }
  ],
  data: []
};

Manual Registration

import { gridComponents } from '@object-ui/plugin-grid';
import { ComponentRegistry } from '@object-ui/core';

// Register grid components
Object.entries(gridComponents).forEach(([type, component]) => {
  ComponentRegistry.register(type, component);
});

Schema API

Grid

Data grid with advanced features:

{
  type: 'grid',
  columns: GridColumn[],
  data?: any[],
  sortable?: boolean,
  filterable?: boolean,
  pagination?: boolean | PaginationConfig,
  selectable?: boolean,
  onRowClick?: (row) => void,
  className?: string
}

Column Definition

interface GridColumn {
  header: string;
  accessorKey: string;
  sortable?: boolean;
  filterable?: boolean;
  width?: number | string;
  align?: 'left' | 'center' | 'right';
  cell?: (value, row) => ReactNode;
}

Examples

Basic Grid

const schema = {
  type: 'grid',
  columns: [
    { header: 'ID', accessorKey: 'id', width: 80 },
    { header: 'Name', accessorKey: 'name' },
    { header: 'Email', accessorKey: 'email' },
    { header: 'Role', accessorKey: 'role' },
    { header: 'Status', accessorKey: 'status' }
  ],
  data: [
    { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'Active' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', status: 'Active' }
  ],
  sortable: true,
  filterable: true,
  pagination: true
};

Grid with Custom Cells

const schema = {
  type: 'grid',
  columns: [
    { header: 'Name', accessorKey: 'name' },
    { 
      header: 'Status', 
      accessorKey: 'status',
      cell: (value) => ({
        type: 'badge',
        label: value,
        variant: value === 'Active' ? 'success' : 'default'
      })
    },
    {
      header: 'Actions',
      accessorKey: 'id',
      cell: (value, row) => ({
        type: 'button-group',
        buttons: [
          { label: 'Edit', onClick: () => console.log('Edit', row) },
          { label: 'Delete', variant: 'destructive', onClick: () => console.log('Delete', row) }
        ]
      })
    }
  ],
  data: [/* data */]
};

Selectable Grid

const schema = {
  type: 'grid',
  columns: [/* columns */],
  data: [/* data */],
  selectable: true,
  onRowClick: (row) => {
    console.log('Row clicked:', row);
  },
  onSelectionChange: (selectedRows) => {
    console.log('Selection changed:', selectedRows);
  }
};

Grid with Pagination

const schema = {
  type: 'grid',
  columns: [/* columns */],
  data: [/* data */],
  pagination: {
    pageSize: 10,
    showSizeChanger: true,
    pageSizeOptions: [10, 20, 50, 100]
  }
};

Integration with Data Sources

Connect grid to backend APIs:

import { createObjectStackAdapter } from '@object-ui/data-objectstack';

const dataSource = createObjectStackAdapter({
  baseUrl: 'https://api.example.com',
  token: 'your-auth-token'
});

const schema = {
  type: 'object-grid',
  dataSource,
  object: 'users',
  columns: [
    { header: 'Name', accessorKey: 'name' },
    { header: 'Email', accessorKey: 'email' },
    { header: 'Created', accessorKey: 'created_at' }
  ],
  pagination: true,
  sortable: true,
  filterable: true
};

Features

Sorting

Enable sorting on columns:

const schema = {
  type: 'grid',
  sortable: true,  // Enable sorting on all columns
  columns: [
    { header: 'Name', accessorKey: 'name', sortable: true },
    { header: 'Email', accessorKey: 'email', sortable: false }  // Disable for specific column
  ]
};

Filtering

Enable column filtering:

const schema = {
  type: 'grid',
  filterable: true,
  columns: [
    { header: 'Status', accessorKey: 'status', filterable: true }
  ]
};

Row Actions

Add actions to rows:

const schema = {
  type: 'grid',
  columns: [/* columns */],
  rowActions: [
    { label: 'View', onClick: (row) => console.log('View', row) },
    { label: 'Edit', onClick: (row) => console.log('Edit', row) },
    { label: 'Delete', onClick: (row) => console.log('Delete', row) }
  ]
};

Inline Editing

Enable inline cell editing for quick updates:

const schema = {
  type: 'object-grid',
  objectName: 'users',
  columns: [
    { header: 'ID', accessorKey: 'id', editable: false },  // Read-only column
    { header: 'Name', accessorKey: 'name' },  // Editable
    { header: 'Email', accessorKey: 'email' },  // Editable
    { header: 'Status', accessorKey: 'status' }  // Editable
  ],
  editable: true,  // Enable editing globally
  onCellChange: (rowIndex, columnKey, newValue, row) => {
    console.log(`Cell at row ${rowIndex}, column ${columnKey} changed to:`, newValue);
    console.log('Full row data:', row);
    // Update your data source here
    // Example: await dataSource.update(row.id, { [columnKey]: newValue });
  }
};

Inline Editing Features:

  • Double-click to edit: Double-click any editable cell to enter edit mode
  • Keyboard shortcuts:
    • Press Enter on a focused cell to start editing
    • Press Enter while editing to save changes
    • Press Escape to cancel editing
  • Column-level control: Set editable: false on specific columns to prevent editing
  • Visual feedback: Editable cells show hover state to indicate they can be edited
  • Automatic focus: Input field is automatically focused and selected when entering edit mode

Use Cases:

  • Quick data corrections
  • Batch data entry
  • Spreadsheet-like editing experience
  • Real-time updates with backend synchronization

Batch Editing & Multi-Row Save

Edit multiple cells across multiple rows and save them individually or all at once:

const schema = {
  type: 'object-grid',
  objectName: 'products',
  columns: [
    { header: 'SKU', accessorKey: 'sku', editable: false },
    { header: 'Name', accessorKey: 'name' },
    { header: 'Price', accessorKey: 'price' },
    { header: 'Stock', accessorKey: 'stock' }
  ],
  editable: true,
  rowActions: true,  // Show row-level save/cancel buttons
  onRowSave: async (rowIndex, changes, row) => {
    // Save a single row
    console.log('Saving row:', rowIndex, changes);
    await dataSource.update(row.id, changes);
  },
  onBatchSave: async (allChanges) => {
    // Save all modified rows at once
    console.log('Batch saving:', allChanges);
    await Promise.all(
      allChanges.map(({ row, changes }) => 
        dataSource.update(row.id, changes)
      )
    );
  }
};

Batch Editing Features:

  • Pending changes tracking: Edit multiple cells across multiple rows before saving
  • Visual indicators:
    • Modified rows are highlighted with amber background
    • Modified cells are shown in bold with amber text
    • Toolbar shows count of modified rows
  • Row-level actions: Save or cancel changes for individual rows
  • Batch operations:
    • "Save All" button to save all modified rows at once
    • "Cancel All" button to discard all pending changes
  • Flexible callbacks:
    • onRowSave: Called when saving a single row
    • onBatchSave: Called when saving multiple rows at once
    • onCellChange: Still called for immediate cell updates (legacy support)

Example Workflow:

  1. User edits multiple cells across different rows
  2. Modified rows are visually highlighted
  3. Toolbar shows "X rows modified" with Save All/Cancel All buttons
  4. User can:
    • Save individual rows using row-level save button
    • Save all changes at once using "Save All" button
    • Cancel individual row changes or all changes

TypeScript Support

import type { GridSchema, GridColumn } from '@object-ui/plugin-grid';

const nameColumn: GridColumn = {
  header: 'Name',
  accessorKey: 'name',
  sortable: true
};

const grid: GridSchema = {
  type: 'grid',
  columns: [nameColumn],
  data: [],
  sortable: true,
  pagination: true
};

License

MIT