diff --git a/src/data-table/src/DataTable.tsx b/src/data-table/src/DataTable.tsx index 7ef8f7279bc..385ae05ea31 100644 --- a/src/data-table/src/DataTable.tsx +++ b/src/data-table/src/DataTable.tsx @@ -225,6 +225,7 @@ export default defineComponent({ scrollXRef: computed(() => props.scrollX), rowsRef, colsRef, + captionRef: toRef(props, 'caption'), paginatedDataRef, leftActiveFixedColKeyRef, leftActiveFixedChildrenColKeysRef, diff --git a/src/data-table/src/TableParts/Body.tsx b/src/data-table/src/TableParts/Body.tsx index f0e33046d43..9e1b996b505 100644 --- a/src/data-table/src/TableParts/Body.tsx +++ b/src/data-table/src/TableParts/Body.tsx @@ -109,6 +109,7 @@ function flatten( const VirtualListItemWrapper = defineComponent({ props: { + caption: String, clsPrefix: { type: String, required: true @@ -125,7 +126,7 @@ const VirtualListItemWrapper = defineComponent({ onMouseleave: Function as PropType<(e: MouseEvent) => void> }, render() { - const { clsPrefix, id, cols, onMouseenter, onMouseleave } = this + const { caption, clsPrefix, id, cols, onMouseenter, onMouseleave } = this return ( + {caption ? : null} {cols.map(col => ( @@ -202,6 +204,7 @@ export default defineComponent({ handleTableBodyScroll, doCheck, doUncheck, + captionRef, renderCell } = inject(dataTableInjectionKey)! const NConfigProvider = inject(configProviderInjectionKey) @@ -526,6 +529,7 @@ export default defineComponent({ handleRadioUpdateChecked, handleUpdateExpanded, renderCell, + caption: captionRef, ...exposedMethods } }, @@ -584,6 +588,7 @@ export default defineComponent({ // coordinate to related hover keys const cordKey: Record> = {} const { + caption, cols, paginatedDataAndInfo, mergedTheme, @@ -1043,6 +1048,7 @@ export default defineComponent({ tableLayout: this.mergedTableLayout }} > + {caption ? : null} {cols.map(col => ( @@ -1080,6 +1086,7 @@ export default defineComponent({ itemSize={this.minRowHeight} visibleItemsTag={VirtualListItemWrapper} visibleItemsProps={{ + caption, clsPrefix: mergedClsPrefix, id: componentId, cols, diff --git a/src/data-table/src/TableParts/Header.tsx b/src/data-table/src/TableParts/Header.tsx index dfef1ef32c6..a6b5a3b513b 100644 --- a/src/data-table/src/TableParts/Header.tsx +++ b/src/data-table/src/TableParts/Header.tsx @@ -38,6 +38,7 @@ function renderTitle( const VirtualListItemWrapper = defineComponent({ props: { + caption: String, clsPrefix: { type: String, required: true @@ -59,6 +60,7 @@ const VirtualListItemWrapper = defineComponent({ style={{ tableLayout: 'fixed', width }} class={`${clsPrefix}-data-table-table`} > + {this.caption ? : null} {cols.map(col => ( @@ -91,6 +93,7 @@ export default defineComponent({ someRowsCheckedRef, rowsRef, colsRef, + captionRef, mergedThemeRef, checkOptionsRef, mergedSortStateRef, @@ -178,6 +181,7 @@ export default defineComponent({ someRowsChecked: someRowsCheckedRef, rows: rowsRef, cols: colsRef, + caption: captionRef, mergedTheme: mergedThemeRef, checkOptions: checkOptionsRef, mergedTableLayout: mergedTableLayoutRef, @@ -203,6 +207,7 @@ export default defineComponent({ someRowsChecked, rows, cols, + caption, mergedTheme, checkOptions, componentId, @@ -223,137 +228,148 @@ export default defineComponent({ getLeft: ((index: number) => number) | null, headerHeightPx: string | undefined ) => - row.map(({ column, colIndex, colSpan, rowSpan, isLast }) => { - const key = getColKey(column) - const { ellipsis } = column - if (!hasEllipsis && ellipsis) - hasEllipsis = true - const createColumnVNode = (): VNode | null => { - if (column.type === 'selection') { - return column.multiple !== false ? ( + row.map( + ({ column, colIndex, colSpan, rowSpan, isLast }, actualRowIndex) => { + const key = getColKey(column) + const { ellipsis } = column + if (!hasEllipsis && ellipsis) + hasEllipsis = true + const createColumnVNode = (): VNode | null => { + if (column.type === 'selection') { + return column.multiple !== false ? ( + <> + + {checkOptions ? ( + + ) : null} + + ) : null + } + return ( <> - - {checkOptions ? ( - +
+
+ {ellipsis === true || (ellipsis && !ellipsis.tooltip) ? ( +
+ {renderTitle(column)} +
+ ) : ellipsis && typeof ellipsis === 'object' ? ( + + {{ + default: () => renderTitle(column) + }} + + ) : ( + renderTitle(column) + )} +
+ {isColumnSortable(column) ? ( + + ) : null} +
+ {isColumnFilterable(column) ? ( + + ) : null} + {isColumnResizable(column) ? ( + { + handleColumnResizeStart(column as TableBaseColumn) + }} + onResize={(displacementX) => { + handleColumnResize( + column as TableBaseColumn, + displacementX + ) + }} + /> ) : null} - ) : null + ) } + const leftFixed = key in fixedColumnLeftMap + const rightFixed = key in fixedColumnRightMap + const { headerCellProps } = column + const resolvedHeaderCellProps = headerCellProps?.( + column, + actualRowIndex + ) + const CellComponent = ( + getLeft && !column.fixed ? 'div' : 'th' + ) as 'th' return ( - <> -
-
- {ellipsis === true || (ellipsis && !ellipsis.tooltip) ? ( -
- {renderTitle(column)} -
- ) : ellipsis && typeof ellipsis === 'object' ? ( - - {{ - default: () => renderTitle(column) - }} - - ) : ( - renderTitle(column) - )} -
- {isColumnSortable(column) ? ( - - ) : null} -
- {isColumnFilterable(column) ? ( - - ) : null} - {isColumnResizable(column) ? ( - { - handleColumnResizeStart(column as TableBaseColumn) - }} - onResize={(displacementX) => { - handleColumnResize(column as TableBaseColumn, displacementX) - }} - /> - ) : null} - + (cellElsRef[key] = el as HTMLTableCellElement)} + key={key} + style={[ + getLeft && !column.fixed + ? { + position: 'absolute', + left: pxfy(getLeft(colIndex)), + top: 0, + bottom: 0 + } + : { + left: pxfy(fixedColumnLeftMap[key]?.start), + right: pxfy(fixedColumnRightMap[key]?.start) + }, + { + width: pxfy(column.width), + textAlign: column.titleAlign || column.align, + height: headerHeightPx + } + ]} + colspan={colSpan} + rowspan={rowSpan} + data-col-key={key} + class={[ + `${mergedClsPrefix}-data-table-th`, + (leftFixed || rightFixed) + && `${mergedClsPrefix}-data-table-th--fixed-${ + leftFixed ? 'left' : 'right' + }`, + { + [`${mergedClsPrefix}-data-table-th--sorting`]: + isColumnSorting(column, mergedSortState), + [`${mergedClsPrefix}-data-table-th--filterable`]: + isColumnFilterable(column), + [`${mergedClsPrefix}-data-table-th--sortable`]: + isColumnSortable(column), + [`${mergedClsPrefix}-data-table-th--selection`]: + column.type === 'selection', + [`${mergedClsPrefix}-data-table-th--last`]: isLast + }, + column.className + ]} + onClick={ + column.type !== 'selection' + && column.type !== 'expand' + && !('children' in column) + ? (e) => { + handleColHeaderClick(e, column) + } + : undefined + } + > + {createColumnVNode()} + ) } - const leftFixed = key in fixedColumnLeftMap - const rightFixed = key in fixedColumnRightMap - const CellComponent = (getLeft && !column.fixed ? 'div' : 'th') as 'th' - return ( - (cellElsRef[key] = el as HTMLTableCellElement)} - key={key} - style={[ - getLeft && !column.fixed - ? { - position: 'absolute', - left: pxfy(getLeft(colIndex)), - top: 0, - bottom: 0 - } - : { - left: pxfy(fixedColumnLeftMap[key]?.start), - right: pxfy(fixedColumnRightMap[key]?.start) - }, - { - width: pxfy(column.width), - textAlign: column.titleAlign || column.align, - height: headerHeightPx - } - ]} - colspan={colSpan} - rowspan={rowSpan} - data-col-key={key} - class={[ - `${mergedClsPrefix}-data-table-th`, - (leftFixed || rightFixed) - && `${mergedClsPrefix}-data-table-th--fixed-${ - leftFixed ? 'left' : 'right' - }`, - { - [`${mergedClsPrefix}-data-table-th--sorting`]: isColumnSorting( - column, - mergedSortState - ), - [`${mergedClsPrefix}-data-table-th--filterable`]: - isColumnFilterable(column), - [`${mergedClsPrefix}-data-table-th--sortable`]: - isColumnSortable(column), - [`${mergedClsPrefix}-data-table-th--selection`]: - column.type === 'selection', - [`${mergedClsPrefix}-data-table-th--last`]: isLast - }, - column.className - ]} - onClick={ - column.type !== 'selection' - && column.type !== 'expand' - && !('children' in column) - ? (e) => { - handleColHeaderClick(e, column) - } - : undefined - } - > - {createColumnVNode()} - - ) - }) + ) if (virtualScrollHeader) { const { headerHeight } = this @@ -383,6 +399,7 @@ export default defineComponent({ itemResizable={false} visibleItemsTag={VirtualListItemWrapper} visibleItemsProps={{ + caption, clsPrefix: mergedClsPrefix, id: componentId, cols, @@ -467,6 +484,7 @@ export default defineComponent({ tableLayout: mergedTableLayout }} > + {caption ?
: null} {cols.map(col => ( diff --git a/src/data-table/src/interface.ts b/src/data-table/src/interface.ts index 3029d8dcedb..40f94bec243 100644 --- a/src/data-table/src/interface.ts +++ b/src/data-table/src/interface.ts @@ -128,6 +128,10 @@ export const dataTableProps = { renderCell: Function as PropType< (value: any, rowData: object, column: TableBaseColumn) => VNodeChild >, + caption: { + type: String, + default: '' + }, renderExpandIcon: Function as PropType, spinProps: { type: Object as PropType, default: {} }, getCsvCell: Function as PropType, @@ -244,6 +248,7 @@ export interface CommonColumnInfo { ellipsisComponent?: 'ellipsis' | 'performant-ellipsis' allowExport?: boolean cellProps?: (rowData: T, rowIndex: number) => HTMLAttributes + headerCellProps?: (column: TableColumn, rowIndex: number) => HTMLAttributes } export type DataTableHeightForRow = ( @@ -457,6 +462,7 @@ export interface DataTableInjection { | undefined | ((value: any, rowData: object, column: TableBaseColumn) => VNodeChild) > + captionRef: Ref } export const dataTableInjectionKey
{caption} {caption} {this.caption} {caption}