import React, { forwardRef, TableHTMLAttributes, useMemo } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { CTableHead, CTableHeadProps } from './CTableHead'
import { CTableHeaderCell } from './CTableHeaderCell'
import { CTableBody } from './CTableBody'
import { CTableDataCell } from './CTableDataCell'
import { CTableRow } from './CTableRow'
import { CTableFoot, CTableFootProps } from './CTableFoot'
import { CTableCaption } from './CTableCaption'
import { CTableResponsiveWrapper } from './CTableResponsiveWrapper'
import { colorPropType } from '../../props'
import type { Colors } from '../../types'
import { getColumnLabel, getColumnNames } from './utils'
import type { Column, FooterItem, Item } from './types'
export interface CTableProps extends Omit, 'align'> {
/**
* Set the vertical aligment.
*/
align?: 'bottom' | 'middle' | 'top' | string
/**
* Sets the border color of the component to one of CoreUI’s themed colors.
*
* @type 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | string
*/
borderColor?: Colors
/**
* Add borders on all sides of the table and cells.
*/
bordered?: boolean
/**
* Remove borders on all sides of the table and cells.
*/
borderless?: boolean
/**
* Put the caption on the top if you set `caption="top"` of the table or set the text of the table caption.
*/
caption?: 'top' | string
/**
* Set the text of the table caption and the caption on the top of the table.
*
* @since 4.3.0
*/
captionTop?: string
/**
* A string of all className you want applied to the component.
*/
className?: string
/**
* Prop for table columns configuration. If prop is not defined, table will display columns based on the first item keys, omitting keys that begins with underscore (e.g. '_props')
*
* In columns prop each array item represents one column. Item might be specified in two ways:
* String: each item define column name equal to item value.
* Object: item is object with following keys available as column configuration:
* - key (required)(String) - define column name equal to item key.
* - label (String) - define visible label of column. If not defined, label will be generated automatically based on column name, by converting kebab-case and snake_case to individual words and capitalization of each word.
* - _props (Object) - adds classes to all cels in column, ex. `_props: { scope: 'col', className: 'custom-class' }`,
* - _style (Object) - adds styles to the column header (useful for defining widths)
*
* @since 4.3.0
*/
columns?: (string | Column)[]
/**
* Sets the color context of the component to one of CoreUI’s themed colors.
*
* @type 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | string
*/
color?: Colors
/**
* Array of objects or strings, where each element represents one cell in the table footer.
*
* Example items:
* `['FooterCell', 'FooterCell', 'FooterCell']`
* or
* `[{ label: 'FooterCell', _props: { color: 'success' }, ...]`
*
* @since 4.3.0
*/
footer?: (FooterItem | string)[]
/**
* Enable a hover state on table rows within a ``.
*/
hover?: boolean
/**
* Array of objects, where each object represents one item - row in table. Additionally, you can add style classes to each row by passing them by '_props' key and to single cell by '_cellProps'.
*
* Example item:
* `{ name: 'John' , age: 12, _props: { color: 'success' }, _cellProps: { age: { className: 'fw-bold'}}}`
*
* @since 4.3.0
*/
items?: Item[]
/**
* Make any table responsive across all viewports or pick a maximum breakpoint with which to have a responsive table up to.
*/
responsive?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
/**
* Make table more compact by cutting all cell `padding` in half.
*/
small?: boolean
/**
* Add zebra-striping to any table row within the ``.
*/
striped?: boolean
/**
* Add zebra-striping to any table column.
*
* @since 4.3.0
*/
stripedColumns?: boolean
/**
* Properties that will be passed to the table footer component.
*
* @link https://coreui.io/react/docs/components/table/#ctablefoot
* @since 4.3.0
*/
tableFootProps?: CTableFootProps
/**
* Properties that will be passed to the table head component.
*
* @link https://coreui.io/react/docs/components/table/#ctablehead
* @since 4.3.0
*/
tableHeadProps?: CTableHeadProps
}
export const CTable = forwardRef(
(
{
children,
align,
borderColor,
bordered,
borderless,
caption,
captionTop,
className,
color,
columns,
footer,
hover,
items,
responsive,
small,
striped,
stripedColumns,
tableFootProps,
tableHeadProps,
...rest
},
ref
) => {
const columnNames = useMemo(() => getColumnNames(columns, items), [columns, items])
return (
{((caption && caption !== 'top') || captionTop) && (
{caption || captionTop}
)}
{columns && (
{columns.map((column: Column, index: number) => (
{getColumnLabel(column)}
))}
)}
{items && (
{items.map((item: Item, index: number) => (
{columnNames &&
columnNames.map((colName: string, index: number) => {
// eslint-disable-next-line unicorn/no-negated-condition
return item[colName] !== undefined ? (
{item[colName]}
) : null
})}
))}
)}
{children}
{footer && (
{footer.map((item: FooterItem | string, index: number) => (
{typeof item === 'object' ? item.label : item}
))}
)}
)
}
)
CTable.propTypes = {
align: PropTypes.oneOf(['bottom', 'middle', 'top']),
borderColor: PropTypes.string,
bordered: PropTypes.bool,
borderless: PropTypes.bool,
caption: PropTypes.oneOfType([PropTypes.string, PropTypes.oneOf(['top'])]),
captionTop: PropTypes.string,
children: PropTypes.node,
className: PropTypes.string,
color: colorPropType,
columns: PropTypes.array,
footer: PropTypes.array,
hover: PropTypes.bool,
items: PropTypes.array,
responsive: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf<'sm' | 'md' | 'lg' | 'xl' | 'xxl'>(['sm', 'md', 'lg', 'xl', 'xxl']),
]),
small: PropTypes.bool,
striped: PropTypes.bool,
stripedColumns: PropTypes.bool,
tableFootProps: PropTypes.shape({ ...CTableFoot.propTypes }),
tableHeadProps: PropTypes.shape({ ...CTableHead.propTypes }),
}
CTable.displayName = 'CTable'