import React, { ReactElement, useContext, useState } from 'react'
import { DataGrid, ScreenSizeContext, SIZES, SplitButton } from '../'
import { HIDE_CONTROL, SPACE, Story, STRING } from '../helpers/storybook'
import { FocusOption, StickyColAlignment } from '../Table/Table'
import { JustifyContent } from './types'
interface Datum {
name: string
created: string
updated: string
items: number
author: string
active: boolean
}
const INITIAL_DATA = [
{
name: 'Config 1',
created: '4/13/2020',
updated: '6/29/2022',
items: 0,
author: 'unknown',
active: true,
},
{
name: 'Config 2',
created: '5/25/2019',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: true,
},
{
name: 'Config 3',
created: '8/16/2019',
updated: '6/29/2022',
items: 2,
author: 'unknown',
active: false,
},
{
name: 'Config 4',
created: '2/20/2019',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: true,
},
{
name: 'Config 5',
created: '5/16/2019',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: false,
},
{
name: 'Config 6',
created: '10/31/2019',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: true,
},
{
name: 'Config 7',
created: '11/23/2019',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: true,
},
{
name: 'Config 8',
created: '3/20/2020',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: false,
},
{
name: 'Config 9',
created: '6/13/2020',
updated: '6/29/2022',
items: 2,
author: 'unknown',
active: false,
},
{
name: 'Config 10',
created: '7/1/2020',
updated: '6/29/2022',
items: 3,
author: 'unknown',
active: true,
},
{
name: 'Config 11',
created: '3/3/2020',
updated: '6/29/2022',
items: 3,
author: 'Danilo',
active: true,
},
]
const justifyOptions: JustifyContent[] = [
'unset',
'flex-start',
'flex-end',
'center',
'space-between',
'space-around',
'space-evenly',
]
const BoolComponent = ({ value }: { value: boolean }): ReactElement => {
return
{value ? 'YES' : 'NO'}
}
interface Args {
align: 'center' | 'right' | 'left'
initialData: Datum[]
includePaginationAndSort?: boolean
activeColumnWidth: string
actionColumnWidth: string
dividers: boolean
showResultsCount: boolean
providePageSizeSelect: boolean
providePageCount: boolean
prevText: string
nextText: string
disableNext: boolean
sortableCols: boolean
topSection: boolean
sticky: StickyColAlignment
fullWidth: boolean
justifyTop: JustifyContent
spacingTop: string
pageSizeSelectLabel: string
justifyBottom: JustifyContent
spacingBottom: string
paginationLabel: string
currentPageLabel: string
prevPageLabel: string
nextPageLabel: string
lastPageLabel: string
rowFocus: FocusOption
rowHover: boolean
}
const DataGridContainer: Story = ({
align,
initialData,
includePaginationAndSort = true,
cardBreakpoint,
variant,
fullWidth,
activeColumnWidth,
actionColumnWidth,
dividers,
showResultsCount,
providePageSizeSelect,
providePageCount,
prevText,
nextText,
disableNext,
sortableCols,
topSection,
justifyTop,
spacingTop,
pageSizeSelectLabel,
justifyBottom,
spacingBottom,
paginationLabel,
currentPageLabel,
prevPageLabel,
nextPageLabel,
lastPageLabel,
margin,
sticky,
rowFocus,
rowHover,
}) => {
const size = useContext(ScreenSizeContext)
const isCardView = cardBreakpoint && size <= SIZES[cardBreakpoint]
const [data, setData] = useState(initialData)
const [paginationOptions, setPaginationOptions] = useState<{
currentPage: number
pageSize: number
itemOffset?: number
}>({ currentPage: 1, pageSize: 4 })
const clone = (index: number) =>
setData((currentData): Datum[] => {
const rowData = currentData[index]
return [...currentData, { ...rowData, name: `${rowData.name} Copy` }]
})
const deleteRow = (deleteIndex: number) =>
setData((currentData) => {
const newData = [...currentData]
newData.splice(deleteIndex, 1)
return newData
})
const onSort = (newSortOptions: { id: string; sortAscending: boolean }[]): void => {
const sortId = newSortOptions[0].id
const sortAscending = newSortOptions[0].sortAscending
const dataCopy = [...data]
if (sortId === 'created') {
if (sortAscending) {
dataCopy.sort((a: Datum, b: Datum): number => {
return Date.parse(a.created) - Date.parse(b.created)
})
} else {
dataCopy.sort((a: Datum, b: Datum): number => {
return Date.parse(b.created) - Date.parse(a.created)
})
}
} else if (sortId === 'active') {
if (sortAscending) {
dataCopy.sort((a: Datum, b: Datum): number => {
return a.active === b.active ? 0 : a.active ? 1 : -1
})
} else {
dataCopy.sort((a: Datum, b: Datum): number => {
return a.active === b.active ? 0 : a.active ? -1 : 1
})
}
}
setData(dataCopy)
}
const itemCount = data.length
const { itemOffset = 0, pageSize } = paginationOptions
const firstItem = itemOffset + 1
const paginateData = (): Datum[] => {
return data.slice(itemOffset, itemOffset + pageSize)
}
const getResultsCountText = (): string => {
const lastItem = Math.min(itemOffset + pageSize, itemCount)
if (providePageCount) {
return `Showing ${firstItem} to ${lastItem} of ${itemCount}`
} else {
return `Showing ${firstItem} to ${lastItem}`
}
}
const usableData = includePaginationAndSort ? paginateData() : data
return (
{topSection && (
{showResultsCount && !isCardView && {getResultsCountText()}}
{includePaginationAndSort && providePageSizeSelect && (
)}
)}
{(_, { rowIndex }) => (
{
return
}}
mainActionLabel="Edit"
>
clone(rowIndex + itemOffset)}>
Clone this row
deleteRow(rowIndex + itemOffset)}>
Delete
)}
{isCardView && showResultsCount && size.toString() !== 'tiny' ? (
{getResultsCountText()}
) : null}
{includePaginationAndSort ? (
providePageCount ? (
) : (
)
) : null}
{isCardView && showResultsCount && size.toString() === 'tiny' ? (
{getResultsCountText()}
) : null}
)
}
export default {
title: 'DataGrid',
component: DataGrid,
argTypes: {
paginationOptions: HIDE_CONTROL,
sortOptions: HIDE_CONTROL,
onPageChange: HIDE_CONTROL,
onSort: HIDE_CONTROL,
cardBreakpoint: { options: ['tiny', 'small', 'medium', 'large'] },
variant: { options: ['table', 'card', 'mini'] },
activeColumnWidth: { name: 'active column width', ...STRING },
actionColumnWidth: { name: 'action column width', ...STRING },
initialData: HIDE_CONTROL,
},
args: {
cardBreakpoint: 'tiny',
dividers: false,
},
} as const
export const BasicUsage = DataGridContainer.bind(null)
BasicUsage.argTypes = {
align: { options: ['left', 'center', 'right'] },
showResultsCount: { name: 'show result count' },
providePageSizeSelect: { name: 'show page size select' },
providePageCount: { name: 'show page count' },
prevText: { name: 'PrevNext: prevText', ...STRING },
nextText: { name: 'PrevNext: nextText', ...STRING },
disableNext: { name: 'PrevNext: disableNext', control: 'boolean' },
sortableCols: { name: 'include sortable columns' },
sticky: { name: 'Sticky column', options: ['none', 'right'] },
fullWidth: { name: 'Full Width' },
topSection: { name: 'show top section' },
justifyTop: {
name: 'top section: justifyContent',
options: justifyOptions,
},
spacingTop: { name: 'top section: spacing', ...SPACE },
pageSizeSelectLabel: { name: 'rows per page label', ...STRING },
justifyBottom: {
name: 'bottom section: justifyContent',
options: justifyOptions,
},
spacingBottom: { name: 'bottom section: spacing', ...SPACE },
paginationLabel: { name: 'Pagination: label', ...STRING },
currentPageLabel: { name: 'Pagination: currentPageLabel', ...STRING },
prevPageLabel: { name: 'Pagination: prevPageLabel', ...STRING },
nextPageLabel: { name: 'Pagination: nextPageLabel', ...STRING },
lastPageLabel: { name: 'Pagination: lastPageLabel', ...STRING },
margin: SPACE,
rowFocus: { options: [true, false, 'mouse-only'] },
}
BasicUsage.args = {
initialData: INITIAL_DATA,
showResultsCount: true,
providePageSizeSelect: true,
providePageCount: true,
prevText: 'Prev',
nextText: 'Next',
sortableCols: true,
topSection: true,
justifyTop: 'space-between',
spacingTop: '4',
justifyBottom: 'flex-end',
spacingBottom: '4',
sticky: 'none',
fullWidth: true,
rowFocus: true,
rowHover: true,
}
export const LotsAndLotsOfRows = DataGridContainer.bind(null)
LotsAndLotsOfRows.argTypes = { includePaginationAndSort: HIDE_CONTROL }
LotsAndLotsOfRows.args = {
includePaginationAndSort: false,
initialData: INITIAL_DATA.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA)
.concat(INITIAL_DATA),
}
LotsAndLotsOfRows.parameters = {
cactus: {
overrides: {
textAlign: 'center',
},
// Only applies to flex container
align: 'top',
},
}
LotsAndLotsOfRows.storyName = 'Lots and Lots of Rows'