@dataloop-ai/components 0.19.147 → 0.19.148
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.
- package/package.json +1 -1
- package/src/components/basic/DlGrid/DlGrid.vue +39 -30
- package/src/components/compound/DlTable/DlTable.vue +122 -50
- package/src/components/compound/DlTable/styles/dl-table-styles.scss +7 -0
- package/src/components/compound/DlTable/utils/emits.ts +2 -0
- package/src/components/shared/DlInfiniteScroll/DlInfiniteScroll.vue +188 -0
- package/src/components/shared/DlInfiniteScroll/components/DlBottomScroll.vue +58 -0
- package/src/components/shared/DlInfiniteScroll/components/DlTopScroll.vue +58 -0
- package/src/components/shared/DlInfiniteScroll/components/index.ts +4 -0
- package/src/components/shared/DlInfiniteScroll/index.ts +4 -0
- package/src/components/shared/DlInfiniteScroll/utils/createIntersectionObserver.ts +14 -0
- package/src/components/shared/DlInfiniteScroll/utils/index.ts +1 -0
- package/src/components/shared/index.ts +1 -0
- package/src/demos/DlGridDemo.vue +4 -1
- package/src/demos/DlInfiniteScrollDemo.vue +236 -0
- package/src/demos/DlTableDemo.vue +7 -147
- package/src/demos/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="
|
|
3
|
-
<dl-
|
|
4
|
-
v-slot="{ item }"
|
|
5
|
-
:scroll-debounce="scrollDebounce"
|
|
6
|
-
style="height: var(--dl-virtual-scroll-height, 500px)"
|
|
2
|
+
<div v-if="infiniteScroll">
|
|
3
|
+
<dl-infinite-scroll
|
|
7
4
|
:items="items"
|
|
8
|
-
:
|
|
5
|
+
:page-size="infiniteScrollPageSize"
|
|
6
|
+
:style="$attrs.style"
|
|
7
|
+
:class="$attrs.class"
|
|
8
|
+
style="height: var(--dl-virtual-scroll-height, 500px)"
|
|
9
|
+
@scroll-to-top="$emit('scroll-to-top')"
|
|
10
|
+
@scroll-to-bottom="$emit('scroll-to-bottom')"
|
|
9
11
|
>
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
<template #content="{ items }">
|
|
13
|
+
<div
|
|
14
|
+
ref="grid"
|
|
15
|
+
:style="gridStyles"
|
|
16
|
+
:class="gridClass"
|
|
17
|
+
>
|
|
18
|
+
<div
|
|
19
|
+
v-for="item in items"
|
|
20
|
+
:key="item.id"
|
|
21
|
+
class="item-wrapper"
|
|
22
|
+
>
|
|
23
|
+
<slot
|
|
24
|
+
name="item-slot"
|
|
25
|
+
v-bind="{ item }"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
</dl-infinite-scroll>
|
|
15
31
|
</div>
|
|
16
32
|
<div
|
|
17
33
|
v-else-if="!hasItems"
|
|
@@ -57,11 +73,11 @@ import { getGridTemplate, swapElementsInMatrix } from './utils'
|
|
|
57
73
|
import { isCustomEvent } from '../utils'
|
|
58
74
|
import { getElementAbove } from '../../../utils'
|
|
59
75
|
import { DlGridMode, GridItem } from './types'
|
|
60
|
-
import {
|
|
76
|
+
import { DlInfiniteScroll } from '../../shared'
|
|
61
77
|
|
|
62
78
|
export default defineComponent({
|
|
63
79
|
components: {
|
|
64
|
-
|
|
80
|
+
DlInfiniteScroll
|
|
65
81
|
},
|
|
66
82
|
model: {
|
|
67
83
|
prop: 'modelValue',
|
|
@@ -92,20 +108,21 @@ export default defineComponent({
|
|
|
92
108
|
type: String as PropType<DlGridMode>,
|
|
93
109
|
default: DlGridMode.LAYOUT
|
|
94
110
|
},
|
|
95
|
-
|
|
96
|
-
type: Number,
|
|
97
|
-
default: 100
|
|
98
|
-
},
|
|
99
|
-
virtualScroll: {
|
|
111
|
+
infiniteScroll: {
|
|
100
112
|
type: Boolean,
|
|
101
113
|
default: false
|
|
102
114
|
},
|
|
103
|
-
|
|
115
|
+
infiniteScrollPageSize: {
|
|
104
116
|
type: Number,
|
|
105
|
-
default:
|
|
117
|
+
default: 15
|
|
106
118
|
}
|
|
107
119
|
},
|
|
108
|
-
emits: [
|
|
120
|
+
emits: [
|
|
121
|
+
'update:model-value',
|
|
122
|
+
'layout-changed',
|
|
123
|
+
'scroll-to-top',
|
|
124
|
+
'scroll-to-bottom'
|
|
125
|
+
],
|
|
109
126
|
setup(props, { emit }) {
|
|
110
127
|
const vm = getCurrentInstance()
|
|
111
128
|
const grid = ref<HTMLElement | null>(null)
|
|
@@ -115,8 +132,7 @@ export default defineComponent({
|
|
|
115
132
|
rowGap,
|
|
116
133
|
columnGap,
|
|
117
134
|
maxElementsPerRow,
|
|
118
|
-
items
|
|
119
|
-
virtualScroll
|
|
135
|
+
items
|
|
120
136
|
} = toRefs(props)
|
|
121
137
|
|
|
122
138
|
const isLayoutMode = computed(() => mode.value == DlGridMode.LAYOUT)
|
|
@@ -129,12 +145,6 @@ export default defineComponent({
|
|
|
129
145
|
: 'dl-grid-wrapper__flex'
|
|
130
146
|
)
|
|
131
147
|
|
|
132
|
-
const hasVirtualScroll = computed(
|
|
133
|
-
() =>
|
|
134
|
-
items.value?.length > props.virtualScrollThreshold ||
|
|
135
|
-
virtualScroll.value
|
|
136
|
-
)
|
|
137
|
-
|
|
138
148
|
const gridStyles = computed(() => {
|
|
139
149
|
const gridStyles: Dictionary<string | number> = {
|
|
140
150
|
'--row-gap': rowGap.value,
|
|
@@ -258,7 +268,6 @@ export default defineComponent({
|
|
|
258
268
|
gridClass,
|
|
259
269
|
gridStyles,
|
|
260
270
|
grid,
|
|
261
|
-
hasVirtualScroll,
|
|
262
271
|
hasItems
|
|
263
272
|
}
|
|
264
273
|
}
|
|
@@ -61,16 +61,16 @@
|
|
|
61
61
|
v-bind="virtProps"
|
|
62
62
|
ref="virtScrollRef"
|
|
63
63
|
type="__dltable"
|
|
64
|
-
:class="
|
|
64
|
+
:class="virtualScrollClasses"
|
|
65
65
|
:style="tableStyle"
|
|
66
|
-
:table-colspan="
|
|
66
|
+
:table-colspan="colspanWithExpandableRow"
|
|
67
67
|
:scroll-target="virtualScrollTarget"
|
|
68
68
|
:items="computedRows"
|
|
69
69
|
:scroll-debounce="scrollDebounce"
|
|
70
70
|
@virtual-scroll="onVScroll"
|
|
71
71
|
>
|
|
72
72
|
<template #before>
|
|
73
|
-
<thead :colspan="
|
|
73
|
+
<thead :colspan="colspanWithExpandableRow">
|
|
74
74
|
<slot
|
|
75
75
|
v-if="!hideHeader"
|
|
76
76
|
name="header"
|
|
@@ -235,22 +235,21 @@
|
|
|
235
235
|
</slot>
|
|
236
236
|
</DlTh>
|
|
237
237
|
</DlTr>
|
|
238
|
-
|
|
239
|
-
<tr
|
|
240
|
-
v-if="loading && !hasLoadingSlot"
|
|
241
|
-
class="dl-table__progress"
|
|
242
|
-
>
|
|
243
|
-
<th
|
|
244
|
-
:colspan="colspanWithActionsRow"
|
|
245
|
-
class="relative-position"
|
|
246
|
-
>
|
|
247
|
-
<dl-progress-bar
|
|
248
|
-
indeterminate
|
|
249
|
-
:color="color"
|
|
250
|
-
/>
|
|
251
|
-
</th>
|
|
252
|
-
</tr>
|
|
253
238
|
</slot>
|
|
239
|
+
<tr
|
|
240
|
+
v-if="loading && !hasLoadingSlot"
|
|
241
|
+
class="dl-table__progress"
|
|
242
|
+
>
|
|
243
|
+
<th
|
|
244
|
+
:colspan="colspanWithExpandableRow"
|
|
245
|
+
class="relative-position"
|
|
246
|
+
>
|
|
247
|
+
<dl-progress-bar
|
|
248
|
+
indeterminate
|
|
249
|
+
:color="color"
|
|
250
|
+
/>
|
|
251
|
+
</th>
|
|
252
|
+
</tr>
|
|
254
253
|
</thead>
|
|
255
254
|
</template>
|
|
256
255
|
<template #default="props">
|
|
@@ -415,8 +414,7 @@
|
|
|
415
414
|
v-if="isRowExpanded(props.item)"
|
|
416
415
|
:key="getRowExpandedKey(props.item)"
|
|
417
416
|
>
|
|
418
|
-
|
|
419
|
-
<td :colspan="columns.length + 1 + 1">
|
|
417
|
+
<td :colspan="colspanWithExpandableRow">
|
|
420
418
|
<slot
|
|
421
419
|
v-bind="{ row: props.item }"
|
|
422
420
|
name="body-cell-expandable-content"
|
|
@@ -455,6 +453,7 @@
|
|
|
455
453
|
|
|
456
454
|
<div
|
|
457
455
|
v-else
|
|
456
|
+
ref="tableScroll"
|
|
458
457
|
class="dl-table__middle scroll"
|
|
459
458
|
>
|
|
460
459
|
<table
|
|
@@ -462,7 +461,7 @@
|
|
|
462
461
|
class="dl-table"
|
|
463
462
|
:class="additionalClasses"
|
|
464
463
|
>
|
|
465
|
-
<thead :colspan="
|
|
464
|
+
<thead :colspan="colspanWithExpandableRow">
|
|
466
465
|
<slot
|
|
467
466
|
v-if="!hideHeader"
|
|
468
467
|
name="header"
|
|
@@ -628,22 +627,21 @@
|
|
|
628
627
|
</slot>
|
|
629
628
|
</DlTh>
|
|
630
629
|
</DlTr>
|
|
631
|
-
|
|
632
|
-
<tr
|
|
633
|
-
v-if="loading && !hasLoadingSlot"
|
|
634
|
-
class="dl-table__progress"
|
|
635
|
-
>
|
|
636
|
-
<th
|
|
637
|
-
:colspan="colspanWithActionsRow"
|
|
638
|
-
class="relative-position"
|
|
639
|
-
>
|
|
640
|
-
<dl-progress-bar
|
|
641
|
-
indeterminate
|
|
642
|
-
:color="color"
|
|
643
|
-
/>
|
|
644
|
-
</th>
|
|
645
|
-
</tr>
|
|
646
630
|
</slot>
|
|
631
|
+
<tr
|
|
632
|
+
v-if="loading && !hasLoadingSlot"
|
|
633
|
+
class="dl-table__progress"
|
|
634
|
+
>
|
|
635
|
+
<th
|
|
636
|
+
:colspan="colspanWithExpandableRow"
|
|
637
|
+
class="relative-position"
|
|
638
|
+
>
|
|
639
|
+
<dl-progress-bar
|
|
640
|
+
indeterminate
|
|
641
|
+
:color="color"
|
|
642
|
+
/>
|
|
643
|
+
</th>
|
|
644
|
+
</tr>
|
|
647
645
|
</thead>
|
|
648
646
|
<slot
|
|
649
647
|
name="tbody"
|
|
@@ -661,13 +659,7 @@
|
|
|
661
659
|
onEnd: handleSortableEvent
|
|
662
660
|
}"
|
|
663
661
|
:is-sortable="hasDraggableRows"
|
|
664
|
-
:options="
|
|
665
|
-
group: 'nested',
|
|
666
|
-
animation: 150,
|
|
667
|
-
fallbackOnBody: true,
|
|
668
|
-
invertSwap: true,
|
|
669
|
-
swapThreshold: 0.5
|
|
670
|
-
}"
|
|
662
|
+
:options="sortableOptions"
|
|
671
663
|
>
|
|
672
664
|
<slot
|
|
673
665
|
name="top-row"
|
|
@@ -677,6 +669,17 @@
|
|
|
677
669
|
name="table-body"
|
|
678
670
|
:computed-rows="computedRows"
|
|
679
671
|
>
|
|
672
|
+
<dl-top-scroll
|
|
673
|
+
v-if="tableScroll && infiniteScroll"
|
|
674
|
+
:container-ref="tableScroll"
|
|
675
|
+
@scroll-to-top="
|
|
676
|
+
$emit(
|
|
677
|
+
'scroll-to-top',
|
|
678
|
+
computedPagination.rowsPerPage,
|
|
679
|
+
tableScroll
|
|
680
|
+
)
|
|
681
|
+
"
|
|
682
|
+
/>
|
|
680
683
|
<slot
|
|
681
684
|
v-for="(row, pageIndex) in computedRows"
|
|
682
685
|
v-bind="
|
|
@@ -819,7 +822,7 @@
|
|
|
819
822
|
v-if="isRowExpanded(row)"
|
|
820
823
|
:key="getRowExpandedKey(row)"
|
|
821
824
|
>
|
|
822
|
-
<td :colspan="
|
|
825
|
+
<td :colspan="colspanWithExpandableRow">
|
|
823
826
|
<slot
|
|
824
827
|
v-bind="{ row }"
|
|
825
828
|
name="body-cell-expandable-content"
|
|
@@ -831,6 +834,17 @@
|
|
|
831
834
|
</td>
|
|
832
835
|
</tr>
|
|
833
836
|
</slot>
|
|
837
|
+
<dl-bottom-scroll
|
|
838
|
+
v-if="tableScroll && infiniteScroll"
|
|
839
|
+
:container-ref="tableScroll"
|
|
840
|
+
@scroll-to-bottom="
|
|
841
|
+
$emit(
|
|
842
|
+
'scroll-to-bottom',
|
|
843
|
+
computedPagination.rowsPerPage,
|
|
844
|
+
tableScroll
|
|
845
|
+
)
|
|
846
|
+
"
|
|
847
|
+
/>
|
|
834
848
|
</slot>
|
|
835
849
|
|
|
836
850
|
<slot
|
|
@@ -992,6 +1006,7 @@ import { insertAtIndex } from './utils/insertAtIndex'
|
|
|
992
1006
|
import { getCellValue } from './utils/getCellValue'
|
|
993
1007
|
import { getContainerClass } from './utils/tableClasses'
|
|
994
1008
|
import { isEqual } from 'lodash'
|
|
1009
|
+
import { DlTopScroll, DlBottomScroll } from '../../shared/DlInfiniteScroll'
|
|
995
1010
|
|
|
996
1011
|
const commonVirtPropsObj = {} as Record<string, any>
|
|
997
1012
|
commonVirtPropsList.forEach((p) => {
|
|
@@ -1015,7 +1030,9 @@ export default defineComponent({
|
|
|
1015
1030
|
DlPopup,
|
|
1016
1031
|
DlList,
|
|
1017
1032
|
Sortable,
|
|
1018
|
-
DlEllipsis
|
|
1033
|
+
DlEllipsis,
|
|
1034
|
+
DlTopScroll,
|
|
1035
|
+
DlBottomScroll
|
|
1019
1036
|
},
|
|
1020
1037
|
props: {
|
|
1021
1038
|
/**
|
|
@@ -1118,6 +1135,13 @@ export default defineComponent({
|
|
|
1118
1135
|
type: Boolean,
|
|
1119
1136
|
default: false
|
|
1120
1137
|
},
|
|
1138
|
+
/**
|
|
1139
|
+
* Enable infinite scroll
|
|
1140
|
+
*/
|
|
1141
|
+
infiniteScroll: {
|
|
1142
|
+
type: Boolean,
|
|
1143
|
+
default: false
|
|
1144
|
+
},
|
|
1121
1145
|
/**
|
|
1122
1146
|
* Hide table pagination
|
|
1123
1147
|
*/
|
|
@@ -1246,7 +1270,7 @@ export default defineComponent({
|
|
|
1246
1270
|
default: 'No data'
|
|
1247
1271
|
},
|
|
1248
1272
|
stickyColumns: {
|
|
1249
|
-
type:
|
|
1273
|
+
type: String as PropType<TableStickyPosition>,
|
|
1250
1274
|
default: null,
|
|
1251
1275
|
validator: (value: string) =>
|
|
1252
1276
|
['first', 'last', 'both'].includes(value)
|
|
@@ -1300,8 +1324,13 @@ export default defineComponent({
|
|
|
1300
1324
|
const rootRef = ref<HTMLDivElement>(null)
|
|
1301
1325
|
const tableRef = ref<HTMLTableElement>(null)
|
|
1302
1326
|
const virtScrollRef = ref(null)
|
|
1327
|
+
const tableScroll = ref(null)
|
|
1328
|
+
|
|
1329
|
+
const hasExpandableSlot = computed(() =>
|
|
1330
|
+
hasSlotByName('body-cell-expandable-content')
|
|
1331
|
+
)
|
|
1303
1332
|
const hasVirtScroll = computed<boolean>(
|
|
1304
|
-
() => virtualScroll.value
|
|
1333
|
+
() => virtualScroll.value && !hasExpandableSlot.value
|
|
1305
1334
|
)
|
|
1306
1335
|
|
|
1307
1336
|
const hasEmptyStateProps = computed(() =>
|
|
@@ -1604,6 +1633,7 @@ export default defineComponent({
|
|
|
1604
1633
|
)
|
|
1605
1634
|
|
|
1606
1635
|
const computedRows = computed(() => {
|
|
1636
|
+
if (props.infiniteScroll) return filteredSortedRows.value
|
|
1607
1637
|
let filtered = filteredSortedRows.value
|
|
1608
1638
|
|
|
1609
1639
|
const { rowsPerPage } = computedPagination.value
|
|
@@ -1628,7 +1658,7 @@ export default defineComponent({
|
|
|
1628
1658
|
return filtered
|
|
1629
1659
|
})
|
|
1630
1660
|
|
|
1631
|
-
const additionalClasses = computed(() => {
|
|
1661
|
+
const additionalClasses = computed<string[]>(() => {
|
|
1632
1662
|
const classes: string[] = []
|
|
1633
1663
|
|
|
1634
1664
|
if (hasDraggableRows.value === true) {
|
|
@@ -1643,7 +1673,9 @@ export default defineComponent({
|
|
|
1643
1673
|
})
|
|
1644
1674
|
|
|
1645
1675
|
const displayPagination = computed(
|
|
1646
|
-
() =>
|
|
1676
|
+
() =>
|
|
1677
|
+
!props.infiniteScroll &&
|
|
1678
|
+
!(hidePagination.value || nothingToDisplay.value)
|
|
1647
1679
|
)
|
|
1648
1680
|
|
|
1649
1681
|
const {
|
|
@@ -1675,6 +1707,12 @@ export default defineComponent({
|
|
|
1675
1707
|
return computedColspan.value + (showRowActions.value ? 1 : 0)
|
|
1676
1708
|
})
|
|
1677
1709
|
|
|
1710
|
+
const colspanWithExpandableRow = computed(() => {
|
|
1711
|
+
return (
|
|
1712
|
+
colspanWithActionsRow.value + (hasExpandableSlot.value ? 1 : 0)
|
|
1713
|
+
)
|
|
1714
|
+
})
|
|
1715
|
+
|
|
1678
1716
|
const { columnToSort, computedSortMethod, sort } = useTableSort(
|
|
1679
1717
|
props as unknown as DlTableProps,
|
|
1680
1718
|
computedPagination,
|
|
@@ -1988,6 +2026,35 @@ export default defineComponent({
|
|
|
1988
2026
|
return slots.length ? slots.map((slot: any) => slot.name) : null
|
|
1989
2027
|
})
|
|
1990
2028
|
|
|
2029
|
+
const sortableOptions: any = {
|
|
2030
|
+
group: 'nested',
|
|
2031
|
+
animation: 150,
|
|
2032
|
+
fallbackOnBody: true,
|
|
2033
|
+
invertSwap: true,
|
|
2034
|
+
swapThreshold: 0.5
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
const virtualScrollClasses = computed(() => {
|
|
2038
|
+
let classes: string[] = []
|
|
2039
|
+
|
|
2040
|
+
if (tableClass.value) {
|
|
2041
|
+
if (Array.isArray(tableClass.value)) {
|
|
2042
|
+
classes = (tableClass.value as string[]) ?? []
|
|
2043
|
+
} else if (typeof tableClass.value === 'string') {
|
|
2044
|
+
classes = (tableClass.value as string)?.split(' ')
|
|
2045
|
+
} else if (typeof tableClass.value === 'object') {
|
|
2046
|
+
classes = Object.keys(
|
|
2047
|
+
tableClass.value as Record<string, any>
|
|
2048
|
+
).filter(
|
|
2049
|
+
(key: string) =>
|
|
2050
|
+
!!(tableClass.value as Record<string, any>)[key]
|
|
2051
|
+
)
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
return classes.concat(additionalClasses.value)
|
|
2056
|
+
})
|
|
2057
|
+
|
|
1991
2058
|
const updatePagination = (value: any, key: string) => {
|
|
1992
2059
|
return setPagination({ [`${key}`]: value })
|
|
1993
2060
|
}
|
|
@@ -2027,6 +2094,9 @@ export default defineComponent({
|
|
|
2027
2094
|
computedCols,
|
|
2028
2095
|
computedColspan,
|
|
2029
2096
|
colspanWithActionsRow,
|
|
2097
|
+
colspanWithExpandableRow,
|
|
2098
|
+
virtualScrollClasses,
|
|
2099
|
+
sortableOptions,
|
|
2030
2100
|
getRowKey,
|
|
2031
2101
|
additionalClasses,
|
|
2032
2102
|
getHeaderScope,
|
|
@@ -2085,7 +2155,9 @@ export default defineComponent({
|
|
|
2085
2155
|
tableRef,
|
|
2086
2156
|
getRowExpandedIcon,
|
|
2087
2157
|
computedPagination,
|
|
2088
|
-
getRowExpandedKey
|
|
2158
|
+
getRowExpandedKey,
|
|
2159
|
+
hasExpandableSlot,
|
|
2160
|
+
tableScroll
|
|
2089
2161
|
}
|
|
2090
2162
|
}
|
|
2091
2163
|
})
|
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
border-right: 1px solid var(--dl-color-separator);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
thead {
|
|
12
|
+
position: sticky;
|
|
13
|
+
top: 0;
|
|
14
|
+
background-color: var(--dl-color-panel-background);
|
|
15
|
+
z-index: 50;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
.sticky-col {
|
|
12
19
|
position: sticky;
|
|
13
20
|
background-color: var(--dl-color-panel-background);
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="containerRef"
|
|
4
|
+
class="dl-infinite-scroll"
|
|
5
|
+
:style="computedStyles"
|
|
6
|
+
:class="computedClasses"
|
|
7
|
+
>
|
|
8
|
+
<DlTopScroll
|
|
9
|
+
:container-ref="containerRef"
|
|
10
|
+
@scroll-to-top="onScrollToTop"
|
|
11
|
+
/>
|
|
12
|
+
<slot
|
|
13
|
+
name="content"
|
|
14
|
+
:items="displayItems"
|
|
15
|
+
>
|
|
16
|
+
<div
|
|
17
|
+
v-for="item in displayItems"
|
|
18
|
+
:key="itemKey(item)"
|
|
19
|
+
>
|
|
20
|
+
<slot :item="item" />
|
|
21
|
+
</div>
|
|
22
|
+
</slot>
|
|
23
|
+
<DlBottomScroll
|
|
24
|
+
:container-ref="containerRef"
|
|
25
|
+
@scroll-to-bottom="onScrollToBottom"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
<script lang="ts">
|
|
30
|
+
import { cloneDeep } from 'lodash'
|
|
31
|
+
import {
|
|
32
|
+
computed,
|
|
33
|
+
defineComponent,
|
|
34
|
+
nextTick,
|
|
35
|
+
PropType,
|
|
36
|
+
ref,
|
|
37
|
+
toRefs,
|
|
38
|
+
watch
|
|
39
|
+
} from 'vue-demi'
|
|
40
|
+
import { DlTopScroll, DlBottomScroll } from './components'
|
|
41
|
+
|
|
42
|
+
const MAX_SLICE_SIZE = 100
|
|
43
|
+
const DEFAULT_SLICE_SIZE = 15
|
|
44
|
+
const MIN_SLICE_SIZE = 0
|
|
45
|
+
|
|
46
|
+
export default defineComponent({
|
|
47
|
+
name: 'DlInfiniteScroll',
|
|
48
|
+
components: { DlTopScroll, DlBottomScroll },
|
|
49
|
+
props: {
|
|
50
|
+
items: {
|
|
51
|
+
type: Array as PropType<Record<string, any>[]>,
|
|
52
|
+
default: () => [] as Record<string, any>[]
|
|
53
|
+
},
|
|
54
|
+
pageSize: {
|
|
55
|
+
type: Number,
|
|
56
|
+
default: DEFAULT_SLICE_SIZE,
|
|
57
|
+
validator: (val: number) =>
|
|
58
|
+
val <= MAX_SLICE_SIZE && val >= MIN_SLICE_SIZE
|
|
59
|
+
},
|
|
60
|
+
scrollDebounce: {
|
|
61
|
+
type: Number,
|
|
62
|
+
default: 100
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
emits: ['scroll-to-top', 'scroll-to-bottom'],
|
|
66
|
+
setup(props, { emit, attrs }) {
|
|
67
|
+
const { items, pageSize, scrollDebounce } = toRefs(props)
|
|
68
|
+
const containerRef = ref(null)
|
|
69
|
+
const currentPage = ref(0)
|
|
70
|
+
const pagesCount = ref(0)
|
|
71
|
+
const itemPages = ref(new Map<number, Record<string, any>[]>())
|
|
72
|
+
const lastOp = ref<string>('')
|
|
73
|
+
|
|
74
|
+
const computedStyles = computed<any>(() => {
|
|
75
|
+
return attrs.style
|
|
76
|
+
})
|
|
77
|
+
const computedClasses = computed<any>(() => {
|
|
78
|
+
return attrs.class
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const displayItems = computed(() => {
|
|
82
|
+
const page = currentPage.value
|
|
83
|
+
const items = cloneDeep(itemPages.value.get(page))
|
|
84
|
+
|
|
85
|
+
const prevPage = cloneDeep(itemPages.value.get(page - 1))
|
|
86
|
+
const nextPage = cloneDeep(itemPages.value.get(page + 1))
|
|
87
|
+
|
|
88
|
+
const toDisplay = items ?? []
|
|
89
|
+
|
|
90
|
+
if (prevPage?.length && nextPage?.length) {
|
|
91
|
+
toDisplay.unshift(...prevPage.slice(-pageSize.value))
|
|
92
|
+
toDisplay.push(...nextPage.slice(0, pageSize.value))
|
|
93
|
+
} else if (prevPage?.length) {
|
|
94
|
+
toDisplay.unshift(...prevPage.slice(-pageSize.value))
|
|
95
|
+
} else if (nextPage?.length) {
|
|
96
|
+
toDisplay.push(...nextPage.slice(0, pageSize.value))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
nextTick(() => {
|
|
100
|
+
if (lastOp.value === 'top' && page !== 0) {
|
|
101
|
+
containerRef.value.scrollTop +=
|
|
102
|
+
containerRef.value.scrollHeight * 0.333
|
|
103
|
+
} else if (
|
|
104
|
+
lastOp.value === 'bottom' &&
|
|
105
|
+
page !== pagesCount.value
|
|
106
|
+
) {
|
|
107
|
+
if (currentPage.value - 1 === 0) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
containerRef.value.scrollTop -=
|
|
112
|
+
containerRef.value.scrollHeight * 0.333
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return toDisplay
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const itemKey = (item: any) => {
|
|
120
|
+
return item.id ?? item.key ?? JSON.stringify(item)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const onScrollToTop = () => {
|
|
124
|
+
lastOp.value = 'top'
|
|
125
|
+
if (currentPage.value <= 0) {
|
|
126
|
+
emit('scroll-to-top')
|
|
127
|
+
} else {
|
|
128
|
+
currentPage.value--
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const onScrollToBottom = () => {
|
|
132
|
+
lastOp.value = 'bottom'
|
|
133
|
+
if (currentPage.value >= pagesCount.value - 1) {
|
|
134
|
+
emit('scroll-to-bottom')
|
|
135
|
+
} else {
|
|
136
|
+
currentPage.value++
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const splitArrayIntoPages = (
|
|
141
|
+
arr: Record<string, any>[],
|
|
142
|
+
pageSize: number
|
|
143
|
+
): Map<number, any[]> => {
|
|
144
|
+
pagesCount.value = Math.ceil(arr.length / pageSize)
|
|
145
|
+
const pages = new Map<number, any[]>()
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < pagesCount.value; i++) {
|
|
148
|
+
const start = i * pageSize
|
|
149
|
+
const end = start + pageSize
|
|
150
|
+
pages.set(i, arr.slice(start, end))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return pages
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
watch(
|
|
157
|
+
[items, pageSize],
|
|
158
|
+
() => {
|
|
159
|
+
itemPages.value = splitArrayIntoPages(
|
|
160
|
+
items.value,
|
|
161
|
+
pageSize.value
|
|
162
|
+
)
|
|
163
|
+
},
|
|
164
|
+
{ immediate: true }
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
containerRef,
|
|
169
|
+
onScrollToTop,
|
|
170
|
+
onScrollToBottom,
|
|
171
|
+
displayItems,
|
|
172
|
+
itemKey,
|
|
173
|
+
computedStyles,
|
|
174
|
+
computedClasses
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
</script>
|
|
179
|
+
<style scoped lang="scss">
|
|
180
|
+
.dl-infinite-scroll {
|
|
181
|
+
overflow-y: auto;
|
|
182
|
+
height: 100%;
|
|
183
|
+
width: 100%;
|
|
184
|
+
position: relative;
|
|
185
|
+
// To not allow any weird scroll jumping behavior
|
|
186
|
+
scroll-behavior: auto !important;
|
|
187
|
+
}
|
|
188
|
+
</style>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="bottomRow"
|
|
4
|
+
class="infinite-scroll-bottom"
|
|
5
|
+
/>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { defineComponent, PropType, ref, toRefs, watch } from 'vue-demi'
|
|
10
|
+
import { createIntersectionObserver } from '../utils'
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
props: {
|
|
14
|
+
containerRef: {
|
|
15
|
+
// todo: fix typing here
|
|
16
|
+
type: null as any as PropType<HTMLElement>,
|
|
17
|
+
default: null
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
emits: ['scroll-to-bottom'],
|
|
21
|
+
setup(props, { emit }) {
|
|
22
|
+
const { containerRef } = toRefs(props)
|
|
23
|
+
const bottomRow = ref(null)
|
|
24
|
+
const observer = ref(null)
|
|
25
|
+
|
|
26
|
+
const initObserver = () => {
|
|
27
|
+
if (!bottomRow.value) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
observer.value?.disconnect()
|
|
32
|
+
observer.value = null
|
|
33
|
+
|
|
34
|
+
observer.value = createIntersectionObserver(
|
|
35
|
+
containerRef.value,
|
|
36
|
+
() => {
|
|
37
|
+
emit('scroll-to-bottom')
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
observer.value.observe(bottomRow.value as HTMLElement)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
watch([containerRef, bottomRow], initObserver, { immediate: true })
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
bottomRow
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style scoped lang="scss">
|
|
53
|
+
.infinite-scroll-bottom {
|
|
54
|
+
content: '';
|
|
55
|
+
height: 3px;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
58
|
+
createIntersectionObservercreateIntersectionObserver./utils/create-observer./utils/createIntersectionObserver
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="topRow"
|
|
4
|
+
class="infinite-scroll-top"
|
|
5
|
+
/>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { defineComponent, PropType, ref, toRefs, watch } from 'vue-demi'
|
|
10
|
+
import { createIntersectionObserver } from '../utils'
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
props: {
|
|
14
|
+
containerRef: {
|
|
15
|
+
// todo: fix typing here
|
|
16
|
+
type: null as any as PropType<HTMLElement>,
|
|
17
|
+
default: null
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
emits: ['scroll-to-top'],
|
|
21
|
+
setup(props, { emit }) {
|
|
22
|
+
const { containerRef } = toRefs(props)
|
|
23
|
+
const topRow = ref(null)
|
|
24
|
+
const observer = ref(null)
|
|
25
|
+
|
|
26
|
+
const initObserver = () => {
|
|
27
|
+
if (!topRow.value) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
observer.value?.disconnect()
|
|
32
|
+
observer.value = null
|
|
33
|
+
|
|
34
|
+
observer.value = createIntersectionObserver(
|
|
35
|
+
containerRef.value,
|
|
36
|
+
() => {
|
|
37
|
+
emit('scroll-to-top')
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
observer.value.observe(topRow.value as HTMLElement)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
watch([containerRef, topRow], initObserver, { immediate: true })
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
topRow
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style scoped lang="scss">
|
|
53
|
+
.infinite-scroll-top {
|
|
54
|
+
content: '';
|
|
55
|
+
height: 3px;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
58
|
+
createIntersectionObservercreateIntersectionObserver./utils/create-observer./utils/createIntersectionObserver
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const createIntersectionObserver = (ref: any, emit: Function) => {
|
|
2
|
+
const root = ref?.$el || ref
|
|
3
|
+
let wasIntersecting = true
|
|
4
|
+
return new IntersectionObserver(
|
|
5
|
+
([entry]) => {
|
|
6
|
+
const isCurrentlyIntersecting = entry.isIntersecting
|
|
7
|
+
if (!wasIntersecting && isCurrentlyIntersecting) {
|
|
8
|
+
emit()
|
|
9
|
+
}
|
|
10
|
+
wasIntersecting = isCurrentlyIntersecting
|
|
11
|
+
},
|
|
12
|
+
{ root, threshold: 0.5 }
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './createIntersectionObserver'
|
package/src/demos/DlGridDemo.vue
CHANGED
|
@@ -204,7 +204,10 @@
|
|
|
204
204
|
</dl-grid>
|
|
205
205
|
</div>
|
|
206
206
|
<div v-if="activeContentType.value === 'prop'">
|
|
207
|
-
<dl-grid
|
|
207
|
+
<dl-grid
|
|
208
|
+
:items="images"
|
|
209
|
+
infinite-scroll
|
|
210
|
+
>
|
|
208
211
|
<template #item-slot="{ item }">
|
|
209
212
|
<img :src="item.src">
|
|
210
213
|
</template>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div>
|
|
4
|
+
<span> full implementation using the component </span>
|
|
5
|
+
<DlInfiniteScroll
|
|
6
|
+
:items="rows"
|
|
7
|
+
:page-size="50"
|
|
8
|
+
style="height: 500px; width: 600px"
|
|
9
|
+
@scroll-to-bottom="pushRows"
|
|
10
|
+
>
|
|
11
|
+
<template #default="{ item }">
|
|
12
|
+
{{ item.name }}
|
|
13
|
+
</template>
|
|
14
|
+
</DlInfiniteScroll>
|
|
15
|
+
</div>
|
|
16
|
+
<div style="margin-top: 10px">
|
|
17
|
+
<span>
|
|
18
|
+
Custom implementation with the top and bottom components
|
|
19
|
+
</span>
|
|
20
|
+
<span>List</span>
|
|
21
|
+
<dl-list
|
|
22
|
+
ref="listRef"
|
|
23
|
+
class="item-list"
|
|
24
|
+
>
|
|
25
|
+
<dl-top-scroll
|
|
26
|
+
:container-ref="listRef"
|
|
27
|
+
@scroll-to-top="handleListScrollToTop"
|
|
28
|
+
/>
|
|
29
|
+
<dl-list-item
|
|
30
|
+
v-for="row in rows"
|
|
31
|
+
:key="row.id"
|
|
32
|
+
>
|
|
33
|
+
{{ row.name }}
|
|
34
|
+
</dl-list-item>
|
|
35
|
+
<dl-bottom-scroll
|
|
36
|
+
:container-ref="listRef"
|
|
37
|
+
@scroll-to-bottom="handleListScrollToBottom"
|
|
38
|
+
/>
|
|
39
|
+
</dl-list>
|
|
40
|
+
<div style="margin-top: 100px">
|
|
41
|
+
<p>Infinite scrolling With custom data and weird expandable</p>
|
|
42
|
+
<dl-table
|
|
43
|
+
:loading="loading"
|
|
44
|
+
:rows="rows"
|
|
45
|
+
:columns="columns"
|
|
46
|
+
style="height: 500px; width: 600px"
|
|
47
|
+
row-key="index"
|
|
48
|
+
infinite-scroll
|
|
49
|
+
expandable-rows
|
|
50
|
+
:rows-per-page-options="[rowsPerPage]"
|
|
51
|
+
@scroll-to-bottom="handleTableScrollToBottom"
|
|
52
|
+
@scroll-to-top="handleTableScrollToTop"
|
|
53
|
+
>
|
|
54
|
+
<template #body-cell-expandable-content="{ row }">
|
|
55
|
+
<div>
|
|
56
|
+
{{ row }}
|
|
57
|
+
</div>
|
|
58
|
+
<div>
|
|
59
|
+
{{ row }}
|
|
60
|
+
</div>
|
|
61
|
+
<div>
|
|
62
|
+
{{ row }}
|
|
63
|
+
</div>
|
|
64
|
+
<div>
|
|
65
|
+
{{ row }}
|
|
66
|
+
</div>
|
|
67
|
+
<div>
|
|
68
|
+
{{ row }}
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
</dl-table>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div style="margin-top: 10px">
|
|
75
|
+
<span> IN A GRID </span>
|
|
76
|
+
<dl-grid
|
|
77
|
+
:items="allRows"
|
|
78
|
+
style="--dl-virtual-scroll-height: 40vh"
|
|
79
|
+
:max-elements-per-row="4"
|
|
80
|
+
column-gap="20px"
|
|
81
|
+
row-gap="20px"
|
|
82
|
+
:infinite-scroll-page-size="32"
|
|
83
|
+
infinite-scroll
|
|
84
|
+
>
|
|
85
|
+
<template #item-slot="{ item }">
|
|
86
|
+
<div
|
|
87
|
+
style="
|
|
88
|
+
height: 50px;
|
|
89
|
+
width: 180px;
|
|
90
|
+
display: grid;
|
|
91
|
+
place-items: center;
|
|
92
|
+
"
|
|
93
|
+
>
|
|
94
|
+
<div>{{ item.name }}</div>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
</dl-grid>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<script lang="ts">
|
|
103
|
+
import { defineComponent, ref } from 'vue-demi'
|
|
104
|
+
import {
|
|
105
|
+
DlTopScroll,
|
|
106
|
+
DlBottomScroll,
|
|
107
|
+
DlList,
|
|
108
|
+
DlListItem,
|
|
109
|
+
DlTable,
|
|
110
|
+
DlInfiniteScroll,
|
|
111
|
+
DlGrid
|
|
112
|
+
} from '../components'
|
|
113
|
+
import { columns } from './DlTableDemo.vue'
|
|
114
|
+
import { cloneDeep, times } from 'lodash'
|
|
115
|
+
|
|
116
|
+
const getRows = (count: number) =>
|
|
117
|
+
times(count, (index) => ({
|
|
118
|
+
name: 'KitKat' + index,
|
|
119
|
+
calories: 518,
|
|
120
|
+
fat: 26.0,
|
|
121
|
+
carbs: 65,
|
|
122
|
+
protein: 7,
|
|
123
|
+
sodium: 54,
|
|
124
|
+
calcium: '12%',
|
|
125
|
+
iron: '6%'
|
|
126
|
+
}))
|
|
127
|
+
|
|
128
|
+
const items = getRows(500)
|
|
129
|
+
|
|
130
|
+
export default defineComponent({
|
|
131
|
+
components: {
|
|
132
|
+
DlTopScroll,
|
|
133
|
+
DlBottomScroll,
|
|
134
|
+
DlList,
|
|
135
|
+
DlListItem,
|
|
136
|
+
DlTable,
|
|
137
|
+
DlInfiniteScroll,
|
|
138
|
+
DlGrid
|
|
139
|
+
},
|
|
140
|
+
setup() {
|
|
141
|
+
const loading = ref(false)
|
|
142
|
+
const scrollOffset = 500
|
|
143
|
+
const rowsPerPage = 30
|
|
144
|
+
const sliceIndex = { from: 0, to: 0 }
|
|
145
|
+
const allRows = ref<any[]>(cloneDeep(items))
|
|
146
|
+
const rows = ref<any[]>(cloneDeep(items.slice(0, 30)))
|
|
147
|
+
const listRef = ref(null)
|
|
148
|
+
|
|
149
|
+
const page = ref(0)
|
|
150
|
+
|
|
151
|
+
const pushRows = () => {
|
|
152
|
+
page.value++
|
|
153
|
+
const start = page.value * 30
|
|
154
|
+
rows.value = rows.value.concat(items.slice(start, start + 30))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const handleInfiniteScroll = (
|
|
158
|
+
rowsPerPage: number,
|
|
159
|
+
direction: 'top' | 'bottom',
|
|
160
|
+
maxLength?: number,
|
|
161
|
+
ref?: HTMLElement
|
|
162
|
+
) => {
|
|
163
|
+
loading.value = true
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
if (!sliceIndex.to) sliceIndex.to = rowsPerPage
|
|
166
|
+
if (maxLength) {
|
|
167
|
+
if (direction === 'bottom') {
|
|
168
|
+
sliceIndex.to += rowsPerPage
|
|
169
|
+
if (rows.value.length > maxLength) {
|
|
170
|
+
sliceIndex.from += rowsPerPage
|
|
171
|
+
if (ref) {
|
|
172
|
+
ref.scrollTop -= scrollOffset
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
sliceIndex.from -= rowsPerPage
|
|
177
|
+
if (rows.value.length > maxLength) {
|
|
178
|
+
sliceIndex.to -= rowsPerPage
|
|
179
|
+
if (ref) {
|
|
180
|
+
ref.scrollTop += scrollOffset
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (sliceIndex.from < 0) {
|
|
184
|
+
sliceIndex.from = 0
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
rows.value = items.slice(sliceIndex.from, sliceIndex.to)
|
|
189
|
+
loading.value = false
|
|
190
|
+
}, 500)
|
|
191
|
+
}
|
|
192
|
+
const handleListScrollToBottom = () => {
|
|
193
|
+
handleInfiniteScroll(rowsPerPage, 'bottom', 100, listRef.value.$el)
|
|
194
|
+
}
|
|
195
|
+
const handleListScrollToTop = () => {
|
|
196
|
+
handleInfiniteScroll(rowsPerPage, 'top', 100, listRef.value.$el)
|
|
197
|
+
}
|
|
198
|
+
const handleTableScrollToBottom = (
|
|
199
|
+
rowsPerPage: number,
|
|
200
|
+
ref: HTMLElement
|
|
201
|
+
) => {
|
|
202
|
+
handleInfiniteScroll(rowsPerPage, 'bottom', 100, ref)
|
|
203
|
+
}
|
|
204
|
+
const handleTableScrollToTop = (
|
|
205
|
+
rowsPerPage: number,
|
|
206
|
+
ref: HTMLElement
|
|
207
|
+
) => {
|
|
208
|
+
handleInfiniteScroll(rowsPerPage, 'top', 100, ref)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
items,
|
|
213
|
+
rows,
|
|
214
|
+
columns,
|
|
215
|
+
loading,
|
|
216
|
+
listRef,
|
|
217
|
+
rowsPerPage,
|
|
218
|
+
handleInfiniteScroll,
|
|
219
|
+
handleListScrollToBottom,
|
|
220
|
+
handleListScrollToTop,
|
|
221
|
+
handleTableScrollToBottom,
|
|
222
|
+
handleTableScrollToTop,
|
|
223
|
+
pushRows,
|
|
224
|
+
allRows
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
</script>
|
|
229
|
+
|
|
230
|
+
<style scoped>
|
|
231
|
+
.item-list {
|
|
232
|
+
height: 300px;
|
|
233
|
+
overflow-y: auto;
|
|
234
|
+
padding: 10px;
|
|
235
|
+
}
|
|
236
|
+
</style>
|
|
@@ -108,12 +108,12 @@
|
|
|
108
108
|
:loading="loading"
|
|
109
109
|
:rows="tableRows"
|
|
110
110
|
:resizable="resizable"
|
|
111
|
+
:rows-per-page-options="[30]"
|
|
111
112
|
row-key="name"
|
|
112
113
|
color="dl-color-secondary"
|
|
113
114
|
title="Table Title"
|
|
114
115
|
:virtual-scroll="vScroll"
|
|
115
116
|
style="height: 500px"
|
|
116
|
-
:rows-per-page-options="rowsPerPageOptions"
|
|
117
117
|
@row-click="log"
|
|
118
118
|
@th-click="log"
|
|
119
119
|
@update:selected="updateSeleted"
|
|
@@ -681,48 +681,6 @@
|
|
|
681
681
|
</template>
|
|
682
682
|
</DlTable>
|
|
683
683
|
</div>
|
|
684
|
-
<div style="margin-top: 100px">
|
|
685
|
-
<p>Infinite scrolling With custom data and weird expandable</p>
|
|
686
|
-
<DlTable
|
|
687
|
-
:selected="selected"
|
|
688
|
-
:separator="separator"
|
|
689
|
-
:draggable="draggable"
|
|
690
|
-
:filter="filter"
|
|
691
|
-
:resizable="resizable"
|
|
692
|
-
:selection="selection"
|
|
693
|
-
:dense="dense"
|
|
694
|
-
title="Treats"
|
|
695
|
-
color="dl-color-secondary"
|
|
696
|
-
:loading="infiniteLoading"
|
|
697
|
-
:rows="generatedRows"
|
|
698
|
-
:columns="tableColumns"
|
|
699
|
-
style="height: 500px"
|
|
700
|
-
row-key="index"
|
|
701
|
-
virtual-scroll
|
|
702
|
-
expandable-rows
|
|
703
|
-
@virtual-scroll="onScrollGenerate"
|
|
704
|
-
@update:pagination="log('hi')"
|
|
705
|
-
@col-update="updateColumns"
|
|
706
|
-
>
|
|
707
|
-
<template #body-cell-expandable-content="{ row }">
|
|
708
|
-
<div>
|
|
709
|
-
{{ row }}
|
|
710
|
-
</div>
|
|
711
|
-
<div>
|
|
712
|
-
{{ row }}
|
|
713
|
-
</div>
|
|
714
|
-
<div>
|
|
715
|
-
{{ row }}
|
|
716
|
-
</div>
|
|
717
|
-
<div>
|
|
718
|
-
{{ row }}
|
|
719
|
-
</div>
|
|
720
|
-
<div>
|
|
721
|
-
{{ row }}
|
|
722
|
-
</div>
|
|
723
|
-
</template>
|
|
724
|
-
</DlTable>
|
|
725
|
-
</div>
|
|
726
684
|
</div>
|
|
727
685
|
</template>
|
|
728
686
|
|
|
@@ -739,7 +697,7 @@ import { defineComponent, ref, computed, nextTick } from 'vue-demi'
|
|
|
739
697
|
import { times, cloneDeep, isNumber } from 'lodash'
|
|
740
698
|
import { DlTablePagination, DlVirtualScrollEvent } from '../types'
|
|
741
699
|
|
|
742
|
-
const columns = [
|
|
700
|
+
export const columns = [
|
|
743
701
|
{
|
|
744
702
|
name: 'name',
|
|
745
703
|
required: true,
|
|
@@ -839,108 +797,8 @@ const columns2 = [
|
|
|
839
797
|
}
|
|
840
798
|
]
|
|
841
799
|
|
|
842
|
-
const
|
|
843
|
-
{
|
|
844
|
-
name: 'Frozen Yogurt',
|
|
845
|
-
calories: 159,
|
|
846
|
-
fat: 6.0,
|
|
847
|
-
carbs: 24,
|
|
848
|
-
protein: 4.0,
|
|
849
|
-
sodium: 87,
|
|
850
|
-
calcium: '14%',
|
|
851
|
-
iron: '1%'
|
|
852
|
-
},
|
|
853
|
-
{
|
|
854
|
-
name: 'Ice cream sandwich',
|
|
855
|
-
calories: 237,
|
|
856
|
-
fat: 9.0,
|
|
857
|
-
carbs: 37,
|
|
858
|
-
protein: 4.3,
|
|
859
|
-
sodium: 129,
|
|
860
|
-
calcium: '8%',
|
|
861
|
-
iron: '1%'
|
|
862
|
-
},
|
|
863
|
-
{
|
|
864
|
-
name: 'Eclair',
|
|
865
|
-
calories: 262,
|
|
866
|
-
fat: 16.0,
|
|
867
|
-
carbs: 23,
|
|
868
|
-
protein: 6.0,
|
|
869
|
-
sodium: 337,
|
|
870
|
-
calcium: '6%',
|
|
871
|
-
iron: '7%'
|
|
872
|
-
},
|
|
873
|
-
{
|
|
874
|
-
name: 'Cupcake',
|
|
875
|
-
calories: 305,
|
|
876
|
-
fat: 3.7,
|
|
877
|
-
carbs: 67,
|
|
878
|
-
protein: 4.3,
|
|
879
|
-
sodium: 413,
|
|
880
|
-
calcium: '3%',
|
|
881
|
-
iron: '8%'
|
|
882
|
-
},
|
|
883
|
-
{
|
|
884
|
-
name: 'Gingerbread',
|
|
885
|
-
calories: 356,
|
|
886
|
-
fat: 16.0,
|
|
887
|
-
carbs: 49,
|
|
888
|
-
protein: 3.9,
|
|
889
|
-
sodium: 327,
|
|
890
|
-
calcium: '7%',
|
|
891
|
-
iron: '16%'
|
|
892
|
-
},
|
|
893
|
-
{
|
|
894
|
-
name: 'Jelly bean',
|
|
895
|
-
calories: 375,
|
|
896
|
-
fat: 0.0,
|
|
897
|
-
carbs: 94,
|
|
898
|
-
protein: 0.0,
|
|
899
|
-
sodium: 50,
|
|
900
|
-
calcium: '0%',
|
|
901
|
-
iron: '0%'
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
name: 'Lollipop',
|
|
905
|
-
calories: 392,
|
|
906
|
-
fat: 0.2,
|
|
907
|
-
carbs: 98,
|
|
908
|
-
protein: 0,
|
|
909
|
-
sodium: 38,
|
|
910
|
-
calcium: '0%',
|
|
911
|
-
iron: '2%'
|
|
912
|
-
},
|
|
913
|
-
{
|
|
914
|
-
name: 'Honeycomb',
|
|
915
|
-
calories: 408,
|
|
916
|
-
fat: 3.2,
|
|
917
|
-
carbs: 87,
|
|
918
|
-
protein: 6.5,
|
|
919
|
-
sodium: 562,
|
|
920
|
-
calcium: '0%',
|
|
921
|
-
iron: '45%'
|
|
922
|
-
},
|
|
923
|
-
{
|
|
924
|
-
name: 'Donut',
|
|
925
|
-
calories: 452,
|
|
926
|
-
fat: 25.0,
|
|
927
|
-
carbs: 51,
|
|
928
|
-
protein: 4.9,
|
|
929
|
-
sodium: 326,
|
|
930
|
-
calcium: '2%',
|
|
931
|
-
iron: '22%'
|
|
932
|
-
},
|
|
933
|
-
{
|
|
934
|
-
name: 'KitKat',
|
|
935
|
-
calories: 518,
|
|
936
|
-
fat: 26.0,
|
|
937
|
-
carbs: 65,
|
|
938
|
-
protein: 7,
|
|
939
|
-
sodium: 54,
|
|
940
|
-
calcium: '12%',
|
|
941
|
-
iron: '6%'
|
|
942
|
-
},
|
|
943
|
-
...times(1000, (index) => ({
|
|
800
|
+
const getRows = (count: number) => [
|
|
801
|
+
...times(count, (index) => ({
|
|
944
802
|
name: 'KitKat' + index,
|
|
945
803
|
calories: 518,
|
|
946
804
|
fat: 26.0,
|
|
@@ -952,6 +810,8 @@ const rows = [
|
|
|
952
810
|
}))
|
|
953
811
|
]
|
|
954
812
|
|
|
813
|
+
const rows = getRows(1000)
|
|
814
|
+
|
|
955
815
|
const columnsAligned = [
|
|
956
816
|
{
|
|
957
817
|
name: 'name',
|
|
@@ -1058,7 +918,7 @@ export default defineComponent({
|
|
|
1058
918
|
const draggable = ref('both')
|
|
1059
919
|
const tableColumns = ref(columns)
|
|
1060
920
|
const tableColumnsAligned = ref(columnsAligned)
|
|
1061
|
-
const rowsPerPageOptions = ref([
|
|
921
|
+
const rowsPerPageOptions = ref([10, 12, 14, 16, 100])
|
|
1062
922
|
|
|
1063
923
|
const infiniteLoading = ref(false)
|
|
1064
924
|
|
package/src/demos/index.ts
CHANGED
|
@@ -67,6 +67,7 @@ import DlThumbnailGallery from './DlThumbnailGalleryDemo.vue'
|
|
|
67
67
|
import DlLayoutDemo from './DlLayoutDemo.vue'
|
|
68
68
|
import { DlCodeEditorDemo } from './DlCodeEditor'
|
|
69
69
|
import DlLabelPickerDemo from './DlLabelPickerDemo.vue'
|
|
70
|
+
import DlInfiniteScrollDemo from './DlInfiniteScrollDemo.vue'
|
|
70
71
|
|
|
71
72
|
export default {
|
|
72
73
|
AvatarDemo,
|
|
@@ -134,5 +135,6 @@ export default {
|
|
|
134
135
|
DlThumbnailGallery,
|
|
135
136
|
DlCodeEditorDemo,
|
|
136
137
|
DlLayoutDemo,
|
|
137
|
-
DlLabelPickerDemo
|
|
138
|
+
DlLabelPickerDemo,
|
|
139
|
+
DlInfiniteScrollDemo
|
|
138
140
|
}
|