create sortable table

This commit is contained in:
Eduard Heimbuch
2019-11-29 15:57:36 +01:00
parent d7de7c2f36
commit 14786d7a1a
5 changed files with 130 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
import React, { FC, ReactNode } from "react";
import { ColumnProps } from "./types";
type Props = ColumnProps & {
children: (row: any) => ReactNode;
};
const Column: FC<Props> = ({ row, children }) => {
return <>{children(row)}</>;
};
export default Column;

View File

@@ -0,0 +1,19 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import Table from "./Table";
import Column from "./Column";
import TextColumn from "./TextColumn";
storiesOf("Table|Table", module)
.add("Default", () => (
<Table data={[{ first: "a", second: "b" }, { first: "d", second: "y" }]}>
<Column header={"FIRST"}>{(row: any) => <h1>{row.first}</h1>}</Column>
<Column header={"SECOND"}>{(row: any) => <h2 style={{ color: "red" }}>{row.second}</h2>}</Column>
</Table>
))
.add("TextColumn", () => (
<Table data={[{ first: "d", second: "y" }, { first: "a", second: "b" }, { first: "z", second: "a" }]}>
<TextColumn header={"FIRST"} dataKey={"first"} />
<TextColumn header={"SECOND"} dataKey={"second"} />
</Table>
));

View File

@@ -0,0 +1,64 @@
import React, { FC, useState } from "react";
type SortableTableProps = {
data: any[];
};
// @ts-ignore
const Table: FC<SortableTableProps> = ({ data, children }) => {
const [tableData, setTableData] = useState(data);
const [ascending, setAscending] = useState(true);
const [lastSortBy, setlastSortBy] = useState(0);
// @ts-ignore
const sortFunctions = React.Children.map(children, child => child.props.createComparator(child.props));
const mapDataToColumns = (row: any) => {
return (
<tr>
{React.Children.map(children, child => {
// @ts-ignore
return <td>{React.cloneElement(child, { ...child.props, row })}</td>;
})}
</tr>
);
};
const sortDescending = (sortAscending: (a: any, b: any) => number) => {
return (a: any, b: any) => {
return sortAscending(a, b) * -1;
};
};
const tableSort = (index: number) => {
const sortableData = [...tableData];
let sortOrder = ascending;
if (lastSortBy !== index) {
setAscending(true);
sortOrder = true;
}
const sortFunction = sortOrder ? sortFunctions[index] : sortDescending(sortFunctions[index]);
sortableData.sort(sortFunction);
setTableData(sortableData);
setAscending(!sortOrder);
setlastSortBy(index);
};
return (
tableData.length > 0 && (
<table className="text-left">
<thead>
<tr>
{React.Children.map(children, (child, index) => (
// @ts-ignore
<th onClick={() => tableSort(index)}>{child.props.header}</th>
))}
</tr>
</thead>
<tbody>{tableData.map(mapDataToColumns)}</tbody>
</table>
)
);
};
export default Table;

View File

@@ -0,0 +1,26 @@
import React, { FC } from "react";
import {ColumnProps} from "./types";
type Props = ColumnProps & {
dataKey: string;
};
const TextColumn: FC<Props> = ({ row, dataKey }) => {
return row[dataKey];
};
TextColumn.defaultProps = {
createComparator: (props: Props) => {
return (a: any, b: any) => {
if (a[props.dataKey] < b[props.dataKey]) {
return -1;
} else if (a[props.dataKey] > b[props.dataKey]) {
return 1;
} else {
return 0;
}
};
}
};
export default TextColumn;

View File

@@ -0,0 +1,9 @@
import { ReactNode } from "react";
export type Comparator = (a: any, b: any) => number;
export type ColumnProps = {
header: ReactNode;
row?: any;
createComparator?: (props: any) => Comparator;
};