mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-02 11:17:46 +08:00
feat(components): [virtual-table] renderers (#7195)
- Move render function into rendering units
This commit is contained in:
parent
8b7d29989a
commit
da63b35c6b
@ -42,7 +42,6 @@ export const tableV2GridProps = buildProps({
|
||||
* Special attributes
|
||||
*/
|
||||
cache: virtualizedListProps.cache,
|
||||
rowKey: tableV2RowProps.rowKey,
|
||||
useIsScrolling: Boolean,
|
||||
|
||||
/**
|
||||
|
127
packages/components/table-v2/src/renderers/cell.tsx
Normal file
127
packages/components/table-v2/src/renderers/cell.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import { get } from 'lodash-unified'
|
||||
import { isFunction, isObject } from '@element-plus/utils'
|
||||
import TableCell from '../table-cell'
|
||||
import ExpandIcon from '../expand-icon'
|
||||
import { Alignment } from '../constants'
|
||||
import { placeholderSign } from '../private'
|
||||
import { enforceUnit, tryCall } from '../utils'
|
||||
|
||||
import type { FunctionalComponent, UnwrapNestedRefs, VNode } from 'vue'
|
||||
import type { TableV2RowCellRenderParam } from '../table-row'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { UseTableReturn } from '../use-table'
|
||||
import type { TableV2Props } from '../table'
|
||||
|
||||
type CellRendererProps = TableV2RowCellRenderParam &
|
||||
Pick<
|
||||
TableV2Props,
|
||||
'cellProps' | 'expandColumnKey' | 'indentSize' | 'iconSize' | 'rowKey'
|
||||
> &
|
||||
UnwrapNestedRefs<
|
||||
Pick<UseTableReturn, 'columnsStyles' | 'expandedRowKeys'>
|
||||
> & {
|
||||
ns: UseNamespaceReturn
|
||||
}
|
||||
|
||||
const CellRenderer: FunctionalComponent<CellRendererProps> = (
|
||||
{
|
||||
// renderer props
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
depth,
|
||||
expandIconProps,
|
||||
isScrolling,
|
||||
rowData,
|
||||
rowIndex,
|
||||
// from use-table
|
||||
columnsStyles,
|
||||
expandedRowKeys,
|
||||
ns,
|
||||
// derived props
|
||||
expandColumnKey,
|
||||
indentSize,
|
||||
iconSize,
|
||||
rowKey,
|
||||
},
|
||||
{ slots }
|
||||
) => {
|
||||
const cellStyle = enforceUnit(columnsStyles[column.key])
|
||||
|
||||
if (column.placeholderSign === placeholderSign) {
|
||||
return <div class={ns.em('row-cell', 'placeholder')} style={cellStyle} />
|
||||
}
|
||||
const { dataKey, dataGetter } = column
|
||||
|
||||
const CellComponent = slots.cell || ((props) => <TableCell {...props} />)
|
||||
const cellData = isFunction(dataGetter)
|
||||
? dataGetter({ columns, column, columnIndex, rowData, rowIndex })
|
||||
: get(rowData, dataKey ?? '')
|
||||
|
||||
const cellProps = {
|
||||
class: ns.e('cell-text'),
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
cellData,
|
||||
isScrolling,
|
||||
rowData,
|
||||
rowIndex,
|
||||
}
|
||||
|
||||
const Cell = CellComponent(cellProps)
|
||||
|
||||
const kls = [
|
||||
ns.e('row-cell'),
|
||||
column.align === Alignment.CENTER && ns.is('align-center'),
|
||||
column.align === Alignment.RIGHT && ns.is('align-right'),
|
||||
]
|
||||
|
||||
const expandable = rowIndex >= 0 && column.key === expandColumnKey
|
||||
const expanded = rowIndex >= 0 && expandedRowKeys.includes(rowData[rowKey])
|
||||
|
||||
let IconOrPlaceholder: VNode | undefined
|
||||
const iconStyle = `margin-inline-start: ${depth * indentSize}px;`
|
||||
if (expandable) {
|
||||
if (isObject(expandIconProps)) {
|
||||
IconOrPlaceholder = (
|
||||
<ExpandIcon
|
||||
{...expandIconProps}
|
||||
class={[ns.e('expand-icon'), ns.is('expanded', expanded)]}
|
||||
size={iconSize}
|
||||
expanded={expanded}
|
||||
style={iconStyle}
|
||||
expandable
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
IconOrPlaceholder = (
|
||||
<div
|
||||
style={[
|
||||
iconStyle,
|
||||
`width: ${iconSize}px; height: ${iconSize}px;`,
|
||||
].join(' ')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
{...tryCall(cellProps, {
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
rowData,
|
||||
rowIndex,
|
||||
})}
|
||||
class={kls}
|
||||
style={cellStyle}
|
||||
>
|
||||
{IconOrPlaceholder}
|
||||
{Cell}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CellRenderer
|
112
packages/components/table-v2/src/renderers/header-cell.tsx
Normal file
112
packages/components/table-v2/src/renderers/header-cell.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import HeaderCell from '../table-header-cell'
|
||||
import ColumnResizer from '../table-column-resizer'
|
||||
import SortIcon from '../sort-icon'
|
||||
import { Alignment, SortOrder, oppositeOrderMap } from '../constants'
|
||||
import { placeholderSign } from '../private'
|
||||
import { tryCall } from '../utils'
|
||||
|
||||
import type { FunctionalComponent, UnwrapNestedRefs } from 'vue'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { TableV2HeaderRowCellRendererParams } from '../table-header-row'
|
||||
import type { UseTableReturn } from '../use-table'
|
||||
import type { TableV2Props } from '../table'
|
||||
import type { TableV2HeaderCell } from '../header-cell'
|
||||
|
||||
type HeaderCellRendererProps = TableV2HeaderRowCellRendererParams &
|
||||
UnwrapNestedRefs<
|
||||
Pick<
|
||||
UseTableReturn,
|
||||
| 'columnsStyles'
|
||||
| 'resizingKey'
|
||||
| 'onColumnSorted'
|
||||
| 'onColumnResized'
|
||||
| 'onColumnResizeEnd'
|
||||
| 'onColumnResizeStart'
|
||||
>
|
||||
> &
|
||||
Pick<TableV2Props, 'sortBy' | 'sortState' | 'headerCellProps'> & {
|
||||
ns: UseNamespaceReturn
|
||||
}
|
||||
|
||||
const HeaderCellRenderer: FunctionalComponent<HeaderCellRendererProps> = (
|
||||
props
|
||||
) => {
|
||||
const {
|
||||
column,
|
||||
ns,
|
||||
resizingKey,
|
||||
columnsStyles,
|
||||
onColumnResizeEnd,
|
||||
onColumnResizeStart,
|
||||
onColumnResized,
|
||||
onColumnSorted,
|
||||
} = props
|
||||
|
||||
if (column.placeholderSign === placeholderSign) {
|
||||
return
|
||||
}
|
||||
|
||||
const { headerCellRenderer, headerClass, sortable, resizable } = column
|
||||
|
||||
/**
|
||||
* render Cell children
|
||||
*/
|
||||
const cellRenderer =
|
||||
headerCellRenderer ||
|
||||
((props: TableV2HeaderCell) => <HeaderCell {...props} />)
|
||||
|
||||
const Cell = cellRenderer({
|
||||
...props,
|
||||
class: ns.e('header-cell-text'),
|
||||
})
|
||||
|
||||
/**
|
||||
* Render cell container and sort indicator
|
||||
*/
|
||||
const { sortBy, sortState, headerCellProps } = props
|
||||
|
||||
const cellKls = [
|
||||
ns.e('header-cell'),
|
||||
...tryCall(headerClass, props, ''),
|
||||
column.align === Alignment.CENTER && ns.is('align-center'),
|
||||
column.align === Alignment.RIGHT && ns.is('align-right'),
|
||||
sortable && ns.is('sortable'),
|
||||
column.key === resizingKey && ns.is('resizing'),
|
||||
]
|
||||
|
||||
let sorting: boolean, sortOrder: SortOrder
|
||||
if (sortState) {
|
||||
const order = sortState[column.key]
|
||||
sorting = Boolean(oppositeOrderMap[order])
|
||||
sortOrder = sorting ? order : SortOrder.ASC
|
||||
} else {
|
||||
sorting = column.key === sortBy.key
|
||||
sortOrder = sorting ? sortBy.order : SortOrder.ASC
|
||||
}
|
||||
|
||||
const cellProps = {
|
||||
...tryCall(headerCellProps, props),
|
||||
onClick: column.sortable ? onColumnSorted : undefined,
|
||||
class: cellKls,
|
||||
style: columnsStyles[column.key],
|
||||
['data-key']: column.key,
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...cellProps}>
|
||||
{Cell}
|
||||
{sortable && <SortIcon sortOrder={sortOrder} />}
|
||||
{resizable && (
|
||||
<ColumnResizer
|
||||
class={ns.e('column-resizer')}
|
||||
column={column}
|
||||
onResize={onColumnResized}
|
||||
onResizeStart={onColumnResizeStart}
|
||||
onResizeStop={onColumnResizeEnd}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeaderCellRenderer
|
52
packages/components/table-v2/src/renderers/header.tsx
Normal file
52
packages/components/table-v2/src/renderers/header.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import HeaderRow from '../table-header-row'
|
||||
import { tryCall } from '../utils'
|
||||
|
||||
import type { FunctionalComponent, UnwrapNestedRefs } from 'vue'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { TableV2HeaderRendererParams } from '../table-header'
|
||||
import type { UseTableReturn } from '../use-table'
|
||||
import type { TableV2Props } from '../table'
|
||||
|
||||
type HeaderRendererProps = TableV2HeaderRendererParams &
|
||||
Pick<TableV2Props, 'headerClass' | 'headerProps'> & {
|
||||
ns: UseNamespaceReturn
|
||||
} & UnwrapNestedRefs<Pick<UseTableReturn, 'resizingKey'>>
|
||||
|
||||
const HeaderRenderer: FunctionalComponent<HeaderRendererProps> = (
|
||||
{
|
||||
columns,
|
||||
headerIndex,
|
||||
style,
|
||||
// derived from root
|
||||
headerClass,
|
||||
headerProps,
|
||||
|
||||
ns,
|
||||
// returned by use-table
|
||||
resizingKey,
|
||||
},
|
||||
{ slots }
|
||||
) => {
|
||||
const param = { columns, headerIndex }
|
||||
|
||||
const kls = [
|
||||
ns.e('header-row'),
|
||||
tryCall(headerClass, param, ''),
|
||||
{
|
||||
[ns.is('resizing')]: Boolean(resizingKey),
|
||||
[ns.is('customized')]: Boolean(slots.header),
|
||||
},
|
||||
]
|
||||
|
||||
const extraProps = {
|
||||
...tryCall(headerProps, param),
|
||||
class: kls,
|
||||
columns,
|
||||
headerIndex,
|
||||
style,
|
||||
}
|
||||
|
||||
return <HeaderRow {...extraProps}>{slots}</HeaderRow>
|
||||
}
|
||||
|
||||
export default HeaderRenderer
|
23
packages/components/table-v2/src/renderers/main-table.tsx
Normal file
23
packages/components/table-v2/src/renderers/main-table.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import Table from '../table-grid'
|
||||
|
||||
import type { FunctionalComponent, Ref } from 'vue'
|
||||
import type { TableV2GridProps } from '../grid'
|
||||
import type { TableGridInstance } from '../table-grid'
|
||||
|
||||
export type MainTableRendererProps = TableV2GridProps & {
|
||||
mainTableRef: Ref<TableGridInstance | undefined>
|
||||
}
|
||||
|
||||
const MainTable: FunctionalComponent<MainTableRendererProps> = (
|
||||
props: MainTableRendererProps,
|
||||
{ slots }
|
||||
) => {
|
||||
const { mainTableRef, ...rest } = props
|
||||
return (
|
||||
<Table ref={mainTableRef} {...rest}>
|
||||
{slots}
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
|
||||
export default MainTable
|
105
packages/components/table-v2/src/renderers/row.tsx
Normal file
105
packages/components/table-v2/src/renderers/row.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import Row from '../table-row'
|
||||
import { tryCall } from '../utils'
|
||||
|
||||
import type { FunctionalComponent, UnwrapNestedRefs } from 'vue'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { UseTableReturn } from '../use-table'
|
||||
import type { TableV2Props } from '../table'
|
||||
import type { TableGridRowSlotParams } from '../table-grid'
|
||||
|
||||
type RowRendererProps = TableGridRowSlotParams &
|
||||
Pick<
|
||||
TableV2Props,
|
||||
| 'expandColumnKey'
|
||||
| 'estimatedRowHeight'
|
||||
| 'rowProps'
|
||||
| 'rowClass'
|
||||
| 'rowKey'
|
||||
| 'rowEventHandlers'
|
||||
> &
|
||||
UnwrapNestedRefs<
|
||||
Pick<
|
||||
UseTableReturn,
|
||||
| 'depthMap'
|
||||
| 'expandedRowKeys'
|
||||
| 'hasFixedColumns'
|
||||
| 'hoveringRowKey'
|
||||
| 'onRowHovered'
|
||||
| 'onRowExpanded'
|
||||
>
|
||||
> & {
|
||||
ns: UseNamespaceReturn
|
||||
}
|
||||
|
||||
const RowRenderer: FunctionalComponent<RowRendererProps> = (
|
||||
props,
|
||||
{ slots }
|
||||
) => {
|
||||
const {
|
||||
columns,
|
||||
depthMap,
|
||||
expandColumnKey,
|
||||
expandedRowKeys,
|
||||
estimatedRowHeight,
|
||||
hasFixedColumns,
|
||||
hoveringRowKey,
|
||||
rowData,
|
||||
rowIndex,
|
||||
style,
|
||||
isScrolling,
|
||||
rowProps,
|
||||
rowClass,
|
||||
rowKey,
|
||||
rowEventHandlers,
|
||||
ns,
|
||||
onRowHovered,
|
||||
onRowExpanded,
|
||||
} = props
|
||||
|
||||
const rowKls = tryCall(rowClass, { columns, rowData, rowIndex }, '')
|
||||
const additionalProps = tryCall(rowProps, {
|
||||
columns,
|
||||
rowData,
|
||||
rowIndex,
|
||||
})
|
||||
const _rowKey = rowData[rowKey]
|
||||
const depth = depthMap[_rowKey] || 0
|
||||
const canExpand = Boolean(expandColumnKey)
|
||||
const isFixedRow = rowIndex < 0
|
||||
const kls = [
|
||||
ns.e('row'),
|
||||
rowKls,
|
||||
{
|
||||
[ns.e(`row-depth-${depth}`)]: canExpand && rowIndex >= 0,
|
||||
[ns.is('expanded')]: canExpand && expandedRowKeys.includes(_rowKey),
|
||||
[ns.is('hovered')]: !isScrolling && _rowKey === hoveringRowKey,
|
||||
[ns.is('fixed')]: !depth && isFixedRow,
|
||||
[ns.is('customized')]: Boolean(slots.row),
|
||||
},
|
||||
]
|
||||
|
||||
const onRowHover = hasFixedColumns ? onRowHovered : undefined
|
||||
|
||||
const _rowProps = {
|
||||
...additionalProps,
|
||||
columns,
|
||||
class: kls,
|
||||
depth,
|
||||
expandColumnKey,
|
||||
estimatedRowHeight: isFixedRow ? undefined : estimatedRowHeight,
|
||||
isScrolling,
|
||||
rowIndex,
|
||||
rowData,
|
||||
rowKey: _rowKey,
|
||||
rowEventHandlers,
|
||||
style,
|
||||
}
|
||||
|
||||
return (
|
||||
<Row {..._rowProps} onRowHover={onRowHover} onRowExpand={onRowExpanded}>
|
||||
{slots}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default RowRenderer
|
@ -19,8 +19,8 @@ const TableV2HeaderRow = defineComponent({
|
||||
})
|
||||
})
|
||||
|
||||
if (slots.default) {
|
||||
Cells = slots.default({
|
||||
if (slots.header) {
|
||||
Cells = slots.header({
|
||||
cells: Cells,
|
||||
columns,
|
||||
headerIndex,
|
||||
|
@ -177,8 +177,8 @@ const TableV2Row = defineComponent({
|
||||
})
|
||||
})
|
||||
|
||||
if (slots.default) {
|
||||
ColumnCells = slots.default({
|
||||
if (slots.row) {
|
||||
ColumnCells = slots.row({
|
||||
cells: ColumnCells.map((node) => {
|
||||
if (isArray(node) && node.length === 1) {
|
||||
return node[0]
|
||||
|
@ -1,28 +1,21 @@
|
||||
import { computed, defineComponent, provide, unref } from 'vue'
|
||||
import { get } from 'lodash-unified'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { isFunction, isObject } from '@element-plus/utils'
|
||||
import { useTable } from './use-table'
|
||||
import { enforceUnit, tryCall } from './utils'
|
||||
import { enforceUnit } from './utils'
|
||||
import { TableV2InjectionKey } from './tokens'
|
||||
import { Alignment, SortOrder, oppositeOrderMap } from './constants'
|
||||
import { placeholderSign } from './private'
|
||||
import { tableV2Props } from './table'
|
||||
// components
|
||||
import Table from './table-grid'
|
||||
import TableRow from './table-row'
|
||||
import TableHeaderRow from './table-header-row'
|
||||
import TableCell from './table-cell'
|
||||
import TableHeaderCell from './table-header-cell'
|
||||
import ColumnResizer from './table-column-resizer'
|
||||
import ExpandIcon from './expand-icon'
|
||||
import SortIcon from './sort-icon'
|
||||
// renderers
|
||||
import MainTable from './renderers/main-table'
|
||||
import Row from './renderers/row'
|
||||
import Cell from './renderers/cell'
|
||||
import Header from './renderers/header'
|
||||
import HeaderCell from './renderers/header-cell'
|
||||
|
||||
import type { CSSProperties, VNode } from 'vue'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import type { TableV2GridProps } from './grid'
|
||||
import type { TableGridRowSlotParams } from './table-grid'
|
||||
import type { TableV2RowCellRenderParam } from './table-row'
|
||||
import type { TableV2HeaderRendererParams } from './table-header'
|
||||
import type { TableV2HeaderCell } from './header-cell'
|
||||
|
||||
import type { TableV2HeaderRowCellRendererParams } from './table-header-row'
|
||||
|
||||
@ -80,39 +73,6 @@ const TableV2 = defineComponent({
|
||||
() => unref(bodyWidth) + (props.fixed ? unref(vScrollbarSize) : 0)
|
||||
)
|
||||
|
||||
function renderMainTable() {
|
||||
const {
|
||||
cache,
|
||||
fixedData,
|
||||
estimatedRowHeight,
|
||||
headerHeight,
|
||||
rowHeight,
|
||||
width,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<Table
|
||||
ref={mainTableRef}
|
||||
cache={cache}
|
||||
class={ns.e('main')}
|
||||
columns={unref(mainColumns)}
|
||||
data={unref(data)}
|
||||
fixedData={fixedData}
|
||||
estimatedRowHeight={estimatedRowHeight}
|
||||
bodyWidth={unref(bodyWidth)}
|
||||
headerHeight={headerHeight}
|
||||
headerWidth={unref(headerWidth)}
|
||||
rowHeight={rowHeight}
|
||||
height={unref(mainTableHeight)}
|
||||
width={width}
|
||||
onRowsRendered={onRowsRendered}
|
||||
onScroll={onScroll}
|
||||
>
|
||||
{{ row: renderTableRow, header: renderHeader }}
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
|
||||
// function renderLeftTable() {
|
||||
// const columns = unref(fixedColumnsOnLeft)
|
||||
// if (columns.length === 0) return
|
||||
@ -124,279 +84,8 @@ const TableV2 = defineComponent({
|
||||
|
||||
// function renderRightTable() {}
|
||||
|
||||
function renderHeader({
|
||||
columns,
|
||||
headerIndex,
|
||||
style,
|
||||
}: TableV2HeaderRendererParams) {
|
||||
const param = { columns, headerIndex }
|
||||
|
||||
const headerClass = [
|
||||
ns.e('header-row'),
|
||||
tryCall(props.headerClass, param, ''),
|
||||
{
|
||||
[ns.is('resizing')]: unref(resizingKey),
|
||||
[ns.is('customized')]: Boolean(slots.header),
|
||||
},
|
||||
]
|
||||
|
||||
const headerProps = {
|
||||
...tryCall(props.headerProps, param),
|
||||
class: headerClass,
|
||||
columns,
|
||||
headerIndex,
|
||||
style,
|
||||
}
|
||||
|
||||
return (
|
||||
<TableHeaderRow {...headerProps}>
|
||||
{{
|
||||
default: slots.header,
|
||||
cell: renderHeaderCell,
|
||||
}}
|
||||
</TableHeaderRow>
|
||||
)
|
||||
}
|
||||
|
||||
// function renderFooter() {}
|
||||
|
||||
function renderTableRow({
|
||||
columns,
|
||||
rowData,
|
||||
rowIndex,
|
||||
style,
|
||||
isScrolling,
|
||||
}: TableGridRowSlotParams) {
|
||||
const {
|
||||
expandColumnKey,
|
||||
estimatedRowHeight,
|
||||
rowProps,
|
||||
rowClass,
|
||||
rowKey,
|
||||
rowEventHandlers,
|
||||
} = props
|
||||
|
||||
const rowKls = tryCall(rowClass, { columns, rowData, rowIndex }, '')
|
||||
const additionalProps = tryCall(rowProps, {
|
||||
columns,
|
||||
rowData,
|
||||
rowIndex,
|
||||
})
|
||||
const _rowKey = rowData[rowKey]
|
||||
const depth = unref(depthMap)[_rowKey] || 0
|
||||
const canExpand = Boolean(expandColumnKey)
|
||||
const isFixedRow = rowIndex < 0
|
||||
const kls = [
|
||||
ns.e('row'),
|
||||
rowKls,
|
||||
{
|
||||
[ns.e(`row-depth-${depth}`)]: canExpand && rowIndex >= 0,
|
||||
[ns.is('expanded')]:
|
||||
canExpand && unref(expandedRowKeys).includes(_rowKey),
|
||||
[ns.is('hovered')]: !isScrolling && _rowKey === unref(hoveringRowKey),
|
||||
[ns.is('fixed')]: !depth && isFixedRow,
|
||||
[ns.is('customized')]: Boolean(slots.row),
|
||||
},
|
||||
]
|
||||
|
||||
const onRowHover = unref(hasFixedColumns) ? onRowHovered : undefined
|
||||
|
||||
const _rowProps = {
|
||||
...additionalProps,
|
||||
columns,
|
||||
class: kls,
|
||||
depth,
|
||||
expandColumnKey,
|
||||
estimatedRowHeight: isFixedRow ? undefined : estimatedRowHeight,
|
||||
isScrolling,
|
||||
rowIndex,
|
||||
rowData,
|
||||
rowKey: _rowKey,
|
||||
rowEventHandlers,
|
||||
style,
|
||||
}
|
||||
|
||||
const children = {
|
||||
...(slots.row ? { default: slots.row } : {}),
|
||||
cell: renderRowCell,
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
{..._rowProps}
|
||||
onRowHover={onRowHover}
|
||||
onRowExpand={onRowExpanded}
|
||||
>
|
||||
{children}
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
|
||||
function renderRowCell({
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
depth,
|
||||
expandIconProps,
|
||||
isScrolling,
|
||||
rowData,
|
||||
rowIndex,
|
||||
}: TableV2RowCellRenderParam) {
|
||||
const cellStyle = enforceUnit(unref(columnsStyles)[column.key])
|
||||
|
||||
if (column.placeholderSign === placeholderSign) {
|
||||
return (
|
||||
<div class={ns.em('row-cell', 'placeholder')} style={cellStyle} />
|
||||
)
|
||||
}
|
||||
const { dataKey, dataGetter } = column
|
||||
|
||||
const CellComponent = slots.cell || ((props) => <TableCell {...props} />)
|
||||
const cellData = isFunction(dataGetter)
|
||||
? dataGetter({ columns, column, columnIndex, rowData, rowIndex })
|
||||
: get(rowData, dataKey ?? '')
|
||||
|
||||
const cellProps = {
|
||||
class: ns.e('cell-text'),
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
cellData,
|
||||
isScrolling,
|
||||
rowData,
|
||||
rowIndex,
|
||||
}
|
||||
|
||||
const Cell = CellComponent(cellProps)
|
||||
|
||||
const kls = [
|
||||
ns.e('row-cell'),
|
||||
column.align === Alignment.CENTER && ns.is('align-center'),
|
||||
column.align === Alignment.RIGHT && ns.is('align-right'),
|
||||
]
|
||||
|
||||
const { expandColumnKey, indentSize, iconSize, rowKey } = props
|
||||
|
||||
const expandable = rowIndex >= 0 && column.key === expandColumnKey
|
||||
const expanded =
|
||||
rowIndex >= 0 && unref(expandedRowKeys).includes(rowData[rowKey])
|
||||
|
||||
let IconOrPlaceholder: VNode | undefined
|
||||
const iconStyle = `margin-inline-start: ${depth * indentSize}px;`
|
||||
if (expandable) {
|
||||
if (isObject(expandIconProps)) {
|
||||
IconOrPlaceholder = (
|
||||
<ExpandIcon
|
||||
{...expandIconProps}
|
||||
class={[ns.e('expand-icon'), ns.is('expanded', expanded)]}
|
||||
size={iconSize}
|
||||
expanded={expanded}
|
||||
style={iconStyle}
|
||||
expandable
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
IconOrPlaceholder = (
|
||||
<div
|
||||
style={[
|
||||
iconStyle,
|
||||
`width: ${iconSize}px; height: ${iconSize}px;`,
|
||||
].join(' ')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
{...tryCall(props.cellProps, {
|
||||
columns,
|
||||
column,
|
||||
columnIndex,
|
||||
rowData,
|
||||
rowIndex,
|
||||
})}
|
||||
class={kls}
|
||||
style={cellStyle}
|
||||
>
|
||||
{IconOrPlaceholder}
|
||||
{Cell}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function renderHeaderCell(
|
||||
renderHeaderCellProps: TableV2HeaderRowCellRendererParams
|
||||
) {
|
||||
const { column } = renderHeaderCellProps
|
||||
|
||||
if (column.placeholderSign === placeholderSign) {
|
||||
return
|
||||
}
|
||||
|
||||
const { headerCellRenderer, headerClass, sortable, resizable } = column
|
||||
|
||||
/**
|
||||
* render Cell children
|
||||
*/
|
||||
const cellRenderer =
|
||||
headerCellRenderer ||
|
||||
((props: TableV2HeaderCell) => <TableHeaderCell {...props} />)
|
||||
|
||||
const Cell = cellRenderer({
|
||||
...renderHeaderCellProps,
|
||||
class: ns.e('header-cell-text'),
|
||||
})
|
||||
|
||||
/**
|
||||
* Render cell container and sort indicator
|
||||
*/
|
||||
const { sortBy, sortState, headerCellProps } = props
|
||||
|
||||
const cellKls = [
|
||||
ns.e('header-cell'),
|
||||
...tryCall(headerClass, renderHeaderCellProps, ''),
|
||||
column.align === Alignment.CENTER && ns.is('align-center'),
|
||||
column.align === Alignment.RIGHT && ns.is('align-right'),
|
||||
sortable && ns.is('sortable'),
|
||||
column.key === unref(resizingKey) && ns.is('resizing'),
|
||||
]
|
||||
|
||||
let sorting: boolean, sortOrder: SortOrder
|
||||
if (sortState) {
|
||||
const order = sortState[column.key]
|
||||
sorting = Boolean(oppositeOrderMap[order])
|
||||
sortOrder = sorting ? order : SortOrder.ASC
|
||||
} else {
|
||||
sorting = column.key === sortBy.key
|
||||
sortOrder = sorting ? sortBy.order : SortOrder.ASC
|
||||
}
|
||||
|
||||
const cellProps = {
|
||||
...tryCall(headerCellProps, renderHeaderCellProps),
|
||||
onClick: column.sortable ? onColumnSorted : undefined,
|
||||
class: cellKls,
|
||||
style: unref(columnsStyles)[column.key],
|
||||
['data-key']: column.key,
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...cellProps}>
|
||||
{Cell}
|
||||
{sortable && <SortIcon sortOrder={sortOrder} />}
|
||||
{resizable && (
|
||||
<ColumnResizer
|
||||
class={ns.e('column-resizer')}
|
||||
column={column}
|
||||
onResize={onColumnResized}
|
||||
onResizeStart={onColumnResizeStart}
|
||||
onResizeStop={onColumnResizeEnd}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
provide(TableV2InjectionKey, {
|
||||
ns,
|
||||
isResetting,
|
||||
@ -405,9 +94,118 @@ const TableV2 = defineComponent({
|
||||
})
|
||||
|
||||
return () => {
|
||||
const {
|
||||
cache,
|
||||
estimatedRowHeight,
|
||||
expandColumnKey,
|
||||
fixedData,
|
||||
headerHeight,
|
||||
headerClass,
|
||||
headerProps,
|
||||
headerCellProps,
|
||||
sortBy,
|
||||
sortState,
|
||||
rowHeight,
|
||||
rowClass,
|
||||
rowEventHandlers,
|
||||
rowKey,
|
||||
rowProps,
|
||||
indentSize,
|
||||
iconSize,
|
||||
useIsScrolling,
|
||||
width,
|
||||
} = props
|
||||
|
||||
const mainTableProps: TableV2GridProps = {
|
||||
cache,
|
||||
class: ns.e('main'),
|
||||
columns: unref(mainColumns),
|
||||
data: unref(data),
|
||||
fixedData,
|
||||
estimatedRowHeight,
|
||||
bodyWidth: unref(bodyWidth),
|
||||
headerHeight,
|
||||
headerWidth: unref(headerWidth),
|
||||
rowHeight,
|
||||
height: unref(mainTableHeight),
|
||||
useIsScrolling,
|
||||
width,
|
||||
onRowsRendered,
|
||||
onScroll,
|
||||
}
|
||||
|
||||
const tableRowProps = {
|
||||
ns,
|
||||
depthMap: unref(depthMap),
|
||||
expandedRowKeys: unref(expandedRowKeys),
|
||||
estimatedRowHeight,
|
||||
hasFixedColumns: unref(hasFixedColumns),
|
||||
hoveringRowKey: unref(hoveringRowKey),
|
||||
rowProps,
|
||||
rowClass,
|
||||
rowKey,
|
||||
rowEventHandlers,
|
||||
onRowHovered,
|
||||
onRowExpanded,
|
||||
}
|
||||
|
||||
const tableCellProps = {
|
||||
expandColumnKey,
|
||||
indentSize,
|
||||
iconSize,
|
||||
rowKey,
|
||||
columnsStyles: unref(columnsStyles),
|
||||
expandedRowKeys: unref(expandedRowKeys),
|
||||
ns,
|
||||
}
|
||||
|
||||
const tableHeaderProps = {
|
||||
ns,
|
||||
headerClass,
|
||||
headerProps,
|
||||
resizingKey: unref(resizingKey),
|
||||
}
|
||||
|
||||
const tableHeaderCellProps = {
|
||||
ns,
|
||||
|
||||
sortBy,
|
||||
sortState,
|
||||
headerCellProps,
|
||||
resizingKey: unref(resizingKey),
|
||||
columnsStyles: unref(columnsStyles),
|
||||
onColumnResizeEnd,
|
||||
onColumnResizeStart,
|
||||
onColumnResized,
|
||||
onColumnSorted,
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={[ns.b(), ns.e('root')]} style={unref(rootStyle)}>
|
||||
{renderMainTable()}
|
||||
<MainTable mainTableRef={mainTableRef} {...mainTableProps}>
|
||||
{{
|
||||
row: (props: TableGridRowSlotParams) => (
|
||||
<Row {...props} {...tableRowProps}>
|
||||
{{
|
||||
row: slots.row,
|
||||
cell: (props: TableV2RowCellRenderParam) => (
|
||||
<Cell {...props} {...tableCellProps} />
|
||||
),
|
||||
}}
|
||||
</Row>
|
||||
),
|
||||
header: (props: TableV2HeaderRendererParams) => (
|
||||
<Header {...props} {...tableHeaderProps}>
|
||||
{{
|
||||
header: slots.header,
|
||||
cell: (props: TableV2HeaderRowCellRendererParams) => (
|
||||
<HeaderCell {...props} {...tableHeaderCellProps} />
|
||||
),
|
||||
}}
|
||||
</Header>
|
||||
),
|
||||
}}
|
||||
</MainTable>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ export const tableV2Props = buildProps({
|
||||
width: requiredNumber,
|
||||
height: requiredNumber,
|
||||
maxHeight: Number,
|
||||
useIsScrolling: Boolean,
|
||||
indentSize: {
|
||||
type: Number,
|
||||
default: 12,
|
||||
|
@ -396,3 +396,5 @@ function useTable(props: TableV2Props) {
|
||||
}
|
||||
|
||||
export { useTable }
|
||||
|
||||
export type UseTableReturn = ReturnType<typeof useTable>
|
||||
|
@ -186,7 +186,6 @@ export type GridDefaultSlotParams = {
|
||||
columnIndex: number
|
||||
rowIndex: number
|
||||
data: any
|
||||
depth
|
||||
key: number | string
|
||||
isScrolling?: boolean
|
||||
style: CSSProperties
|
||||
|
Loading…
Reference in New Issue
Block a user