Skip to content

Commit

Permalink
fix: improve Table component types
Browse files Browse the repository at this point in the history
  • Loading branch information
haideralsh committed May 7, 2024
1 parent fdbfb6b commit 3070f93
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 222 deletions.
2 changes: 0 additions & 2 deletions src/Table/BaseTable.story.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import React from "react";
import styled from "styled-components";
import { boolean, text } from "@storybook/addon-knobs";
Expand Down Expand Up @@ -392,7 +391,6 @@ export const WithAFooter = () => (
WithAFooter.story = {
name: "with a footer",
};
/* eslint-enable react/prop-types */

const TableWithBorderedRows = styled(Table)`
border-collapse: collapse;
Expand Down
115 changes: 50 additions & 65 deletions src/Table/BaseTable.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,87 @@
import React from "react";
import styled from "styled-components";
import PropTypes from "prop-types";
import { space } from "styled-system";
import propTypes from "@styled-system/prop-types";
import { addStyledProps } from "../StyledProps";
import TableHead from "./TableHead";
import TableBody from "./TableBody";
import TableFoot from "./TableFoot";
import { rowsPropType, RowType, Columns } from "./Table.types";
import { ColumnType } from "./Table.types";

export type BaseTableProps = {
columns: Columns;
rows: RowType[];
export type BaseTableProps<Row> = {
columns: ColumnType<Row>[];
rows: Row[];
noRowsContent?: string;
keyField?: string;
id?: string;
loading?: boolean;
footerRows?: any;
footerRows?: Row[];
rowHovers?: boolean;
compact?: boolean;
className?: string;
stickyHeader?: boolean;
onRowMouseEnter?: (...args: any[]) => any;
onRowMouseLeave?: (...args: any[]) => any;
onMouseEnter?: any;
onMouseLeave?: any;
onRowMouseEnter?: React.DOMAttributes<HTMLTableRowElement>["onMouseEnter"];
onRowMouseLeave?: React.DOMAttributes<HTMLTableRowElement>["onMouseLeave"];
onMouseEnter?: React.DOMAttributes<HTMLTableElement>["onMouseEnter"];
onMouseLeave?: React.DOMAttributes<HTMLTableElement>["onMouseLeave"];
};

const StyledTable = styled.table<any>(space, {
borderCollapse: "collapse",
width: "100%",
background: "white",
position: "relative",
});
const StyledTable = styled.table(
{
borderCollapse: "collapse",
width: "100%",
background: "white",
position: "relative",
},
addStyledProps
);

const BaseTable: React.FC<BaseTableProps> = ({
export default function BaseTable<Row>({
columns,
rows,
// @todo: remove this default value and internationalize it
noRowsContent = "No records have been created for this table.",
keyField = "id",
keyField,
id,
loading,
footerRows = [],
rowHovers = true,
footerRows,
rowHovers,
compact,
className,
stickyHeader,
onRowMouseEnter = () => {},
onRowMouseLeave = () => {},
onRowMouseEnter,
onRowMouseLeave,
...props
}) => (
<StyledTable id={id} className={className} {...props}>
<TableHead columns={columns} compact={compact} sticky={stickyHeader} />
<TableBody
columns={columns}
rows={rows}
keyField={keyField}
noRowsContent={noRowsContent}
loading={loading}
rowHovers={rowHovers}
compact={compact}
onRowMouseLeave={onRowMouseLeave}
onRowMouseEnter={onRowMouseEnter}
/>
{footerRows && (
<TableFoot columns={columns} rows={footerRows} keyField={keyField} loading={loading} compact={compact} />
)}
</StyledTable>
);
}: BaseTableProps<Row>) {
return (
<StyledTable id={id} className={className} {...props}>
<TableHead columns={columns} compact={compact} sticky={stickyHeader} />
<TableBody
columns={columns}
rows={rows}
keyField={keyField}
noRowsContent={noRowsContent}
loading={loading}
rowHovers={rowHovers}
compact={compact}
onRowMouseLeave={onRowMouseLeave}
onRowMouseEnter={onRowMouseEnter}
/>
{footerRows && (
<TableFoot columns={columns} rows={footerRows} keyField={keyField} loading={loading} compact={compact} />
)}
</StyledTable>
);
}

BaseTable.propTypes = {
...propTypes.space,
columns: PropTypes.any,
rows: PropTypes.any,
noRowsContent: PropTypes.string,
keyField: PropTypes.string,
id: PropTypes.string,
loading: PropTypes.bool,
footerRows: rowsPropType,
rowHovers: PropTypes.bool,
compact: PropTypes.bool,
className: PropTypes.string,
stickyHeader: PropTypes.bool,
onRowMouseEnter: PropTypes.func,
onRowMouseLeave: PropTypes.func,
};
const noop = () => {};

BaseTable.defaultProps = {
noRowsContent: "No records have been created for this table.",
keyField: "id",
id: undefined,
loading: false,
footerRows: [],
rowHovers: true,
compact: false,
className: undefined,
stickyHeader: false,
onRowMouseEnter: () => {},
onRowMouseLeave: () => {},
onRowMouseEnter: noop,
onRowMouseLeave: noop,
};

export default BaseTable;
2 changes: 1 addition & 1 deletion src/Table/SortingColumnHeader.story.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { action } from "@storybook/addon-actions";
import { withKnobs, text, boolean } from "@storybook/addon-knobs";
import { text, boolean } from "@storybook/addon-knobs";
import { Table } from "../index";

export default {
Expand Down
32 changes: 30 additions & 2 deletions src/Table/StatefulTable.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import propTypes from "@styled-system/prop-types";
import { Pagination } from "../Pagination";
import { getSubset } from "../utils/subset";
import BaseTable, { BaseTableProps } from "./BaseTable";
import { addExpandableControl } from "./addExpandableControl";
import { addSelectableControl } from "./addSelectableControl";

export type StatefulTableProps = BaseTableProps & {
export type StatefulTableProps = BaseTableProps<unknown> & {
selectedRows?: string[];
onRowSelectionChange?: (...args: any[]) => any;
onRowExpansionChange?: (...args: any[]) => any;
Expand Down Expand Up @@ -224,7 +226,33 @@ class StatefulTable extends Component<StatefulTableProps, StatefulTableState> {
render() {
const { paginatedRows, currentPage } = this.state;
const { rowsPerPage, paginationProps, paginationCss } = this.props;
const baseTableProps = getSubset(this.getControlProps(), BaseTable.propTypes);
const baseTableProps = getSubset(this.getControlProps(), {
...propTypes.space,
columns: PropTypes.any,
rows: PropTypes.any,
noRowsContent: PropTypes.string,
keyField: PropTypes.string,
id: PropTypes.string,
loading: PropTypes.bool,
rowHovers: PropTypes.bool,
compact: PropTypes.bool,
className: PropTypes.string,
stickyHeader: PropTypes.bool,
onRowMouseEnter: PropTypes.func,
onRowMouseLeave: PropTypes.func,
footerRows: PropTypes.arrayOf(
PropTypes.objectOf(
PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool,
PropTypes.func,
PropTypes.node,
PropTypes.shape({}),
])
)
),
});
return (
<>
<BaseTable {...baseTableProps} />
Expand Down
12 changes: 8 additions & 4 deletions src/Table/StyledTh.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styled, { CSSObject } from "styled-components";
import styled, { CSSObject, CSSProperties } from "styled-components";
import { DefaultNDSThemeType } from "../theme.type";

const stickyStyles = (theme: DefaultNDSThemeType): CSSObject => ({
position: "sticky",
top: 0,
Expand All @@ -9,13 +10,15 @@ const stickyStyles = (theme: DefaultNDSThemeType): CSSObject => ({
});

type StyledThProps = {
width?: any;
width?: CSSProperties["width"];
compact?: boolean;
theme?: DefaultNDSThemeType;
sticky?: any;
sticky?: boolean;
};
const StyledTh = styled.th(({ width, compact, theme, sticky }: StyledThProps): CSSObject => {

const StyledTh = styled.th<StyledThProps>(({ width, compact, theme, sticky }) => {
const padding = compact ? theme.space.x1 : theme.space.x2;

return {
fontWeight: "normal",
textAlign: "left",
Expand All @@ -29,4 +32,5 @@ const StyledTh = styled.th(({ width, compact, theme, sticky }: StyledThProps): C
width: width || "auto",
};
});

export default StyledTh;
16 changes: 5 additions & 11 deletions src/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@ import StatefulTable from "./StatefulTable";
import BaseTable from "./BaseTable";
import SortingColumnHeader from "./SortingColumnHeader";
import { StatefulTableProps } from "./StatefulTable";
import { ColumnType, RowType, CellInfoType } from "./Table.types";

export type TableProps = StatefulTableProps;
export type TableColumnType = ColumnType;
export type TableRowType = RowType;
export type TableCellInfoType = CellInfoType;

const Table = ({
export default function Table<Row>({
hasSelectableRows,
rowsPerPage,
hasExpandableRows,
Expand All @@ -23,8 +17,8 @@ const Table = ({
paginationCss,
paginationProps,
...props
}: TableProps) =>
hasSelectableRows || rowsPerPage || hasExpandableRows ? (
}: StatefulTableProps<Row>) {
return hasSelectableRows || rowsPerPage || hasExpandableRows ? (
<StatefulTable
hasExpandableRows={hasExpandableRows}
hasSelectableRows={hasSelectableRows}
Expand All @@ -42,6 +36,6 @@ const Table = ({
) : (
<BaseTable {...props} />
);
Table.SortingHeader = SortingColumnHeader;
}

export default Table;
Table.SortingHeader = SortingColumnHeader;
46 changes: 8 additions & 38 deletions src/Table/Table.types.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,27 @@
import type { Key } from "react";
import PropTypes from "prop-types";

export type RowType = unknown;

export interface CellInfoType {
export interface CellInfoType<Row> {
cellData: unknown;
column: ColumnType;
row: RowType;
column: ColumnType<Row>[];
row: Row;
}

interface ColumnInfoType {
align?: ColumnAlignment;
label: string;
dataKey?: Key;
width?: string | number;
metadata?: Record<string, unknown>;
}

type ColumnAlignment = "left" | "right" | "center";
export type ColumnAlignment = "left" | "right" | "center";

export type ColumnType = {
export type ColumnType<Row> = {
align?: ColumnAlignment;
label?: string;
cellFormatter?: (cell: CellInfoType) => React.ReactNode;
cellRenderer?: (cell: CellInfoType) => React.ReactNode;
cellFormatter?: (cell: CellInfoType<Row>) => React.ReactNode;
cellRenderer?: (cell: CellInfoType<Row>) => React.ReactNode;
headerRenderer?: (column: ColumnInfoType) => React.ReactNode;
headerFormatter?: (column: ColumnInfoType) => React.ReactNode;
width?: string | number;
} & ({ key: Key; dataKey?: never | undefined } | { dataKey: Key; key?: never | undefined });

export type Columns = ColumnType[];

export const columnPropType = PropTypes.shape({
align: PropTypes.oneOf(["right", "left", "center"]),
label: PropTypes.string,
dataKey: PropTypes.oneOf([PropTypes.string, PropTypes.number]),
key: PropTypes.oneOf([PropTypes.string, PropTypes.number]),
cellFormatter: PropTypes.func,
cellRenderer: PropTypes.func,
headerRenderer: PropTypes.func,
width: PropTypes.string,
});

export const rowPropType = PropTypes.objectOf(
PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool,
PropTypes.func,
PropTypes.node,
PropTypes.shape({}),
])
);

export const columnsPropType = PropTypes.arrayOf(columnPropType);

export const rowsPropType = PropTypes.arrayOf(rowPropType);
Loading

0 comments on commit 3070f93

Please sign in to comment.