# React Dynamic Table

A highly configurable, feature-rich table component library for React applications with advanced rendering capabilities, dark mode support, and flexible customization options.

## Features

- 🔄 **Dynamic Data Rendering**: Display any data structure with custom cell rendering
- 🌗 **Dark Mode Support**: Built-in light and dark theme compatibility
- 📱 **Responsive Design**: Mobile-friendly layout with responsive controls
- 📊 **Advanced Pagination**: Intuitive pagination with configurable controls
- 🧩 **Composable Components**: Use the entire table or individual components
- 🔍 **Search & Filtering**: Built-in search functionality
- 📝 **Customizable Headers & Cells**: Full control over column rendering
- 🔗 **Automatic Link Support**: Both standard and Next.js links supported
- 🎨 **Style Flexibility**: Easy styling with Tailwind CSS and className props
- ⚠️ **Error Handling**: Robust error recovery with useful debug information

## Installation

```bash
npm install react-dynamic-table
# or
yarn add react-dynamic-table
```

## Basic Usage

```tsx
import { DynamicTable } from "react-dynamic-table";

// Sample data
const users = [
  { id: 1, name: "John Doe", email: "john@example.com", status: "Active" },
  { id: 2, name: "Jane Smith", email: "jane@example.com", status: "Inactive" },
  // ...more data
];

// Column configuration
const columns = [
  { columnName: "ID", accessor: "id" },
  { columnName: "Name", accessor: "name" },
  { columnName: "Email", accessor: "email" },
  {
    columnName: "Status",
    accessor: "status",
    useChip: true,
    chipOptions: {
      className: (item) =>
        item.status === "Active"
          ? "bg-green-100 text-green-800"
          : "bg-red-100 text-red-800",
    },
  },
  {
    columnName: "Actions",
    useAction: true,
    actionOptions: {
      components: (item) => (
        <div className="flex space-x-2">
          <button className="text-blue-600 hover:underline">Edit</button>
          <button className="text-red-600 hover:underline">Delete</button>
        </div>
      ),
    },
  },
];

function UserTable() {
  return (
    <DynamicTable
      items={users}
      columns={columns}
      tableName="Users"
      keyAccessor="id"
      topContentOptions={{
        searchInput: {
          placeholder: "Search users...",
          onChange: (e) => console.log(e.target.value),
        },
        addButton: {
          title: "Add User",
          onClick: () => console.log("Add user clicked"),
        },
      }}
      usePagination={true}
      pagination={{
        page: 1,
        per_page: 10,
        totalPages: 5,
        handlePageChange: (page) => console.log(`Page changed to ${page}`),
      }}
    />
  );
}
```

## Advanced Configuration

### Column Types

The library supports various column types with specific rendering behaviors:

```tsx
type ColumnType<K extends string> = {
  // Basic properties
  columnName: string; // Display name in the header
  accessor?: K; // Data property to access (supports dot notation)
  static?: string | number; // Static value for all cells in this column
  showIf?: boolean; // Conditional display of the entire column
  rename?: string; // Alternative display name

  // Rendering options
  useDate?: boolean; // Format as date
  join?: K[]; // Join multiple fields

  // Special column types
  useAction?: boolean; // Action buttons column
  actionOptions?: ActionsType;

  useOption?: boolean; // Dropdown/select column
  optionOptions?: OptionOptions;

  useLink?: boolean; // Make content a clickable link
  linkOptions?: LinkOptionsType;

  useChip?: boolean; // Display as a badge/chip
  chipOptions?: ChipOptions;

  // Conditional rendering
  useCondition?: boolean;
  condtions?: ColumnConditionsType<K>[];

  // Custom props
  normalProps?: {
    th?: HTMLProps<HTMLTableColElement>;
    td?: HTMLProps<HTMLTableCellElement>;
  };
};
```

### Pagination

Configure pagination with the following options:

```tsx
type PAGINATION_TYPE = {
  per_page: number; // Items per page
  page: number; // Current page
  totalPages: number; // Total number of pages
  handlePageChange: (page: number) => void; // Page change handler
  per_pageComponent?: ReactNode; // Custom per-page selector
  baseProps?: HTMLProps<HTMLDivElement>;
  leftBaseProps?: HTMLProps<HTMLDivElement>;
  rightBaseProps?: HTMLProps<HTMLUListElement>;
};
```

### Dynamic Data Access

The table supports nested data access using dot notation:

```tsx
// Data with nested structure
const items = [
  {
    id: 1,
    name: "John Doe",
    contact: {
      email: "john@example.com",
      phone: {
        home: "555-1234",
        work: "555-5678",
      },
    },
  },
];

// Column configuration with nested access
const columns = [
  { columnName: "ID", accessor: "id" },
  { columnName: "Name", accessor: "name" },
  { columnName: "Email", accessor: "contact.email" },
  { columnName: "Work Phone", accessor: "contact.phone.work" },
];
```

### Dynamic Links

Create links with dynamic parameters from row data:

```tsx
{
  columnName: 'View Details',
  accessor: 'name',
  useLink: true,
  linkOptions: {
    href: '/users/[id]/profile',
    className: 'text-blue-600 hover:underline'
  }
}
```

