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

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 (35) 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 +721 -671
  19. package/dist/index.js +6 -6
  20. package/dist/lib/useResizeColumns.js +24 -22
  21. package/dist/style.css +1 -1
  22. package/package.json +1 -1
  23. package/src/components/pagination/BuiPaginationCommon.vue +16 -4
  24. package/src/components/scroll-area/BuiScrollBar.vue +4 -4
  25. package/src/components/table/BuiDataTable.vue +135 -26
  26. package/src/components/table/BuiTable.vue +1 -0
  27. package/src/components/table/BuiTableRow.vue +6 -0
  28. package/src/components/table/index.ts +2 -0
  29. package/src/lib/useResizeColumns.ts +13 -1
  30. package/src/stories/BuiDataTable.stories.ts +13 -0
  31. package/src/stories/components/BuiDataTableStory.vue +3 -3
  32. package/src/stories/components/BuiDataTableWithScrollStory.vue +292 -0
  33. package/dist/BuiPaginationCommon.vue_vue_type_script_setup_true_lang-DhSRYKth.js +0 -170
  34. package/dist/BuiTable.vue_vue_type_script_setup_true_lang-CQpc0Sr1.js +0 -36
  35. package/dist/BuiTableRow.vue_vue_type_script_setup_true_lang-BJk8Yk1B.js +0 -54
