From abe904cf5cff916030f0d8c9b4539f56b03a1745 Mon Sep 17 00:00:00 2001 From: sam-m-m Date: Tue, 18 Aug 2020 16:49:34 -0700 Subject: [PATCH] Feat #30 - Add table component --- src/__snapshots__/storybook.test.ts.snap | 366 +++++++++++++++++++++++ src/components/Table/Table.stories.tsx | 64 ++++ src/components/Table/Table.test.tsx | 33 ++ src/components/Table/index.tsx | 34 +++ src/components/Table/utils.ts | 48 +++ src/components/index.ts | 1 + src/setupTests.ts | 14 + 7 files changed, 560 insertions(+) create mode 100644 src/components/Table/Table.stories.tsx create mode 100644 src/components/Table/Table.test.tsx create mode 100644 src/components/Table/index.tsx create mode 100644 src/components/Table/utils.ts diff --git a/src/__snapshots__/storybook.test.ts.snap b/src/__snapshots__/storybook.test.ts.snap index 01b61210..9a9b6277 100644 --- a/src/__snapshots__/storybook.test.ts.snap +++ b/src/__snapshots__/storybook.test.ts.snap @@ -130,6 +130,372 @@ exports[`Storyshots Link Default 1`] = ` `; +exports[`Storyshots Table Default 1`] = ` +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + First Name + + + + + + + + + + + +
+
+
+ + Age + + + + + + + + + + + +
+
+ Address +
+ Dolor Sit + + 30 + + San Francisco +
+ Lorem Ipsum + + 20 + + San Jose +
+ Amet Consectetur + + 35 + + Sunnyvale +
+
+
+
+
    +
  • + +
  • +
  • + + 1 + +
  • +
  • + +
  • +
+
+
+
+`; + exports[`Storyshots Tag Colored 1`] = ` = { + columns, + data +} + +const Template: Story> = args => + +export const Default = Template.bind({}) +Default.args = { + ...tableData +} diff --git a/src/components/Table/Table.test.tsx b/src/components/Table/Table.test.tsx new file mode 100644 index 00000000..4ded8874 --- /dev/null +++ b/src/components/Table/Table.test.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import Table from '.' +import { tableData } from './Table.stories' +import { mount, ReactWrapper } from 'enzyme' + +const mockData = tableData +let wrapper: ReactWrapper + +beforeEach(() => { + wrapper = mount( +
+
+ + ) +}) + +describe('Table', () => { + it('renders', () => { + const table = wrapper.find(Table) + expect(table).toHaveLength(1) + }) + + it('renders table rows with react keys', () => { + const table = wrapper.find(Table), + tableBody = table.find('tbody') + + expect(tableBody).toHaveLength(1) + + tableBody.forEach((node, i) => { + expect(node.find(`tr[data-row-key=${i}]`)).toHaveLength(1) + }) + }) +}) diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx new file mode 100644 index 00000000..31a630ba --- /dev/null +++ b/src/components/Table/index.tsx @@ -0,0 +1,34 @@ +import 'antd/lib/table/style/index.css' +import 'antd/lib/pagination/style/index.css' +import { Table as AntDTable } from 'antd' +import { processColumns, processData } from './utils' +import React, { ReactElement } from 'react' + +export interface ColumnType { + dataIndex: string + title: string // we need to pass a key instead of strings for i18n + type: 'string' | 'number' + sort?: boolean +} + +export interface TableProps { + data: DataType[] + columns: ColumnType[] +} + +function Table({ + columns, + data +}: TableProps): ReactElement { + const processedData = processData(data) + const processedColumns = processColumns(columns) + + return ( + + columns={processedColumns} + dataSource={processedData} + /> + ) +} + +export default Table diff --git a/src/components/Table/utils.ts b/src/components/Table/utils.ts new file mode 100644 index 00000000..b39e6445 --- /dev/null +++ b/src/components/Table/utils.ts @@ -0,0 +1,48 @@ +import { ColumnType as AntDColumnType } from 'antd/es/table' +import { ColumnType } from '.' +import { Key } from 'react' + +function sortStringCompare(column: ColumnType) { + return (a: any, b: any) => + a[column.dataIndex].localeCompare(b[column.dataIndex]) +} + +function sortNumberCompare(column: ColumnType) { + return (a: any, b: any) => a[column.dataIndex] - b[column.dataIndex] +} + +export function processData(data: DataType[]) { + const processedData: DataType[] = [] + let i: Key = 0 + + for (const item of data) { + const row = { + ...item, + key: i++ + } + processedData.push(row) + } + return processedData +} + +export function processColumns(columns: ColumnType[]) { + const processedColumns: AntDColumnType[] = [] + + for (const column of columns) { + const { dataIndex, title, sort, type } = column + const antDColumn: AntDColumnType = { + dataIndex, + showSorterTooltip: false, + title + } + + if (sort === undefined || sort) { + if (type === 'string') antDColumn.sorter = sortStringCompare(column) + if (type === 'number') antDColumn.sorter = sortNumberCompare(column) + } + + processedColumns.push(antDColumn) + } + + return processedColumns +} diff --git a/src/components/index.ts b/src/components/index.ts index 49944001..12aebb69 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,4 +2,5 @@ import 'normalize.css' import '../styles/index.css' export { default as Button } from './Button' export { default as Link } from './Link' +export { default as Table } from './Table' export { default as Tag } from './Tag' diff --git a/src/setupTests.ts b/src/setupTests.ts index 911f6563..997e9c4f 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -2,3 +2,17 @@ import Adapter from 'enzyme-adapter-react-16' import Enzyme from 'enzyme' Enzyme.configure({ adapter: new Adapter() }) + +Object.defineProperty(window, 'matchMedia', { + value: jest.fn().mockImplementation(query => ({ + addEventListener: jest.fn(), + addListener: jest.fn(), // deprecated + dispatchEvent: jest.fn(), + matches: false, + media: query, + onchange: null, + removeEventListener: jest.fn(), + removeListener: jest.fn() // deprecated + })), + writable: true +})