Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/components/Table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,46 @@ const AdvancedTable: React.FC = () => {
| `placeholder?` | `string` | Input placeholder |
| `defaultValue?` | `any` | Default filter value |

### SelectionConfig

| Property | Type | Description |
| --------------------- | ------------------------------------ | -------------------------------------------- |
| `mode` | `'single' \| 'multiple' \| 'none'` | Selection mode |
| `selectedIds` | `Set<T['id']>` | Set of currently selected row IDs |
| `onSelectionChange` | `(selectedIds: Set<T['id']>) => void` | Callback when selection changes |
| `selectableRowIds?` | `Set<T['id']>` | Optional set of IDs that can be selected |
| `showSelectAll?` | `boolean` | Show select all checkbox (default: true) |

**Important:** To enable row selection, you must explicitly configure the `selectable` property in your table config or call `.enableSelection()` when using the table builder. If `selectable` is not defined, no checkbox columns will be rendered. See the examples below for correct usage.

#### Enabling Selection with Builder

```tsx
const config = createTableBuilder<User>()
.addColumn("name", "Name")
.addColumn("email", "Email")
.enableSelection("multiple", {
selectedIds,
onSelectionChange: setSelectedIds,
})
.build();
```

#### Table Without Selection

If you don't call `.enableSelection()` or set `selectable` in the config, the table will **not** render checkbox columns:

```tsx
// No selection - checkboxes will NOT be rendered
const config = createTableBuilder<User>()
.addColumn("name", "Name")
.addColumn("email", "Email")
.enableSorting()
.build();
```

For more examples, see `NoSelectionExample.tsx` and `SelectionComparisonExample.tsx` in the examples directory.

## Hooks

The Table component provides several custom hooks for advanced usage:
Expand Down
4 changes: 2 additions & 2 deletions src/components/Table/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ const Table = <T extends DataItem>({
data={paginatedData}
mobileConfig={config.mobileConfig}
actions={config.actions}
selectable={config.selectable?.mode !== "none"}
selectable={!!config.selectable && config.selectable.mode !== "none"}
selectedIds={selectedIds}
onSelectItem={handleSelectItem}
onRowClick={config.onRowClick}
Expand All @@ -220,7 +220,7 @@ const Table = <T extends DataItem>({
columns={config.columns}
actions={config.actions}
sortable={config.sortable}
selectable={config.selectable?.mode !== "none"}
selectable={!!config.selectable && config.selectable.mode !== "none"}
selectedIds={selectedIds}
onSort={handleSort}
getSortDirection={getSortDirection}
Expand Down
86 changes: 86 additions & 0 deletions src/components/Table/examples/NoSelectionExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from "react";
import { Table, createTableBuilder, type DataItem } from "../";

// Sample data type
interface Product extends DataItem {
id: number;
name: string;
category: string;
price: number;
stock: number;
}

// Sample data
const products: Product[] = [
{
id: 1,
name: "Laptop",
category: "Electronics",
price: 999.99,
stock: 15,
},
{
id: 2,
name: "Mouse",
category: "Electronics",
price: 29.99,
stock: 50,
},
{
id: 3,
name: "Keyboard",
category: "Electronics",
price: 79.99,
stock: 30,
},
{
id: 4,
name: "Monitor",
category: "Electronics",
price: 299.99,
stock: 20,
},
];

/**
* Example demonstrating a table WITHOUT selection enabled.
* This should NOT render checkbox columns.
*/
const NoSelectionExample: React.FC = () => {
// Create a table configuration WITHOUT calling enableSelection()
const tableConfig = createTableBuilder<Product>()
.addColumn("name", "Product Name", { sortable: true, width: "200px" })
.addColumn("category", "Category", { sortable: true, width: "150px" })
.addColumn("price", "Price", {
sortable: true,
width: "100px",
align: "right",
render: (value: number) => `$${value.toFixed(2)}`,
})
.addColumn("stock", "Stock", {
sortable: true,
width: "100px",
align: "right",
})
.enableSorting()
.build();

return (
<div style={{ padding: "20px" }}>
<h1>Table Without Selection</h1>
<p>
This example demonstrates a table created without calling
enableSelection(). No checkbox column should be visible.
</p>

<Table
data={products}
config={tableConfig}
style={{ marginTop: "20px" }}
data-testid="no-selection-table"
/>
</div>
);
};

export default NoSelectionExample;
163 changes: 163 additions & 0 deletions src/components/Table/examples/SelectionComparisonExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import React, { useState } from "react";
import { Box } from "@mui/joy";
import { Table, createTableBuilder, type DataItem } from "../";

// Sample data type
interface Task extends DataItem {
id: number;
title: string;
status: "todo" | "in-progress" | "done";
priority: "low" | "medium" | "high";
assignee: string;
}

// Sample data
const tasks: Task[] = [
{
id: 1,
title: "Fix bug in authentication",
status: "in-progress",
priority: "high",
assignee: "John Doe",
},
{
id: 2,
title: "Update documentation",
status: "todo",
priority: "medium",
assignee: "Jane Smith",
},
{
id: 3,
title: "Review pull request #42",
status: "todo",
priority: "low",
assignee: "Bob Johnson",
},
{
id: 4,
title: "Deploy to production",
status: "done",
priority: "high",
assignee: "Alice Williams",
},
];

/**
* Example demonstrating the difference between tables with and without selection.
* This validates that the fix properly handles both scenarios.
*/
const SelectionComparisonExample: React.FC = () => {
const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());

// Table WITHOUT selection (should NOT show checkboxes)
const tableWithoutSelection = createTableBuilder<Task>()
.addColumn("title", "Task", { sortable: true, width: "250px" })
.addColumn("status", "Status", {
sortable: true,
width: "120px",
render: (value: string) => (
<span
style={{
padding: "4px 8px",
borderRadius: "4px",
backgroundColor:
value === "done"
? "#e8f5e8"
: value === "in-progress"
? "#fff3e0"
: "#f5f5f5",
color:
value === "done"
? "#2e7d32"
: value === "in-progress"
? "#ef6c00"
: "#666",
}}
>
{value}
</span>
),
})
.addColumn("priority", "Priority", { sortable: true, width: "100px" })
.addColumn("assignee", "Assignee", { sortable: true, width: "150px" })
.enableSorting()
.build();

// Table WITH selection (should show checkboxes)
const tableWithSelection = createTableBuilder<Task>()
.addColumn("title", "Task", { sortable: true, width: "250px" })
.addColumn("status", "Status", {
sortable: true,
width: "120px",
render: (value: string) => (
<span
style={{
padding: "4px 8px",
borderRadius: "4px",
backgroundColor:
value === "done"
? "#e8f5e8"
: value === "in-progress"
? "#fff3e0"
: "#f5f5f5",
color:
value === "done"
? "#2e7d32"
: value === "in-progress"
? "#ef6c00"
: "#666",
}}
>
{value}
</span>
),
})
.addColumn("priority", "Priority", { sortable: true, width: "100px" })
.addColumn("assignee", "Assignee", { sortable: true, width: "150px" })
.enableSelection("multiple", {
selectedIds,
onSelectionChange: setSelectedIds,
})
.enableSorting()
.build();

return (
<div style={{ padding: "20px" }}>
<h1>Selection Comparison Example</h1>
<p>
This example demonstrates the fix for the checkbox column rendering
issue. The first table does NOT call enableSelection() and should NOT
show checkboxes. The second table calls enableSelection() and SHOULD
show checkboxes.
</p>

<Box sx={{ marginTop: 3, marginBottom: 3 }}>
<h2 style={{ marginBottom: "10px" }}>Table WITHOUT Selection</h2>
<p style={{ marginBottom: "10px", color: "#666" }}>
✓ No checkbox column should be visible
</p>
<Table
data={tasks}
config={tableWithoutSelection}
data-testid="table-without-selection"
/>
</Box>

<Box sx={{ marginTop: 3, marginBottom: 3 }}>
<h2 style={{ marginBottom: "10px" }}>Table WITH Selection</h2>
<p style={{ marginBottom: "10px", color: "#666" }}>
✓ Checkbox column should be visible | Selected: {selectedIds.size}{" "}
tasks
</p>
<Table
data={tasks}
config={tableWithSelection}
data-testid="table-with-selection"
/>
</Box>
</div>
);
};

export default SelectionComparisonExample;
Loading