js-kompo-utils 1.0.24 → 1.0.25

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,21 @@ 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.isFocused) this.refresh()
133
+ })
134
+ },
124
135
  },
125
136
  mounted() {
126
137
  this.teleportOptions()
127
138
  if (typeof window !== 'undefined' && window.matchMedia) {
128
139
  this.isTouchDevice = window.matchMedia('(pointer: coarse)').matches
129
140
  }
141
+ if (this.useNativeMobile && this.ajaxOptions) {
142
+ this.$nextTick(() => this.onNativeOpen())
143
+ }
130
144
  },
131
145
  beforeDestroy() {
132
146
  this.cleanupOptions()
@@ -136,9 +150,19 @@ export default {
136
150
  onNativeChange(e) {
137
151
  const v = e.target.value
138
152
  if (v === '') return
139
- const opt = this.options.find(o => String(o.value) === String(v))
153
+ const list = this.nativeOptionsList || []
154
+ const opt = list.find(o => String(o.value) === String(v))
140
155
  if (opt) this.select(opt)
141
156
  },
157
+ onNativeOpen() {
158
+ if (!this.ajaxOptions) return
159
+ if (this.ajaxOptionsFromField) {
160
+ this.$kompo.vlRequestFieldValue(this.kompoid, this.ajaxOptionsFromField, this.$_elKompoId)
161
+ this.performAjax(this.$_getFromStore())
162
+ } else {
163
+ this.performAjax('')
164
+ }
165
+ },
142
166
  nativeLabel(opt) {
143
167
  const l = opt.label
144
168
  let raw = ''
@@ -171,22 +195,82 @@ export default {
171
195
  },
172
196
  attachListeners() {
173
197
  if (this._listenersAttached) return
198
+ this._rafId = null
174
199
  this._onScroll = (e) => {
175
200
  const opts = this.$refs.selectOptions
176
201
  if (opts && e.target instanceof Node && opts.contains(e.target)) return
177
- this.blur()
202
+ if (this._rafId) return
203
+ this._rafId = requestAnimationFrame(() => {
204
+ this._rafId = null
205
+ this.trackPosition()
206
+ })
178
207
  }
179
208
  this._onResize = () => this.refresh()
180
209
  window.addEventListener('scroll', this._onScroll, true)
181
210
  window.addEventListener('resize', this._onResize, { passive: true })
211
+
212
+ const opts = this.$refs.selectOptions
213
+ const anchor = this.anchorEl()
214
+ if (typeof ResizeObserver !== 'undefined') {
215
+ this._panelObserver = new ResizeObserver(() => {
216
+ if (this.isFocused) this.trackPosition()
217
+ })
218
+ if (opts) this._panelObserver.observe(opts)
219
+ this._anchorObserver = new ResizeObserver((entries) => {
220
+ const entry = entries[0]
221
+ if (!entry) return
222
+ const r = entry.contentRect
223
+ const el = entry.target
224
+ if (r.width === 0 || r.height === 0 || !el.isConnected) {
225
+ this.blur()
226
+ }
227
+ })
228
+ if (anchor) this._anchorObserver.observe(anchor)
229
+ }
230
+ if (typeof IntersectionObserver !== 'undefined' && anchor) {
231
+ this._anchorIntersection = new IntersectionObserver((entries) => {
232
+ const entry = entries[entries.length - 1]
233
+ if (entry && entry.intersectionRatio === 0) this.blur()
234
+ }, { threshold: 0 })
235
+ this._anchorIntersection.observe(anchor)
236
+ }
237
+
182
238
  this._listenersAttached = true
183
239
  },
184
240
  detachListeners() {
185
241
  if (!this._listenersAttached) return
242
+ if (this._rafId) {
243
+ cancelAnimationFrame(this._rafId)
244
+ this._rafId = null
245
+ }
186
246
  window.removeEventListener('scroll', this._onScroll, true)
187
247
  window.removeEventListener('resize', this._onResize)
248
+ if (this._panelObserver) {
249
+ this._panelObserver.disconnect()
250
+ this._panelObserver = null
251
+ }
252
+ if (this._anchorObserver) {
253
+ this._anchorObserver.disconnect()
254
+ this._anchorObserver = null
255
+ }
256
+ if (this._anchorIntersection) {
257
+ this._anchorIntersection.disconnect()
258
+ this._anchorIntersection = null
259
+ }
188
260
  this._listenersAttached = false
189
261
  },
262
+ trackPosition() {
263
+ const opts = this.$refs.selectOptions
264
+ const anchor = this.anchorEl()
265
+ if (!opts || !anchor) return
266
+ const rect = anchor.getBoundingClientRect()
267
+ const x = Math.round(rect.left)
268
+ const y = this.flipUp
269
+ ? Math.round(rect.top) - opts.offsetHeight + 1
270
+ : Math.round(rect.bottom) - 1
271
+ opts.style.transform = `translate3d(${x}px, ${y}px, 0)`
272
+ opts.style.width = Math.round(rect.width) + 'px'
273
+ },
190
274
  refresh() {
191
275
  const opts = this.$refs.selectOptions
192
276
  const anchor = this.anchorEl()
@@ -194,13 +278,17 @@ export default {
194
278
 
195
279
  const rect = anchor.getBoundingClientRect()
196
280
  const inOverlay = !!anchor.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l')
281
+ const x = Math.round(rect.left)
282
+ const yBelow = Math.round(rect.bottom) - 1
197
283
  const baseStyle = {
198
284
  position: 'fixed',
199
- left: rect.left + 'px',
200
- width: rect.width + 'px',
201
- zIndex: inOverlay ? 5001 : 1000,
202
- top: rect.bottom + 'px',
285
+ top: '0px',
286
+ left: '0px',
203
287
  bottom: 'auto',
288
+ width: Math.round(rect.width) + 'px',
289
+ zIndex: inOverlay ? 5001 : 1000,
290
+ transform: `translate3d(${x}px, ${yBelow}px, 0)`,
291
+ willChange: 'transform',
204
292
  }
205
293
  this.panelStyle = baseStyle
206
294
 
@@ -211,10 +299,10 @@ export default {
211
299
  const shouldFlip = this.forceUp || (spaceBelow < optsHeight && spaceAbove > spaceBelow)
212
300
  this.flipUp = shouldFlip
213
301
  if (shouldFlip) {
302
+ const yAbove = Math.round(rect.top) - optsHeight + 1
214
303
  this.panelStyle = {
215
304
  ...baseStyle,
216
- top: 'auto',
217
- bottom: (window.innerHeight - rect.top) + 'px',
305
+ transform: `translate3d(${x}px, ${yAbove}px, 0)`,
218
306
  borderRadius: '5px 5px 0 0',
219
307
  }
220
308
  }
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.25",
4
4
  "description": "",
5
5
  "main": "app.js",
6
6
  "scripts": {