UNPKG

@spaced-out/ui-design-system

Version:
241 lines (223 loc) 6.47 kB
// @flow strict import * as React from 'react'; import type {ColorTypes} from '../../types/typography'; import classify from '../../utils/classify'; import type {ClassNameComponent} from '../../utils/makeClassNameComponent'; import {makeClassNameComponent} from '../../utils/makeClassNameComponent'; import {Checkbox} from '../Checkbox'; import {Icon} from '../Icon'; import {SubTitleExtraSmall, TEXT_COLORS} from '../Text'; import {BasicRow} from './DefaultRow'; import type {SortDirection} from './hooks'; import type {GenericObject} from './Table'; import css from './Table.module.css'; export type GenericHeaderItem<T: GenericObject, U: GenericObject> = { label: React.Node, key: $Keys<T>, className?: string, filterIcon?: React.Node, filtered?: boolean, subtext?: string, sortable?: boolean, headerIconClassName?: string, sticky?: boolean, render?: React.ComponentType<{ data: T, extras?: U, className?: string, selected?: boolean, disabled?: boolean, }>, }; export type GenericHeaderItems<T, U> = GenericHeaderItem<T, U>[]; export const BasicHeadCell: ClassNameComponent<'th'> = makeClassNameComponent( css.defaultHeaderCell, 'th', ); export const BasicTableHead: ClassNameComponent<'thead'> = makeClassNameComponent(css.defaultTableHead, 'thead'); export type TableHeaderProps<T, U> = { className?: string, tableHeaderClassName?: string, sortable?: boolean, columns: GenericHeaderItems<T, U>, handleSortClick?: (sortKey: $Keys<T>) => mixed, sortKey?: $Keys<T>, sortDirection?: SortDirection, checked?: 'true' | 'false' | 'mixed', handleCheckboxClick?: ({value: string, checked: boolean}) => mixed, disabled?: boolean, stickyHeader?: boolean, }; const SortIcon = ({ sortDirection, color, className, }: { sortDirection: SortDirection, className: string, color: ColorTypes, }) => { if (sortDirection === 'original') { return ( <Icon color={color} name="caret-down" size="small" type="solid" className={className} /> ); } else if (sortDirection === 'asc') { return ( <Icon color={color} name="arrow-up" size="small" type="regular" className={className} /> ); } else if (sortDirection === 'desc') { return ( <Icon color={color} name="arrow-down" size="small" type="regular" className={className} /> ); } }; export function DefaultTableHeader<T: GenericObject, U: GenericObject>( props: TableHeaderProps<T, U>, ): React.Node { const { className, sortable = false, columns, handleSortClick, sortKey, sortDirection = 'original', handleCheckboxClick, checked, disabled, stickyHeader, } = props; const tableHeaderCells = () => ( <> {columns.map((columnData, index) => { const { key, label, subtext, filterIcon, filtered, className, sticky, sortable: columnSortable = false, } = columnData; let headerClassName; const filterable = Boolean(filterIcon); if ((sortable && columnSortable) || filterable) { headerClassName = classify( css.defaultHeaderCellSortable, { [css.filtered]: filtered, [css.stickyHeaderCell]: sticky, }, css[sortDirection], className, ); } else { headerClassName = classify(className, { [css.stickyHeaderCell]: sticky, }); } const headCellClickHandler = () => { if (sortable && columnSortable && handleSortClick) { handleSortClick(key); } }; let columnSortDirection = 'original'; if (sortKey === key) { columnSortDirection = sortDirection; } return ( <BasicHeadCell className={classify( { [css.selectedHeader]: sortKey === key && columnSortDirection !== 'original', }, headerClassName, )} // eslint-disable-next-line react/no-array-index-key key={index} scope="col" onClick={headCellClickHandler} > <div className={classify(css.labelContents)}> <div className={css.labelContainer}> <SubTitleExtraSmall color={TEXT_COLORS.secondary} className={classify({ [css.selectedHeader]: sortKey === key && columnSortDirection !== 'original', })} > {label} </SubTitleExtraSmall> <span className={css.headerSubtext}>{subtext && subtext}</span> </div> {(sortable || filterIcon != null) && ( <div className={css.headerIconContainer}> {columnSortable && ( <SortIcon color={TEXT_COLORS.secondary} className={classify(css.sortArrow, { [css.selectedSortArrow]: sortKey === key, })} sortDirection={columnSortDirection} /> )} {filterIcon != null && ( <div className={css.filterIcon}>{filterIcon}</div> )} </div> )} </div> </BasicHeadCell> ); })} </> ); return ( <BasicTableHead className={classify( css.tableHeaderSortable, {[css.stickyHeader]: stickyHeader}, className, )} > <BasicRow className={css.defaultHeaderRow}> {handleCheckboxClick && ( <BasicHeadCell scope="col"> <div className={css.checkbox}> <Checkbox value="all" checked={checked === 'true' ? true : false} indeterminate={checked === 'mixed'} onChange={handleCheckboxClick} disabled={disabled} ariaLabel="Select all rows" /> </div> </BasicHeadCell> )} {tableHeaderCells()} </BasicRow> </BasicTableHead> ); }