The `[id]` part will be replaced with the actual `id` value from each row.

## Component Hierarchy

The library consists of several composable components:

```
DynamicTable
├── TableTopContent (search, add button)
├── TableBase
│   └── Table
│       ├── Thead
│       │   └── TheadTr (header row)
│       │       └── Th (header cells)
│       └── Tbody
│           └── TbodyTr (body rows)
│               ├── Td (standard cells)
│               ├── ActionTd (action cells)
│               └── Link (linked cells)
└── PaginationController
    ├── PaginationLeftBase (page info)
    └── PaginationRightBase (page navigation)
```

## Individual Component Exports

You can import individual components for custom table implementations:

```tsx
import {
  Table,
  Thead,
  Tbody,
  Th,
  Td,
  ActionTd,
  PaginationController,
} from "react-dynamic-table";
```

## Conditional Rendering

The library supports conditional rendering based on data values:

```tsx
{
  columnName: 'Status Display',
  accessor: 'status',
  useCondition: true,
  condtions: [
    {
      // Render differently when status is "active"
      condtion: {
        compare: ['[status]', 'active']
      },
      redner: {
        useChip: true,
        chipOptions: {
          className: 'bg-green-100 text-green-800'
        }
      }
    },
    {
      // Render differently when status is "pending"
      condtion: {
        compare: ['[status]', 'pending']
      },
      redner: {
        useChip: true,
        chipOptions: {
          className: 'bg-yellow-100 text-yellow-800'
        }
      }
    }
  ]
}
```

## Custom Cell Rendering

Use the `actionOptions.components` property to create custom cell content:

```tsx
{
  columnName: 'Custom Cell',
  useAction: true,
  actionOptions: {
    components: (item) => (
      <div className="flex items-center gap-2">
        <img
          src={item.avatar}
          alt={item.name}
          className="w-8 h-8 rounded-full"
        />
        <div>
          <div className="font-medium">{item.name}</div>
          <div className="text-sm text-gray-500">{item.role}</div>
        </div>
      </div>
    )
  }
}
```

## Dark Mode Support

The library includes built-in dark mode support using Tailwind CSS classes:

```tsx
// Add dark mode class to your app's root element
document.documentElement.classList.add("dark");

// The table will automatically adapt to dark mode
```

## Advanced Usage Examples

### Table with Inline Editing

```tsx
{
  columnName: 'Status',
  accessor: 'status',
  useOption: true,
  optionOptions: {
    data: ['Active', 'Inactive', 'Pending'],
    apiLink: '/api/update-status',
    onRes: (response) => {
      console.log('Status updated:', response);
      // Update your local data or refetch
    }
  }
}
```

### Dynamic Expressions in Props

You can use dynamic expressions in various props using the `{}` syntax:

```tsx
{
  columnName: 'Status',
  accessor: 'status',
  normalProps: {
    td: {
      className: 'font-medium {status === "active" ? "text-green-600" : "text-red-600"}'
    }
  }
}
```

### Nested Property Access with Square Brackets

Use square brackets to access nested properties:

```tsx
{
  columnName: 'Full Address',
  useLink: true,
  linkOptions: {
    href: 'https://maps.google.com/?q=[location.address], [location.city], [location.country]'
  }
}
```

## API Reference

### DynamicTable Props

```tsx
type DynamicTablePropsType<T> = {
  tableName?: string; // Display name for the table
  topContent?: ReactNode; // Custom top content
  topContentOptions?: TopContentOptionsType; // Configuration for built-in top content
  columns: ColumnType<NestedFieldPaths<T>>[]; // Column definitions
  items: T[]; // Data items to display
  keyAccessor?: NestedFieldPaths<T>; // Unique key field in data
  emptyContent?: ReactNode; // Content to show when no data
  isLoading?: boolean; // Loading state flag
  loadingContent?: ReactNode; // Content to show while loading
  actions?: ActionsType[]; // Global actions configuration
  actionColumName?: string; // Custom name for action column
  usePagination?: boolean; // Enable/disable pagination
  pagination?: PAGINATION_TYPE; // Pagination configuration

  // Various HTML props for customizing subcomponents
  tBodyProps?: HTMLProps<HTMLTableSectionElement>;
  tHeadProps?: HTMLProps<HTMLTableSectionElement>;
  tHeadTrProps?: HTMLProps<HTMLTableRowElement>;
  tBodyTrProps?: HTMLProps<HTMLTableRowElement>;
  baseProps?: HTMLProps<HTMLDivElement>;
  tableBaseProps?: HTMLProps<HTMLDivElement>;
  tableProps?: HTMLProps<HTMLTableElement>;
  id?: string; // Custom ID for the table
};
```

## Utility Functions

The library exports several utility functions that can be useful:

```tsx
import { cn, getNestedValue, generateDynamicLink } from "react-dynamic-table";

// Combine class names with Tailwind CSS
const className = cn("base-class", conditional && "conditional-class");

// Get nested value from object using dot notation
const email = getNestedValue(user, "contact.email");

// Generate dynamic URL with data values
const profileUrl = generateDynamicLink("/users/[id]/profile", user);
```

## License

MIT