@@ -22,13 +22,13 @@ const delegatedProps = computed(() => {
22
22
  v-bind="delegatedProps"
23
23
  :class="
24
24
  cn(
25
- 'z-2 flex touch-none select-none transition-colors',
26
- orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-px',
27
- orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-px',
25
+ 'z-10 flex touch-none transition-colors select-none',
26
+ props.orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-px',
27
+ props.orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-px',
28
28
  props.class
29
29
  )
30
30
  "
31
31
  >
32
- <ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
32
+ <ScrollAreaThumb class="bg-border relative flex-1 rounded-full" />
33
33
  </ScrollAreaScrollbar>
34
34
  </template>
@@ -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
@@ -277,16 +299,35 @@ const {
277
299
  isMouseUpOnHandler
278
300
  } = useResizeColumns()
279
301
 
302
+ const isColumnSizingEnabled = computed(() => props.enableColumnResizing && columnSizing.value)
303
+
280
304
  onBeforeMount(() => {
281
305
  calculatedColumnSizing.value = columnSizing.value
282
306
  })
283
307
 
284
308
  onMounted(() => {
285
- if (tableElementRef.value && tableHeaderRef.value) {
309
+ if (isColumnSizingEnabled.value && tableElementRef.value && tableHeaderRef.value) {
286
310
  tableElement.value = tableElementRef.value
287
311
  tableHeaderElement.value = tableHeaderRef.value
288
312
 
289
- setInitialColumnWidths()
313
+ //проставляем изначальные значения ширины колонок, только если на маунте таблицу видно
314
+ if (tableElementRef.value.tableRef?.offsetWidth !== 0) {
315
+ setInitialColumnWidths()
316
+ }
317
+
318
+ //дополнительно проставляем значения ширины колонок, когда таблица появляется на экране
319
+ const { stop } = useIntersectionObserver(
320
+ tableElementRef.value.tableRef,
321
+ ([{ isIntersecting }]) => {
322
+ if (isIntersecting) {
323
+ if (!tableElementRef.value?.tableRef?.getAttribute('initialResize')) {
324
+ setInitialColumnWidths()
325
+ }
326
+
327
+ stop()
328
+ }
329
+ }
330
+ )
290
331
  }
291
332
 
292
333
  groupsOpenStateInStorage.value = {}
@@ -417,6 +458,65 @@ watch(isResizing, () => {
417
458
  resetCursor()
418
459
  }
419
460
  })
461
+
462
+ const rows = computed(() => table.getRowModel().rows)
463
+ const rowsLength = computed(() => rows.value.length)
464
+ const sentinel = ref<HTMLElement | null>(null)
465
+ const sentinelVisible = useElementVisibility(sentinel)
466
+ const sentinelKey = computed(() => `sentinel-${rowsLength.value}`)
467
+
468
+ const { stop } = useIntersectionObserver(
469
+ sentinel,
470
+ async ([{ isIntersecting }]) => {
471
+ if (isIntersecting && pageAuto.value) {
472
+ await nextTick()
473
+ loadMore()
474
+ }
475
+
476
+ if (tablePageSize.value >= props.totalItems) {
477
+ stop()
478
+ }
479
+ },
480
+ {
481
+ rootMargin: '0px 0px 50px 0px'
482
+ }
483
+ )
484
+
485
+ let loadingMore = false
486
+ async function loadMore() {
487
+ if (loadingMore) return
488
+ loadingMore = true
489
+
490
+ const newSize = Math.min(tablePageSize.value + 50, props.totalItems)
491
+ table.setPageSize(newSize)
492
+
493
+ await nextTick()
494
+ loadingMore = false
495
+ }
496
+
497
+ watch(pageAuto, (newPageAuto, oldPageAuto) => {
498
+ if (newPageAuto && !oldPageAuto) {
499
+ if (tableElementRef.value && tableElementRef.value.scrollAreaElementRef?.tableWrapperRef) {
500
+ tableElementRef.value.scrollAreaElementRef.tableWrapperRef.scrollTop()
501
+ }
502
+ }
503
+ })
504
+
505
+ const isUpdating = ref(false)
506
+ watch(rowsLength, async () => {
507
+ if (!pageAuto.value || isUpdating.value) return
508
+
509
+ isUpdating.value = true
510
+ await nextTick()
511
+
512
+ //Add a small delay to ensure rendering is complete
513
+ setTimeout(() => {
514
+ if (sentinelVisible.value) {
515
+ loadMore()
516
+ }
517
+ isUpdating.value = false
518
+ }, 50)
519
+ })
420
520
  </script>
421
521
 
422
522
  <template>
@@ -506,7 +606,7 @@ watch(isResizing, () => {
506
606
  />
507
607
  <div
508
608
  v-if="
509
- enableColumnResizing &&
609
+ isColumnSizingEnabled &&
510
610
  index < tableHeaders.length - 1 &&
511
611
  header.column.getCanResize()
512
612
  "
@@ -635,6 +735,14 @@ watch(isResizing, () => {
635
735
  <slot name="nodata">No data</slot>
636
736
  </BuiTableEmpty>
637
737
  </template>
738
+
739
+ <tr
740
+ v-if="pageAuto && tablePageSize < props.totalItems"
741
+ ref="sentinel"
742
+ class="h-4 w-full"
743
+ :data-key="sentinelKey"
744
+ :key="sentinelKey"
745
+ />
638
746
  </BuiTableBody>
639
747
  </BuiTable>
640
748
  <div
@@ -654,6 +762,7 @@ watch(isResizing, () => {
654
762
  :total="computedItems"
655
763
  v-model:pageIndex="pageIndex"
656
764
  v-model:pageSize="tablePageSize"
765
+ v-model:pageAuto="pageAuto"
657
766
  :translations="paginationTranslations"
658
767
  >
659
768
  </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()
@@ -36,7 +36,10 @@ export function useResizeColumns() {
36
36
  headerCells.forEach((cell) => {
37
37
  const cellId = getCellId(cell)
38
38
 
39
- cell.style.width = columnSizing && columnSizing[cellId] ? columnSizing[cellId] + 'px' : ''
39
+ cell.style.width =
40
+ columnSizing && columnSizing[cellId] && columnSizing[cellId] !== 0
41
+ ? columnSizing[cellId] + 'px'
42
+ : ''
40
43
  })
41
44
  }
42
45
  }
@@ -49,6 +52,12 @@ export function useResizeColumns() {
49
52
  tableElement.value?.tableRef
50
53
  ) {
51
54
  const headerCells = [...tableHeaderElement.value.headRef.querySelectorAll('th')]
55
+
56
+ if (calculatedColumnSizing.value && calculatedColumnSizing.value['table'] === 0) {
57
+ calculatedColumnSizing.value = {}
58
+ tableElement.value.tableRef.style.width = ''
59
+ }
60
+
52
61
  const tableInitialWidth = getTableWidth()
53
62
 
54
63
  tableElement.value.tableRef.style.width = 'min-content'
@@ -316,11 +325,14 @@ export function useResizeColumns() {
316
325
  } else {
317
326
  initialTableWidth.value = tableOffsetWidth
318
327
  tableElement.value.tableRef.style.width = tableOffsetWidth + 'px'
328
+
329
+ tableElement.value.tableRef.setAttribute('initialResize', 'set')
319
330
  updatedColumnSizingValue['table'] = tableOffsetWidth
320
331
  }
321
332
  }
322
333
 
323
334
  minTableWidth.value = getTableWrapperWidth()
335
+
324
336
  calculatedColumnSizing.value = updatedColumnSizingValue
325
337
  }
326
338
  }
@@ -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
  }"