Files
sigpro-ui/docs/components/table.md
2026-04-03 01:41:07 +02:00

412 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Table
Data table component with sorting, pagination, zebra stripes, pin rows, and custom cell rendering.
## Tag
`Table`
## Props
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `items` | `Array \| Signal<Array>` | `[]` | Data array to display |
| `columns` | `Array<Column>` | `[]` | Column definitions |
| `keyFn` | `function` | `(item, idx) => idx` | Unique key function for rows |
| `zebra` | `boolean \| Signal<boolean>` | `false` | Enable zebra striping |
| `pinRows` | `boolean \| Signal<boolean>` | `false` | Pin header rows on scroll |
| `empty` | `string \| VNode` | `'No data'` | Content to show when no data |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
### Column Structure
| Property | Type | Description |
| :--- | :--- | :--- |
| `label` | `string` | Column header text |
| `key` | `string` | Property key to display from item |
| `render` | `function(item, index)` | Custom render function for cell content |
| `class` | `string` | Additional CSS classes for column cells |
| `footer` | `string \| VNode` | Footer content for the column |
## Styling
Table supports all **daisyUI Table classes**:
| Category | Keywords | Description |
| :--- | :--- | :--- |
| Base | `table` | Base table styling |
| Variant | `table-zebra` | Zebra striping |
| Size | `table-xs`, `table-sm`, `table-md`, `table-lg`, `table-xl` | Table scale |
| Feature | `table-pin-rows`, `table-pin-cols` | Pin headers/columns |
> For further details, check the [daisyUI Table Documentation](https://daisyui.com/components/table) Full reference for CSS classes.
## Live Examples
### Basic Table
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const BasicDemo = () => {
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor' }
];
return Table({
items: users,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' },
{ label: 'Email', key: 'email' },
{ label: 'Role', key: 'role' }
]
});
};
$mount(BasicDemo, '#demo-basic');
```
### With Zebra Stripes
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-zebra" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ZebraDemo = () => {
const products = [
{ id: 1, name: 'Laptop', price: '$999', stock: 15 },
{ id: 2, name: 'Mouse', price: '$29', stock: 42 },
{ id: 3, name: 'Keyboard', price: '$79', stock: 28 },
{ id: 4, name: 'Monitor', price: '$299', stock: 12 }
];
return Table({
items: products,
columns: [
{ label: 'Product', key: 'name' },
{ label: 'Price', key: 'price' },
{ label: 'Stock', key: 'stock' }
],
zebra: true
});
};
$mount(ZebraDemo, '#demo-zebra');
```
### With Custom Cell Rendering
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-custom" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const CustomDemo = () => {
const orders = [
{ id: 101, customer: 'Alice', amount: 250, status: 'completed' },
{ id: 102, customer: 'Bob', amount: 89, status: 'pending' },
{ id: 103, customer: 'Charlie', amount: 450, status: 'shipped' }
];
return Table({
items: orders,
columns: [
{ label: 'Order ID', key: 'id' },
{ label: 'Customer', key: 'customer' },
{
label: 'Amount',
key: 'amount',
render: (item) => `$${item.amount}`
},
{
label: 'Status',
key: 'status',
render: (item) => {
const statusClass = {
completed: 'badge badge-success',
pending: 'badge badge-warning',
shipped: 'badge badge-info'
};
return Span({ class: statusClass[item.status] }, item.status);
}
}
],
zebra: true
});
};
$mount(CustomDemo, '#demo-custom');
```
### With Footers
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-footer" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const FooterDemo = () => {
const sales = [
{ month: 'January', revenue: 12500, expenses: 8900 },
{ month: 'February', revenue: 14200, expenses: 9200 },
{ month: 'March', revenue: 16800, expenses: 10100 }
];
const totalRevenue = sales.reduce((sum, item) => sum + item.revenue, 0);
const totalExpenses = sales.reduce((sum, item) => sum + item.expenses, 0);
return Table({
items: sales,
columns: [
{ label: 'Month', key: 'month' },
{
label: 'Revenue',
key: 'revenue',
render: (item) => `$${item.revenue.toLocaleString()}`,
footer: `Total: $${totalRevenue.toLocaleString()}`
},
{
label: 'Expenses',
key: 'expenses',
render: (item) => `$${item.expenses.toLocaleString()}`,
footer: `Total: $${totalExpenses.toLocaleString()}`
},
{
label: 'Profit',
render: (item) => `$${(item.revenue - item.expenses).toLocaleString()}`,
footer: `$${(totalRevenue - totalExpenses).toLocaleString()}`
}
],
zebra: true
});
};
$mount(FooterDemo, '#demo-footer');
```
### Empty State
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-empty" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const EmptyDemo = () => {
const emptyList = [];
return Table({
items: emptyList,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' }
],
empty: Div({ class: 'flex flex-col items-center gap-2 p-4' }, [
Span({ class: 'text-2xl' }, '📭'),
Span({}, 'No records found')
])
});
};
$mount(EmptyDemo, '#demo-empty');
```
### Reactive Data
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-reactive" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ReactiveDemo = () => {
const filter = $('all');
const tasks = $([
{ id: 1, title: 'Complete documentation', completed: true },
{ id: 2, title: 'Review pull requests', completed: false },
{ id: 3, title: 'Deploy to production', completed: false },
{ id: 4, title: 'Update dependencies', completed: true }
]);
const filteredTasks = () => {
if (filter() === 'completed') {
return tasks().filter(t => t.completed);
} else if (filter() === 'pending') {
return tasks().filter(t => !t.completed);
}
return tasks();
};
const addTask = () => {
const newId = Math.max(...tasks().map(t => t.id), 0) + 1;
tasks([...tasks(), { id: newId, title: `Task ${newId}`, completed: false }]);
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2' }, [
Button({
class: 'btn btn-sm',
onclick: () => filter('all')
}, 'All'),
Button({
class: 'btn btn-sm',
onclick: () => filter('completed')
}, 'Completed'),
Button({
class: 'btn btn-sm',
onclick: () => filter('pending')
}, 'Pending'),
Button({
class: 'btn btn-sm btn-primary',
onclick: addTask
}, 'Add Task')
]),
Table({
items: filteredTasks,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Title', key: 'title' },
{
label: 'Status',
render: (item) => item.completed
? Span({ class: 'badge badge-success' }, '✓ Done')
: Span({ class: 'badge badge-warning' }, '○ Pending')
}
],
zebra: true
})
]);
};
$mount(ReactiveDemo, '#demo-reactive');
```
### With Actions
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-actions" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ActionsDemo = () => {
const users = $([
{ id: 1, name: 'John Doe', email: 'john@example.com', active: true },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', active: false },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', active: true }
]);
const deleteUser = (id) => {
users(users().filter(u => u.id !== id));
Toast('User deleted', 'alert-info', 2000);
};
const toggleActive = (id) => {
users(users().map(u =>
u.id === id ? { ...u, active: !u.active } : u
));
};
return Table({
items: users,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' },
{ label: 'Email', key: 'email' },
{
label: 'Status',
render: (item) => item.active
? Span({ class: 'badge badge-success' }, 'Active')
: Span({ class: 'badge badge-ghost' }, 'Inactive')
},
{
label: 'Actions',
render: (item) => Div({ class: 'flex gap-1' }, [
Button({
class: 'btn btn-xs btn-ghost',
onclick: () => toggleActive(item.id)
}, item.active ? 'Deactivate' : 'Activate'),
Button({
class: 'btn btn-xs btn-error',
onclick: () => deleteUser(item.id)
}, 'Delete')
])
}
],
zebra: true
});
};
$mount(ActionsDemo, '#demo-actions');
```
### All Variants
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-6"></div>
</div>
</div>
```javascript
const VariantsDemo = () => {
const data = [
{ id: 1, name: 'Item 1', value: 100 },
{ id: 2, name: 'Item 2', value: 200 },
{ id: 3, name: 'Item 3', value: 300 }
];
return Div({ class: 'flex flex-col gap-6' }, [
Div({ class: 'text-sm font-bold' }, 'Default Table'),
Table({
items: data,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' },
{ label: 'Value', key: 'value' }
]
}),
Div({ class: 'text-sm font-bold mt-4' }, 'Zebra Stripes'),
Table({
items: data,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' },
{ label: 'Value', key: 'value' }
],
zebra: true
}),
Div({ class: 'text-sm font-bold mt-4' }, 'Compact Table'),
Table({
items: data,
columns: [
{ label: 'ID', key: 'id' },
{ label: 'Name', key: 'name' },
{ label: 'Value', key: 'value' }
],
class: 'table-compact'
})
]);
};
$mount(VariantsDemo, '#demo-variants');
```