js-kompo-utils 1.0.24 → 1.0.26
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 +124 -12
- package/package.json +1 -1
package/components/VlSelect.vue
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
class="vlNativeSelect"
|
|
28
28
|
:value="nativeValue"
|
|
29
29
|
@change="onNativeChange"
|
|
30
|
+
@mousedown="onNativeOpen"
|
|
31
|
+
@focus="onNativeOpen"
|
|
30
32
|
:style="nativeSelectStyle">
|
|
31
33
|
<option value="">{{ nativePlaceholder }}</option>
|
|
32
|
-
<option v-for="opt in
|
|
34
|
+
<option v-for="opt in nativeOptionsList" :key="opt.value" :value="opt.value">{{ nativeLabel(opt) }}</option>
|
|
33
35
|
</select>
|
|
34
36
|
</div>
|
|
35
37
|
<div class="vlOptions vlOptionsTeleported"
|
|
@@ -86,7 +88,10 @@ export default {
|
|
|
86
88
|
},
|
|
87
89
|
useNativeMobile() {
|
|
88
90
|
if (!this.$_config('native_on_mobile')) return false
|
|
89
|
-
return this.isTouchDevice && !this.$_multiple
|
|
91
|
+
return this.isTouchDevice && !this.$_multiple
|
|
92
|
+
},
|
|
93
|
+
nativeOptionsList() {
|
|
94
|
+
return this.ajaxOptions ? this.filteredOptions : this.options
|
|
90
95
|
},
|
|
91
96
|
nativeValue() {
|
|
92
97
|
return this.$_value && this.$_value.length ? this.$_value[0].value : ''
|
|
@@ -121,12 +126,25 @@ export default {
|
|
|
121
126
|
filteredOptions() {
|
|
122
127
|
if (this.isFocused) this.$nextTick(() => this.refresh())
|
|
123
128
|
},
|
|
129
|
+
optionsKey() {
|
|
130
|
+
this.$nextTick(() => {
|
|
131
|
+
this.teleportOptions()
|
|
132
|
+
if (this._panelObserver && this.$refs.selectOptions) {
|
|
133
|
+
this._panelObserver.disconnect()
|
|
134
|
+
this._panelObserver.observe(this.$refs.selectOptions)
|
|
135
|
+
}
|
|
136
|
+
if (this.isFocused) this.refresh()
|
|
137
|
+
})
|
|
138
|
+
},
|
|
124
139
|
},
|
|
125
140
|
mounted() {
|
|
126
141
|
this.teleportOptions()
|
|
127
142
|
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
128
143
|
this.isTouchDevice = window.matchMedia('(pointer: coarse)').matches
|
|
129
144
|
}
|
|
145
|
+
if (this.useNativeMobile && this.ajaxOptions) {
|
|
146
|
+
this.$nextTick(() => this.onNativeOpen())
|
|
147
|
+
}
|
|
130
148
|
},
|
|
131
149
|
beforeDestroy() {
|
|
132
150
|
this.cleanupOptions()
|
|
@@ -136,9 +154,19 @@ export default {
|
|
|
136
154
|
onNativeChange(e) {
|
|
137
155
|
const v = e.target.value
|
|
138
156
|
if (v === '') return
|
|
139
|
-
const
|
|
157
|
+
const list = this.nativeOptionsList || []
|
|
158
|
+
const opt = list.find(o => String(o.value) === String(v))
|
|
140
159
|
if (opt) this.select(opt)
|
|
141
160
|
},
|
|
161
|
+
onNativeOpen() {
|
|
162
|
+
if (!this.ajaxOptions) return
|
|
163
|
+
if (this.ajaxOptionsFromField) {
|
|
164
|
+
this.$kompo.vlRequestFieldValue(this.kompoid, this.ajaxOptionsFromField, this.$_elKompoId)
|
|
165
|
+
this.performAjax(this.$_getFromStore())
|
|
166
|
+
} else {
|
|
167
|
+
this.performAjax('')
|
|
168
|
+
}
|
|
169
|
+
},
|
|
142
170
|
nativeLabel(opt) {
|
|
143
171
|
const l = opt.label
|
|
144
172
|
let raw = ''
|
|
@@ -171,22 +199,99 @@ export default {
|
|
|
171
199
|
},
|
|
172
200
|
attachListeners() {
|
|
173
201
|
if (this._listenersAttached) return
|
|
202
|
+
this._rafId = null
|
|
174
203
|
this._onScroll = (e) => {
|
|
175
204
|
const opts = this.$refs.selectOptions
|
|
176
205
|
if (opts && e.target instanceof Node && opts.contains(e.target)) return
|
|
177
|
-
this.
|
|
206
|
+
if (this._rafId) return
|
|
207
|
+
this._rafId = requestAnimationFrame(() => {
|
|
208
|
+
this._rafId = null
|
|
209
|
+
this.trackPosition()
|
|
210
|
+
})
|
|
178
211
|
}
|
|
179
212
|
this._onResize = () => this.refresh()
|
|
180
213
|
window.addEventListener('scroll', this._onScroll, true)
|
|
181
214
|
window.addEventListener('resize', this._onResize, { passive: true })
|
|
215
|
+
|
|
216
|
+
if (window.visualViewport) {
|
|
217
|
+
this._onViewportChange = () => {
|
|
218
|
+
if (this._rafId) return
|
|
219
|
+
this._rafId = requestAnimationFrame(() => {
|
|
220
|
+
this._rafId = null
|
|
221
|
+
this.refresh()
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
window.visualViewport.addEventListener('resize', this._onViewportChange)
|
|
225
|
+
window.visualViewport.addEventListener('scroll', this._onViewportChange)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const opts = this.$refs.selectOptions
|
|
229
|
+
const anchor = this.anchorEl()
|
|
230
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
231
|
+
this._panelObserver = new ResizeObserver(() => {
|
|
232
|
+
if (this.isFocused) this.trackPosition()
|
|
233
|
+
})
|
|
234
|
+
if (opts) this._panelObserver.observe(opts)
|
|
235
|
+
this._anchorObserver = new ResizeObserver((entries) => {
|
|
236
|
+
const entry = entries[0]
|
|
237
|
+
if (!entry) return
|
|
238
|
+
const r = entry.contentRect
|
|
239
|
+
const el = entry.target
|
|
240
|
+
if (r.width === 0 || r.height === 0 || !el.isConnected) {
|
|
241
|
+
this.blur()
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
if (anchor) this._anchorObserver.observe(anchor)
|
|
245
|
+
}
|
|
246
|
+
if (typeof IntersectionObserver !== 'undefined' && anchor) {
|
|
247
|
+
this._anchorIntersection = new IntersectionObserver((entries) => {
|
|
248
|
+
const entry = entries[entries.length - 1]
|
|
249
|
+
if (entry && entry.intersectionRatio === 0) this.blur()
|
|
250
|
+
}, { threshold: 0 })
|
|
251
|
+
this._anchorIntersection.observe(anchor)
|
|
252
|
+
}
|
|
253
|
+
|
|
182
254
|
this._listenersAttached = true
|
|
183
255
|
},
|
|
184
256
|
detachListeners() {
|
|
185
257
|
if (!this._listenersAttached) return
|
|
258
|
+
if (this._rafId) {
|
|
259
|
+
cancelAnimationFrame(this._rafId)
|
|
260
|
+
this._rafId = null
|
|
261
|
+
}
|
|
186
262
|
window.removeEventListener('scroll', this._onScroll, true)
|
|
187
263
|
window.removeEventListener('resize', this._onResize)
|
|
264
|
+
if (this._onViewportChange && window.visualViewport) {
|
|
265
|
+
window.visualViewport.removeEventListener('resize', this._onViewportChange)
|
|
266
|
+
window.visualViewport.removeEventListener('scroll', this._onViewportChange)
|
|
267
|
+
this._onViewportChange = null
|
|
268
|
+
}
|
|
269
|
+
if (this._panelObserver) {
|
|
270
|
+
this._panelObserver.disconnect()
|
|
271
|
+
this._panelObserver = null
|
|
272
|
+
}
|
|
273
|
+
if (this._anchorObserver) {
|
|
274
|
+
this._anchorObserver.disconnect()
|
|
275
|
+
this._anchorObserver = null
|
|
276
|
+
}
|
|
277
|
+
if (this._anchorIntersection) {
|
|
278
|
+
this._anchorIntersection.disconnect()
|
|
279
|
+
this._anchorIntersection = null
|
|
280
|
+
}
|
|
188
281
|
this._listenersAttached = false
|
|
189
282
|
},
|
|
283
|
+
trackPosition() {
|
|
284
|
+
const opts = this.$refs.selectOptions
|
|
285
|
+
const anchor = this.anchorEl()
|
|
286
|
+
if (!opts || !anchor) return
|
|
287
|
+
const rect = anchor.getBoundingClientRect()
|
|
288
|
+
const x = Math.round(rect.left)
|
|
289
|
+
const y = this.flipUp
|
|
290
|
+
? Math.round(rect.top) - opts.offsetHeight + 1
|
|
291
|
+
: Math.round(rect.bottom) - 1
|
|
292
|
+
opts.style.transform = `translate3d(${x}px, ${y}px, 0)`
|
|
293
|
+
opts.style.width = Math.round(rect.width) + 'px'
|
|
294
|
+
},
|
|
190
295
|
refresh() {
|
|
191
296
|
const opts = this.$refs.selectOptions
|
|
192
297
|
const anchor = this.anchorEl()
|
|
@@ -194,27 +299,34 @@ export default {
|
|
|
194
299
|
|
|
195
300
|
const rect = anchor.getBoundingClientRect()
|
|
196
301
|
const inOverlay = !!anchor.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l')
|
|
302
|
+
const x = Math.round(rect.left)
|
|
303
|
+
const yBelow = Math.round(rect.bottom) - 1
|
|
197
304
|
const baseStyle = {
|
|
198
305
|
position: 'fixed',
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
zIndex: inOverlay ? 5001 : 1000,
|
|
202
|
-
top: rect.bottom + 'px',
|
|
306
|
+
top: '0px',
|
|
307
|
+
left: '0px',
|
|
203
308
|
bottom: 'auto',
|
|
309
|
+
width: Math.round(rect.width) + 'px',
|
|
310
|
+
zIndex: inOverlay ? 5001 : 1000,
|
|
311
|
+
transform: `translate3d(${x}px, ${yBelow}px, 0)`,
|
|
312
|
+
willChange: 'transform',
|
|
204
313
|
}
|
|
205
314
|
this.panelStyle = baseStyle
|
|
206
315
|
|
|
207
316
|
this.$nextTick(() => {
|
|
208
317
|
const optsHeight = opts.offsetHeight
|
|
209
|
-
const
|
|
210
|
-
const
|
|
318
|
+
const vv = window.visualViewport
|
|
319
|
+
const viewportHeight = vv ? vv.height : window.innerHeight
|
|
320
|
+
const viewportTop = vv ? vv.offsetTop : 0
|
|
321
|
+
const spaceBelow = (viewportTop + viewportHeight) - rect.bottom
|
|
322
|
+
const spaceAbove = rect.top - viewportTop
|
|
211
323
|
const shouldFlip = this.forceUp || (spaceBelow < optsHeight && spaceAbove > spaceBelow)
|
|
212
324
|
this.flipUp = shouldFlip
|
|
213
325
|
if (shouldFlip) {
|
|
326
|
+
const yAbove = Math.round(rect.top) - optsHeight + 1
|
|
214
327
|
this.panelStyle = {
|
|
215
328
|
...baseStyle,
|
|
216
|
-
|
|
217
|
-
bottom: (window.innerHeight - rect.top) + 'px',
|
|
329
|
+
transform: `translate3d(${x}px, ${yAbove}px, 0)`,
|
|
218
330
|
borderRadius: '5px 5px 0 0',
|
|
219
331
|
}
|
|
220
332
|
}
|