@soft-stech/bootsman-ui-shadcn 2.0.21 → 2.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/BuiPaginationCommon.vue_vue_type_script_setup_true_lang-BOuWIF4c.js +179 -0
  2. package/dist/{BuiScrollArea.vue_vue_type_script_setup_true_lang-O7VUcRC4.js → BuiScrollArea.vue_vue_type_script_setup_true_lang-lyWD8KAT.js} +1 -1
  3. package/dist/{BuiScrollBar.vue_vue_type_script_setup_true_lang-cV0od8j0.js → BuiScrollBar.vue_vue_type_script_setup_true_lang-BCvjzEmb.js} +4 -4
  4. package/dist/BuiTable.vue_vue_type_script_setup_true_lang-BQRl7YR1.js +37 -0
  5. package/dist/{BuiTableEmpty.vue_vue_type_script_setup_true_lang-Da4qHIWo.js → BuiTableEmpty.vue_vue_type_script_setup_true_lang-CuffOAuP.js} +1 -1
  6. package/dist/BuiTableRow.vue_vue_type_script_setup_true_lang-BQnadEa7.js +51 -0
  7. package/dist/components/pagination/BuiPaginationCommon.js +1 -1
  8. package/dist/components/pagination/BuiPaginationCommon.vue.d.ts +4 -0
  9. package/dist/components/pagination/index.js +1 -1
  10. package/dist/components/scroll-area/BuiScrollArea.js +1 -1
  11. package/dist/components/scroll-area/BuiScrollBar.js +1 -1
  12. package/dist/components/scroll-area/index.js +2 -2
  13. package/dist/components/table/BuiDataTable.vue.d.ts +8 -4
  14. package/dist/components/table/BuiTable.js +1 -1
  15. package/dist/components/table/BuiTableEmpty.js +1 -1
  16. package/dist/components/table/BuiTableRow.js +1 -1
  17. package/dist/components/table/index.d.ts +1 -0
  18. package/dist/components/table/index.js +713 -672
  19. package/dist/index.js +6 -6
  20. package/dist/style.css +1 -1
  21. package/package.json +1 -1
  22. package/src/components/pagination/BuiPaginationCommon.vue +16 -4
  23. package/src/components/scroll-area/BuiScrollBar.vue +4 -4
  24. package/src/components/table/BuiDataTable.vue +113 -23
  25. package/src/components/table/BuiTable.vue +1 -0
  26. package/src/components/table/BuiTableRow.vue +6 -0
  27. package/src/components/table/index.ts +2 -0
  28. package/src/stories/BuiDataTable.stories.ts +13 -0
  29. package/src/stories/components/BuiDataTableStory.vue +3 -3
  30. package/src/stories/components/BuiDataTableWithScrollStory.vue +292 -0
  31. package/dist/BuiPaginationCommon.vue_vue_type_script_setup_true_lang-DhSRYKth.js +0 -170
  32. package/dist/BuiTable.vue_vue_type_script_setup_true_lang-CQpc0Sr1.js +0 -36
  33. package/dist/BuiTableRow.vue_vue_type_script_setup_true_lang-BJk8Yk1B.js +0 -54
@@ -1,17 +1,38 @@
1
+ <script lang="ts">
2
+ import type { PaginationState } from '@tanstack/vue-table'
3
+
4
+ export type PaginationAutoState = PaginationState & {
5
+ pageAuto?: boolean
6
+ }
7
+ </script>
8
+
1
9
  <script setup lang="ts" generic="TData, TValue">
10
+ import { BuiButton } from '@/components/button'
2
11
  import {
3
12
  BuiCollapsible,
4
13
  BuiCollapsibleContent,
5
14
  BuiCollapsibleTrigger
6
15
  } from '@/components/collapsible'
16
+ import {
17
+ BuiCommand,
18
+ BuiCommandEmpty,
19
+ BuiCommandInput,
20
+ BuiCommandItem,
21
+ BuiCommandList,
22
+ BuiCommandSeparator
23
+ } from '@/components/command'
24
+ import { BuiContextMenuContent, BuiContextMenuItem } from '@/components/context-menu'
7
25
  import { BuiPaginationCommon, type PageSize } from '@/components/pagination'
