import { Collection, CollectionBy, CollectionProxy, FormDisplayerProps, FormFieldProps, FormService, Item, ItemAdaptee, Primitive, QueryFilterCriteriaOperator, QueryFilterOrCriteria, QuerySortBy, UseCollectionOptions, ValidationStatus, } from 'onekijs-framework'; import React, { ComponentType, FC, PropsWithChildren, ReactNode } from 'react'; import { StylableProps, TshirtSize } from '../../styles/typings'; import { CheckboxProps } from '../checkbox/typings'; import { FieldLayoutProps } from '../field/typings'; import { InputProps } from '../input/typings'; import { ListItemProps, ListItems, ListNotFoundProps, ListState, UseListOptions } from '../list/typings'; import { FormSelectProps, SelectBroker, SelectItem, SelectProps } from '../select/typings'; import { TextareaProps } from '../textarea/typings'; import TableService from './TableService'; export type ArrayTableProps = TableItem> = TableConfig & { adapter?: TableItemAdapter; columns?: TableColumn[]; dataSource?: string | T[] | (() => T[] | Promise); fetchOnce?: boolean; selected?: T[]; }; export type ControllerTableProps< T = any, I extends TableItem = TableItem, S extends TableState = TableState, C extends TableController = TableController, > = TableConfig & { controller: CollectionProxy; }; export type FormCellDisplayerProps = { Displayer: React.FC; name: string; label?: string; }; export type FormTableProps< T = any, I extends TableItem = TableItem, S extends TableState = TableState, C extends TableController = TableController, > = ControllerTableProps & FormFieldProps & FieldLayoutProps & { addLabel?: string; format?: 'id' | 'object' | 'auto'; defaultValue?: T[]; DeleteRowComponent?: React.FC>; FieldComponent?: React.FC>; value?: T[]; onAdd?: (initialValue: Partial | undefined) => void; onBlur?: () => void; onChange?: (value: T[]) => void; onFocus?: () => void; onRemove?: (form: FormService, removedValue: T, index: number) => void; SelectRowComponent?: React.FC>; status?: ValidationStatus; size?: TshirtSize; showAddButton?: boolean; ValueDisplayer?: React.FC>; }; export type FormTableContext = { tableName: string; onSelect: (item: TableItem, selected: boolean) => void; onAdd: (initialValue: Partial | undefined) => void; onRemove?: (form: FormService, removedValue: T, index: number) => void; addLabel: string; required?: boolean; maxLength?: number; minLength?: number; editable?: boolean; // if we add a element afterwards, it must be editable (if not, mark it as read only) }; export type FormTableItemDisplayerProps = { value: T; columns: TableColumn[]; first: boolean; last: boolean; className?: string; format: FormDisplayerProps['format']; name: string; index: number; }; export type TableValueDisplayerProps = { columns: TableColumn[]; value: T[]; format: FormDisplayerProps['format']; name: string; className?: string; }; export type TableBodyCellProps = TableItem> = { className?: string; colIndex: number; column: TableColumn; rowId?: string | number; rowIndex: number; item: I; data: T; }; export type Cell = TableItem> = FC>; export type TableBodyProps = TableItem> = { className?: string; columns: TableColumn[]; items: (I | undefined)[]; contentRef: React.RefObject; tableRef: React.RefObject; }; export type TableBodyRowProps = TableItem> = Omit< ListItemProps, 'CellComponent' > & { className?: string; CellComponent?: React.FC, 'data'>>; columns: TableColumn[]; onExpand?: (item: I | undefined, index: number) => void; onExpanding?: (item: I | undefined, index: number) => void; onExpanded?: (item: I | undefined, index: number) => void; onCollapse?: (item: I | undefined, index: number) => void; onCollapsing?: (item: I | undefined, index: number) => void; onCollapsed?: (item: I | undefined, index: number) => void; }; export type TableSerializerFormat = 'csv' | 'json'; export type TableConfig = TableItem> = { autoRefresh?: number; bodyClassName?: string; BodyComponent?: React.FC>; className?: string; ExpandedComponent?: React.FC>; filterable?: boolean; fit?: boolean; fixHeader?: boolean; follow?: number; footer?: boolean; footerClassName?: string; FooterComponent?: React.FC>; grow?: string; header?: boolean; headerClassName?: string; HeaderComponent?: React.FC>; height?: string | number; highlightRow?: boolean; increment?: number; itemHeight?: number | ((index: number) => number); LoadingComponent?: React.FC; LoadingRowComponent?: React.FC; NotFoundComponent?: React.FC | null; onRowClick?: TableRowHandler; onRowEnter?: TableRowHandler; onRowLeave?: TableRowHandler; onRowOver?: TableRowHandler; onRowOut?: TableRowHandler; paddingEnd?: number; paddingStart?: number; parentRef?: React.MutableRefObject; preload?: number; rowClassName?: string | ((item: I | undefined, rowIndex: number, columns: TableColumn[]) => string); RowComponent?: React.FC>; serializer?: (data: T[], format: TableSerializerFormat) => string; sortable?: boolean; stripRows?: boolean; tail?: boolean; ToolbarBottomComponent?: React.FC; ToolbarTopComponent?: React.FC; ToolbarBottomCenterComponent?: React.FC; ToolbarBottomLeftComponent?: React.FC; ToolbarBottomRightComponent?: React.FC; ToolbarTopCenterComponent?: React.FC; ToolbarTopLeftComponent?: React.FC; ToolbarTopRightComponent?: React.FC; }; export type TableController< T = any, I extends TableItem = TableItem, S extends TableState = TableState, > = Collection & { addColumn(column: TableColumn, position?: number): void; addSelected>(by: B, target: CollectionBy[B] | CollectionBy[B][]): I[]; columns: TableColumn[]; config?: TableConfig; initCell( rowIndex: number | 'header-title' | 'header-filter' | 'footer', colId: string, ref: React.RefObject, ): void; removeColumn(id: string): void; removeSelected>( by: B, target: CollectionBy[B] | CollectionBy[B][], ): I[]; serialize: (data: T[], format: TableSerializerFormat) => string; setSelected>(by: B, target: CollectionBy[B] | CollectionBy[B][]): I[]; startAutoRefresh: (interval: number) => void; stopAutoRefresh: () => void; toggle(item: I): void; }; export type TableColumn = TableItem> = TableColumnSpec & { computedWidth?: TableColumnComputedWidth; }; export type TableCellDisplayerProps = TableItem> = { column: TableColumn; rowIndex: number; colIndex: number; firstCol: boolean; lastCol: boolean; firstRow: boolean; lastRow: boolean; rowName: string; value: T; format: FormDisplayerProps['format']; }; export type TableCellSerializer = TableItem> = ( data: T, column: TableColumn, format: TableSerializerFormat, ) => any; export type TableColumnSpec = TableItem> = { className?: string | ((item: I, column: TableColumn, rowIndex: number) => string); CellComponent?: Cell; Displayer?: React.FC>; ErrorBoundaryComponent?: ComponentType>>; footerClassName?: string | ((column: TableColumn) => string); FooterComponent?: React.FC>; filterable?: boolean; FilterComponent?: React.FC>; headerClassName?: string | ((column: TableColumn) => string); help?: ReactNode; id: string; maxWidth?: string; minWidth?: string; serializer?: TableCellSerializer; sortable?: boolean; title?: string; TitleComponent?: React.FC>; weight?: number; width?: string; }; export type TableColumnWidth = { auto?: boolean; grow?: boolean; force?: boolean; unit?: 'px' | '%'; value?: number; }; export type TableColumnComputedWidth = { width?: string; minWidth?: string; }; export type TableExpandedProps = TableItem> = { item: I; rowId?: string | number; rowIndex: number; }; export type TableFilterOperator = { not: boolean; operator: QueryFilterCriteriaOperator; text: string; }; export type TableFilterOperatorProps = StylableProps & { onChange: (operator: TableFilterOperator) => void; operators: TableFilterOperator[]; selected: TableFilterOperator; }; export type TableFooterCellProps = TableItem> = { className?: string; colIndex: number; column: TableColumn; }; export type TableFooterProps = TableItem> = { className?: string; columns: TableColumn[]; }; export type TableHeaderCellProps = TableItem> = { className?: string; colIndex: number; column: TableColumn; filter?: QueryFilterOrCriteria; filterable: boolean; sort?: QuerySortBy; sortable: boolean; }; export type TableHeaderProps = TableItem> = { className?: string; columns: TableColumn[]; }; export type TableItem = Item & { expanded?: boolean; }; export type TableItemAdaptee = ItemAdaptee; export type TableItemAdapter = (data: T) => TableItemAdaptee; export type TableRowHandler = TableItem> = (item: I, index: number) => void; export type TableItems = ListItems; export type TableNotFoundProps = ListNotFoundProps; export type TableProps< T = any, I extends TableItem = TableItem, S extends TableState = TableState, C extends TableController = TableController, > = TableConfig & { adapter?: TableItemAdapter; controller?: CollectionProxy; columns?: TableColumn[]; dataSource?: string | T[] | (() => T[] | Promise); fetchOnce?: boolean; selected?: T[]; }; export type TableSortProps = TableItem> = { column: TableColumn; sort?: QuerySortBy; }; export type TableState = TableItem> = ListState & { adapter?: TableItemAdapter; columns: TableColumn[]; dataSource?: T[] | string; selected?: string[]; }; export type TableColumnsState = TableItem> = { columns: TableColumn[]; }; export type CheckboxColumn = TableItem> = TableColumn; export type InputColumn = TableItem> = TableColumn; export type SelectColumn< T = any, F = any, I extends TableItem = TableItem, FI extends SelectItem = SelectItem, > = TableColumn & { broker: SelectBroker; }; export type TextareaColumn = TableItem> = TableColumn; export type EnumColumnOptions = TableItem> = Omit, 'id'> & { filterDataSource: [Primitive, string][] | string[]; }; export type LinkColumnOptions = TableItem> = Omit< TableColumnSpec, 'CellComponent' | 'id' > & { href: string | ((item: I) => string); }; export type CheckboxColumnOptions = TableItem> = Omit< TableColumnSpec, 'CellComponent' | 'id' > & Omit & Omit & { CellComponent?: (options: CheckboxColumnOptions) => React.FC>; defaultValue?: boolean; }; export type InputColumnOptions = TableItem> = Omit< TableColumnSpec, 'CellComponent' | 'id' > & Omit & Omit & { CellComponent?: (options: InputColumnOptions) => React.FC>; }; export type SelectColumnOptions< T = any, S = any, TI extends TableItem = TableItem, SI extends SelectItem = SelectItem, > = Omit, 'CellComponent' | 'id'> & Omit, 'className' | 'onFocus' | 'onChange' | 'onBlur' | 'items'> & Omit & UseCollectionOptions & { CellComponent?: SelectCell; } & { Component?: React.FC>; }; export type TableColumnOptions = TableItem> = Omit, 'id'>; export type TextareaColumnOptions = TableItem> = Omit< TableColumnSpec, 'CellComponent' | 'id' > & Omit & Omit & { CellComponent?: (options: TextareaColumnOptions) => React.FC>; }; export type SelectCell< T = any, S = any, TI extends TableItem = TableItem, SI extends SelectItem = SelectItem, > = (options: SelectColumnOptions, broker: SelectBroker) => React.FC>; export type UseTableOptions = TableItem> = UseListOptions & { adapter?: TableItemAdapter; selected?: T[]; }; export type UseTableController = ( dataSource: T[] | string | undefined, initialColumns: TableColumn>[] | undefined, options: UseTableOptions>, ) => CollectionProxy< T, TableItem, TableState>, TableService, TableState>> >;