js-kompo-utils 1.0.27 → 1.0.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/components/VlSelect.vue +205 -128
- package/package.json +1 -1
package/components/VlSelect.vue
CHANGED
|
@@ -34,11 +34,15 @@
|
|
|
34
34
|
<option v-for="opt in nativeOptionsList" :key="opt.value" :value="opt.value">{{ nativeLabel(opt) }}</option>
|
|
35
35
|
</select>
|
|
36
36
|
</div>
|
|
37
|
-
<div class="vlOptions
|
|
37
|
+
<div class="vlOptions"
|
|
38
38
|
:key="optionsKey"
|
|
39
39
|
ref="selectOptions"
|
|
40
40
|
:style="optionsStyle"
|
|
41
|
-
:class="{
|
|
41
|
+
:class="{
|
|
42
|
+
'vlOptionsTeleported': useFloatingOptions,
|
|
43
|
+
'vlOptionsFlipUp': useFloatingOptions && flipUp,
|
|
44
|
+
'vlOptionsVisible': useFloatingOptions && isFocused
|
|
45
|
+
}">
|
|
42
46
|
<template v-if="filteredOptions.length">
|
|
43
47
|
<div v-for="(option,key) in filteredOptions" :key="option.value" :ref="key"
|
|
44
48
|
class="vlOption"
|
|
@@ -64,6 +68,7 @@
|
|
|
64
68
|
</template>
|
|
65
69
|
|
|
66
70
|
<script>
|
|
71
|
+
import { autoUpdate, computePosition, flip, hide, offset, shift, size } from '@floating-ui/dom'
|
|
67
72
|
import Select from 'vue-kompo/js/form/form-fields/Select.vue'
|
|
68
73
|
|
|
69
74
|
export default {
|
|
@@ -71,7 +76,6 @@ export default {
|
|
|
71
76
|
data() {
|
|
72
77
|
return {
|
|
73
78
|
flipUp: false,
|
|
74
|
-
panelStyle: null,
|
|
75
79
|
isTouchDevice: false,
|
|
76
80
|
}
|
|
77
81
|
},
|
|
@@ -82,9 +86,18 @@ export default {
|
|
|
82
86
|
forceUp() {
|
|
83
87
|
return !!this.$_config('openUpward')
|
|
84
88
|
},
|
|
89
|
+
forceDown() {
|
|
90
|
+
return !!this.$_config('openDownward') || this.$_config('autoOptionsPlacement') === false
|
|
91
|
+
},
|
|
92
|
+
useFloatingOptions() {
|
|
93
|
+
const explicitFloating = this.$_config('floatingOptions')
|
|
94
|
+
if (explicitFloating !== undefined && explicitFloating !== null) return !!explicitFloating
|
|
95
|
+
|
|
96
|
+
return !!this.$_config('teleportedOptions') || this.forceUp
|
|
97
|
+
},
|
|
85
98
|
optionsStyle() {
|
|
86
|
-
if (!this.
|
|
87
|
-
return this.
|
|
99
|
+
if (!this.useFloatingOptions) return null
|
|
100
|
+
return this.isFocused ? null : { display: 'none' }
|
|
88
101
|
},
|
|
89
102
|
useNativeMobile() {
|
|
90
103
|
if (!this.$_config('native_on_mobile')) return false
|
|
@@ -114,31 +127,39 @@ export default {
|
|
|
114
127
|
},
|
|
115
128
|
watch: {
|
|
116
129
|
isFocused(focused) {
|
|
130
|
+
if (!this.useFloatingOptions) {
|
|
131
|
+
if (!focused) {
|
|
132
|
+
this.flipUp = false
|
|
133
|
+
this.detachListeners()
|
|
134
|
+
this.resetPanelStyles()
|
|
135
|
+
}
|
|
136
|
+
return
|
|
137
|
+
}
|
|
117
138
|
if (focused) {
|
|
118
|
-
this.$nextTick(() => this.refresh())
|
|
119
139
|
this.attachListeners()
|
|
140
|
+
this.$nextTick(() => {
|
|
141
|
+
this.teleportOptions()
|
|
142
|
+
this.startPositioning()
|
|
143
|
+
})
|
|
120
144
|
} else {
|
|
121
145
|
this.flipUp = false
|
|
122
|
-
this.panelStyle = null
|
|
123
146
|
this.detachListeners()
|
|
147
|
+
this.resetPanelStyles()
|
|
124
148
|
}
|
|
125
149
|
},
|
|
126
150
|
filteredOptions() {
|
|
127
|
-
if (this.isFocused) this.$nextTick(() => this.
|
|
151
|
+
if (this.useFloatingOptions && this.isFocused) this.$nextTick(() => this.queuePositionUpdate())
|
|
128
152
|
},
|
|
129
153
|
optionsKey() {
|
|
154
|
+
if (!this.useFloatingOptions) return
|
|
130
155
|
this.$nextTick(() => {
|
|
131
156
|
this.teleportOptions()
|
|
132
|
-
if (this.
|
|
133
|
-
this._panelObserver.disconnect()
|
|
134
|
-
this._panelObserver.observe(this.$refs.selectOptions)
|
|
135
|
-
}
|
|
136
|
-
if (this.isFocused) this.refresh()
|
|
157
|
+
if (this.isFocused) this.startPositioning()
|
|
137
158
|
})
|
|
138
159
|
},
|
|
139
160
|
},
|
|
140
161
|
mounted() {
|
|
141
|
-
this.teleportOptions()
|
|
162
|
+
if (this.useFloatingOptions) this.teleportOptions()
|
|
142
163
|
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
143
164
|
this.isTouchDevice = window.matchMedia('(pointer: coarse)').matches
|
|
144
165
|
}
|
|
@@ -182,57 +203,61 @@ export default {
|
|
|
182
203
|
tmp.innerHTML = str
|
|
183
204
|
return (tmp.textContent || tmp.innerText || '').trim()
|
|
184
205
|
},
|
|
185
|
-
teleportOptions() {
|
|
206
|
+
teleportOptions(anchor = this.anchorEl()) {
|
|
207
|
+
if (!this.useFloatingOptions) return
|
|
186
208
|
const opts = this.$refs.selectOptions
|
|
187
|
-
|
|
188
|
-
|
|
209
|
+
const context = this.floatingContext(anchor)
|
|
210
|
+
const root = context?.root
|
|
211
|
+
if (opts && root && opts.parentNode !== root) {
|
|
212
|
+
root.appendChild(opts)
|
|
189
213
|
}
|
|
190
214
|
},
|
|
191
215
|
cleanupOptions() {
|
|
216
|
+
if (!this.useFloatingOptions) return
|
|
192
217
|
const opts = this.$refs.selectOptions
|
|
193
|
-
if (opts && opts.parentNode
|
|
194
|
-
|
|
218
|
+
if (opts && opts.parentNode && this.$el && !this.$el.contains(opts)) {
|
|
219
|
+
opts.parentNode.removeChild(opts)
|
|
195
220
|
}
|
|
196
221
|
},
|
|
197
222
|
anchorEl() {
|
|
198
223
|
return this.$refs.taggableInput?.$el || this.$refs.input?.parentElement
|
|
199
224
|
},
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
overlayAncestor(anchor = this.anchorEl()) {
|
|
226
|
+
return anchor?.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l, .vl-sidebar-r') || null
|
|
227
|
+
},
|
|
228
|
+
floatingContext(anchor = this.anchorEl()) {
|
|
229
|
+
if (!anchor || typeof document === 'undefined') return null
|
|
230
|
+
|
|
231
|
+
const drawerOrSidebar = anchor.closest('.kompoDrawer, .vl-sidebar-l, .vl-sidebar-r')
|
|
232
|
+
if (drawerOrSidebar && typeof window !== 'undefined') {
|
|
233
|
+
const position = window.getComputedStyle(drawerOrSidebar).position
|
|
234
|
+
if (position && position !== 'static') {
|
|
235
|
+
return {
|
|
236
|
+
root: drawerOrSidebar,
|
|
237
|
+
strategy: 'absolute',
|
|
238
|
+
zIndex: 5001,
|
|
239
|
+
}
|
|
240
|
+
}
|
|
211
241
|
}
|
|
212
|
-
this._onResize = () => this.refresh()
|
|
213
|
-
window.addEventListener('scroll', this._onScroll, true)
|
|
214
|
-
window.addEventListener('resize', this._onResize, { passive: true })
|
|
215
242
|
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.trackPosition()
|
|
222
|
-
})
|
|
243
|
+
if (this.overlayAncestor(anchor)) {
|
|
244
|
+
return {
|
|
245
|
+
root: document.body,
|
|
246
|
+
strategy: 'fixed',
|
|
247
|
+
zIndex: 5001,
|
|
223
248
|
}
|
|
224
|
-
this._onViewportResize = () => this.refresh()
|
|
225
|
-
window.visualViewport.addEventListener('scroll', this._onViewportScroll)
|
|
226
|
-
window.visualViewport.addEventListener('resize', this._onViewportResize)
|
|
227
249
|
}
|
|
228
250
|
|
|
229
|
-
|
|
251
|
+
return {
|
|
252
|
+
root: document.body,
|
|
253
|
+
strategy: 'absolute',
|
|
254
|
+
zIndex: 1000,
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
attachListeners() {
|
|
258
|
+
if (this._listenersAttached) return
|
|
230
259
|
const anchor = this.anchorEl()
|
|
231
260
|
if (typeof ResizeObserver !== 'undefined') {
|
|
232
|
-
this._panelObserver = new ResizeObserver(() => {
|
|
233
|
-
if (this.isFocused) this.trackPosition()
|
|
234
|
-
})
|
|
235
|
-
if (opts) this._panelObserver.observe(opts)
|
|
236
261
|
this._anchorObserver = new ResizeObserver((entries) => {
|
|
237
262
|
const entry = entries[0]
|
|
238
263
|
if (!entry) return
|
|
@@ -244,105 +269,157 @@ export default {
|
|
|
244
269
|
})
|
|
245
270
|
if (anchor) this._anchorObserver.observe(anchor)
|
|
246
271
|
}
|
|
247
|
-
const inOverlay = !!(anchor && anchor.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l'))
|
|
248
|
-
if (inOverlay && typeof IntersectionObserver !== 'undefined' && anchor) {
|
|
249
|
-
let intersectionInitialised = false
|
|
250
|
-
this._anchorIntersection = new IntersectionObserver((entries) => {
|
|
251
|
-
const entry = entries[entries.length - 1]
|
|
252
|
-
if (!entry) return
|
|
253
|
-
if (!intersectionInitialised) {
|
|
254
|
-
intersectionInitialised = true
|
|
255
|
-
return
|
|
256
|
-
}
|
|
257
|
-
if (entry.intersectionRatio === 0) this.blur()
|
|
258
|
-
}, { threshold: 0 })
|
|
259
|
-
this._anchorIntersection.observe(anchor)
|
|
260
|
-
}
|
|
261
|
-
|
|
262
272
|
this._listenersAttached = true
|
|
263
273
|
},
|
|
264
274
|
detachListeners() {
|
|
265
275
|
if (!this._listenersAttached) return
|
|
266
|
-
|
|
267
|
-
cancelAnimationFrame(this._rafId)
|
|
268
|
-
this._rafId = null
|
|
269
|
-
}
|
|
270
|
-
window.removeEventListener('scroll', this._onScroll, true)
|
|
271
|
-
window.removeEventListener('resize', this._onResize)
|
|
272
|
-
if (window.visualViewport) {
|
|
273
|
-
if (this._onViewportScroll) {
|
|
274
|
-
window.visualViewport.removeEventListener('scroll', this._onViewportScroll)
|
|
275
|
-
this._onViewportScroll = null
|
|
276
|
-
}
|
|
277
|
-
if (this._onViewportResize) {
|
|
278
|
-
window.visualViewport.removeEventListener('resize', this._onViewportResize)
|
|
279
|
-
this._onViewportResize = null
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (this._panelObserver) {
|
|
283
|
-
this._panelObserver.disconnect()
|
|
284
|
-
this._panelObserver = null
|
|
285
|
-
}
|
|
276
|
+
this.stopPositioning()
|
|
286
277
|
if (this._anchorObserver) {
|
|
287
278
|
this._anchorObserver.disconnect()
|
|
288
279
|
this._anchorObserver = null
|
|
289
280
|
}
|
|
290
|
-
if (this._anchorIntersection) {
|
|
291
|
-
this._anchorIntersection.disconnect()
|
|
292
|
-
this._anchorIntersection = null
|
|
293
|
-
}
|
|
294
281
|
this._listenersAttached = false
|
|
295
282
|
},
|
|
296
|
-
|
|
283
|
+
startPositioning() {
|
|
297
284
|
const opts = this.$refs.selectOptions
|
|
298
285
|
const anchor = this.anchorEl()
|
|
299
|
-
if (!opts || !anchor) return
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
opts.style.
|
|
286
|
+
if (!opts || !anchor || !this.isFocused) return
|
|
287
|
+
|
|
288
|
+
this.stopPositioning()
|
|
289
|
+
this.teleportOptions(anchor)
|
|
290
|
+
const context = this.floatingContext(anchor)
|
|
291
|
+
if (!context) return
|
|
292
|
+
this.applyBasePanelStyles(opts, anchor, context)
|
|
293
|
+
opts.style.visibility = 'hidden'
|
|
294
|
+
opts.style.transform = 'translate3d(0px, 0px, 0)'
|
|
295
|
+
|
|
296
|
+
const updatePosition = () => this.queuePositionUpdate()
|
|
297
|
+
this._autoUpdateCleanup = autoUpdate(anchor, opts, updatePosition, {
|
|
298
|
+
ancestorScroll: true,
|
|
299
|
+
ancestorResize: true,
|
|
300
|
+
elementResize: true,
|
|
301
|
+
layoutShift: true,
|
|
302
|
+
animationFrame: true,
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
this.queuePositionUpdate(true)
|
|
306
|
+
},
|
|
307
|
+
stopPositioning() {
|
|
308
|
+
if (this._positionRafId) {
|
|
309
|
+
cancelAnimationFrame(this._positionRafId)
|
|
310
|
+
this._positionRafId = null
|
|
311
|
+
}
|
|
312
|
+
this._positionVersion = (this._positionVersion || 0) + 1
|
|
313
|
+
if (!this._autoUpdateCleanup) return
|
|
314
|
+
this._autoUpdateCleanup()
|
|
315
|
+
this._autoUpdateCleanup = null
|
|
316
|
+
},
|
|
317
|
+
applyBasePanelStyles(opts, anchor, context = this.floatingContext(anchor)) {
|
|
318
|
+
if (!context) return
|
|
319
|
+
|
|
320
|
+
opts.style.position = context.strategy
|
|
321
|
+
opts.style.top = '0px'
|
|
322
|
+
opts.style.left = '0px'
|
|
323
|
+
opts.style.bottom = 'auto'
|
|
324
|
+
opts.style.width = Math.round(anchor.getBoundingClientRect().width) + 'px'
|
|
325
|
+
opts.style.maxHeight = '240px'
|
|
326
|
+
opts.style.zIndex = String(context.zIndex)
|
|
327
|
+
opts.style.willChange = 'transform'
|
|
328
|
+
},
|
|
329
|
+
resetPanelStyles() {
|
|
330
|
+
const opts = this.$refs.selectOptions
|
|
331
|
+
if (!opts) return
|
|
332
|
+
|
|
333
|
+
opts.style.position = ''
|
|
334
|
+
opts.style.top = ''
|
|
335
|
+
opts.style.left = ''
|
|
336
|
+
opts.style.bottom = ''
|
|
337
|
+
opts.style.transform = ''
|
|
338
|
+
opts.style.width = ''
|
|
339
|
+
opts.style.maxHeight = ''
|
|
340
|
+
opts.style.zIndex = ''
|
|
341
|
+
opts.style.willChange = ''
|
|
342
|
+
opts.style.visibility = ''
|
|
343
|
+
opts.style.borderRadius = ''
|
|
307
344
|
},
|
|
308
|
-
|
|
345
|
+
queuePositionUpdate(immediate = false) {
|
|
346
|
+
if (!this.isFocused) return
|
|
347
|
+
if (immediate) {
|
|
348
|
+
if (this._positionRafId) {
|
|
349
|
+
cancelAnimationFrame(this._positionRafId)
|
|
350
|
+
this._positionRafId = null
|
|
351
|
+
}
|
|
352
|
+
this.updatePosition()
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
if (this._positionRafId) return
|
|
356
|
+
this._positionRafId = requestAnimationFrame(() => {
|
|
357
|
+
this._positionRafId = null
|
|
358
|
+
this.updatePosition()
|
|
359
|
+
})
|
|
360
|
+
},
|
|
361
|
+
placementConfig() {
|
|
362
|
+
if (this.forceUp) return { placement: 'top-start', auto: false }
|
|
363
|
+
if (this.forceDown) return { placement: 'bottom-start', auto: false }
|
|
364
|
+
return { placement: 'bottom-start', auto: true }
|
|
365
|
+
},
|
|
366
|
+
updatePosition() {
|
|
309
367
|
const opts = this.$refs.selectOptions
|
|
310
368
|
const anchor = this.anchorEl()
|
|
311
|
-
if (!opts || !anchor) return
|
|
369
|
+
if (!opts || !anchor || !this.isFocused) return
|
|
370
|
+
|
|
371
|
+
const floatingEl = opts
|
|
372
|
+
const referenceEl = anchor
|
|
373
|
+
const positionVersion = this._positionVersion || 0
|
|
374
|
+
const { placement, auto } = this.placementConfig()
|
|
375
|
+
const context = this.floatingContext(referenceEl)
|
|
376
|
+
if (!context) return
|
|
312
377
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
position: 'fixed',
|
|
319
|
-
top: '0px',
|
|
320
|
-
left: '0px',
|
|
321
|
-
bottom: 'auto',
|
|
322
|
-
width: Math.round(rect.width) + 'px',
|
|
323
|
-
zIndex: inOverlay ? 5001 : 1000,
|
|
324
|
-
transform: `translate3d(${x}px, ${yBelow}px, 0)`,
|
|
325
|
-
willChange: 'transform',
|
|
378
|
+
if (floatingEl.parentNode !== context.root) {
|
|
379
|
+
this.$nextTick(() => {
|
|
380
|
+
if (this.isFocused) this.startPositioning()
|
|
381
|
+
})
|
|
382
|
+
return
|
|
326
383
|
}
|
|
327
|
-
this.panelStyle = baseStyle
|
|
328
384
|
|
|
329
|
-
this
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
385
|
+
this.applyBasePanelStyles(floatingEl, referenceEl, context)
|
|
386
|
+
|
|
387
|
+
const middleware = [
|
|
388
|
+
offset(-1),
|
|
389
|
+
...(auto ? [flip({ fallbackPlacements: ['top-start'], padding: 8 })] : []),
|
|
390
|
+
shift({ padding: 8, crossAxis: true }),
|
|
391
|
+
size({
|
|
392
|
+
padding: 8,
|
|
393
|
+
apply: ({ availableHeight, rects, elements }) => {
|
|
394
|
+
const maxHeight = Math.max(0, Math.min(240, Math.floor(availableHeight)))
|
|
395
|
+
elements.floating.style.width = Math.round(rects.reference.width) + 'px'
|
|
396
|
+
elements.floating.style.maxHeight = maxHeight + 'px'
|
|
397
|
+
},
|
|
398
|
+
}),
|
|
399
|
+
hide(),
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
computePosition(referenceEl, floatingEl, {
|
|
403
|
+
strategy: context.strategy,
|
|
404
|
+
placement,
|
|
405
|
+
middleware,
|
|
406
|
+
}).then(({ x, y, placement, middlewareData }) => {
|
|
407
|
+
if (positionVersion !== (this._positionVersion || 0)) return
|
|
408
|
+
if (!this.isFocused) return
|
|
409
|
+
if (floatingEl !== this.$refs.selectOptions || referenceEl !== this.anchorEl()) {
|
|
410
|
+
this.$nextTick(() => {
|
|
411
|
+
if (this.isFocused) this.startPositioning()
|
|
412
|
+
})
|
|
413
|
+
return
|
|
345
414
|
}
|
|
415
|
+
|
|
416
|
+
const hidden = middlewareData.hide?.referenceHidden || middlewareData.hide?.escaped
|
|
417
|
+
const flipsUp = placement.startsWith('top')
|
|
418
|
+
|
|
419
|
+
this.flipUp = flipsUp
|
|
420
|
+
floatingEl.style.transform = `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`
|
|
421
|
+
floatingEl.style.borderRadius = flipsUp ? '5px 5px 0 0' : '0 0 5px 5px'
|
|
422
|
+
floatingEl.style.visibility = hidden ? 'hidden' : 'visible'
|
|
346
423
|
})
|
|
347
424
|
},
|
|
348
425
|
},
|