@mixd-id/web-scaffold 0.1.230406356 → 0.1.230406358
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
CHANGED
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<div v-for="(item, index) in visibleItems" :key="item" :data-id="item.id"
|
|
10
|
-
@click="">
|
|
11
|
-
<slot name="item" :item="item" :index="index">
|
|
12
|
-
{{ item }}
|
|
13
|
-
</slot>
|
|
14
|
-
</div>
|
|
15
|
-
<slot name="end"></slot>
|
|
2
|
+
<div :class="$style.virtualGrid" @click="resize">
|
|
3
|
+
|
|
4
|
+
<div ref="scroller" :class="$style.scroller" :style="scrollerStyle">
|
|
5
|
+
<div :class="spacerClass" ref="spacer" :style="spacerStyle">
|
|
6
|
+
<div v-for="(item, index) in visibleItems" :key="item" :data-id="item.id"
|
|
7
|
+
@click="">
|
|
8
|
+
<slot name="item" :item="item" :index="index"></slot>
|
|
16
9
|
</div>
|
|
17
10
|
</div>
|
|
18
11
|
</div>
|
|
19
12
|
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
</div>
|
|
43
|
-
</Teleport>
|
|
44
|
-
|
|
45
|
-
</div>
|
|
13
|
+
<div :class="$style.calc" v-if="items && items.length > 0" ref="calc">
|
|
14
|
+
<slot name="item" :item="items[0]" :index="0"></slot>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<Teleport v-if="optBar" :to="optBar">
|
|
18
|
+
<div class="flex flex-row gap-2 items-center">
|
|
19
|
+
<small class="text-text-400">Column</small>
|
|
20
|
+
<select v-model="config.gridColumn"
|
|
21
|
+
class="appearance-none outline-none text-text-400 w-[20px] bg-transparent border-[1px] border-text-100 text-center">
|
|
22
|
+
<option v-for="i in 8" :value="i">{{ i }}</option>
|
|
23
|
+
</select>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="flex flex-row gap-2 items-center">
|
|
26
|
+
<small class="text-text-400">Gap</small>
|
|
27
|
+
<select v-model="config.gridGap"
|
|
28
|
+
class="appearance-none outline-none text-text-400 w-[20px] bg-transparent border-[1px] border-text-100 text-center">
|
|
29
|
+
<option v-for="i in 8" :value="`gap-${i}`">{{ i }}</option>
|
|
30
|
+
</select>
|
|
31
|
+
</div>
|
|
32
|
+
</Teleport>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
46
35
|
</template>
|
|
47
36
|
|
|
48
37
|
<script>
|
|
@@ -51,202 +40,200 @@ import throttle from "lodash/throttle";
|
|
|
51
40
|
|
|
52
41
|
export default{
|
|
53
42
|
|
|
54
|
-
|
|
43
|
+
emits: [ 'scroll-end' ],
|
|
55
44
|
|
|
56
|
-
|
|
45
|
+
props: {
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
column: {
|
|
48
|
+
type: [ Number, String ],
|
|
49
|
+
default: 1
|
|
50
|
+
},
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
gap: {
|
|
53
|
+
type: [ String ],
|
|
54
|
+
default: 'gap-0'
|
|
55
|
+
},
|
|
67
56
|
|
|
68
57
|
containerClass: String,
|
|
69
58
|
|
|
70
|
-
|
|
59
|
+
items: Array,
|
|
71
60
|
|
|
72
|
-
|
|
61
|
+
pinned: Function,
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
optBar: String,
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
config: Object
|
|
77
66
|
|
|
78
|
-
|
|
67
|
+
},
|
|
79
68
|
|
|
80
|
-
|
|
69
|
+
methods: {
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
handleScroll: throttle(function(){
|
|
72
|
+
this.scrollTop = this.$el.scrollTop
|
|
84
73
|
|
|
85
|
-
|
|
74
|
+
if(this.scrollTop > this.$refs.scroller.offsetHeight - this.$el.clientHeight - this.itemHeight){
|
|
75
|
+
if(!this.isOnEndScroll){
|
|
76
|
+
this.$emit('scroll-end')
|
|
77
|
+
this.isOnEndScroll = true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else{
|
|
81
|
+
if(this.isOnEndScroll){
|
|
82
|
+
this.isOnEndScroll = false
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}, 16),
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
else{
|
|
94
|
-
if(this.isOnEndScroll){
|
|
95
|
-
this.isOnEndScroll = false
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}, 16),
|
|
87
|
+
init(){
|
|
88
|
+
this.$el.addEventListener(
|
|
89
|
+
"scroll",
|
|
90
|
+
this.handleScroll,
|
|
91
|
+
this.passiveScrollSupported() ? { passive: true } : false
|
|
92
|
+
)
|
|
99
93
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"scroll",
|
|
103
|
-
this.handleScroll,
|
|
104
|
-
this.passiveScrollSupported() ? { passive: true } : false
|
|
105
|
-
)
|
|
94
|
+
this.resize()
|
|
95
|
+
},
|
|
106
96
|
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
passiveScrollSupported() {
|
|
98
|
+
let passiveSupported = false;
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const options = {
|
|
102
|
+
get passive() {
|
|
103
|
+
passiveSupported = true;
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
window.addEventListener("test", null, options);
|
|
108
|
+
window.removeEventListener("test", null, options);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
passiveSupported = false;
|
|
111
|
+
}
|
|
112
|
+
return passiveSupported;
|
|
113
|
+
},
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
resetState(){
|
|
116
|
+
this.state = 1
|
|
117
|
+
},
|
|
112
118
|
|
|
113
|
-
|
|
114
|
-
const options = {
|
|
115
|
-
get passive() {
|
|
116
|
-
passiveSupported = true;
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
window.addEventListener("test", null, options);
|
|
121
|
-
window.removeEventListener("test", null, options);
|
|
122
|
-
} catch (err) {
|
|
123
|
-
passiveSupported = false;
|
|
124
|
-
}
|
|
125
|
-
return passiveSupported;
|
|
126
|
-
},
|
|
119
|
+
async resize(){
|
|
127
120
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
this.$nextTick(() => {
|
|
122
|
+
if(this.$refs.calc){
|
|
123
|
+
const elHeight = parseInt(window.getComputedStyle(this.$el).height !== '0px' ?
|
|
124
|
+
window.getComputedStyle(this.$el).height :
|
|
125
|
+
window.getComputedStyle(this.$el).maxHeight)
|
|
131
126
|
|
|
132
|
-
|
|
127
|
+
if(isNaN(elHeight)) return
|
|
133
128
|
|
|
134
|
-
|
|
135
|
-
if(this.$refs.calc){
|
|
136
|
-
const elHeight = parseInt(window.getComputedStyle(this.$refs.container).height !== '0px' ?
|
|
137
|
-
window.getComputedStyle(this.$refs.container).height :
|
|
138
|
-
window.getComputedStyle(this.$refs.container).maxHeight)
|
|
129
|
+
this.itemHeight = parseFloat(window.getComputedStyle(this.$refs.calc).height.replace('px', ''))
|
|
139
130
|
|
|
140
|
-
|
|
131
|
+
this.itemGap = parseFloat(window.getComputedStyle(this.$refs.spacer)['row-gap'].replace('px', ''));
|
|
141
132
|
|
|
142
|
-
|
|
133
|
+
this.maxVisibleItems = elHeight > 0 ? (Math.ceil(elHeight / this.itemHeight) * this.column) : this.items.length
|
|
143
134
|
|
|
144
|
-
|
|
135
|
+
if(this.itemHeight <= 0){
|
|
136
|
+
console.error('Unable to calculate virtual grid item height, async component not supported.')
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
})
|
|
145
140
|
|
|
146
|
-
|
|
141
|
+
},
|
|
147
142
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
})
|
|
143
|
+
setState(state){
|
|
144
|
+
this.state = state
|
|
145
|
+
}
|
|
153
146
|
|
|
154
|
-
|
|
147
|
+
},
|
|
155
148
|
|
|
156
|
-
|
|
157
|
-
this.state = state
|
|
158
|
-
}
|
|
149
|
+
computed: {
|
|
159
150
|
|
|
160
|
-
|
|
151
|
+
scrollerStyle(){
|
|
152
|
+
if(!this.items || this.items.length < 1)
|
|
153
|
+
return {}
|
|
161
154
|
|
|
162
|
-
|
|
155
|
+
const rowCount = Math.ceil((this.items.length / this.column))
|
|
156
|
+
const height = (rowCount * this.itemHeight) + (this.itemGap * (rowCount - 1))
|
|
163
157
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
return {
|
|
159
|
+
height: height + 'px'
|
|
160
|
+
}
|
|
161
|
+
},
|
|
167
162
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
]
|
|
193
|
-
}
|
|
194
|
-
return this.items
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
spacerClass(){
|
|
198
|
-
return [
|
|
199
|
-
this.$style.spacer,
|
|
163
|
+
sortedItems(){
|
|
164
|
+
if(!Array.isArray(this.items)) return []
|
|
165
|
+
|
|
166
|
+
if(typeof this.pinned === 'function'){
|
|
167
|
+
const pinnedItems = []
|
|
168
|
+
const unpinnedItems = []
|
|
169
|
+
this.items.forEach((item) => {
|
|
170
|
+
if(this.pinned(item))
|
|
171
|
+
pinnedItems.push(item)
|
|
172
|
+
else
|
|
173
|
+
unpinnedItems.push(item)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
return [
|
|
177
|
+
...pinnedItems,
|
|
178
|
+
...unpinnedItems
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
return this.items
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
spacerClass(){
|
|
185
|
+
return [
|
|
186
|
+
this.$style.spacer,
|
|
200
187
|
this.containerClass,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
188
|
+
this.gap
|
|
189
|
+
]
|
|
190
|
+
.join(' ')
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
spacerStyle(){
|
|
194
|
+
return {
|
|
195
|
+
transform: "translateY(" + (this.visibleStartIndex * (this.itemHeight + this.itemGap)) + "px)",
|
|
196
|
+
'grid-template-columns': `repeat(${this.column}, minmax(0, 1fr))`,
|
|
197
|
+
gap: this.gap
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
visibleItems(){
|
|
202
|
+
if(this.itemHeight <= 0) return []
|
|
203
|
+
return this.sortedItems.slice(this.visibleStartIndex * this.column, (this.visibleStartIndex * this.column) + this.maxVisibleItems)
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
visibleStartIndex(){
|
|
207
|
+
return Math.floor((this.scrollTop < 0 ? 0 : this.scrollTop) / (this.itemHeight + this.itemGap))
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
data(){
|
|
213
|
+
return {
|
|
214
|
+
scrollTop: 0,
|
|
215
|
+
itemHeight: 0,
|
|
216
|
+
itemGap: 0,
|
|
217
|
+
maxVisibleItems: 0,
|
|
218
|
+
isOnEndScroll: false,
|
|
219
|
+
selectedIndex: -1,
|
|
220
|
+
state: 1,
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
mounted() {
|
|
225
|
+
this.init()
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
watch: {
|
|
229
|
+
|
|
230
|
+
column(to){
|
|
231
|
+
this.resize()
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
gap(to){
|
|
235
|
+
this.resize()
|
|
236
|
+
},
|
|
250
237
|
|
|
251
238
|
items: {
|
|
252
239
|
deep: true,
|
|
@@ -259,7 +246,7 @@ export default{
|
|
|
259
246
|
}
|
|
260
247
|
},
|
|
261
248
|
|
|
262
|
-
|
|
249
|
+
}
|
|
263
250
|
|
|
264
251
|
}
|
|
265
252
|
|
|
@@ -268,25 +255,25 @@ export default{
|
|
|
268
255
|
<style module>
|
|
269
256
|
|
|
270
257
|
.virtualGrid{
|
|
271
|
-
|
|
258
|
+
@apply flex-1 overflow-y-auto;
|
|
272
259
|
}
|
|
273
260
|
|
|
274
261
|
.scroller{
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
262
|
+
position: relative;
|
|
263
|
+
overflow: hidden;
|
|
264
|
+
will-change: auto;
|
|
265
|
+
@apply min-w-full;
|
|
279
266
|
}
|
|
280
267
|
|
|
281
268
|
.spacer{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
269
|
+
will-change: auto;
|
|
270
|
+
position: relative;
|
|
271
|
+
@apply grid;
|
|
285
272
|
}
|
|
286
273
|
|
|
287
274
|
.calc{
|
|
288
|
-
|
|
289
|
-
|
|
275
|
+
@apply absolute invisible max-w-full;
|
|
276
|
+
top: -10000px;
|
|
290
277
|
|
|
291
278
|
}
|
|
292
279
|
|