Skip to content

Commit f4bc70c

Browse files
Refactor/mobile responsive (#15)
* refactor: Enhance MultiLevelTable structure and styling - Updated MultiLevelTable component to improve readability and maintainability by restructuring code and formatting. - Introduced a new wrapper for the table to handle overflow and ensure proper styling. - Added CSS rules to prevent cell content from wrapping and enhance table responsiveness. - Refactored rendering logic for pagination and table body for better separation of concerns. * Fix: Update test case
1 parent 9281bc7 commit f4bc70c

File tree

3 files changed

+113
-69
lines changed

3 files changed

+113
-69
lines changed

src/components/MultiLevelTable.tsx

Lines changed: 93 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Pagination } from "./Pagination";
1313
import type { PaginationProps } from "./Pagination";
1414
import { TableHeader } from "./TableHeader";
1515
import { TableRow } from "./TableRow";
16-
import { SortType } from '../constants/sort';
16+
import { SortType } from "../constants/sort";
1717
import { defaultTheme } from "../constants/theme";
1818
import { mergeThemeProps } from "../mergeThemeProps";
1919
import type { ThemeProps } from "../types/theme";
@@ -76,13 +76,17 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
7676
disableSortBy: sortable ? col.sortable === false : true,
7777
sortType: col.customSortFn ? SortType.Custom : SortType.Basic,
7878
sortFn: col.customSortFn,
79-
Cell: ({ row, value }: { row: Row<DataItem>; value: string | number }) => {
79+
Cell: ({
80+
row,
81+
value,
82+
}: {
83+
row: Row<DataItem>;
84+
value: string | number;
85+
}) => {
8086
const item = row.original;
8187

8288
return (
83-
<div>
84-
{col.render ? col.render(value, item) : value?.toString()}
85-
</div>
89+
<div>{col.render ? col.render(value, item) : value?.toString()}</div>
8690
);
8791
},
8892
Filter: col.filterable
@@ -122,8 +126,12 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
122126
initialState: { pageSize } as TableStateWithPagination<DataItem>,
123127
// @ts-expect-error - sortTypes is not included in the type definition but is supported by react-table
124128
sortTypes: {
125-
custom: (rowA: Row<DataItem>, rowB: Row<DataItem>, columnId: string) => {
126-
const column = columns.find(col => col.key === columnId);
129+
custom: (
130+
rowA: Row<DataItem>,
131+
rowB: Row<DataItem>,
132+
columnId: string
133+
) => {
134+
const column = columns.find((col) => col.key === columnId);
127135

128136
if (column?.customSortFn)
129137
return column.customSortFn(rowA.original, rowB.original, columnId);
@@ -162,7 +170,6 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
162170
newSet.delete(rowId);
163171
else
164172
newSet.add(rowId);
165-
166173

167174
return newSet;
168175
});
@@ -194,69 +201,87 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
194201
});
195202
};
196203

