@v1nt1248/3nclient-lib 0.3.35 → 0.3.37
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/README.md +1 -0
- package/dist/src/components/index.d.ts +4 -2
- package/dist/src/components/ui3n-scrollbar/types.d.ts +61 -0
- package/dist/src/components/ui3n-scrollbar/ui3n-scrollbar.d.ts +53 -0
- package/dist/src/components/ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.d.ts +1 -1
- package/dist/src/components/ui3n-table/composables/useTable.d.ts +6 -1
- package/dist/src/components/ui3n-table/types.d.ts +52 -0
- package/dist/src/components/ui3n-virtual-scroll/types.d.ts +38 -0
- package/dist/src/components/ui3n-virtual-scroll/ui3n-virtual-scroll.d.ts +9 -5
- package/dist/src/index.d.ts +2 -0
- package/dist/src/ui3n-components.d.ts +2 -0
- package/dist/style.css +1 -1
- package/dist/ui3n-components.js +1819 -1181
- package/package.json +2 -14
- package/src/components/index.ts +26 -1
- package/src/components/ui3n-scrollbar/types.ts +63 -0
- package/src/components/ui3n-scrollbar/ui3n-scrollbar.vue +697 -0
- package/src/components/ui3n-table/composables/useTable.ts +169 -16
- package/src/components/ui3n-table/types.ts +52 -0
- package/src/components/ui3n-table/ui3n-table.vue +376 -6
- package/src/components/ui3n-virtual-scroll/types.ts +40 -0
- package/src/components/ui3n-virtual-scroll/ui3n-virtual-scroll.vue +368 -59
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Ui3nTableBodyBaseItem">
|
|
2
2
|
import size from 'lodash/size';
|
|
3
|
+
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
|
3
4
|
import { useTable } from './composables/useTable';
|
|
4
5
|
import type {
|
|
5
6
|
Ui3nTableBodyBaseItem,
|
|
@@ -11,11 +12,18 @@
|
|
|
11
12
|
import Ui3nButton from '../ui3n-button/ui3n-button.vue';
|
|
12
13
|
import Ui3nCheckbox from '../ui3n-checkbox/ui3n-checkbox.vue';
|
|
13
14
|
import Ui3nTableSortIcon from './ui3n-table-sort-icon.vue';
|
|
15
|
+
import Ui3nScrollbar from '../ui3n-scrollbar/ui3n-scrollbar.vue';
|
|
14
16
|
|
|
15
17
|
const props = defineProps<Ui3nTableProps<T>>();
|
|
16
18
|
const emits = defineEmits<Ui3nTableEmits<T>>();
|
|
17
19
|
defineSlots<Ui3nTableSlots<T, string & keyof T>>();
|
|
18
20
|
|
|
21
|
+
const scrollbarRef = ref<InstanceType<typeof Ui3nScrollbar> | null>(null);
|
|
22
|
+
const scrollbarContainer = computed(() => scrollbarRef.value?.getContainer() ?? null);
|
|
23
|
+
const headerEl = ref<HTMLDivElement | null>(null);
|
|
24
|
+
const headerHeight = ref(0);
|
|
25
|
+
let headerResizeObserver: ResizeObserver | null = null;
|
|
26
|
+
|
|
19
27
|
const {
|
|
20
28
|
tableEl,
|
|
21
29
|
tableColumnWidth,
|
|
@@ -27,6 +35,10 @@
|
|
|
27
35
|
selectedRows,
|
|
28
36
|
selectedRowsArray,
|
|
29
37
|
selectedRowsSize,
|
|
38
|
+
stickyColumnsActive,
|
|
39
|
+
stickyColumnsCount,
|
|
40
|
+
stickyColumnLefts,
|
|
41
|
+
scrollportWidth,
|
|
30
42
|
closeGroupActionsRow,
|
|
31
43
|
getRowKey,
|
|
32
44
|
isRowSelected,
|
|
@@ -35,12 +47,70 @@
|
|
|
35
47
|
toggleSelectedRows,
|
|
36
48
|
changeSortOrder,
|
|
37
49
|
clear,
|
|
38
|
-
} = useTable(props, emits);
|
|
50
|
+
} = useTable(props, emits, scrollbarContainer);
|
|
39
51
|
|
|
40
52
|
const eventHandlers = {
|
|
41
53
|
select: processSelection,
|
|
42
54
|
};
|
|
43
55
|
|
|
56
|
+
const scrollbarAxes = computed(() => props.config?.scrollbar?.axes ?? 'both');
|
|
57
|
+
|
|
58
|
+
const scrollbarVertical = computed(() => {
|
|
59
|
+
const base = props.config?.scrollbar?.vertical ?? {};
|
|
60
|
+
const axes = scrollbarAxes.value;
|
|
61
|
+
const needsVerticalOffset = axes === 'vertical' || axes === 'both';
|
|
62
|
+
|
|
63
|
+
if (!needsVerticalOffset || !headerHeight.value) {
|
|
64
|
+
return base;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...base,
|
|
69
|
+
trackOffsetTop: headerHeight.value,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const tableStyle = computed(() => {
|
|
74
|
+
const style: Record<string, string> = {
|
|
75
|
+
'--ui3n-table-columns-width': tableColumnWidth.value,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (scrollportWidth.value != null) {
|
|
79
|
+
style['--ui3n-table-scrollport-width'] = `${scrollportWidth.value}px`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return style;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
function syncHeaderObserver() {
|
|
86
|
+
headerResizeObserver?.disconnect();
|
|
87
|
+
headerResizeObserver = null;
|
|
88
|
+
|
|
89
|
+
const el = headerEl.value;
|
|
90
|
+
if (!el || !props.config?.scrollbar) {
|
|
91
|
+
headerHeight.value = 0;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const update = () => {
|
|
96
|
+
headerHeight.value = el.offsetHeight;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
update();
|
|
100
|
+
headerResizeObserver = new ResizeObserver(update);
|
|
101
|
+
headerResizeObserver.observe(el);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
watch([headerEl, () => props.config?.scrollbar, showGroupActionsRow], syncHeaderObserver, {
|
|
105
|
+
immediate: true,
|
|
106
|
+
flush: 'post',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
onBeforeUnmount(() => {
|
|
110
|
+
headerResizeObserver?.disconnect();
|
|
111
|
+
headerResizeObserver = null;
|
|
112
|
+
});
|
|
113
|
+
|
|
44
114
|
defineExpose<Ui3nTableExpose<T>>({
|
|
45
115
|
getRowStyle,
|
|
46
116
|
selectedRows,
|
|
@@ -52,10 +122,202 @@
|
|
|
52
122
|
</script>
|
|
53
123
|
|
|
54
124
|
<template>
|
|
125
|
+
<Ui3nScrollbar
|
|
126
|
+
v-if="config?.scrollbar"
|
|
127
|
+
ref="scrollbarRef"
|
|
128
|
+
:class="$style.tableHost"
|
|
129
|
+
:axes="scrollbarAxes"
|
|
130
|
+
:vertical="scrollbarVertical"
|
|
131
|
+
:horizontal="config.scrollbar.horizontal"
|
|
132
|
+
>
|
|
133
|
+
<div
|
|
134
|
+
ref="tableEl"
|
|
135
|
+
:style="tableStyle"
|
|
136
|
+
:class="[$style.ui3nTable, $style.ui3nTableInsideScrollbar, stickyColumnsActive && $style.stickyColumns]"
|
|
137
|
+
>
|
|
138
|
+
<fieldset
|
|
139
|
+
v-if="config?.tableName && selectedRowsSize > 0"
|
|
140
|
+
:class="$style.hiddenBlock"
|
|
141
|
+
>
|
|
142
|
+
<input
|
|
143
|
+
v-for="(row, rowIndex) in selectedRowsArray"
|
|
144
|
+
:key="getRowKey(row, rowIndex)"
|
|
145
|
+
type="hidden"
|
|
146
|
+
:name="config.selectable === 'multiple' ? `${config.tableName}[]` : config.tableName"
|
|
147
|
+
:value="String(getRowKey(row, rowIndex))"
|
|
148
|
+
/>
|
|
149
|
+
</fieldset>
|
|
150
|
+
|
|
151
|
+
<div
|
|
152
|
+
ref="headerEl"
|
|
153
|
+
:class="[$style.header, showGroupActionsRow && $style.withGroupActions]"
|
|
154
|
+
>
|
|
155
|
+
<!-- group actions -->
|
|
156
|
+
<div
|
|
157
|
+
v-if="showGroupActionsRow"
|
|
158
|
+
:class="$style.groupActions"
|
|
159
|
+
>
|
|
160
|
+
<ui3n-checkbox
|
|
161
|
+
:indeterminate="selectedRowsSize < body.content.length && selectedRowsSize !== 0"
|
|
162
|
+
:model-value="selectedRowsSize === body.content.length"
|
|
163
|
+
@change="toggleSelectedRows"
|
|
164
|
+
>
|
|
165
|
+
Selected: {{ selectedRowsSize }}
|
|
166
|
+
</ui3n-checkbox>
|
|
167
|
+
|
|
168
|
+
<div :class="$style.groupActionsBody">
|
|
169
|
+
<slot
|
|
170
|
+
name="group-actions"
|
|
171
|
+
:selected-rows="selectedRowsArray"
|
|
172
|
+
/>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<ui3n-button
|
|
176
|
+
type="secondary"
|
|
177
|
+
@click="closeGroupActionsRow"
|
|
178
|
+
>
|
|
179
|
+
Cancel
|
|
180
|
+
</ui3n-button>
|
|
181
|
+
</div>
|
|
182
|
+
<!-- table header -->
|
|
183
|
+
<template
|
|
184
|
+
v-for="(h, hIndex) in visibleColumns"
|
|
185
|
+
:key="h.key"
|
|
186
|
+
>
|
|
187
|
+
<div
|
|
188
|
+
:class="[
|
|
189
|
+
$style.headerItemWrapper,
|
|
190
|
+
hIndex === 0 && $style.headerItemFirst,
|
|
191
|
+
hIndex < stickyColumnsCount && $style.headerItemSticky,
|
|
192
|
+
h.sortable && $style.sortable,
|
|
193
|
+
h.sortable && currentConfig.sortOrder?.field === h.key && $style.sortableActive,
|
|
194
|
+
]"
|
|
195
|
+
:style="[
|
|
196
|
+
h.headCellStyle,
|
|
197
|
+
hIndex < stickyColumnsCount ? { left: stickyColumnLefts[hIndex], zIndex: 6 + hIndex } : undefined,
|
|
198
|
+
]"
|
|
199
|
+
>
|
|
200
|
+
<div
|
|
201
|
+
:class="$style.headerItem"
|
|
202
|
+
:style="h.headCellStyle"
|
|
203
|
+
v-on="h.sortable ? { click: () => changeSortOrder(h.key) } : {}"
|
|
204
|
+
>
|
|
205
|
+
<slot :name="`header-cell-${h.key as string & keyof T}`">
|
|
206
|
+
<span :class="$style.headerText">
|
|
207
|
+
{{ h.text }}
|
|
208
|
+
</span>
|
|
209
|
+
</slot>
|
|
210
|
+
<ui3n-table-sort-icon
|
|
211
|
+
v-if="h.sortable && currentConfig.sortOrder?.field === h.key"
|
|
212
|
+
:value="currentConfig.sortOrder?.direction"
|
|
213
|
+
size="16"
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</template>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<!-- table: body -->
|
|
221
|
+
<div :class="$style.body">
|
|
222
|
+
<template v-if="config?.showNoDataMessage && !size(body.content)">
|
|
223
|
+
<slot name="no-data">
|
|
224
|
+
<div :class="$style.noData">No data</div>
|
|
225
|
+
</slot>
|
|
226
|
+
</template>
|
|
227
|
+
|
|
228
|
+
<template v-else>
|
|
229
|
+
<template v-if="$slots['row']">
|
|
230
|
+
<div
|
|
231
|
+
v-for="(row, rowIndex) in body.content"
|
|
232
|
+
:key="getRowKey(row, rowIndex)"
|
|
233
|
+
:class="[
|
|
234
|
+
$style.row,
|
|
235
|
+
$slots['row'] && $style.customRow,
|
|
236
|
+
isRowSelected(row) && $style.selected,
|
|
237
|
+
config.selectable && $style.selectable,
|
|
238
|
+
]"
|
|
239
|
+
>
|
|
240
|
+
<slot
|
|
241
|
+
name="row"
|
|
242
|
+
:row="row"
|
|
243
|
+
:row-style="getRowStyle(row)"
|
|
244
|
+
:row-index="rowIndex"
|
|
245
|
+
:is-row-selected="isRowSelected(row)"
|
|
246
|
+
:column-style="config?.columnStyle"
|
|
247
|
+
:sticky-columns-count="stickyColumnsCount"
|
|
248
|
+
:sticky-column-lefts="stickyColumnLefts"
|
|
249
|
+
:events="eventHandlers"
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
</template>
|
|
253
|
+
|
|
254
|
+
<template v-else>
|
|
255
|
+
<div
|
|
256
|
+
v-for="(row, rowIndex) in body.content"
|
|
257
|
+
:key="getRowKey(row, rowIndex)"
|
|
258
|
+
:class="[$style.row, isRowSelected(row) && $style.selected, config.selectable && $style.selectable]"
|
|
259
|
+
:style="getRowStyle(row)"
|
|
260
|
+
>
|
|
261
|
+
<div
|
|
262
|
+
v-if="config.selectable"
|
|
263
|
+
:class="$style.rowCheckbox"
|
|
264
|
+
>
|
|
265
|
+
<ui3n-checkbox
|
|
266
|
+
:model-value="isRowSelected(row)"
|
|
267
|
+
@change="processSelection(row)"
|
|
268
|
+
/>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<template
|
|
272
|
+
v-for="(col, colIndex) in visibleColumns"
|
|
273
|
+
:key="col.key"
|
|
274
|
+
>
|
|
275
|
+
<div
|
|
276
|
+
:class="[
|
|
277
|
+
$style.bodyItem,
|
|
278
|
+
colIndex === 0 && $style.bodyItemFirst,
|
|
279
|
+
colIndex < stickyColumnsCount && $style.bodyItemSticky,
|
|
280
|
+
]"
|
|
281
|
+
:style="
|
|
282
|
+
colIndex < stickyColumnsCount
|
|
283
|
+
? { left: stickyColumnLefts[colIndex], zIndex: 2 + colIndex }
|
|
284
|
+
: undefined
|
|
285
|
+
"
|
|
286
|
+
>
|
|
287
|
+
<slot
|
|
288
|
+
:name="`row-cell-${col.key as string & keyof T}`"
|
|
289
|
+
:row="row"
|
|
290
|
+
:row-index="rowIndex"
|
|
291
|
+
:is-row-selected="isRowSelected(row)"
|
|
292
|
+
:column-style="config?.columnStyle"
|
|
293
|
+
:cell="row[col.key]"
|
|
294
|
+
>
|
|
295
|
+
<span :class="$style.cell">
|
|
296
|
+
{{ col.format ? col.format(row[col.key]) : row[col.key] }}
|
|
297
|
+
</span>
|
|
298
|
+
</slot>
|
|
299
|
+
</div>
|
|
300
|
+
</template>
|
|
301
|
+
</div>
|
|
302
|
+
</template>
|
|
303
|
+
</template>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
<!-- table: unused space-->
|
|
307
|
+
<div
|
|
308
|
+
:class="$style.unusedPlace"
|
|
309
|
+
:style="unusedPlaceCssStyle"
|
|
310
|
+
>
|
|
311
|
+
<slot name="unused-place" />
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
</Ui3nScrollbar>
|
|
315
|
+
|
|
55
316
|
<div
|
|
317
|
+
v-else
|
|
56
318
|
ref="tableEl"
|
|
57
|
-
:style="
|
|
58
|
-
:class="$style.ui3nTable"
|
|
319
|
+
:style="tableStyle"
|
|
320
|
+
:class="[$style.ui3nTable, stickyColumnsActive && $style.stickyColumns]"
|
|
59
321
|
>
|
|
60
322
|
<fieldset
|
|
61
323
|
v-if="config?.tableName && selectedRowsSize > 0"
|
|
@@ -100,16 +362,21 @@
|
|
|
100
362
|
</div>
|
|
101
363
|
<!-- table header -->
|
|
102
364
|
<template
|
|
103
|
-
v-for="h in visibleColumns"
|
|
365
|
+
v-for="(h, hIndex) in visibleColumns"
|
|
104
366
|
:key="h.key"
|
|
105
367
|
>
|
|
106
368
|
<div
|
|
107
369
|
:class="[
|
|
108
370
|
$style.headerItemWrapper,
|
|
371
|
+
hIndex === 0 && $style.headerItemFirst,
|
|
372
|
+
hIndex < stickyColumnsCount && $style.headerItemSticky,
|
|
109
373
|
h.sortable && $style.sortable,
|
|
110
374
|
h.sortable && currentConfig.sortOrder?.field === h.key && $style.sortableActive,
|
|
111
375
|
]"
|
|
112
|
-
:style="
|
|
376
|
+
:style="[
|
|
377
|
+
h.headCellStyle,
|
|
378
|
+
hIndex < stickyColumnsCount ? { left: stickyColumnLefts[hIndex], zIndex: 6 + hIndex } : undefined,
|
|
379
|
+
]"
|
|
113
380
|
>
|
|
114
381
|
<div
|
|
115
382
|
:class="$style.headerItem"
|
|
@@ -158,6 +425,8 @@
|
|
|
158
425
|
:row-index="rowIndex"
|
|
159
426
|
:is-row-selected="isRowSelected(row)"
|
|
160
427
|
:column-style="config?.columnStyle"
|
|
428
|
+
:sticky-columns-count="stickyColumnsCount"
|
|
429
|
+
:sticky-column-lefts="stickyColumnLefts"
|
|
161
430
|
:events="eventHandlers"
|
|
162
431
|
/>
|
|
163
432
|
</div>
|
|
@@ -184,7 +453,18 @@
|
|
|
184
453
|
v-for="(col, colIndex) in visibleColumns"
|
|
185
454
|
:key="col.key"
|
|
186
455
|
>
|
|
187
|
-
<div
|
|
456
|
+
<div
|
|
457
|
+
:class="[
|
|
458
|
+
$style.bodyItem,
|
|
459
|
+
colIndex === 0 && $style.bodyItemFirst,
|
|
460
|
+
colIndex < stickyColumnsCount && $style.bodyItemSticky,
|
|
461
|
+
]"
|
|
462
|
+
:style="
|
|
463
|
+
colIndex < stickyColumnsCount
|
|
464
|
+
? { left: stickyColumnLefts[colIndex], zIndex: 2 + colIndex }
|
|
465
|
+
: undefined
|
|
466
|
+
"
|
|
467
|
+
>
|
|
188
468
|
<slot
|
|
189
469
|
:name="`row-cell-${col.key as string & keyof T}`"
|
|
190
470
|
:row="row"
|
|
@@ -217,6 +497,13 @@
|
|
|
217
497
|
<style lang="scss" module>
|
|
218
498
|
@use '@/assets/styles/mixins.scss' as mixins;
|
|
219
499
|
|
|
500
|
+
.tableHost {
|
|
501
|
+
width: 100%;
|
|
502
|
+
height: 100%;
|
|
503
|
+
position: relative;
|
|
504
|
+
overflow: hidden;
|
|
505
|
+
}
|
|
506
|
+
|
|
220
507
|
.ui3nTable {
|
|
221
508
|
--ui3n-table-columns-width: auto;
|
|
222
509
|
--ui3n-table-base-head-height: 36px;
|
|
@@ -245,6 +532,24 @@
|
|
|
245
532
|
align-items: stretch;
|
|
246
533
|
}
|
|
247
534
|
|
|
535
|
+
/* Scroll lives on Ui3nScrollbar; overflow must stay visible so sticky sticks to scrollport. */
|
|
536
|
+
.ui3nTableInsideScrollbar {
|
|
537
|
+
width: max-content;
|
|
538
|
+
min-width: 100%;
|
|
539
|
+
height: auto;
|
|
540
|
+
min-height: 100%;
|
|
541
|
+
overflow: visible;
|
|
542
|
+
|
|
543
|
+
&.stickyColumns {
|
|
544
|
+
overflow: visible;
|
|
545
|
+
|
|
546
|
+
.body {
|
|
547
|
+
width: max-content;
|
|
548
|
+
min-width: 100%;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
248
553
|
.hiddenBlock {
|
|
249
554
|
display: none;
|
|
250
555
|
border: none;
|
|
@@ -415,4 +720,69 @@
|
|
|
415
720
|
.unusedPlace {
|
|
416
721
|
flex-grow: 1;
|
|
417
722
|
}
|
|
723
|
+
|
|
724
|
+
.stickyColumns {
|
|
725
|
+
overflow: auto;
|
|
726
|
+
|
|
727
|
+
.header,
|
|
728
|
+
.row {
|
|
729
|
+
width: max-content;
|
|
730
|
+
min-width: 100%;
|
|
731
|
+
display: grid;
|
|
732
|
+
grid-template-columns: var(--ui3n-table-columns-width);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.header {
|
|
736
|
+
padding-left: 0;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.row:not(.customRow) {
|
|
740
|
+
padding-left: 0;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.row.customRow {
|
|
744
|
+
padding-left: 0;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.headerItemSticky {
|
|
748
|
+
position: sticky;
|
|
749
|
+
background-color: var(--ui3n-table-header-bg-color);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.headerItemFirst.headerItemSticky {
|
|
753
|
+
padding-left: var(--ui3n-table-padding-inline);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.headerItemWrapper:not(.headerItemFirst) {
|
|
757
|
+
padding: 0 calc(var(--ui3n-table-padding-inline) / 4);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.bodyItemSticky {
|
|
761
|
+
position: sticky;
|
|
762
|
+
background-color: var(--color-bg-table-cell-default);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.bodyItemFirst.bodyItemSticky {
|
|
766
|
+
padding-left: calc(var(--ui3n-table-padding-inline) + var(--ui3n-table-padding-inline) * 1.5);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.row:hover .bodyItemSticky {
|
|
770
|
+
background-color: var(--color-bg-control-primary-hover);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.row.selected .bodyItemSticky {
|
|
774
|
+
background-color: var(--ui3n-table-row-bg-color-selected);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.rowCheckbox {
|
|
778
|
+
position: sticky;
|
|
779
|
+
left: var(--ui3n-table-padding-inline);
|
|
780
|
+
z-index: 3;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.groupActions {
|
|
784
|
+
width: var(--ui3n-table-scrollport-width, 100%);
|
|
785
|
+
left: 0;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
418
788
|
</style>
|
|
@@ -16,6 +16,39 @@ export interface Ui3nVirtualScrollProps<T> {
|
|
|
16
16
|
* Number of items to render ahead
|
|
17
17
|
*/
|
|
18
18
|
renderAhead?: number;
|
|
19
|
+
/**
|
|
20
|
+
* When true, if the user is near the bottom of the list,
|
|
21
|
+
* keep the viewport stuck to the bottom after items update
|
|
22
|
+
* (typical chat behavior). Default: false.
|
|
23
|
+
*/
|
|
24
|
+
stickToBottom?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Distance from the bottom (px) treated as "near bottom" for stickToBottom.
|
|
27
|
+
* Default: 32.
|
|
28
|
+
*/
|
|
29
|
+
stickToBottomThreshold?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Distance from an edge (px) at which 'reached-top' / 'reached-bottom' fire.
|
|
32
|
+
* Default: 64.
|
|
33
|
+
*/
|
|
34
|
+
reachEdgeThreshold?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Virtual scroll component emits
|
|
39
|
+
*/
|
|
40
|
+
export interface Ui3nVirtualScrollEmits {
|
|
41
|
+
(ev: 'scroll', value: Event): void;
|
|
42
|
+
/**
|
|
43
|
+
* The list has been scrolled close to its top - the moment to load
|
|
44
|
+
* a previous page of items. Fires once per approach: it will not repeat
|
|
45
|
+
* until the list leaves the edge or 'items' change.
|
|
46
|
+
*/
|
|
47
|
+
(ev: 'reached-top'): void;
|
|
48
|
+
/**
|
|
49
|
+
* Same as 'reached-top', for the bottom edge.
|
|
50
|
+
*/
|
|
51
|
+
(ev: 'reached-bottom'): void;
|
|
19
52
|
}
|
|
20
53
|
|
|
21
54
|
/**
|
|
@@ -27,3 +60,10 @@ export interface Ui3nVirtualScrollSlots<T> {
|
|
|
27
60
|
*/
|
|
28
61
|
item: ({ value, index }: { value: T; index: number }) => VNode;
|
|
29
62
|
}
|
|
63
|
+
|
|
64
|
+
export interface Ui3nVirtualScrollExpose {
|
|
65
|
+
scrollToBottom(): void;
|
|
66
|
+
scrollToItem(id: string, align?: 'start' | 'end' | 'center'): void;
|
|
67
|
+
getScrollTop(): number;
|
|
68
|
+
isStuckToBottom(): boolean;
|
|
69
|
+
}
|