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.
@@ -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 options" :key="opt.value" :value="opt.value">{{ nativeLabel(opt) }}</option>
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 && !this.ajaxOptions
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 opt = this.options.find(o => String(o.value) === String(v))
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.blur()
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
- left: rect.left + 'px',
200
- width: rect.width + 'px',
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 spaceBelow = window.innerHeight - rect.bottom
210
- const spaceAbove = rect.top
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
- top: 'auto',
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-kompo-utils",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "",
5
5
  "main": "app.js",
6
6
  "scripts": {