@v1nt1248/3nclient-lib 0.3.28 → 0.3.29
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/dist/chunks/ui3n-notification-Dr_3Td9N.js +279 -0
- package/dist/components/index.d.ts +12 -12
- package/dist/components/ui3n-autocomplete/types.d.ts +8 -0
- package/dist/components/ui3n-autocomplete/ui3n-autocomplete.d.ts +2 -2
- package/dist/components/ui3n-badge/types.d.ts +12 -0
- package/dist/components/ui3n-badge/ui3n-badge-simple.d.ts +1 -1
- package/dist/components/ui3n-badge/ui3n-badge.d.ts +1 -1
- package/dist/components/ui3n-breadcrumbs/types.d.ts +1 -1
- package/dist/components/ui3n-breadcrumbs/ui3n-breadcrumb.d.ts +2 -2
- package/dist/components/ui3n-button/types.d.ts +4 -2
- package/dist/components/ui3n-checkbox/types.d.ts +11 -0
- package/dist/components/ui3n-checkbox/ui3n-checkbox.d.ts +4 -1
- package/dist/components/ui3n-chip/types.d.ts +6 -1
- package/dist/components/ui3n-chip/ui3n-chip.d.ts +2 -0
- package/dist/components/ui3n-drop-files/types.d.ts +7 -0
- package/dist/components/ui3n-drop-files/ui3n-drop-files.d.ts +7 -1
- package/dist/components/ui3n-editable/types.d.ts +11 -0
- package/dist/components/ui3n-editable/ui3n-editable.d.ts +4 -2
- package/dist/components/ui3n-icon/types.d.ts +5 -1
- package/dist/components/ui3n-icon/ui3n-icon.d.ts +2 -2
- package/dist/components/ui3n-input/types.d.ts +4 -0
- package/dist/components/ui3n-input/ui3n-input.d.ts +4 -1
- package/dist/components/ui3n-input-file/types.d.ts +11 -0
- package/dist/components/ui3n-input-file/ui3n-input-file.d.ts +4 -1
- package/dist/components/ui3n-list/types.d.ts +4 -0
- package/dist/components/ui3n-menu/types.d.ts +4 -0
- package/dist/components/ui3n-menu/ui3n-menu.d.ts +1 -1
- package/dist/components/ui3n-notification/ui3n-notification.d.ts +2 -2
- package/dist/components/ui3n-progress/ui3n-progress-circular.d.ts +1 -1
- package/dist/components/ui3n-progress/ui3n-progress-linear.d.ts +1 -1
- package/dist/components/ui3n-radio-group/types.d.ts +18 -0
- package/dist/components/ui3n-radio-group/ui3n-radio-group.d.ts +3 -1
- package/dist/components/ui3n-radio-group/ui3n-radio.d.ts +6 -7
- package/dist/components/ui3n-scrollbar-vertical/types.d.ts +2 -0
- package/dist/components/ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.d.ts +2 -0
- package/dist/components/ui3n-selector/types.d.ts +11 -0
- package/dist/components/ui3n-selector/ui3n-selector.d.ts +2 -2
- package/dist/components/ui3n-slider/types.d.ts +11 -0
- package/dist/components/ui3n-slider/ui3n-slider.d.ts +4 -1
- package/dist/components/ui3n-step-line-bar/types.d.ts +4 -0
- package/dist/components/ui3n-switch/types.d.ts +11 -0
- package/dist/components/ui3n-switch/ui3n-switch.d.ts +4 -1
- package/dist/components/ui3n-table/composables/useTable.d.ts +1 -0
- package/dist/components/ui3n-table/types.d.ts +4 -0
- package/dist/components/ui3n-table/ui3n-table-sort-icon.d.ts +4 -1
- package/dist/components/ui3n-tabs/types.d.ts +4 -0
- package/dist/components/ui3n-text/types.d.ts +11 -0
- package/dist/components/ui3n-text/ui3n-text.d.ts +4 -1
- package/dist/components/ui3n-tooltip/types.d.ts +4 -0
- package/dist/components/ui3n-tooltip/ui3n-tooltip.d.ts +4 -2
- package/dist/style.css +1 -1
- package/dist/ui3n-components.js +2066 -1690
- package/dist/ui3n-plugins.js +1 -1
- package/package.json +1 -1
- package/src/components/index.ts +29 -7
- package/src/components/ui3n-autocomplete/types.ts +9 -1
- package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +182 -51
- package/src/components/ui3n-badge/types.ts +10 -0
- package/src/components/ui3n-badge/ui3n-badge-simple.vue +54 -55
- package/src/components/ui3n-badge/ui3n-badge.vue +4 -0
- package/src/components/ui3n-breadcrumbs/types.ts +1 -1
- package/src/components/ui3n-breadcrumbs/ui3n-breadcrumb.vue +7 -5
- package/src/components/ui3n-button/types.ts +4 -2
- package/src/components/ui3n-button/ui3n-button.vue +24 -19
- package/src/components/ui3n-checkbox/types.ts +12 -0
- package/src/components/ui3n-checkbox/ui3n-checkbox.vue +79 -29
- package/src/components/ui3n-chip/types.ts +6 -1
- package/src/components/ui3n-chip/ui3n-chip.vue +64 -61
- package/src/components/ui3n-dialog/ui3n-dialog.vue +3 -3
- package/src/components/ui3n-drop-files/types.ts +8 -0
- package/src/components/ui3n-drop-files/ui3n-drop-files.vue +73 -29
- package/src/components/ui3n-editable/types.ts +12 -0
- package/src/components/ui3n-editable/ui3n-editable.vue +56 -24
- package/src/components/ui3n-icon/types.ts +5 -1
- package/src/components/ui3n-icon/ui3n-icon.vue +45 -50
- package/src/components/ui3n-input/types.ts +4 -0
- package/src/components/ui3n-input/ui3n-input.vue +14 -1
- package/src/components/ui3n-input-file/types.ts +12 -0
- package/src/components/ui3n-input-file/ui3n-input-file.vue +33 -16
- package/src/components/ui3n-list/types.ts +4 -0
- package/src/components/ui3n-list/ui3n-list.vue +3 -1
- package/src/components/ui3n-menu/types.ts +4 -0
- package/src/components/ui3n-menu/ui3n-menu.vue +43 -32
- package/src/components/ui3n-notification/ui3n-notification.vue +190 -175
- package/src/components/ui3n-progress/ui3n-progress-circular.vue +40 -22
- package/src/components/ui3n-progress/ui3n-progress-linear.vue +14 -7
- package/src/components/ui3n-radio-group/types.ts +20 -0
- package/src/components/ui3n-radio-group/ui3n-radio-group.vue +61 -48
- package/src/components/ui3n-radio-group/ui3n-radio.vue +60 -65
- package/src/components/ui3n-scrollbar-vertical/types.ts +2 -0
- package/src/components/ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.vue +4 -4
- package/src/components/ui3n-selector/types.ts +12 -0
- package/src/components/ui3n-selector/ui3n-selector.vue +63 -40
- package/src/components/ui3n-slider/types.ts +12 -0
- package/src/components/ui3n-slider/ui3n-slider.vue +88 -39
- package/src/components/ui3n-step-line-bar/types.ts +4 -0
- package/src/components/ui3n-step-line-bar/ui3n-step-line-bar.vue +8 -10
- package/src/components/ui3n-switch/types.ts +12 -0
- package/src/components/ui3n-switch/ui3n-switch.vue +57 -25
- package/src/components/ui3n-table/composables/useTable.ts +17 -0
- package/src/components/ui3n-table/types.ts +4 -0
- package/src/components/ui3n-table/ui3n-table-sort-icon.vue +9 -8
- package/src/components/ui3n-table/ui3n-table.vue +48 -17
- package/src/components/ui3n-tabs/types.ts +4 -0
- package/src/components/ui3n-tabs/ui3n-tabs.vue +146 -108
- package/src/components/ui3n-text/types.ts +12 -0
- package/src/components/ui3n-text/ui3n-text.vue +56 -15
- package/src/components/ui3n-tooltip/types.ts +4 -0
- package/src/components/ui3n-tooltip/ui3n-tooltip.vue +61 -43
- package/src/components/ui3n-virtual-scroll/ui3n-virtual-scroll.vue +201 -17
- package/dist/chunks/ui3n-notification-DlDM-u-R.js +0 -276
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
3
3
|
import type { Nullable } from '@/types';
|
|
4
4
|
import type { Ui3nTooltipProps, Ui3nTooltipEmits, Ui3nTooltipSlots } from './types';
|
|
5
5
|
import { arrow, autoUpdate, offset, useFloating } from '@floating-ui/vue';
|
|
@@ -20,23 +20,17 @@
|
|
|
20
20
|
defineSlots<Ui3nTooltipSlots>();
|
|
21
21
|
|
|
22
22
|
const showTooltip = ref(false);
|
|
23
|
-
const
|
|
23
|
+
const referenceContainer = ref<Nullable<HTMLElement>>(null);
|
|
24
24
|
const floatingEl = ref<Nullable<HTMLElement>>(null);
|
|
25
25
|
const floatingArrowEl = ref<Nullable<HTMLElement>>(null);
|
|
26
26
|
|
|
27
|
-
const maxContentWidthCssValue = computed(() => `${props.maxContentWidth}px`);
|
|
28
|
-
const baseOffsetCssValue = computed(() => `${-baseOffset}px`);
|
|
29
|
-
const arrowSizeCssValue = computed(() => `${baseOffset}px`);
|
|
30
27
|
const mainPlacement = computed(() => {
|
|
31
|
-
|
|
32
|
-
const [part1, _] = props.placement.split('-');
|
|
28
|
+
const [part1] = props.placement.split('-');
|
|
33
29
|
return part1;
|
|
34
30
|
});
|
|
31
|
+
|
|
35
32
|
const offsetOptions = computed(() => {
|
|
36
|
-
const options = {
|
|
37
|
-
mainAxis: 0,
|
|
38
|
-
crossAxis: 0,
|
|
39
|
-
};
|
|
33
|
+
const options = { mainAxis: 0, crossAxis: 0 };
|
|
40
34
|
switch (mainPlacement.value) {
|
|
41
35
|
case 'top':
|
|
42
36
|
options.mainAxis = -1 * Number(props.offsetY) + baseOffset;
|
|
@@ -58,16 +52,32 @@
|
|
|
58
52
|
return options;
|
|
59
53
|
});
|
|
60
54
|
|
|
61
|
-
const
|
|
55
|
+
const middlewareComputed = computed(() => [
|
|
56
|
+
offset(offsetOptions.value),
|
|
57
|
+
arrow({ element: floatingArrowEl, padding: 8 }),
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const { floatingStyles, isPositioned, middlewareData } = useFloating(referenceContainer, floatingEl, {
|
|
62
61
|
open: showTooltip,
|
|
63
62
|
placement: props.placement,
|
|
64
63
|
strategy: props.positionStrategy,
|
|
65
|
-
middleware:
|
|
64
|
+
middleware: middlewareComputed,
|
|
66
65
|
whileElementsMounted: props.positionStrategy === 'fixed' ? autoUpdate : undefined,
|
|
67
66
|
});
|
|
68
67
|
|
|
68
|
+
const tooltipStylesComputed = computed(() => ({
|
|
69
|
+
...floatingStyles.value,
|
|
70
|
+
'--ui3n-tooltip-bg-color': props.color,
|
|
71
|
+
'--ui3n-tooltip-text-color': props.textColor,
|
|
72
|
+
'--ui3n-tooltip-max-width': `${props.maxContentWidth}px`,
|
|
73
|
+
'--ui3n-tooltip-arrow-size': `${baseOffset}px`,
|
|
74
|
+
'--ui3n-tooltip-base-offset': `${-baseOffset}px`,
|
|
75
|
+
}));
|
|
76
|
+
|
|
69
77
|
function onMouseenter() {
|
|
70
|
-
if (props.disabled)
|
|
78
|
+
if (props.disabled) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
71
81
|
|
|
72
82
|
showTooltip.value = true;
|
|
73
83
|
emits('open');
|
|
@@ -75,7 +85,9 @@
|
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
function onMouseleave() {
|
|
78
|
-
if (props.disabled && !showTooltip.value)
|
|
88
|
+
if (props.disabled && !showTooltip.value) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
79
91
|
|
|
80
92
|
showTooltip.value = false;
|
|
81
93
|
emits('close');
|
|
@@ -83,7 +95,9 @@
|
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
function onClick() {
|
|
86
|
-
if (props.disabled && !showTooltip.value)
|
|
98
|
+
if (props.disabled && !showTooltip.value) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
87
101
|
|
|
88
102
|
if (showTooltip.value) {
|
|
89
103
|
onMouseleave();
|
|
@@ -93,32 +107,28 @@
|
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
onMounted(() => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (!el) {
|
|
99
|
-
throw new Error('[ui3n-tooltip] A reference element is absent.');
|
|
110
|
+
if (!referenceContainer.value) {
|
|
111
|
+
return;
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
referenceEl.value = el.nodeName === '#text' ? el.nextElementSibling : el;
|
|
103
|
-
|
|
104
|
-
if (!referenceEl.value) return;
|
|
105
|
-
|
|
106
114
|
if (props.trigger === 'hover') {
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
referenceContainer.value.addEventListener('mouseenter', onMouseenter);
|
|
116
|
+
referenceContainer.value.addEventListener('mouseleave', onMouseleave);
|
|
109
117
|
} else if (props.trigger === 'click') {
|
|
110
|
-
|
|
118
|
+
referenceContainer.value.addEventListener('click', onClick);
|
|
111
119
|
}
|
|
112
120
|
});
|
|
113
121
|
|
|
114
122
|
onBeforeUnmount(() => {
|
|
115
|
-
if (!
|
|
123
|
+
if (!referenceContainer.value) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
116
126
|
|
|
117
127
|
if (props.trigger === 'hover') {
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
referenceContainer.value.removeEventListener('mouseenter', onMouseenter);
|
|
129
|
+
referenceContainer.value.removeEventListener('mouseleave', onMouseleave);
|
|
120
130
|
} else if (props.trigger === 'click') {
|
|
121
|
-
|
|
131
|
+
referenceContainer.value.removeEventListener('click', onClick);
|
|
122
132
|
}
|
|
123
133
|
});
|
|
124
134
|
|
|
@@ -134,13 +144,18 @@
|
|
|
134
144
|
</script>
|
|
135
145
|
|
|
136
146
|
<template>
|
|
137
|
-
<
|
|
147
|
+
<div
|
|
148
|
+
ref="referenceContainer"
|
|
149
|
+
:class="$style.container"
|
|
150
|
+
>
|
|
151
|
+
<slot />
|
|
152
|
+
</div>
|
|
138
153
|
|
|
139
154
|
<div
|
|
140
155
|
v-if="showTooltip"
|
|
141
156
|
ref="floatingEl"
|
|
142
157
|
:class="$style.floating"
|
|
143
|
-
:style="
|
|
158
|
+
:style="tooltipStylesComputed"
|
|
144
159
|
>
|
|
145
160
|
<slot name="content">
|
|
146
161
|
<div :class="$style.content">
|
|
@@ -159,10 +174,13 @@
|
|
|
159
174
|
</template>
|
|
160
175
|
|
|
161
176
|
<style lang="scss" module>
|
|
162
|
-
.
|
|
163
|
-
|
|
164
|
-
|
|
177
|
+
.container {
|
|
178
|
+
display: inline-block;
|
|
179
|
+
width: max-content;
|
|
180
|
+
max-width: 100%;
|
|
181
|
+
}
|
|
165
182
|
|
|
183
|
+
.floating {
|
|
166
184
|
width: max-content;
|
|
167
185
|
z-index: 5;
|
|
168
186
|
}
|
|
@@ -175,41 +193,41 @@
|
|
|
175
193
|
&-top,
|
|
176
194
|
&-bottom {
|
|
177
195
|
border-style: solid;
|
|
178
|
-
border-width: 0
|
|
196
|
+
border-width: 0 var(--ui3n-tooltip-arrow-size) var(--ui3n-tooltip-arrow-size) var(--ui3n-tooltip-arrow-size);
|
|
179
197
|
border-color: transparent transparent var(--ui3n-tooltip-bg-color) transparent;
|
|
180
198
|
}
|
|
181
199
|
|
|
182
200
|
&-top {
|
|
183
|
-
bottom:
|
|
201
|
+
bottom: var(--ui3n-tooltip-base-offset);
|
|
184
202
|
transform: rotate(180deg);
|
|
185
203
|
}
|
|
186
204
|
|
|
187
205
|
&-bottom {
|
|
188
|
-
top:
|
|
206
|
+
top: var(--ui3n-tooltip-base-offset);
|
|
189
207
|
transform: rotate(0deg);
|
|
190
208
|
}
|
|
191
209
|
|
|
192
210
|
&-left,
|
|
193
211
|
&-right {
|
|
194
212
|
border-style: solid;
|
|
195
|
-
border-width:
|
|
213
|
+
border-width: var(--ui3n-tooltip-arrow-size) 0 var(--ui3n-tooltip-arrow-size) var(--ui3n-tooltip-arrow-size);
|
|
196
214
|
border-color: transparent transparent transparent var(--ui3n-tooltip-bg-color);
|
|
197
215
|
}
|
|
198
216
|
|
|
199
217
|
&-left {
|
|
200
|
-
right:
|
|
218
|
+
right: var(--ui3n-tooltip-base-offset);
|
|
201
219
|
transform: rotate(0deg);
|
|
202
220
|
}
|
|
203
221
|
|
|
204
222
|
&-right {
|
|
205
|
-
left:
|
|
223
|
+
left: var(--ui3n-tooltip-base-offset);
|
|
206
224
|
transform: rotate(180deg);
|
|
207
225
|
}
|
|
208
226
|
}
|
|
209
227
|
|
|
210
228
|
.content {
|
|
211
229
|
position: relative;
|
|
212
|
-
max-width:
|
|
230
|
+
max-width: var(--ui3n-tooltip-max-width);
|
|
213
231
|
padding: 6px var(--spacing-s);
|
|
214
232
|
border-radius: 6px;
|
|
215
233
|
font-size: var(--font-11);
|
|
@@ -1,47 +1,228 @@
|
|
|
1
1
|
<script lang="ts" setup generic="T extends { id?: string }">
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
import { computed, ref, shallowRef, onMounted, onBeforeUnmount, watch } from 'vue';
|
|
4
|
+
import Ui3nScrollbarVertical from '../ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.vue';
|
|
4
5
|
import type { Ui3nVirtualScrollProps, Ui3nVirtualScrollSlots } from './types';
|
|
5
6
|
|
|
7
|
+
interface MeasuredSize {
|
|
8
|
+
height: number;
|
|
9
|
+
top: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
const props = withDefaults(defineProps<Ui3nVirtualScrollProps<T>>(), {
|
|
7
13
|
renderAhead: 20,
|
|
14
|
+
minChildHeight: 16,
|
|
8
15
|
});
|
|
9
16
|
defineSlots<Ui3nVirtualScrollSlots<T>>();
|
|
10
17
|
|
|
11
18
|
const scrollTop = ref(0);
|
|
19
|
+
const viewportHeight = ref<number | null>(null);
|
|
12
20
|
const scrollbarComponentRef = ref<InstanceType<typeof Ui3nScrollbarVertical> | null>(null);
|
|
13
21
|
|
|
14
|
-
const
|
|
15
|
-
const
|
|
22
|
+
const sizeCache = shallowRef<MeasuredSize[]>([]);
|
|
23
|
+
const cacheVersion = ref(0);
|
|
24
|
+
|
|
25
|
+
let isAdjustingScroll = false;
|
|
26
|
+
let listResizeObserver: ResizeObserver | null = null;
|
|
27
|
+
let containerResizeObserver: ResizeObserver | null = null;
|
|
28
|
+
|
|
29
|
+
const itemRefs = new Map<string | number, HTMLElement>();
|
|
30
|
+
|
|
31
|
+
const totalHeight = computed(() => {
|
|
32
|
+
cacheVersion.value;
|
|
33
|
+
if (!sizeCache.value.length) {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lastItem = sizeCache.value[sizeCache.value.length - 1];
|
|
38
|
+
return lastItem.top + lastItem.height;
|
|
39
|
+
});
|
|
16
40
|
|
|
17
41
|
const wrapElementHeight = computed(() => {
|
|
42
|
+
if (viewportHeight.value !== null) {
|
|
43
|
+
return viewportHeight.value;
|
|
44
|
+
}
|
|
45
|
+
|
|
18
46
|
const el = scrollbarComponentRef.value?.getContainer();
|
|
19
47
|
return el ? el.clientHeight : 0;
|
|
20
48
|
});
|
|
21
49
|
|
|
22
50
|
const startNode = computed(() => {
|
|
23
|
-
|
|
24
|
-
|
|
51
|
+
cacheVersion.value;
|
|
52
|
+
const targetTop = scrollTop.value;
|
|
53
|
+
|
|
54
|
+
if (!sizeCache.value.length) {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let low = 0;
|
|
59
|
+
let high = sizeCache.value.length - 1;
|
|
60
|
+
let foundIndex = -1;
|
|
61
|
+
|
|
62
|
+
while (low <= high) {
|
|
63
|
+
const mid = Math.floor((low + high) / 2);
|
|
64
|
+
const item = sizeCache.value[mid];
|
|
65
|
+
|
|
66
|
+
if (item.top <= targetTop && item.top + item.height > targetTop) {
|
|
67
|
+
foundIndex = mid;
|
|
68
|
+
break;
|
|
69
|
+
} else if (item.top > targetTop) {
|
|
70
|
+
high = mid - 1;
|
|
71
|
+
} else {
|
|
72
|
+
low = mid + 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (foundIndex === -1) {
|
|
77
|
+
foundIndex = Math.max(0, high);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return Math.max(0, foundIndex - props.renderAhead);
|
|
25
81
|
});
|
|
26
82
|
|
|
27
83
|
const visibleNodeCount = computed(() => {
|
|
28
|
-
|
|
84
|
+
const height = wrapElementHeight.value;
|
|
85
|
+
if (!height) {
|
|
86
|
+
return props.renderAhead * 2;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const estimatedVisible = Math.ceil(height / props.minChildHeight);
|
|
90
|
+
return estimatedVisible + 2 * props.renderAhead;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const offsetY = computed(() => {
|
|
94
|
+
cacheVersion.value;
|
|
95
|
+
if (!sizeCache.value.length) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return sizeCache.value[startNode.value]?.top || 0;
|
|
29
100
|
});
|
|
30
101
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
102
|
+
const visibleChildren = computed(() => {
|
|
103
|
+
const start = startNode.value;
|
|
104
|
+
const count = visibleNodeCount.value;
|
|
105
|
+
|
|
106
|
+
if (start + count >= props.items.length - props.renderAhead) {
|
|
107
|
+
return props.items.slice(start);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return props.items.slice(start, start + count);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
function onScroll(event: Event) {
|
|
114
|
+
if (isAdjustingScroll) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
35
117
|
|
|
36
|
-
const onScroll = (event: Event) => {
|
|
37
118
|
scrollTop.value = (event.target as HTMLDivElement).scrollTop;
|
|
38
|
-
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setItemRef(el: any, id: string | number) {
|
|
122
|
+
if (el) {
|
|
123
|
+
const element = el.$el || el;
|
|
124
|
+
itemRefs.set(id, element);
|
|
125
|
+
listResizeObserver?.observe(element);
|
|
126
|
+
} else {
|
|
127
|
+
itemRefs.delete(id);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function initCache() {
|
|
132
|
+
let currentTop = 0;
|
|
133
|
+
sizeCache.value = props.items.map(() => {
|
|
134
|
+
const size = { height: props.minChildHeight, top: currentTop };
|
|
135
|
+
currentTop += props.minChildHeight;
|
|
136
|
+
return size;
|
|
137
|
+
});
|
|
138
|
+
cacheVersion.value++;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
onMounted(() => {
|
|
142
|
+
const containerEl = scrollbarComponentRef.value?.getContainer();
|
|
143
|
+
|
|
144
|
+
if (containerEl) {
|
|
145
|
+
viewportHeight.value = containerEl.clientHeight;
|
|
146
|
+
containerResizeObserver = new ResizeObserver(entries => {
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
viewportHeight.value = entry.contentRect.height || entry.target.clientHeight;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
containerResizeObserver.observe(containerEl);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
listResizeObserver = new ResizeObserver(entries => {
|
|
155
|
+
requestAnimationFrame(() => {
|
|
156
|
+
let lowestChangedIndex = Infinity;
|
|
157
|
+
let totalDeltaAboveKey = 0;
|
|
158
|
+
|
|
159
|
+
const updatedCache = [...sizeCache.value];
|
|
160
|
+
const currentScrollTop = scrollTop.value;
|
|
161
|
+
|
|
162
|
+
for (const entry of entries) {
|
|
163
|
+
const sid = entry.target.getAttribute('data-sid');
|
|
164
|
+
if (!sid) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const index = props.items.findIndex((item, idx) => (item.id ?? idx).toString() === sid);
|
|
169
|
+
if (index === -1) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const realHeight = entry.contentRect.height || entry.target.getBoundingClientRect().height;
|
|
174
|
+
|
|
175
|
+
if (updatedCache[index] && updatedCache[index].height !== realHeight) {
|
|
176
|
+
const oldHeight = updatedCache[index].height;
|
|
177
|
+
updatedCache[index] = { ...updatedCache[index], height: realHeight };
|
|
178
|
+
|
|
179
|
+
if (updatedCache[index].top < currentScrollTop) {
|
|
180
|
+
totalDeltaAboveKey += realHeight - oldHeight;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (index < lowestChangedIndex) {
|
|
184
|
+
lowestChangedIndex = index;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (lowestChangedIndex !== Infinity) {
|
|
190
|
+
let currentTop = updatedCache[lowestChangedIndex].top;
|
|
191
|
+
|
|
192
|
+
for (let i = lowestChangedIndex; i < updatedCache.length; i++) {
|
|
193
|
+
updatedCache[i].top = currentTop;
|
|
194
|
+
currentTop += updatedCache[i].height;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
sizeCache.value = updatedCache;
|
|
198
|
+
cacheVersion.value++;
|
|
199
|
+
|
|
200
|
+
if (containerEl && totalDeltaAboveKey !== 0) {
|
|
201
|
+
isAdjustingScroll = true;
|
|
202
|
+
containerEl.scrollTop = currentScrollTop + totalDeltaAboveKey;
|
|
203
|
+
scrollTop.value = containerEl.scrollTop;
|
|
204
|
+
isAdjustingScroll = false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
scrollbarComponentRef.value?.updateMetrics();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
onBeforeUnmount(() => {
|
|
214
|
+
listResizeObserver?.disconnect();
|
|
215
|
+
containerResizeObserver?.disconnect();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
watch(() => props.items, initCache, { immediate: true });
|
|
39
219
|
</script>
|
|
40
220
|
|
|
41
221
|
<template>
|
|
42
222
|
<ui3n-scrollbar-vertical
|
|
43
223
|
ref="scrollbarComponentRef"
|
|
44
224
|
:class="$style.ui3nVirtualScroll"
|
|
225
|
+
:auto-update="false"
|
|
45
226
|
@scroll="onScroll"
|
|
46
227
|
>
|
|
47
228
|
<div
|
|
@@ -55,7 +236,8 @@
|
|
|
55
236
|
<div
|
|
56
237
|
v-for="(item, index) in visibleChildren"
|
|
57
238
|
:key="item.id"
|
|
58
|
-
:
|
|
239
|
+
:ref="el => setItemRef(el, item.id ?? startNode + index)"
|
|
240
|
+
v-bind="{ 'data-sid': item.id ?? startNode + index }"
|
|
59
241
|
:class="$style.item"
|
|
60
242
|
>
|
|
61
243
|
<slot
|
|
@@ -71,8 +253,6 @@
|
|
|
71
253
|
|
|
72
254
|
<style lang="scss" module>
|
|
73
255
|
.ui3nVirtualScroll {
|
|
74
|
-
--ui3n-virtual-scroll-item-min-height: 16px;
|
|
75
|
-
|
|
76
256
|
background-color: var(--color-bg-block-primary-default);
|
|
77
257
|
}
|
|
78
258
|
|
|
@@ -80,6 +260,9 @@
|
|
|
80
260
|
position: relative;
|
|
81
261
|
overflow: hidden;
|
|
82
262
|
will-change: transform;
|
|
263
|
+
box-sizing: border-box;
|
|
264
|
+
margin: 0 !important;
|
|
265
|
+
padding: 0 !important;
|
|
83
266
|
}
|
|
84
267
|
|
|
85
268
|
.content {
|
|
@@ -88,6 +271,7 @@
|
|
|
88
271
|
|
|
89
272
|
.item {
|
|
90
273
|
position: relative;
|
|
91
|
-
min-height:
|
|
274
|
+
min-height: v-bind('props.minChildHeight + "px"');
|
|
275
|
+
box-sizing: border-box;
|
|
92
276
|
}
|
|
93
277
|
</style>
|