diff --git a/package-lock.json b/package-lock.json index ff48639f..a1c7bc37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dassana-io/web-components", - "version": "0.10.1", + "version": "0.10.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 077024fc..9a7f13fa 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/components/ColoredDot/index.tsx b/src/components/ColoredDot/index.tsx index b3690600..cd7e85b4 100644 --- a/src/components/ColoredDot/index.tsx +++ b/src/components/ColoredDot/index.tsx @@ -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 @@ -49,7 +49,7 @@ export const ColoredDot: FC = ({ const showTooltip = colors && tooltipText return showTooltip ? ( - + ) : ( diff --git a/src/components/Table/CellWithTooltip.tsx b/src/components/Table/CellWithTooltip.tsx index 6d7b5f1c..7796f9ab 100644 --- a/src/components/Table/CellWithTooltip.tsx +++ b/src/components/Table/CellWithTooltip.tsx @@ -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({ @@ -26,9 +27,13 @@ export const CellWithTooltip: FC = ({ }: CellWithTooltipProps) => { const [hasTooltip, setHasTooltip] = useState(false) + const { isMobile } = useTableContext() + const classes = useStyles() - return ( + return isMobile ? ( + <>{text} + ) : (
.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' } }) @@ -40,7 +46,9 @@ export const MultipleIcons: FC = ({ height = defaultIconHeight, truncateLength = 2 }: Props) => { - const classes = useStyles() + const { isMobile } = useTableContext() + + const classes = useStyles({ isMobile }) interface RenderIcons { sliceStartIndex: number @@ -71,12 +79,13 @@ export const MultipleIcons: FC = ({ }) return ( - <> +
{renderIcons({ sliceEndIndex: truncateLength, sliceStartIndex: 0 })} {truncateLength < iconPropsArr.length && ( = ({ )} - +
) } diff --git a/src/components/Table/TableContext.ts b/src/components/Table/TableContext.ts new file mode 100644 index 00000000..b1be6328 --- /dev/null +++ b/src/components/Table/TableContext.ts @@ -0,0 +1,9 @@ +import { createCtx } from '@dassana-io/web-utils' + +export interface TableContextProps { + isMobile: boolean +} + +const [useTableContext, TableCtxProvider] = createCtx() + +export { TableCtxProvider, useTableContext } diff --git a/src/components/Table/TableSkeleton.tsx b/src/components/Table/TableSkeleton.tsx index 4ff3b5e6..f92cf053 100644 --- a/src/components/Table/TableSkeleton.tsx +++ b/src/components/Table/TableSkeleton.tsx @@ -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' @@ -127,13 +128,17 @@ export const TableSkeleton: FC = ({ columns, rowCount }: TableSkeletonProps) => { + const { isMobile } = useTableContext() + const classes = useStyles() + const columnCount = isMobile ? 2 : columns.length + return ( - {times(columns.length, (j: number) => ( + {times(columnCount, (j: number) => ( ))} @@ -141,7 +146,7 @@ export const TableSkeleton: FC = ({ {times(rowCount, (i: number) => ( - {times(columns.length, (j: number) => ( + {times(columnCount, (j: number) => ( { - wrapper = mount() + wrapper = mount( + + + + ) }) describe('TableSkeleton', () => { diff --git a/src/components/Table/fixtures/7_sample_data.ts b/src/components/Table/fixtures/7_sample_data.ts index 53589a6a..0491258a 100644 --- a/src/components/Table/fixtures/7_sample_data.ts +++ b/src/components/Table/fixtures/7_sample_data.ts @@ -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: [ { diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index c7d2ca0a..5513733f 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -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, { @@ -24,6 +26,15 @@ export interface OnRowClick { (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 @@ -60,6 +71,7 @@ export interface TableProps extends CommonComponentProps { * Optional callback that runs when a table row is clicked */ onRowClick?: OnRowClick> + scrollConfig?: ScrollConfig /** * Optional prop to enable/disable table search */ @@ -86,6 +98,7 @@ export const Table = ({ dataTag, loading = false, onRowClick, + scrollConfig, search = true, skeletonRowCount = 5, searchProps = {} as SearchProps @@ -94,6 +107,8 @@ export const Table = ({ const [filteredData, setFilteredData] = useState[]>([]) const [pagination, setPagination] = useState(false) + const { isMobile } = useWindowSize() + const tableClasses = useStyles({ onRowClick, searchProps @@ -205,35 +220,58 @@ export const Table = ({ }) } + 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 ( -
- {search && ( -
- +
+ {search && ( +
+ +
+ )} + {loading ? ( + + ) : ( + -
- )} - {loading ? ( - - ) : ( - - )} -
+ )} +
+ ) } diff --git a/src/components/Table/styles.ts b/src/components/Table/styles.ts index 6770c4d6..dc7a8681 100644 --- a/src/components/Table/styles.ts +++ b/src/components/Table/styles.ts @@ -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 diff --git a/src/components/Table/useWindowSize.ts b/src/components/Table/useWindowSize.ts new file mode 100644 index 00000000..08ad09a0 --- /dev/null +++ b/src/components/Table/useWindowSize.ts @@ -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(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 } +} diff --git a/src/components/Table/utils.tsx b/src/components/Table/utils.tsx index fd4a00d5..95953724 100644 --- a/src/components/Table/utils.tsx +++ b/src/components/Table/utils.tsx @@ -7,7 +7,6 @@ import { getJSONPathValue } from 'components/utils' import isUndefined from 'lodash/isUndefined' import { JSONPath } from 'jsonpath-plus' import moment from 'moment' -import { MultipleIcons } from './MultipleIcons' import { ColumnFormats, ColumnType, @@ -20,14 +19,13 @@ import { NumberDateType, RenderPropsIcon } from './types' +import { defaultIconHeight, MultipleIcons } from './MultipleIcons' import { Icon, IconName, IconProps } from '../Icon' import { Link, LinkProps } from '../Link' import React, { Key, MouseEvent } from 'react' import { Tag, TagProps } from '../Tag' import { Toggle, ToggleProps } from '../Toggle' -export const defaultIconHeight = 25 - /* ------- Exported Functions ------- */ interface MappedData { @@ -57,6 +55,7 @@ export function processColumns( ) { return columns.map(column => { const { dataIndex, title, sort = true } = column + const antDColumn: AntDColumnType = { dataIndex, showSorterTooltip: false,