204+
const renderPagination = () => {
205+
if (renderCustomPagination)
206+
return renderCustomPagination({
207+
canPreviousPage,
208+
canNextPage,
209+
pageOptions,
210+
pageCount,
211+
pageIndex,
212+
pageSize: currentPageSize,
213+
gotoPage,
214+
nextPage,
215+
previousPage,
216+
setPageSize,
217+
theme: mergedTheme,
218+
});
219+
220+
221+
return (
222+
<Pagination
223+
canPreviousPage={canPreviousPage}
224+
canNextPage={canNextPage}
225+
pageOptions={pageOptions}
226+
pageCount={pageCount}
227+
pageIndex={pageIndex}
228+
gotoPage={gotoPage}
229+
nextPage={nextPage}
230+
previousPage={previousPage}
231+
pageSize={currentPageSize}
232+
setPageSize={setPageSize}
233+
theme={mergedTheme}
234+
/>
235+
);
236+
};
237+
238+
const renderTableBody = () => {
239+
return (
240+
<tbody {...getTableBodyProps()}>
241+
{page.map((row) => {
242+
prepareRow(row);
243+
const parentId = row.original.id;
244+
const hasChildren = rowsMap.has(parentId);
245+
246+
return (
247+
<React.Fragment key={parentId}>
248+
<TableRow
249+
row={row}
250+
columns={columns}
251+
hasChildren={hasChildren}
252+
isExpanded={expandedRows.has(parentId)}
253+
onToggle={() => hasChildren && toggleRow(parentId)}
254+
theme={mergedTheme}
255+
expandIcon={expandIcon}
256+
/>
257+
{renderNestedRows(parentId)}
258+
</React.Fragment>
259+
);
260+
})}
261+
</tbody>
262+
);
263+
};
264+
197265
return (
198266
<div style={{ backgroundColor: mergedTheme.colors?.background }}>
199-
<table
200-
{...getTableProps()}
201-
className="table-container"
202-
style={{ borderColor: mergedTheme.table?.cell?.borderColor }}
203-
>
204-
<TableHeader headerGroups={headerGroups} theme={mergedTheme} sortable={sortable}
205-
ascendingIcon={ascendingIcon}
206-
descendingIcon={descendingIcon} />
207-
<tbody {...getTableBodyProps()}>
208-
{page.map((row) => {
209-
prepareRow(row);
210-
const parentId = row.original.id;
211-
const hasChildren = rowsMap.has(parentId);
212-
213-
return (
214-
<React.Fragment key={parentId}>
215-
<TableRow
216-
row={row}
217-
columns={columns}
218-
hasChildren={hasChildren}
219-
isExpanded={expandedRows.has(parentId)}
220-
onToggle={() => hasChildren && toggleRow(parentId)}
221-
theme={mergedTheme}
222-
expandIcon={expandIcon}
223-
/>
224-
{renderNestedRows(parentId)}
225-
</React.Fragment>
226-
);
227-
})}
228-
</tbody>
229-
</table>
267+
<div className="table-wrapper">
268+
<table
269+
{...getTableProps()}
270+
className="table-container"
271+
style={{ borderColor: mergedTheme.table?.cell?.borderColor }}
272+
>
273+
<TableHeader
274+
headerGroups={headerGroups}
275+
theme={mergedTheme}
276+
sortable={sortable}
277+
ascendingIcon={ascendingIcon}
278+
descendingIcon={descendingIcon}
279+
/>
280+
{renderTableBody()}
281+
</table>
230282

231-
{renderCustomPagination ? (
232-
renderCustomPagination({
233-
canPreviousPage,
234-
canNextPage,
235-
pageOptions,
236-
pageCount,
237-
pageIndex,
238-
pageSize: currentPageSize,
239-
gotoPage,
240-
nextPage,
241-
previousPage,
242-
setPageSize,
243-
theme: mergedTheme,
244-
})
245-
) : (
246-
<Pagination
247-
canPreviousPage={canPreviousPage}
248-
canNextPage={canNextPage}
249-
pageOptions={pageOptions}
250-
pageCount={pageCount}
251-
pageIndex={pageIndex}
252-
gotoPage={gotoPage}
253-
nextPage={nextPage}
254-
previousPage={previousPage}
255-
pageSize={currentPageSize}
256-
setPageSize={setPageSize}
257-
theme={mergedTheme}
258-
/>
259-
)}
283+
{renderPagination()}
284+
</div>
260285
</div>
261286
);
262287
};

src/styles/MultiLevelTable.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
.table-container {
22
width: 100%;
33
border-collapse: collapse;
4+
}
5+
6+
.table-wrapper {
7+
width: 100%;
8+
overflow-x: auto;
9+
-webkit-overflow-scrolling: touch;
10+
}
11+
12+
.table-container {
13+
min-width: 100%;
14+
white-space: nowrap;
15+
}
16+
17+
/* Ensure table cells don't wrap content */
18+
.table-container td,
19+
.table-container th {
20+
white-space: nowrap;
21+
padding: 8px;
422
}

tests/components/MultiLevelTable.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ describe('MultiLevelTable', () => {
189189
);
190190

191191
const table = screen.getByRole('table');
192-
expect(table.parentElement).toHaveStyle({ backgroundColor: '#f0f0f0' });
192+
const tableWrapper = table.closest('.table-wrapper');
193+
expect(tableWrapper?.parentElement).toHaveStyle({ backgroundColor: '#f0f0f0' });
193194
expect(table).toHaveStyle({ borderColor: '#ff0000' });
194195
});
195196
it('handles custom column rendering', () => {

0 commit comments

Comments
 (0)