Skip to content

Commit

Permalink
feat(VDataTable): add headerProps/rowProps/cellProps (#18589)
Browse files Browse the repository at this point in the history
closes #16648
closes #16991
  • Loading branch information
KaelWD authored Nov 3, 2023
1 parent 397daa9 commit 0c87f70
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 60 deletions.
3 changes: 1 addition & 2 deletions packages/vuetify/src/labs/VDataTable/VDataTableColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const VDataTableColumn = defineFunctionalComponent({
noPadding: Boolean,
tag: String,
width: [Number, String],
}, (props, { slots, attrs }) => {
}, (props, { slots }) => {
const Tag = props.tag ?? 'td'
return (
<Tag
Expand All @@ -34,7 +34,6 @@ export const VDataTableColumn = defineFunctionalComponent({
width: convertToUnit(props.width),
left: convertToUnit(props.fixedOffset || null),
}}
{ ...attrs }
>
{ slots.default?.() }
</Tag>
Expand Down
11 changes: 6 additions & 5 deletions packages/vuetify/src/labs/VDataTable/VDataTableHeaders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
onClick={ column.sortable ? () => toggleSort(column) : undefined }
lastFixed={ column.lastFixed }
noPadding={ noPadding }
{ ...column.headerProps }
>
{{
default: () => {
Expand Down Expand Up @@ -200,11 +201,11 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
{ slots.headers
? slots.headers(slotProps.value)
: headers.value.map((row, y) => (
<tr>
{ row.map((column, x) => (
<VDataTableHeaderCell column={ column } x={ x } y={ y } />
))}
</tr>
<tr>
{ row.map((column, x) => (
<VDataTableHeaderCell column={ column } x={ x } y={ y } />
))}
</tr>
))}

{ props.loading && (
Expand Down
123 changes: 73 additions & 50 deletions packages/vuetify/src/labs/VDataTable/VDataTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { genericComponent, getObjectValueByPath, propsFactory, useRender } from

// Types
import type { PropType } from 'vue'
import type { DataTableItem, ItemKeySlot } from './types'
import type { CellProps, DataTableItem, ItemKeySlot } from './types'

export type VDataTableRowSlots = {
'item.data-table-select': Omit<ItemKeySlot, 'value'>
Expand All @@ -24,6 +24,7 @@ export type VDataTableRowSlots = {
export const makeVDataTableRowProps = propsFactory({
index: Number,
item: Object as PropType<DataTableItem>,
cellProps: [Object, Function] as PropType<CellProps>,
onClick: Function as PropType<(e: MouseEvent) => void>,
}, 'VDataTableRow')

Expand All @@ -47,59 +48,81 @@ export const VDataTableRow = genericComponent<VDataTableRowSlots>()({
]}
onClick={ props.onClick }
>
{ props.item && columns.value.map((column, i) => (
<VDataTableColumn
align={ column.align }
fixed={ column.fixed }
fixedOffset={ column.fixedOffset }
lastFixed={ column.lastFixed }
noPadding={ column.key === 'data-table-select' || column.key === 'data-table-expand' }
width={ column.width }
>
{{
default: () => {
const item = props.item!
const slotName = `item.${column.key}` as const
const slotProps = {
index: props.index!,
item: item.raw,
internalItem: item,
value: getObjectValueByPath(item.columns, column.key),
column,
isSelected,
toggleSelect,
isExpanded,
toggleExpand,
} satisfies ItemKeySlot
{ props.item && columns.value.map((column, i) => {
const item = props.item!
const slotName = `item.${column.key}` as const
const slotProps = {
index: props.index!,
item: item.raw,
internalItem: item,
value: getObjectValueByPath(item.columns, column.key),
column,
isSelected,
toggleSelect,
isExpanded,
toggleExpand,
} satisfies ItemKeySlot

if (slots[slotName]) return slots[slotName]!(slotProps)
const cellProps = typeof props.cellProps === 'function'
? props.cellProps({
index: slotProps.index,
item: slotProps.item,
internalItem: slotProps.internalItem,
value: slotProps.value,
column,
})
: props.cellProps
const columnCellProps = typeof column.cellProps === 'function'
? column.cellProps({
index: slotProps.index,
item: slotProps.item,
internalItem: slotProps.internalItem,
value: slotProps.value,
})
: column.cellProps

if (column.key === 'data-table-select') {
return slots['item.data-table-select']?.(slotProps) ?? (
<VCheckboxBtn
disabled={ !item.selectable }
modelValue={ isSelected([item]) }
onClick={ withModifiers(() => toggleSelect(item), ['stop']) }
/>
)
}
return (
<VDataTableColumn
align={ column.align }
fixed={ column.fixed }
fixedOffset={ column.fixedOffset }
lastFixed={ column.lastFixed }
noPadding={ column.key === 'data-table-select' || column.key === 'data-table-expand' }
width={ column.width }
{ ...cellProps }
{ ...columnCellProps }
>
{{
default: () => {
if (slots[slotName]) return slots[slotName]!(slotProps)

if (column.key === 'data-table-expand') {
return slots['item.data-table-expand']?.(slotProps) ?? (
<VBtn
icon={ isExpanded(item) ? '$collapse' : '$expand' }
size="small"
variant="text"
onClick={ withModifiers(() => toggleExpand(item), ['stop']) }
/>
)
}
if (column.key === 'data-table-select') {
return slots['item.data-table-select']?.(slotProps) ?? (
<VCheckboxBtn
disabled={ !item.selectable }
modelValue={ isSelected([item]) }
onClick={ withModifiers(() => toggleSelect(item), ['stop']) }
/>
)
}

return toDisplayString(slotProps.value)
},
}}
</VDataTableColumn>
))}
if (column.key === 'data-table-expand') {
return slots['item.data-table-expand']?.(slotProps) ?? (
<VBtn
icon={ isExpanded(item) ? '$collapse' : '$expand' }
size="small"
variant="text"
onClick={ withModifiers(() => toggleExpand(item), ['stop']) }
/>
)
}

return toDisplayString(slotProps.value)
},
}}
</VDataTableColumn>
)
})}
</tr>
))
},
Expand Down
14 changes: 12 additions & 2 deletions packages/vuetify/src/labs/VDataTable/VDataTableRows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { genericComponent, getPrefixedEventHandlers, propsFactory, useRender } f
// Types
import type { PropType } from 'vue'
import type { Group } from './composables/group'
import type { DataTableItem, GroupHeaderSlot, ItemSlot } from './types'
import type { CellProps, DataTableItem, GroupHeaderSlot, ItemSlot, RowProps } from './types'
import type { VDataTableGroupHeaderRowSlots } from './VDataTableGroupHeaderRow'
import type { VDataTableRowSlots } from './VDataTableRow'

Expand Down Expand Up @@ -44,6 +44,8 @@ export const makeVDataTableRowsProps = propsFactory({
default: '$vuetify.noDataText',
},
rowHeight: Number,
rowProps: [Object, Function] as PropType<RowProps>,
cellProps: [Object, Function] as PropType<CellProps>,
}, 'VDataTableRows')

export const VDataTableRows = genericComponent<VDataTableRowsSlots>()({
Expand Down Expand Up @@ -134,8 +136,16 @@ export const VDataTableRows = genericComponent<VDataTableRowsSlots>()({
} : undefined,
index,
item,
cellProps: props.cellProps,
},
getPrefixedEventHandlers(attrs, ':row', () => slotProps)
getPrefixedEventHandlers(attrs, ':row', () => slotProps),
typeof props.rowProps === 'function'
? props.rowProps({
item: slotProps.item,
index: slotProps.index,
internalItem: slotProps.internalItem,
})
: props.rowProps,
),
}

Expand Down
4 changes: 3 additions & 1 deletion packages/vuetify/src/labs/VDataTable/composables/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getPropertyFromItem, propsFactory } from '@/util'

// Types
import type { PropType, Ref } from 'vue'
import type { DataTableItem, InternalDataTableHeader } from '../types'
import type { CellProps, DataTableItem, InternalDataTableHeader, RowProps } from '../types'
import type { SelectItemKey } from '@/util'

export interface DataTableItemProps {
Expand All @@ -28,6 +28,8 @@ export const makeDataTableItemsProps = propsFactory({
type: [String, Array, Function] as PropType<SelectItemKey>,
default: null,
},
rowProps: [Object, Function] as PropType<RowProps>,
cellProps: [Object, Function] as PropType<CellProps>,
returnObject: Boolean,
}, 'DataTable-items')

Expand Down
15 changes: 15 additions & 0 deletions packages/vuetify/src/labs/VDataTable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export type DataTableHeader = {
minWidth?: string
maxWidth?: string

headerProps?: Record<string, any>
cellProps?: HeaderCellProps

sortable?: boolean
sort?: DataTableCompareFunction

Expand Down Expand Up @@ -74,3 +77,15 @@ export type ItemKeySlot<T = any> = ItemSlotBase<T> & {
value: any
column: InternalDataTableHeader
}

export type RowProps =
| Record<string, any>
| ((data: Pick<ItemKeySlot, 'index' | 'item' | 'internalItem'>) => Record<string, any>)

export type CellProps =
| Record<string, any>
| ((data: Pick<ItemKeySlot, 'index' | 'item' | 'internalItem' | 'value' | 'column'>) => Record<string, any>)

export type HeaderCellProps =
| Record<string, any>
| ((data: Pick<ItemKeySlot, 'index' | 'item' | 'internalItem' | 'value'>) => Record<string, any>)

0 comments on commit 0c87f70

Please sign in to comment.