From f08e71a3d2684008e37e7c21eb115fbe14bcca6c Mon Sep 17 00:00:00 2001 From: Maksim Nedoshev Date: Wed, 16 Jul 2025 12:04:48 +0300 Subject: [PATCH] fix(DataTable): expose expandable prop --- .../va-data-table/VaDataTable.stories.ts | 178 ++++++++++++++++++ .../components/va-data-table/VaDataTable.vue | 8 +- .../components/va-data-table/hooks/useRows.ts | 13 +- .../std/internal/useVModelStateful.ts | 6 +- 4 files changed, 200 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/components/va-data-table/VaDataTable.stories.ts b/packages/ui/src/components/va-data-table/VaDataTable.stories.ts index 350e50434f..048fa92c48 100644 --- a/packages/ui/src/components/va-data-table/VaDataTable.stories.ts +++ b/packages/ui/src/components/va-data-table/VaDataTable.stories.ts @@ -351,3 +351,181 @@ export const RowSlot = defineStory({ `, }), }) + +export const ExpandableRowPagination = () => ({ + components: { VaDataTable, VaPagination }, + data () { + const items = [ + { + id: 1, + name: 'Leanne Graham', + username: 'Bret', + email: 'Sincere@april.biz', + phone: '1-770-736-8031', + website: 'hildegard.org', + }, + { + id: 2, + name: 'Ervin Howell', + username: 'Antonette', + email: 'Shanna@melissa.tv', + phone: '010-692-6593', + website: 'anastasia.net', + }, + { + id: 3, + name: 'Clementine Bauch', + username: 'Samantha', + email: 'Nathan@yesenia.net', + phone: '1-463-123-4447', + website: 'ramiro.info', + }, + { + id: 4, + name: 'Patricia Lebsack', + username: 'Karianne', + email: 'Julianne.OConner@kory.org', + phone: '493-170-9623', + website: 'kale.biz', + }, + { + id: 5, + name: 'Chelsey Dietrich', + username: 'Kamren', + email: 'Lucio_Hettinger@annie.ca', + phone: '(254)954-1289', + website: 'demarco.info', + }, + ] + + const columns = [ + { key: 'name' }, + { key: 'username' }, + { key: 'email' }, + { key: 'actions', width: 80 }, + ] + + const currentPage = ref(0) + + return { + items, + columns, + currentPage, + } + }, + + template: ` + + + + + + + `, +}) + +export const ExpandableRowPaginationSlice = () => ({ + components: { VaDataTable, VaPagination }, + data () { + const items = [ + { + id: 1, + name: 'Leanne Graham', + username: 'Bret', + email: 'Sincere@april.biz', + phone: '1-770-736-8031', + website: 'hildegard.org', + }, + { + id: 2, + name: 'Ervin Howell', + username: 'Antonette', + email: 'Shanna@melissa.tv', + phone: '010-692-6593', + website: 'anastasia.net', + }, + { + id: 3, + name: 'Clementine Bauch', + username: 'Samantha', + email: 'Nathan@yesenia.net', + phone: '1-463-123-4447', + website: 'ramiro.info', + }, + { + id: 4, + name: 'Patricia Lebsack', + username: 'Karianne', + email: 'Julianne.OConner@kory.org', + phone: '493-170-9623', + website: 'kale.biz', + }, + { + id: 5, + name: 'Chelsey Dietrich', + username: 'Kamren', + email: 'Lucio_Hettinger@annie.ca', + phone: '(254)954-1289', + website: 'demarco.info', + }, + ] + + const columns = [ + { key: 'name' }, + { key: 'username' }, + { key: 'email' }, + { key: 'actions', width: 80 }, + ] + + const currentPage = ref(0) + + return { + items, + columns, + currentPage, + } + }, + + template: ` + + + + + + + `, +}) diff --git a/packages/ui/src/components/va-data-table/VaDataTable.vue b/packages/ui/src/components/va-data-table/VaDataTable.vue index 2d51b1f78e..d3843f96af 100644 --- a/packages/ui/src/components/va-data-table/VaDataTable.vue +++ b/packages/ui/src/components/va-data-table/VaDataTable.vue @@ -293,12 +293,18 @@ const props = defineProps({ ariaSelectRowLabel: useTranslationProp('$t:selectRowByIndex'), delay: { type: [Number, String], default: 0 }, + + expanded: { + type: Array as PropType, + default: () => [], + }, }) const emit = defineEmits([ 'update:modelValue', // `modelValue` is selectedItems 'update:sortBy', 'update:sortingOrder', + 'update:expanded', 'filtered', 'sorted', 'selectionChange', @@ -311,7 +317,7 @@ const emit = defineEmits([ const { columnsComputed } = useColumns(props) -const { rowsComputed } = useRows(columnsComputed, props) +const { rowsComputed } = useRows(columnsComputed, props, emit) const { filteredRows } = useFilterable(rowsComputed, props, emit) diff --git a/packages/ui/src/components/va-data-table/hooks/useRows.ts b/packages/ui/src/components/va-data-table/hooks/useRows.ts index dab5fd0f70..c4cd1730c7 100644 --- a/packages/ui/src/components/va-data-table/hooks/useRows.ts +++ b/packages/ui/src/components/va-data-table/hooks/useRows.ts @@ -1,4 +1,4 @@ -import { Ref, ref, computed, ExtractPropTypes } from 'vue' +import { Ref, computed, ExtractPropTypes, watch } from 'vue' import { createItemsProp, useItemsTrackByProp } from './useCommonProps' @@ -12,6 +12,7 @@ import type { DataTableItemKey, DataTableRowData, } from '../types' +import { useVModelStateful } from '../../../composables' export const getItemKey = >(source: DataTableItem, itemsTrackBy: string | ((item: DataTableItem) => any)): DataTableItemKey => ( typeof itemsTrackBy === 'function' @@ -60,14 +61,16 @@ const buildTableRow = ( } type RowsProps = Omit>, 'items'> & { - items: Item[] + items: Item[], + expanded: boolean[] } export const useRows = >( columns: Ref, props: RowsProps, + emit: (event: 'update:expanded', value: boolean[]) => void, ) => { - const expandableRows = ref>({}) + const expandableRows = useVModelStateful(props, 'expanded', emit) const rowsComputed = computed(() => props.items .map((rawItem, index) => ({ @@ -82,6 +85,10 @@ export const useRows = >( isExpandableRowVisible: !!expandableRows.value[index], }))) + watch(() => props.items, () => { + expandableRows.value = props.items.map(() => false) + }) + return { rowsComputed, } diff --git a/packages/ui/src/composables/std/internal/useVModelStateful.ts b/packages/ui/src/composables/std/internal/useVModelStateful.ts index 4a78327a2d..3b5c23d702 100644 --- a/packages/ui/src/composables/std/internal/useVModelStateful.ts +++ b/packages/ui/src/composables/std/internal/useVModelStateful.ts @@ -18,5 +18,9 @@ export const useVModelStateful = (props: P, key: K, emit: }, }) - return valueProxy + Object.defineProperty(valueProxy, 'userProvided', { + get: () => isUserProvided.value, + }) + + return valueProxy as unknown as Ref & { userProvided: boolean } }