UNPKG

@spaced-out/ui-design-system

Version:
213 lines (196 loc) 6.27 kB
// @flow strict import * as React from 'react'; import get from 'lodash/get'; import xor from 'lodash/xor'; import {useWindowSize} from '../../hooks/useWindowSize'; import {sizeFluid} from '../../styles/variables/_size'; import {classify} from '../../utils/classify'; import type {ClassNameComponent} from '../../utils/makeClassNameComponent'; import {makeClassNameComponent} from '../../utils/makeClassNameComponent'; import {DefaultRow, EmptyRow} from './DefaultRow'; import {DefaultTableHeader} from './DefaultTableHeader'; import type {SortDirection} from './hooks'; import type {GenericObject, TableProps} from './Table'; import css from './Table.module.css'; export const BasicTable: ClassNameComponent<'table'> = makeClassNameComponent( css.defaultTable, 'table', ); export const BasicTableBody: ClassNameComponent<'tbody'> = makeClassNameComponent(css.defaultTableBody, 'tbody'); /** * A Static Default Table. * * Our */ export function StaticTable<Data: GenericObject, Extras: GenericObject>(props: { ...TableProps<Data, Extras>, handleSortClick?: (sortKey: string) => mixed, sortKey?: string, sortDirection?: SortDirection, rowKeys?: string[], }): React.Node { const { classNames, className, TableRow, entries, extras, rowKeys, headers, showHeader = true, tableHeaderClassName, sortable, // eslint-disable-next-line unused-imports/no-unused-vars defaultSortKey, // eslint-disable-next-line unused-imports/no-unused-vars defaultSortDirection = 'original', // eslint-disable-next-line unused-imports/no-unused-vars onSort, handleSortClick, sortKey, sortDirection, selectedKeys, disabledKeys = [], onSelect, isLoading, idName = 'id', emptyText, disabled, customLoader, borderRadius, stickyHeader, } = props; // this is a fallback and honestly probably doesn't need the // memo'ing const mappedKeys = React.useMemo( () => rowKeys ?? entries.map((e) => get(e, idName)), [entries, idName, rowKeys], ); const tableRef = React.useRef(null); const {width} = useWindowSize(); const [tableWidth, setTableWidth] = React.useState(); React.useEffect(() => { if (tableRef.current) { setTableWidth(tableRef.current.offsetWidth); } }, [width]); /** * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined in case selectedKeys is not there. */ const handleHeaderCheckboxClick = selectedKeys ? ({checked}: {value: string, checked: boolean}) => { let selectedRowIds = []; if (selectedKeys) { if (checked === true) { selectedRowIds = entries.map((singleRowObj) => get(singleRowObj, idName), ); } onSelect?.(selectedRowIds); } } : undefined; return ( <div className={classify(css.tableContainer, classNames?.wrapper)} data-id="table-wrap" ref={tableRef} style={{ '--border-radius': borderRadius, '--table-width': tableWidth ? `${tableWidth}px` : sizeFluid, }} > <BasicTable data-id="basic-table" className={classify( className, { [css.fullHeightTable]: isLoading || (!entries.length && !!emptyText), }, classNames?.table, )} > {showHeader && ( <DefaultTableHeader className={classify(tableHeaderClassName, classNames?.tableHeader)} sortable={sortable} columns={headers} handleSortClick={handleSortClick} sortKey={sortKey} sortDirection={sortDirection} disabled={disabled} handleCheckboxClick={handleHeaderCheckboxClick} stickyHeader={stickyHeader} checked={ selectedKeys == null || selectedKeys.length === 0 ? 'false' : selectedKeys.length < entries.length ? 'mixed' : 'true' } /> )} <BasicTableBody className={classNames?.tableBody}> {isLoading || !entries.length ? ( <EmptyRow isLoading={isLoading} emptyText={emptyText} headersLength={ handleHeaderCheckboxClick ? headers.length + 1 : headers.length } customLoader={customLoader} /> ) : ( mappedKeys.map((key) => { const data = entries.find((e) => get(e, idName) === key); if (data == null) { return null; } (data: Data); const selected = selectedKeys && Array.isArray(selectedKeys) ? selectedKeys.includes(get(data, idName)) : undefined; const isRowDisabled = disabledKeys && Array.isArray(disabledKeys) ? disabledKeys.includes(get(data, idName)) : false; return TableRow ? ( <TableRow key={key} data={data} headers={headers} // extras and rowKeys are both 'optional' extras={extras} sortedKeys={rowKeys ?? mappedKeys} selected={selected} disabled={disabled || isRowDisabled} /> ) : ( <DefaultRow key={key} data={data} extras={extras} headers={headers} selected={selected} onSelect={ selectedKeys != null ? (_v) => onSelect?.(xor(selectedKeys ?? [], [key])) : undefined } disabled={disabled || isRowDisabled} classNames={{ tableRow: classNames?.tableRow, checkbox: classNames?.checkbox, }} /> ); }) )} </BasicTableBody> </BasicTable> </div> ); }