Skip to content

Commit

Permalink
feat(data-table): add item generic (#4145)
Browse files Browse the repository at this point in the history
* feat(data-table): add item generic

* feat(data-table): show ts suggestions in data table slots
  • Loading branch information
m0ksem committed Mar 7, 2024
1 parent feb0302 commit b2a1b5b
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 43 deletions.
8 changes: 4 additions & 4 deletions packages/ui/src/components/va-data-table/VaDataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ import { useSelectableRow, useSelectableProps } from './hooks/useSelectableRow'
import { useStylable, useStylableProps } from './hooks/useStylable'
import { useBinding, useBindingProps } from './hooks/useBinding'
import { useAnimationName, useAnimationNameProps } from './hooks/useAnimationName'
import { useRows, useRowsProps } from './hooks/useRows'
import { useRows, createRowsProps } from './hooks/useRows'
import { useFilterable, useFilterableProps } from './hooks/useFilterable'
import { useSortable, useSortableProps } from './hooks/useSortable'
import { useTableScroll, useTableScrollProps, useTableScrollEmits } from './hooks/useTableScroll'
Expand Down Expand Up @@ -242,7 +242,7 @@ type emitNames = 'update:modelValue' |
'scroll:bottom'
</script>
<script lang="ts" setup>
<script lang="ts" generic="Item extends Record<string, any>" setup>
const { tp } = useTranslation()
Expand All @@ -262,7 +262,7 @@ const props = defineProps({
...useColumnsProps,
...useFilterableProps,
...usePaginatedRowsProps,
...useRowsProps,
...createRowsProps<Item>(),
...useSelectableProps,
...useThrottleProps,
...pick(VaDataTableThRowProps, ['ariaSelectAllRowsLabel', 'ariaSortColumnByLabel']),
Expand Down Expand Up @@ -312,7 +312,7 @@ const {
sortingOrderIconName,
} = useSortable(columnsComputed, filteredRows, props, emit)
const { paginatedRows } = usePaginatedRows(sortedRows, props)
const { paginatedRows } = usePaginatedRows<Item>(sortedRows, props)
const {
ctrlSelectRow,
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/va-data-table/hooks/useColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { computed, ExtractPropTypes, PropType } from 'vue'
import startCase from 'lodash/startCase.js'
import merge from 'lodash/merge.js'

import { useItemsProp } from './useCommonProps'
import { createItemsProp } from './useCommonProps'

import { warn } from '../../../utils/console'

Expand All @@ -21,7 +21,7 @@ export const sortingOptionsValidator = (options: DataTableSortingOptions) => {
}

export const useColumnsProps = {
...useItemsProp,
...createItemsProp(),
columns: { type: Array as PropType<DataTableColumnSource[]>, default: () => [] as DataTableColumnSource[] },
sortingOptions: {
type: Array as PropType<DataTableSortingOptions>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { DataTableItem } from '../types'

export const useCurrentPageProp = { currentPage: { type: Number as PropType<number | undefined> } }

export const useItemsProp = { items: { type: Array as PropType<DataTableItem[]>, default: () => [] as DataTableItem[] } }
export const createItemsProp = <T>() => ({
items: { type: Array as PropType<DataTableItem<T>[]>, default: () => [] as DataTableItem<T>[] },
})

export const useSelectableProp = { selectable: { type: Boolean, default: false } }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export const useFilterableProps = {
export type TFilteredArgs = { items: DataTableItem[], itemsIndexes: number[] }
export type TFilterableEmits = (event: 'filtered', arg: TFilteredArgs) => void

export const useFilterable = (
rawRows: Ref<DataTableRow[]>,
export const useFilterable = <Item extends DataTableRow>(
rawRows: Ref<Item[]>,
props: ExtractPropTypes<typeof useFilterableProps>,
emit: TFilterableEmits,
) => {
const filteredRows = computed<DataTableRow[]>(() => {
const filteredRows = computed<Item[]>(() => {
if (!rawRows.value.length) {
return rawRows.value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import { useCurrentPageProp } from './useCommonProps'

import { useThrottleValue, useThrottleProps } from '../../../composables'

import type { DataTableRow } from '../types'
import type { DataTableItem, DataTableRow } from '../types'

export const usePaginatedRowsProps = {
...useThrottleProps,
...useCurrentPageProp,
perPage: { type: Number as PropType<number | undefined> },
}

export const usePaginatedRows = (
sortedRows: Ref<DataTableRow[]>,
props: ExtractPropTypes<typeof usePaginatedRowsProps>,
type PaginatedProps<Item extends DataTableItem> = Omit<ExtractPropTypes<typeof usePaginatedRowsProps>, 'items'> & {
items: Item[]
}

export const usePaginatedRows = <Item extends DataTableItem>(
sortedRows: Ref<DataTableRow<Item>[]>,
props: PaginatedProps<Item>,
) => {
const paginatedRows = computed(() => {
if (!props.perPage || props.perPage < 0) {
Expand Down
39 changes: 22 additions & 17 deletions packages/ui/src/components/va-data-table/hooks/useRows.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Ref, ref, computed, ExtractPropTypes } from 'vue'

import { useItemsProp, useItemsTrackByProp } from './useCommonProps'
import { createItemsProp, useItemsTrackByProp } from './useCommonProps'

import { getValueByPath } from '../../../utils/value-by-key'

Expand All @@ -10,43 +10,44 @@ import type {
DataTableCell,
DataTableRow,
DataTableItemKey,
DataTableRowData,
} from '../types'

export const getItemKey = (source: DataTableItem, itemsTrackBy: string | ((item: DataTableItem) => any)): DataTableItemKey => (
export const getItemKey = <T extends Record<string, any>>(source: DataTableItem<T>, itemsTrackBy: string | ((item: DataTableItem<T>) => any)): DataTableItemKey => (
typeof itemsTrackBy === 'function'
? itemsTrackBy(source)
: getValueByPath(source, itemsTrackBy) || source
)

export const useRowsProps = {
...useItemsProp,
export const createRowsProps = <T extends Record<string, any>>() => ({
...createItemsProp<T>(),
...useItemsTrackByProp,
}
})

const buildTableCell = (
const buildTableCell = <Item extends DataTableItem>(
rowIndex: number,
rowKey: string,
rowData: DataTableItem,
rowData: DataTableRowData<Item>,
column: DataTableColumnInternal,
): DataTableCell => {
): DataTableCell<Item> => {
const source = getValueByPath(rowData, column.key)

return {
rowIndex,
rowKey,
rowData,
column,
source,
source: source as string,
value: source?.toString?.() || '',
}
}

const buildTableRow = (
source: DataTableItem,
const buildTableRow = <Item extends DataTableItem>(
source: DataTableItem<Item>,
initialIndex: number,
itemsTrackBy: string | ((item: DataTableItem) => any),
itemsTrackBy: string | ((item: DataTableItem<Item>) => any),
columns: DataTableColumnInternal[],
) => {
): Omit<DataTableRow<Item>, 'toggleRowDetails' | 'isExpandableRowVisible'> => {
const itemKey = getItemKey(source, itemsTrackBy)

return {
Expand All @@ -58,15 +59,19 @@ const buildTableRow = (
}
}

export const useRows = (
type RowsProps<Item> = Omit<ExtractPropTypes<ReturnType<typeof createRowsProps>>, 'items'> & {
items: Item[]
}

export const useRows = <Item extends Record<string, any>>(
columns: Ref<DataTableColumnInternal[]>,
props: ExtractPropTypes<typeof useRowsProps>,
props: RowsProps<Item>,
) => {
const expandableRows = ref<Record<number, boolean>>({})

const rowsComputed = computed<DataTableRow[]>(() => props.items
const rowsComputed = computed(() => props.items
.map((rawItem, index) => ({
...buildTableRow(rawItem, index, props.itemsTrackBy, columns.value),
...buildTableRow<Item>(rawItem, index, props.itemsTrackBy, columns.value),
toggleRowDetails: (show?: boolean) => {
if (typeof show === 'boolean') {
expandableRows.value[index] = show
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/va-data-table/hooks/useSortable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ export type TSortableEmits = ((

export type TSortIcon = 'va-arrow-up' | 'va-arrow-down' | 'unfold_more'

export const useSortable = (
export const useSortable = <Item extends DataTableRow>(
columns: Ref<DataTableColumnInternal[]>,
filteredRows: Ref<DataTableRow[]>,
filteredRows: Ref<Item[]>,
props: ExtractPropTypes<typeof useSortableProps>,
emit: TSortableEmits,
) => {
Expand Down
22 changes: 12 additions & 10 deletions packages/ui/src/components/va-data-table/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export type DataTableSortingOptions = DataTableSortingOrder[]

// provided column definitions (<va-data-table `:columns="myColumns"` />)
// should look like an array of the following objects (and/or strings)
export type DataTableColumn<T = string> = {
export type DataTableColumn<Key = string> = {
[key: string]: any
key: T // name of an item's property: 'userName', 'address.zipCode'
key: Key // name of an item's property: 'userName', 'address.zipCode'
name?: string // column unique name (used in slots)
label?: string // what to display in the respective heading
thTitle?: string // <th>'s `title` attribute's value
Expand Down Expand Up @@ -83,27 +83,29 @@ export interface DataTableColumnInternal {
thStyle?: DataTableColumnStyle
}

export type DataTableItem = Record<string, any>
export type DataTableItem<T = Record<string, any>> = T
export type DataTableItemKey = any

export type DataTableRowData<Item extends Record<string, any>> = Item

// the inner representation of table cells
export interface DataTableCell {
export interface DataTableCell<Item extends DataTableItem = DataTableItem> {
rowIndex: number
rowKey: DataTableItemKey
rowData: DataTableItem
rowData: DataTableRowData<Item>
column: DataTableColumnInternal
source: any
source: string
value: string
}

// the inner representation of table rows
export interface DataTableRow {
export interface DataTableRow<Item extends DataTableItem = DataTableItem> {
initialIndex: number
itemKey: DataTableItemKey
source: DataTableItem
cells: DataTableCell[]
source: Item
cells: DataTableCell<Item>[]
/** Same rowData as in DataTableCell */
rowData: DataTableItem
rowData: DataTableRowData<Item>
toggleRowDetails: (show?: boolean) => void
isExpandableRowVisible: boolean
}
Expand Down

0 comments on commit b2a1b5b

Please sign in to comment.