Files
NewSmoop/management-ui/src/customcompometns/DataTableNoCheckboxScroll.vue

110 lines
4.0 KiB
Vue

<script setup lang="ts" generic="TData, TValue">
import { defineProps } from 'vue'
import type { DefineComponent } from 'vue'
import type { ColumnDef } from '@tanstack/vue-table'
import {
useVueTable,
getCoreRowModel,
FlexRender,
} from '@tanstack/vue-table'
import {
Table, TableHeader, TableRow, TableHead, TableBody, TableCell,
} from '@/components/ui/table'
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area' // <-- add ScrollBar
const props = defineProps<{
columns: ColumnDef<TData, TValue>[]
data: TData[]
dropdownComponent?: DefineComponent<{ row: TData }, any, any>
dropdownProps?: Record<string, any>
/** Optional tailwind class to control min table width for horizontal scrolling */
minTableWidth?: string
}>()
const table = useVueTable({
get data() { return props.data },
get columns() { return props.columns },
getCoreRowModel: getCoreRowModel(),
})
const emit = defineEmits<{
(e: 'row-updated', row: TData, payload: any): void
(e: 'row-deleted', row: TData): void
}>()
const minWidthClass = props.minTableWidth ?? 'min-w-[1100px]' // tweak as needed
</script>
<template>
<!-- Parent must not rely on h-full; use overflow-hidden to contain scrollbars -->
<div class="w-full max-h-full border rounded-md flex flex-col overflow-hidden">
<!-- This element grows and can scroll internally -->
<ScrollArea class="flex-1 min-h-0 w-full">
<!-- min-width keeps horizontal scroll available when needed -->
<div :class="['w-full', minWidthClass]">
<!-- separate borders help sticky headers render above rows -->
<Table class="w-full border-separate border-spacing-0">
<TableHeader>
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
<TableHead
v-for="header in headerGroup.headers"
:key="header.id"
class="sticky top-0 bg-background z-10 whitespace-nowrap"
>
<FlexRender
v-if="!header.isPlaceholder"
:render="header.column.columnDef.header"
:props="header.getContext()"
/>
</TableHead>
<TableHead
v-if="props.dropdownComponent"
class="sticky top-0 bg-background z-10 w-12"
/>
</TableRow>
</TableHeader>
<TableBody>
<template v-if="table.getRowModel().rows.length">
<TableRow
v-for="row in table.getRowModel().rows"
:key="row.id"
class="whitespace-nowrap"
>
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
</TableCell>
<TableCell v-if="props.dropdownComponent" class="text-right">
<component
:is="props.dropdownComponent"
:row="row.original"
v-bind="props.dropdownProps"
@updated="(payload: any) => emit('row-updated', row.original, payload)"
@deleted="() => emit('row-deleted', row.original)"
/>
</TableCell>
</TableRow>
</template>
<template v-else>
<TableRow>
<TableCell
:colspan="props.columns.length + (props.dropdownComponent ? 1 : 0)"
class="h-24 text-center"
>
No data.
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
<!-- Always show both scrollbars when needed -->
<ScrollBar orientation="horizontal" />
<ScrollBar orientation="vertical" />
</ScrollArea>
</div>
</template>