mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 07:25:44 +01:00
create sortable table
This commit is contained in:
12
scm-ui/ui-components/src/table/Column.tsx
Normal file
12
scm-ui/ui-components/src/table/Column.tsx
Normal 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;
|
||||
19
scm-ui/ui-components/src/table/Table.stories.tsx
Normal file
19
scm-ui/ui-components/src/table/Table.stories.tsx
Normal 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>
|
||||
));
|
||||
64
scm-ui/ui-components/src/table/Table.tsx
Normal file
64
scm-ui/ui-components/src/table/Table.tsx
Normal 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;
|
||||
26
scm-ui/ui-components/src/table/TextColumn.tsx
Normal file
26
scm-ui/ui-components/src/table/TextColumn.tsx
Normal 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;
|
||||
9
scm-ui/ui-components/src/table/types.ts
Normal file
9
scm-ui/ui-components/src/table/types.ts
Normal 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;
|
||||
};
|
||||
Reference in New Issue
Block a user