Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(data-table): add item generic #4145

Merged
merged 2 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -208,7 +208,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 @@ -241,7 +241,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 @@ -261,7 +261,7 @@ const props = defineProps({
...useColumnsProps,
...useFilterableProps,
...usePaginatedRowsProps,
...useRowsProps,
...createRowsProps<Item>(),
...useSelectableProps,
...useThrottleProps,
...pick(VaDataTableThRowProps, ['ariaSelectAllRowsLabel', 'ariaSortColumnByLabel']),
Expand Down Expand Up @@ -311,7 +311,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 @@ -81,27 +81,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