Skip to content

Commit

Permalink
feat: Port minimalist table from design-system
Browse files Browse the repository at this point in the history
  • Loading branch information
antonjoel82 committed Jun 5, 2024
1 parent f3ae141 commit a229591
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
60 changes: 60 additions & 0 deletions libs/novui/src/components/table/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useState } from 'react';
import { StoryFn, Meta } from '@storybook/react';
import { Badge, Switch } from '@mantine/core';

import { Table } from './Table';
import { ColumnDef } from '@tanstack/react-table';

export default {
title: 'Components/Table',
component: Table,
argTypes: {
data: {
control: false,
},
columns: {
control: false,
},
},
} as Meta<typeof Table>;

const SwitchCell = (props) => {
const [status, setStatus] = useState(props.status);
const switchHandler = () => {
setStatus((prev) => (prev === 'Enabled' ? 'Disabled' : 'Enabled'));
};

return <Switch label={status} onChange={switchHandler} checked={status === 'Enabled'} />;
};

const BadgeCell = (props) => {
return (
<Badge variant="outline" size="md" radius="xs">
{props.getValue()}
</Badge>
);
};

interface IExampleData {
name: string;
category: string;
creationDate: string;
status: string;
}

const columns: ColumnDef<IExampleData>[] = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'category', header: 'Category', cell: BadgeCell },
{ accessorKey: 'creationDate', header: 'Date Created' },
{ accessorKey: 'status', header: 'Status', cell: SwitchCell },
];

const data: IExampleData[] = [
{ name: 'Great', category: 'Fun', status: 'Disabled', creationDate: '01/01/2021 16:36' },
{ name: 'Whats up?', category: 'Done', status: 'Enabled', creationDate: '01/01/2021 16:36' },
];

const Template: StoryFn<typeof Table> = ({ ...args }) => <Table columns={columns} data={data} {...args} />;

export const PrimaryUse = Template.bind({});
PrimaryUse.args = {};
69 changes: 69 additions & 0 deletions libs/novui/src/components/table/Table.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { type TableStylesNames } from '@mantine/core';
import { css } from '../../../styled-system/css';

const tableStyles: Partial<Record<TableStylesNames, string>> = {
tr: css({
'& td': {
textOverflow: 'ellipsis',
},
}),
table: css({
borderCollapse: 'collapse',
borderSpacingX: '125',
textStyle: 'text.main',
'& tr td:first-of-type': {
pl: '200',
pr: '200',
},
'& tr th:first-of-type': {
pl: '200',
pr: '200',
},
'& tr td:last-child': {
pr: '200',
},
'& tr th:last-child': {
pr: '200',
},
'& thead tr': {
borderBottom: 'solid',
borderColor: 'table.header.border',
},
'& thead tr th': {
fontWeight: 'regular',
// height: '17px',
textAlign: 'left',
color: 'typography.text.tertiary',
borderBottom: 'none',
borderSpacing: '0',
pb: '100',
},
'& tbody tr td': {
// TODO: replace with token value
maxWidth: '[100px]',
// TODO: replace with token value
height: '[80px]',

color: 'typography.text.main',
borderBottom: 'solid',
borderColor: 'table.row.border',
},
'& tbody tr[data-disabled="true"]:hover': {
cursor: 'default',
},
'& tbody tr[data-disabled="false"]:hover': {
cursor: 'pointer',
},
'& tbody tr:last-of-type td': {
borderBottom: 'solid',
borderColor: 'table.bottom.border',
},
_hover: {
'& tbody tr:hover': {
bg: 'table.row.surface.hover',
},
},
}),
};

export default tableStyles;
93 changes: 93 additions & 0 deletions libs/novui/src/components/table/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Table as ExternalTable } from '@mantine/core';
import { flexRender, getCoreRowModel, Row, useReactTable } from '@tanstack/react-table';
import React, { useMemo } from 'react';
import { CoreProps } from 'src/types';

import classes from './Table.styles';

export type IRow<T extends object = {}> = Row<T>;

export interface ITableProps<T extends object> extends CoreProps {
columns?: any[];
data?: T[];
isLoading?: boolean;
pagination?: any;
noDataPlaceholder?: React.ReactNode;
loadingItems?: number;
hasMore?: boolean;
onRowClick?: (row: Row<T>) => void;
onRowSelect?: (row: Row<T>) => void;
}

/**
* Table component
*
*/
export function Table<T extends object>({
columns: userColumns,
data: userData,
isLoading = false,
noDataPlaceholder,
loadingItems = 10,
onRowClick,
onRowSelect,
...props
}: ITableProps<T>) {
const columns = useMemo(() => userColumns?.map((col) => ({ ...col })), [userColumns]);
const data = useMemo(() => (userData || [])?.map((row) => ({ ...row })), [userData]);
const fakeData = useMemo(() => Array.from({ length: loadingItems }).map((_, index) => ({ index })), [loadingItems]);

const table = useReactTable<T>({
columns,
data: isLoading ? (fakeData as T[]) : data,
getCoreRowModel: getCoreRowModel(),
// FIXME: remove this
debugTable: true,
});

return (
<ExternalTable classNames={classes} highlightOnHover {...props}>
<thead>
{table.getHeaderGroups().map((headerGroup, i) => {
return (
<tr key={headerGroup.id} {...headerGroup}>
{headerGroup.headers.map((header) => {
return (
<th key={header.id} {...header}>
{flexRender(header.column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
);
})}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => {
return (
<tr
key={row.id}
onClick={(e) => {
e.stopPropagation();
if (!isLoading && onRowClick) {
onRowClick(row);
}
}}
{...row}
className={classes.tr}
data-disabled={isLoading || !onRowClick}
>
{row.getVisibleCells().map((cell) => {
return (
<td key={cell.id} {...cell}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
);
})}
</tbody>
</ExternalTable>
);
}
2 changes: 2 additions & 0 deletions libs/novui/src/components/table/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Table } from './Table';
export type { IRow, ITableProps } from './Table';
26 changes: 26 additions & 0 deletions libs/novui/src/tokens/semanticColors.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ export const LEGACY_COLOR_SEMANTIC_TOKENS = defineSemanticTokens.colors({
},
},
},
table: {
header: {
border: {
value: { base: '{colors.legacy.B98}', _dark: '{colors.legacy.B30}' },
type: 'color',
},
},
row: {
border: {
value: { base: '{colors.legacy.B98}', _dark: '{colors.legacy.B20}' },
type: 'color',
},
surface: {
hover: {
value: { base: '{colors.legacy.B98}', _dark: '{colors.legacy.B20}' },
type: 'color',
},
},
},
bottom: {
border: {
value: { base: '{colors.legacy.B98}', _dark: '{colors.legacy.B30}' },
type: 'color',
},
},
},
icon: {
main: {
value: { base: '{colors.legacy.B60}', _dark: '{colors.legacy.B60}' },
Expand Down

0 comments on commit a229591

Please sign in to comment.