26
+ import { BuiPopover, BuiPopoverContent, BuiPopoverTrigger } from '@/components/popover'
27
+ import { BuiScrollArea } from '@/components/scroll-area'
8
28
  import BuiTableRowSubrow from '@/components/table/BuiTableRowSubrow.vue'
29
+ import { useResizeColumns } from '@/lib/useResizeColumns'
30
+ import { cn, valueUpdater } from '@/lib/utils'
9
31
  import type {
10
32
  Column,
11
33
  ColumnDef,
12
34
  ColumnOrderState,
13
35
  Header,
14
- PaginationState,
15
36
  Row,
16
37
  RowSelectionState,
17
38
  SortingState,
@@ -24,8 +45,18 @@ import {
24
45
  getSortedRowModel,
25
46
  useVueTable
26
47
  } from '@tanstack/vue-table'
27
- import { computed, watchEffect, ref, watch, onMounted, onBeforeMount, nextTick } from 'vue'
28
48
  import {
49
+ useElementSize,
50
+ useEventListener,
51
+ useSessionStorage,
52
+ useIntersectionObserver,
53
+ useElementVisibility
54
+ } from '@vueuse/core'
55
+ import { isEqual } from 'lodash-es'
56
+ import { ChevronDown, Settings2Icon } from 'lucide-vue-next'
57
+ import { computed, nextTick, onBeforeMount, onMounted, ref, watch, watchEffect } from 'vue'
58
+ import {
59
+ BuiDataTableColumnList,
29
60
  BuiTable,
30
61
  BuiTableBody,
31
62
  BuiTableCell,
@@ -33,27 +64,8 @@ import {
33
64
  BuiTableHead,
34
65
  BuiTableHeader,
35
66
  BuiTableRow,
36
- getPinningStyle,
37
- BuiDataTableColumnList
67
+ getPinningStyle
38
68
  } from './'
39
- import {
40
- BuiCommand,
41
- BuiCommandEmpty,
42
- BuiCommandInput,
43
- BuiCommandList,
44
- BuiCommandItem,
45
- BuiCommandSeparator
46
- } from '@/components/command'
47
- import { BuiContextMenuContent, BuiContextMenuItem } from '@/components/context-menu'
48
- import { BuiPopover, BuiPopoverContent, BuiPopoverTrigger } from '@/components/popover'
49
- import { BuiScrollArea } from '@/components/scroll-area'
50
- import { BuiButton } from '@/components/button'
51
- import { Settings2Icon, ChevronDown } from 'lucide-vue-next'
52
- import { useElementSize, useEventListener } from '@vueuse/core'
53
- import { isEqual } from 'lodash-es'
54
- import { cn, valueUpdater } from '@/lib/utils'
55
- import { useResizeColumns } from '@/lib/useResizeColumns'
56
- import { useSessionStorage } from '@vueuse/core'
57
69
  import { useGlobalCursor } from '@/lib/useGlobalCursor'
58
70
 
59
71
  const NO_GROUP_KEY = '#UNDEFINED#'
@@ -87,6 +99,7 @@ const props = withDefaults(
87
99
  columnResetVisibility?: string
88
100
  paginationTranslations?: {
89
101
  itemsPerPage: string
102
+ itemsPerPageAuto: string
90
103
  page: string
91
104
  of: string
92
105
  }
@@ -113,7 +126,7 @@ const props = withDefaults(
113
126
  )
114
127
 
115
128
  const sorting = defineModel<SortingState>('sorting')
116
- const pagination = defineModel<PaginationState>('pagination')
129
+ const pagination = defineModel<PaginationAutoState>('pagination')
117
130
  const rowSelection = defineModel<RowSelectionState>('selection')
118
131
  const columnVisibility = defineModel<VisibilityState>('columnVisibility')
119
132
  const columnOrder = defineModel<ColumnOrderState>('columnOrder')
@@ -182,6 +195,15 @@ const table = useVueTable({
182
195
  getRowId: props.getRowId
183
196
  })
184
197
 
198
+ const pageAuto = computed({
199
+ get() {
200
+ return pagination.value?.pageAuto || false
201
+ },
202
+ set: (state: boolean) => {
203
+ if (!pagination.value) return
204
+ pagination.value.pageAuto = state
205
+ }
206
+ })
185
207
  const tablePageSize = computed<PageSize>({
186
208
  get() {
187
209
  return table.getState().pagination.pageSize as PageSize
@@ -417,6 +439,65 @@ watch(isResizing, () => {
417
439
  resetCursor()
418
440
  }
419
441
  })
442
+
443
+ const rows = computed(() => table.getRowModel().rows)
444
+ const rowsLength = computed(() => rows.value.length)
445
+ const sentinel = ref<HTMLElement | null>(null)
446
+ const sentinelVisible = useElementVisibility(sentinel)
447
+ const sentinelKey = computed(() => `sentinel-${rowsLength.value}`)
448
+
449
+ const { stop } = useIntersectionObserver(
450
+ sentinel,
451
+ async ([{ isIntersecting }]) => {
452
+ if (isIntersecting && pageAuto.value) {
453
+ await nextTick()
454
+ loadMore()
455
+ }
456
+
457
+ if (tablePageSize.value >= props.totalItems) {
458
+ stop()
459
+ }
460
+ },
461
+ {
462
+ rootMargin: '0px 0px 50px 0px'
463
+ }
464
+ )
465
+
466
+ let loadingMore = false
467
+ async function loadMore() {
468
+ if (loadingMore) return
469
+ loadingMore = true
470
+
471
+ const newSize = Math.min(tablePageSize.value + 50, props.totalItems)
472
+ table.setPageSize(newSize)
473
+
474
+ await nextTick()
475
+ loadingMore = false
476
+ }
477
+
478
+ watch(pageAuto, (newPageAuto, oldPageAuto) => {
479
+ if (newPageAuto && !oldPageAuto) {
480
+ if (tableElementRef.value && tableElementRef.value.scrollAreaElementRef?.tableWrapperRef) {
481
+ tableElementRef.value.scrollAreaElementRef.tableWrapperRef.scrollTop()
482
+ }
483
+ }
484
+ })
485
+
486
+ const isUpdating = ref(false)
487
+ watch(rowsLength, async () => {
488
+ if (!pageAuto.value || isUpdating.value) return
489
+
490
+ isUpdating.value = true
491
+ await nextTick()
492
+
493
+ //Add a small delay to ensure rendering is complete
494
+ setTimeout(() => {
495
+ if (sentinelVisible.value) {
496
+ loadMore()
497
+ }
498
+ isUpdating.value = false
499
+ }, 50)
500
+ })
420
501
  </script>
421
502
 
422
503
  <template>
@@ -635,6 +716,14 @@ watch(isResizing, () => {
635
716
  <slot name="nodata">No data</slot>
636
717
  </BuiTableEmpty>
637
718
  </template>
719
+
720
+ <tr
721
+ v-if="pageAuto && tablePageSize < props.totalItems"
722
+ ref="sentinel"
723
+ class="h-4 w-full"
724
+ :data-key="sentinelKey"
725
+ :key="sentinelKey"
726
+ />
638
727
  </BuiTableBody>
639
728
  </BuiTable>
640
729
  <div
@@ -654,6 +743,7 @@ watch(isResizing, () => {
654
743
  :total="computedItems"
655
744
  v-model:pageIndex="pageIndex"
656
745
  v-model:pageSize="tablePageSize"
746
+ v-model:pageAuto="pageAuto"
657
747
  :translations="paginationTranslations"
658
748
  >
659
749
  </BuiPaginationCommon>
@@ -14,6 +14,7 @@ defineExpose({ tableRef, scrollAreaElementRef })
14
14
  <BuiScrollArea
15
15
  ref="scrollAreaElementRef"
16
16
  class="border-border/16 w-full grow overflow-auto rounded-sm border"
17
+ :scroll-hide-delay="100"
17
18
  >
18
19
  <slot name="columnVisibility" />
19
20
  <div class="flex min-h-[90px] w-full grow flex-col">
@@ -4,6 +4,10 @@ import { cn } from '@/lib/utils'
4
4
 
5
5
  const props = defineProps<{ class?: string }>()
6
6
  const emits = defineEmits(['mouseenter', 'mouseleave'])
7
+
8
+ defineOptions({
9
+ inheritAttrs: false
10
+ })
7
11
  </script>
8
12
 
9
13
  <template>
@@ -19,6 +23,7 @@ const emits = defineEmits(['mouseenter', 'mouseleave'])
19
23
  :data-row-state="$attrs['data-row-state']"
20
24
  @mouseenter="emits('mouseenter')"
21
25
  @mouseleave="emits('mouseleave')"
26
+ v-bind="$attrs"
22
27
  >
23
28
  <slot />
24
29
  </tr>
@@ -36,6 +41,7 @@ const emits = defineEmits(['mouseenter', 'mouseleave'])
36
41
  :data-row-state="$attrs['data-row-state']"
37
42
  @mouseenter="emits('mouseenter')"
38
43
  @mouseleave="emits('mouseleave')"
44
+ v-bind="$attrs"
39
45
  >
40
46
  <slot />
41
47
  </tr>
@@ -14,6 +14,8 @@ export { default as BuiTableFooter } from './BuiTableFooter.vue'
14
14
  export { default as BuiDataTable } from './BuiDataTable.vue'
15
15
  export { default as BuiDataTableColumnList } from './BuiDataTableColumnList.vue'
16
16
 
17
+ export type { PaginationAutoState } from './BuiDataTable.vue'
18
+
17
19
  export function getPinningStyle<TData>(_column: Column<TData, unknown>): CSSProperties {
18
20
  // FYI sticky columns not possible with transparent background colors
19
21
  // const isPinned = column.getIsPinned()
@@ -1,5 +1,6 @@
1
1
  import { BuiDataTable } from '@/components/table'
2
2
  import BuiDataTableStory from '@/stories/components/BuiDataTableStory.vue'
3
+ import BuiDataTableWithScrollStory from '@/stories/components/BuiDataTableWithScrollStory.vue'
3
4
  import type { Meta, StoryObj } from '@storybook/vue3-vite'
4
5
 
5
6
  const meta = {
@@ -24,3 +25,15 @@ export const Default: Story = {
24
25
  template: `<BuiDataTableStory v-bind="args" />`
25
26
  })
26
27
  }
28
+
29
+ export const WithScroll: Story = {
30
+ // @ts-expect-error no need to describe all args, see BuiDataTableStory
31
+ args: {},
32
+ render: (args) => ({
33
+ components: { BuiDataTableWithScrollStory },
34
+ setup() {
35
+ return { args }
36
+ },
37
+ template: `<BuiDataTableWithScrollStory v-bind="args" />`
38
+ })
39
+ }
@@ -3,7 +3,6 @@ import { BuiDataTable } from '@/components/table'
3
3
  import RowActionsMenuContent from './ActionsMenuContent.vue'
4
4
  import type {
5
5
  ColumnDef,
6
- PaginationState,
7
6
  Row,
8
7
  RowSelectionState,
9
8
  VisibilityState,
@@ -25,6 +24,7 @@ import { BuiCheckbox } from '@/components/checkbox'
25
24
  import { tableColumnSortCommon } from '@/lib/utils'
26
25
  import { BuiButton } from '@/components/button'
27
26
  import { BuiTabs, BuiTabsList, BuiTabsTrigger } from '@/components/tabs'
27
+ import type { PaginationAutoState } from '@/components/table/BuiDataTable.vue'
28
28
 
29
29
  const taskSchema = z.object({
30
30
  id: z.string(),
@@ -102,7 +102,7 @@ function onGroupAction(group: string | number, action: string) {
102
102
 
103
103
  type TaskSortingState = { id: keyof Task; desc: boolean }
104
104
  const sorting = ref<TaskSortingState[]>([{ id: 'id', desc: false }])
105
- const pagination = ref<PaginationState>({
105
+ const pagination = ref<PaginationAutoState>({
106
106
  pageIndex: 0,
107
107
  pageSize: 10
108
108
  })
@@ -202,7 +202,6 @@ function groupName(group: string | number) {
202
202
  v-model:column-order="columnOrder"
203
203
  @update:selection="updateSelection"
204
204
  :total-items="totalItems"
205
- class="caption-top"
206
205
  :manualPagination="false"
207
206
  :getRowId="(row) => row.id"
208
207
  :groupBy="groupBy === 'none' ? undefined : groupBy"
@@ -212,6 +211,7 @@ function groupName(group: string | number) {
212
211
  :enable-group-folding="true"
213
212
  :pagination-translations="{
214
213
  itemsPerPage: 'Tasks per page',
214
+ itemsPerPageAuto: 'Auto',
215
215
  page: 'Page',
216
216
  of: 'of'
217
217
  }"
@@ -0,0 +1,292 @@
1
+ <script setup lang="ts">
2
+ import { BuiDataTable } from '@/components/table'
3
+ import RowActionsMenuContent from './ActionsMenuContent.vue'
4
+ import type {
5
+ ColumnDef,
6
+ PaginationState,
7
+ Row,
8
+ RowSelectionState,
9
+ VisibilityState,
10
+ ColumnOrderState
11
+ } from '@tanstack/vue-table'
12
+ import { sort, type ISortByObjectSorter } from 'fast-sort'
13
+ import {
14
+ AlignJustifyIcon,
15
+ ArrowUpNarrowWideIcon,
16
+ FolderIcon,
17
+ SignalHighIcon,
18
+ SignalMediumIcon,
19
+ SignalLowIcon
20
+ } from 'lucide-vue-next'
21
+ import { computed, h, ref, withModifiers } from 'vue'
22
+ import { z } from 'zod'
23
+ import tasks from '@/stories/data/tasks.json'
24
+ import { BuiCheckbox } from '@/components/checkbox'
25
+ import { tableColumnSortCommon } from '@/lib/utils'
26
+ import { BuiButton } from '@/components/button'
27
+ import { BuiTabs, BuiTabsList, BuiTabsTrigger } from '@/components/tabs'
28
+
29
+ const taskSchema = z.object({
30
+ id: z.string(),
31
+ title: z.string(),
32
+ status: z.string().nullable().optional(),
33
+ label: z.string(),
34
+ priority: z.string(),
35
+ errorMessage: z.string().optional(),
36
+ age: z.string().optional()
37
+ })
38
+ type Task = z.infer<typeof taskSchema>
39
+
40
+ const columns: ColumnDef<Task>[] = [
41
+ {
42
+ id: 'id',
43
+ accessorKey: 'id',
44
+ header: ({ table, column }) => {
45
+ return h('div', { class: 'flex items-center gap-2' }, [
46
+ h(BuiCheckbox, {
47
+ modelValue: table.getIsSomePageRowsSelected()
48
+ ? 'indeterminate'
49
+ : table.getIsAllPageRowsSelected(),
50
+ 'onUpdate:modelValue': (value: boolean | 'indeterminate') =>
51
+ table.getIsSomePageRowsSelected()
52
+ ? table.toggleAllPageRowsSelected(false)
53
+ : table.toggleAllPageRowsSelected(!!value),
54
+ ariaLabel: 'Select row',
55
+ onClick: withModifiers(() => {}, ['stop'])
56
+ }),
57
+ tableColumnSortCommon(column, 'ID')
58
+ ])
59
+ },
60
+ cell: ({ row }) =>
61
+ h('div', { class: 'flex items-center gap-2' }, [
62
+ h(BuiCheckbox, {
63
+ modelValue: row.getIsSelected(),
64
+ 'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
65
+ ariaLabel: 'Select row'
66
+ }),
67
+ `${row.getValue('id')}`
68
+ ]),
69
+ enableHiding: false,
70
+ meta: { title: 'ID', pinLeft: true }
71
+ },
72
+ {
73
+ accessorKey: 'title',
74
+ header: 'Title',
75
+ enableSorting: false
76
+ },
77
+ {
78
+ accessorKey: 'status',
79
+ header: ({ column }) => tableColumnSortCommon(column, 'Очень длинный заголовок для статуса'),
80
+ meta: { title: 'Статус таска' }
81
+ },
82
+ {
83
+ accessorKey: 'priority',
84
+ header: ({ column }) => tableColumnSortCommon(column, 'Priorities')
85
+ },
86
+ {
87
+ accessorKey: 'age',
88
+ header: ({ column }) => tableColumnSortCommon(column, 'Age')
89
+ },
90
+ { id: 'hiddenColumn', header: 'Hidden Column', cell: 'secret info' }
91
+ ]
92
+ const data = ref<Task[]>(tasks)
93
+
94
+ function onRowAction(row: Task, action: string) {
95
+ const str = `${action}: ${row.id}`
96
+ alert(str)
97
+ }
98
+ function onGroupAction(group: string | number, action: string) {
99
+ const str = `${action}: ${group}`
100
+ alert(str)
101
+ }
102
+
103
+ type TaskSortingState = { id: keyof Task; desc: boolean }
104
+ const sorting = ref<TaskSortingState[]>([{ id: 'id', desc: false }])
105
+ const pagination = ref<PaginationState>({
106
+ pageIndex: 0,
107
+ pageSize: 10
108
+ })
109
+ const totalItems = tasks.length
110
+
111
+ const selection = ref<RowSelectionState | undefined>({})
112
+ function updateSelection(val?: RowSelectionState) {
113
+ console.log('selection was changed', val)
114
+ selection.value = val
115
+ }
116
+
117
+ const columnVisibility = ref<VisibilityState>({ hiddenColumn: false })
118
+ const columnSizing = ref<Record<string, number>>({ title: 450 })
119
+ const columnOrder = ref<ColumnOrderState>()
120
+
121
+ type GroupBy = 'none' | 'status' | 'priority'
122
+ const groupBy = ref<GroupBy>('none')
123
+ const groupLabels = {
124
+ status: ['Status', 'Not in any status'],
125
+ priority: ['Priority', 'Not in any priorities']
126
+ }
127
+
128
+ const sortedData = computed(() => {
129
+ const sortDirection = (sorting.value[0].desc ? 'desc' : 'asc') as 'asc'
130
+ const sortColumn = sorting.value[0].id
131
+ const groupByStr = groupBy.value
132
+
133
+ const sortBy: ISortByObjectSorter<Task> | ISortByObjectSorter<Task>[] = [
134
+ {
135
+ [sortDirection]: sortColumn
136
+ }
137
+ ]
138
+
139
+ // sort by grouping column first, but not when manually sorting by it
140
+ if (groupByStr !== 'none' && sortColumn !== groupByStr) {
141
+ sortBy.unshift({
142
+ asc: groupByStr
143
+ })
144
+ }
145
+
146
+ // sort by ID when possible
147
+ if (sortColumn !== 'id') {
148
+ sortBy.push({
149
+ asc: 'id'
150
+ })
151
+ }
152
+
153
+ return sort(data.value).by([...sortBy])
154
+ })
155
+
156
+ function renderSubComponent(row: Row<Task>) {
157
+ if (row.original.errorMessage) {
158
+ return () => h('span', { style: 'color: red' }, `Subrow: ${row.original.errorMessage}`)
159
+ } else {
160
+ return undefined
161
+ }
162
+ }
163
+
164
+ function deleteRow() {
165
+ data.value = data.value.map((a) => a)
166
+ }
167
+ function updateRows() {
168
+ data.value.shift()
169
+ }
170
+
171
+ function groupName(group: string | number) {
172
+ if (groupBy.value === 'priority') {
173
+ if (group === 'high') {
174
+ return () => h(SignalHighIcon, { class: 'size-4 inline-block' })
175
+ }
176
+
177
+ if (group === 'medium') {
178
+ return () => h(SignalMediumIcon, { class: 'size-4 inline-block' })
179
+ }
180
+
181
+ if (group === 'low') {
182
+ return () => h(SignalLowIcon, { class: 'size-4 inline-block' })
183
+ }
184
+
185
+ return () => group
186
+ }
187
+
188
+ return () => group
189
+ }
190
+ </script>
191
+
192
+ <template>
193
+ <Story title="BuiDataTable" autoPropsDisabled :layout="{ type: 'grid', width: '95%' }">
194
+ <Variant key="variant" title="Sorting, Pagination, Grouping, Subrow">
195
+ <div class="page-wrapper">
196
+ <div class="table-wrapper">
197
+ <BuiDataTable
198
+ :columns="columns"
199
+ :data="sortedData"
200
+ v-model:sorting="sorting"
201
+ v-model:pagination="pagination"
202
+ v-model:column-visibility="columnVisibility"
203
+ v-model:column-sizing="columnSizing"
204
+ v-model:column-order="columnOrder"
205
+ @update:selection="updateSelection"
206
+ :total-items="totalItems"
207
+ class="caption-top"
208
+ :manualPagination="false"
209
+ :getRowId="(row) => row.id"
210
+ :groupBy="groupBy === 'none' ? undefined : groupBy"
211
+ :groupLabels="groupLabels"
212
+ :renderSubComponent="renderSubComponent"
213
+ :freeze-header="true"
214
+ enable-column-list-control
215
+ :enable-group-folding="true"
216
+ :pagination-translations="{
217
+ itemsPerPage: 'Tasks per page',
218
+ itemsPerPageAuto: 'Auto',
219
+ page: 'Page',
220
+ of: 'of'
221
+ }"
222
+ >
223
+ <template #caption="{ table }">
224
+ <div class="flex h-fit items-center justify-between">
225
+ <div class="flex h-full flex-row items-center gap-3">
226
+ <BuiButton variant="outline">Download YAML</BuiButton>
227
+ <BuiButton variant="outline" @click="updateRows"> Delete row </BuiButton>
228
+ <BuiButton variant="outline" @click="deleteRow"> Update rows </BuiButton>
229
+ </div>
230
+
231
+ <div class="flex h-full flex-row items-center gap-3">
232
+ <BuiTabs v-model="groupBy">
233
+ <BuiTabsList class="grid w-full grid-cols-3" variant="default">
234
+ <BuiTabsTrigger value="none" variant="default">
235
+ <AlignJustifyIcon :size="14" />
236
+ </BuiTabsTrigger>
237
+ <BuiTabsTrigger value="status" variant="default">
238
+ <FolderIcon :size="14" />
239
+ </BuiTabsTrigger>
240
+ <BuiTabsTrigger value="priority" variant="default">
241
+ <ArrowUpNarrowWideIcon :size="14" />
242
+ </BuiTabsTrigger>
243
+ </BuiTabsList>
244
+ </BuiTabs>
245
+
246
+ <span>
247
+ {{ table.getFilteredSelectedRowModel().rows?.length }} of
248
+ {{ table.getFilteredRowModel().rows?.length }} row(s) selected
249
+ </span>
250
+ </div>
251
+ </div>
252
+ </template>
253
+ <template #nodata>No data</template>
254
+ <template #groupByRow="{ group }"> Optional slot for: `{{ group }}` </template>
255
+ <template #groupName="{ group }">
256
+ <component :is="groupName(group)"></component>
257
+ </template>
258
+ <template #groupActions="{ group }">
259
+ <RowActionsMenuContent
260
+ :actions="['Group action']"
261
+ @select="(action) => onGroupAction(group, action)"
262
+ />
263
+ </template>
264
+ <template #rowActions="{ row }">
265
+ <RowActionsMenuContent
266
+ :actions="['action 1', 'action 2']"
267
+ @select="(action) => onRowAction(row, action)"
268
+ />
269
+ </template>
270
+ <template #numberOfItems>{{ data.length }} tasks</template>
271
+ </BuiDataTable>
272
+ </div>
273
+ </div>
274
+ </Variant>
275
+ </Story>
276
+ </template>
277
+
278
+ <style scoped>
279
+ .page-wrapper {
280
+ height: 95vh;
281
+ flex-direction: column;
282
+ flex-grow: 1;
283
+ display: flex;
284
+ overflow: hidden auto;
285
+ }
286
+
287
+ .table-wrapper {
288
+ height: 100%;
289
+ flex-direction: column;
290
+ display: flex;
291
+ }
292
+ </style>