import { selectDefined } from '@o/utils' import React, { useCallback, useMemo } from 'react' import { guessColumns } from '../forms/guessColumns' import { normalizeRow } from '../forms/normalizeRow' import { useGet } from '../hooks/useGet' import { useNodeSize } from '../hooks/useNodeSize' import { useParentNodeSize } from '../hooks/useParentNodeSize' import { useScale } from '../Scale' import { Section, SectionParentProps, SectionSpecificProps, useSectionProps } from '../Section' import { useShareStore } from '../Share' import { TitleRowSpecificProps } from '../TitleRow' import { DataColumnsShort } from '../types' import { useVisibility } from '../Visibility' import { FilterableProps, FilterableSearchInput, useFilterable } from './Filterable' import { ManagedTable, ManagedTableProps } from './ManagedTable' import { DEFAULT_ROW_HEIGHT } from './types' export type TableProps = Partial> & Omit & FilterableProps & Omit & { /** Flexibly define which columns to show, how to show them, and attach events to changes. Accepts array of strings, objects, or an object. */ columns?: DataColumnsShort /** Automatically adds a search input to the table */ searchable?: boolean /** Automatically exports selections to the Share store */ shareable?: boolean } const defaultColumns = { resizable: true, sortable: true, } function deepMergeDefined(obj: A, defaults: Record): A { for (const key in obj) { obj[key] = { ...defaults, ...obj[key], } } return obj } export const Table = (tableProps: TableProps) => { const shareStore = useShareStore() const sectionProps: SectionSpecificProps = useSectionProps(tableProps as any) // TODO fix const { flex = 1, bordered, title, subTitle, icon, beforeTitle, afterTitle, titleBorder, searchable, titlePadding = true, titleElement, shareable, maxHeight, maxWidth, padding, children: _discardChildren, rowLineHeight = DEFAULT_ROW_HEIGHT, ...props } = { ...sectionProps, ...tableProps, } const isVisible = useVisibility() const scale = useScale() const rowHeight = rowLineHeight * scale const sizer = useNodeSize({ throttle: 150, disable: !isVisible }) const height = typeof maxHeight === 'number' ? Math.min(maxHeight, sizer.height) : sizer.height const items = useMemo(() => (props.items ? props.items.map(normalizeRow) : null), [props.items]) const columns = useMemo( () => deepMergeDefined(guessColumns(props.columns, items && items[0]), defaultColumns), [props.columns, items], ) // do filtering... const filterable = useFilterable(props) const parentNodeSize = useParentNodeSize({ disable: !isVisible, throttle: 150 }) const getOnSelect = useGet(props.onSelect) const onSelect = useCallback( (selectedItems, indices) => { if (shareable) { shareStore.setSelected(shareable, selectedItems) } if (getOnSelect()) { getOnSelect()(selectedItems.map(row => row.values), indices) } }, [props.items, shareable], ) return (
} > 0 ? Math.min(height, rowHeight * items.length) : 800} height={height} flex={flex} {...props} columns={columns} filter={filterable.filter} onAddFilter={filterable.onAddFilter} onSelect={onSelect} rowLineHeight={rowHeight} />
) } Table.accepts = { surfaceProps: true, }