Skip to content

Commit

Permalink
feat #253 - Table updates to make component responsive (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-dassana authored Mar 15, 2021
1 parent ae4d20a commit 936ce11
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 42 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dassana-io/web-components",
"version": "0.10.1",
"version": "0.10.2",
"publishConfig": {
"registry": "https://npm.pkg.github.com/dassana-io"
},
Expand Down
4 changes: 2 additions & 2 deletions src/components/ColoredDot/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cn from 'classnames'
import { createUseStyles as createJssUseStyles } from 'react-jss'
import { ThemeType } from 'components/assets/styles'
import { Tooltip } from 'antd'
import { Tooltip } from 'components/Tooltip'
import React, { FC } from 'react'

const { light, dark } = ThemeType
Expand Down Expand Up @@ -49,7 +49,7 @@ export const ColoredDot: FC<ColoredDotProps> = ({
const showTooltip = colors && tooltipText

return showTooltip ? (
<Tooltip title={tooltipText}>
<Tooltip placement='top' renderWithoutDataTag title={tooltipText}>
<span className={dotClasss}></span>
</Tooltip>
) : (
Expand Down
7 changes: 6 additions & 1 deletion src/components/Table/CellWithTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createUseStyles } from 'react-jss'
import { Tooltip } from 'components/Tooltip'
import { useTableContext } from './TableContext'
import React, { FC, SyntheticEvent, useState } from 'react'

const useStyles = createUseStyles({
Expand All @@ -26,9 +27,13 @@ export const CellWithTooltip: FC<CellWithTooltipProps> = ({
}: CellWithTooltipProps) => {
const [hasTooltip, setHasTooltip] = useState(false)

const { isMobile } = useTableContext()

const classes = useStyles()

return (
return isMobile ? (
<>{text}</>
) : (
<div className={classes.container}>
<div
className={classes.wrapper}
Expand Down
19 changes: 14 additions & 5 deletions src/components/Table/MultipleIcons.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import cn from 'classnames'
import { createUseStyles } from 'react-jss'
import { defaultIconHeight } from './utils'
import { styleguide } from 'components/assets/styles'
import { Tooltip } from 'components/Tooltip'
import { useTableContext } from './TableContext'
import { Icon, IconProps } from '../Icon'
import React, { FC } from 'react'

const { spacing } = styleguide

export const defaultIconHeight = 25

const useStyles = createUseStyles({
count: { borderBottom: '1px solid', marginLeft: spacing.s },
icon: {
Expand All @@ -24,8 +26,12 @@ const useStyles = createUseStyles({
'& > .ant-tooltip-content > .ant-tooltip-inner': {
padding: `${spacing.s}px 0 0 ${spacing.s}px`
},
maxWidth: 250 - spacing.s
maxWidth: ({ isMobile }) => (isMobile ? 140 : 250 - spacing.s)
}
},
wrapper: {
display: 'flex',
flexWrap: 'no-wrap'
}
})

Expand All @@ -40,7 +46,9 @@ export const MultipleIcons: FC<Props> = ({
height = defaultIconHeight,
truncateLength = 2
}: Props) => {
const classes = useStyles()
const { isMobile } = useTableContext()

const classes = useStyles({ isMobile })

interface RenderIcons {
sliceStartIndex: number
Expand Down Expand Up @@ -71,12 +79,13 @@ export const MultipleIcons: FC<Props> = ({
})

return (
<>
<div className={classes.wrapper}>
{renderIcons({ sliceEndIndex: truncateLength, sliceStartIndex: 0 })}
{truncateLength < iconPropsArr.length && (
<Tooltip
classes={[classes.tooltip]}
placement='bottom'
popupContainerSelector={`.${classes.wrapper}`}
renderWithoutDataTag
title={renderIcons({
isInsideTooltip: true,
Expand All @@ -95,6 +104,6 @@ export const MultipleIcons: FC<Props> = ({
</span>
</Tooltip>
)}
</>
</div>
)
}
9 changes: 9 additions & 0 deletions src/components/Table/TableContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createCtx } from '@dassana-io/web-utils'

export interface TableContextProps {
isMobile: boolean
}

const [useTableContext, TableCtxProvider] = createCtx<TableContextProps>()

export { TableCtxProvider, useTableContext }
9 changes: 7 additions & 2 deletions src/components/Table/TableSkeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import random from 'lodash/random'
import { Skeleton } from '../Skeleton'
import { tablePalette } from './styles'
import times from 'lodash/times'
import { useTableContext } from './TableContext'
import { ColumnFormats, ColumnType, ColumnTypes } from './types'
import React, { FC } from 'react'
import { styleguide, ThemeType } from 'components/assets/styles'
Expand Down Expand Up @@ -127,21 +128,25 @@ export const TableSkeleton: FC<TableSkeletonProps> = ({
columns,
rowCount
}: TableSkeletonProps) => {
const { isMobile } = useTableContext()

const classes = useStyles()

const columnCount = isMobile ? 2 : columns.length

return (
<table className={classes.table}>
<thead>
<tr>
{times(columns.length, (j: number) => (
{times(columnCount, (j: number) => (
<THeaderCellSkeleton key={j} />
))}
</tr>
</thead>
<tbody>
{times(rowCount, (i: number) => (
<tr key={i}>
{times(columns.length, (j: number) => (
{times(columnCount, (j: number) => (
<TDataCellSkeleton
columns={columns}
index={j}
Expand Down
7 changes: 6 additions & 1 deletion src/components/Table/__tests__/TableSkeleton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import mockData from '__mocks__/table_mock_data'
import React from 'react'
import { TableCtxProvider } from '../TableContext'
import { TableSkeleton } from '../TableSkeleton'
import { mount, ReactWrapper } from 'enzyme'

let wrapper: ReactWrapper

beforeEach(() => {
wrapper = mount(<TableSkeleton columns={mockData.columns} rowCount={5} />)
wrapper = mount(
<TableCtxProvider value={{ isMobile: false }}>
<TableSkeleton columns={mockData.columns} rowCount={5} />
</TableCtxProvider>
)
})

describe('TableSkeleton', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/fixtures/7_sample_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const data: JSONPathData[] = [
{
company: { id: 'c2', value: 'dassana' },
id: 2,
name: { id: 'n2', value: 'Amet Consectetur' },
name: { id: 'n2', value: 'Amet Consectetur Adipiscing Elit' },
start_date: { date: 1553932342212, id: 'sd3' },
vendors: [
{
Expand Down
86 changes: 62 additions & 24 deletions src/components/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import debounce from 'lodash/debounce'
import Fuse from 'fuse.js'
import { getDataTestAttributeProp } from '../utils'
import { Input } from '../Input'
import { TableCtxProvider } from './TableContext'
import { TableSkeleton } from './TableSkeleton'
import { useStyles } from './styles'
import { useWindowSize } from './useWindowSize'
import { ColumnType, TableData } from './types'
import { mapData, mapFilterKeys, processColumns, processData } from './utils'
import React, {
Expand All @@ -24,6 +26,15 @@ export interface OnRowClick<TableData> {
(data: TableData, rowIndex: number): void
}

export interface ScrollConfig {
/**
* whether the table is scrollable on mobile only
* @default true
*/
mobileOnly?: boolean
x: number
}

export interface SearchProps {
/**
* Describes expected value of element
Expand Down Expand Up @@ -60,6 +71,7 @@ export interface TableProps<Data> extends CommonComponentProps {
* Optional callback that runs when a table row is clicked
*/
onRowClick?: OnRowClick<TableData<Data>>
scrollConfig?: ScrollConfig
/**
* Optional prop to enable/disable table search
*/
Expand All @@ -86,6 +98,7 @@ export const Table = <Data,>({
dataTag,
loading = false,
onRowClick,
scrollConfig,
search = true,
skeletonRowCount = 5,
searchProps = {} as SearchProps
Expand All @@ -94,6 +107,8 @@ export const Table = <Data,>({
const [filteredData, setFilteredData] = useState<TableData<Data>[]>([])
const [pagination, setPagination] = useState<Pagination>(false)

const { isMobile } = useWindowSize()

const tableClasses = useStyles({
onRowClick,
searchProps
Expand Down Expand Up @@ -205,35 +220,58 @@ export const Table = <Data,>({
})
}

let scrollProps = {}

if (scrollConfig && !scrollConfig.mobileOnly) {
scrollProps = {
scroll: {
x: scrollConfig.x
}
}
} else if (isMobile) {
scrollProps = {
scroll: {
x: scrollConfig ? scrollConfig.x : columns.length * 150
}
}
}

if (skeletonRowCount < 1)
throw new Error('skeletonRowCount must be a positive integer')

return (
<div className={cn(tableClasses.tableContainer, classes)}>
{search && (
<div className={tableClasses.searchBarWrapper}>
<Input
dataTag='table-search'
loading={loading}
onChange={handleChange}
placeholder={searchProps.placeholder}
<TableCtxProvider value={{ isMobile }}>
<div className={cn(tableClasses.tableContainer, classes)}>
{search && (
<div className={tableClasses.searchBarWrapper}>
<Input
dataTag='table-search'
fullWidth={isMobile}
loading={loading}
onChange={handleChange}
placeholder={searchProps.placeholder}
/>
</div>
)}
{loading ? (
<TableSkeleton
columns={columns}
rowCount={skeletonRowCount}
/>
) : (
<AntDTable
columns={processedColumns}
dataSource={searchTerm ? filteredData : processedData}
pagination={pagination}
rowClassName={getRowClassName}
rowKey={getRowKey}
{...getDataTestAttributeProp('table', dataTag)}
{...optionalProps}
{...scrollProps}
/>
</div>
)}
{loading ? (
<TableSkeleton columns={columns} rowCount={skeletonRowCount} />
) : (
<AntDTable
columns={processedColumns}
dataSource={searchTerm ? filteredData : processedData}
pagination={pagination}
rowClassName={getRowClassName}
rowKey={getRowKey}
{...getDataTestAttributeProp('table', dataTag)}
{...optionalProps}
/>
)}
</div>
)}
</div>
</TableCtxProvider>
)
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/Table/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ export const useStyles = createUseStyles({
searchBarWrapper: {
alignSelf: props =>
props.searchProps.placement === 'right' ? 'flex-end' : 'flex-start',
marginBottom: spacing.m
marginBottom: spacing.m,
width: '100%'
},
tableContainer: generateTableStyles(light),
// eslint-disable-next-line sort-keys
Expand Down
38 changes: 38 additions & 0 deletions src/components/Table/useWindowSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useState } from 'react'

const getWindowSize = () => ({
height: window.innerHeight,
width: window.innerWidth
})

export interface WindowSize {
height: number
width: number
}

export enum Breakpoints {
mobile = 480
}

export const useWindowSize = () => {
const [windowSize, setWindowSize] = useState<WindowSize>(getWindowSize())
const [isMobile, setIsMobile] = useState(false)

useEffect(() => {
const handleResize = () => setWindowSize(getWindowSize())

window.addEventListener('resize', handleResize)

handleResize()

return () => window.removeEventListener('resize', handleResize)
}, [])

useEffect(() => {
windowSize.width <= Breakpoints.mobile
? setIsMobile(true)
: setIsMobile(false)
}, [windowSize])

return { isMobile, windowSize }
}
Loading

0 comments on commit 936ce11

Please sign in to comment.