quasar 1.18.8 → 1.19.0

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.
Files changed (149) hide show
  1. package/dist/api/QDialog.json +12 -1
  2. package/dist/api/QVideo.json +40 -0
  3. package/dist/icon-set/bootstrap-icons.umd.min.js +1 -1
  4. package/dist/icon-set/eva-icons.umd.min.js +1 -1
  5. package/dist/icon-set/fontawesome-v5-pro.umd.min.js +1 -1
  6. package/dist/icon-set/fontawesome-v5.umd.min.js +1 -1
  7. package/dist/icon-set/fontawesome-v6-pro.umd.min.js +1 -1
  8. package/dist/icon-set/fontawesome-v6.umd.min.js +1 -1
  9. package/dist/icon-set/ionicons-v4.umd.min.js +1 -1
  10. package/dist/icon-set/line-awesome.umd.min.js +1 -1
  11. package/dist/icon-set/material-icons-outlined.umd.min.js +1 -1
  12. package/dist/icon-set/material-icons-round.umd.min.js +1 -1
  13. package/dist/icon-set/material-icons-sharp.umd.min.js +1 -1
  14. package/dist/icon-set/material-icons.umd.min.js +1 -1
  15. package/dist/icon-set/material-symbols-outlined.umd.min.js +6 -0
  16. package/dist/icon-set/material-symbols-rounded.umd.min.js +6 -0
  17. package/dist/icon-set/material-symbols-sharp.umd.min.js +6 -0
  18. package/dist/icon-set/mdi-v3.umd.min.js +1 -1
  19. package/dist/icon-set/mdi-v4.umd.min.js +1 -1
  20. package/dist/icon-set/mdi-v5.umd.min.js +1 -1
  21. package/dist/icon-set/mdi-v6.umd.min.js +1 -1
  22. package/dist/icon-set/svg-bootstrap-icons.umd.min.js +1 -1
  23. package/dist/icon-set/svg-eva-icons.umd.min.js +1 -1
  24. package/dist/icon-set/svg-fontawesome-v5.umd.min.js +1 -1
  25. package/dist/icon-set/svg-fontawesome-v6.umd.min.js +1 -1
  26. package/dist/icon-set/svg-ionicons-v4.umd.min.js +1 -1
  27. package/dist/icon-set/svg-ionicons-v5.umd.min.js +1 -1
  28. package/dist/icon-set/svg-ionicons-v6.umd.min.js +1 -1
  29. package/dist/icon-set/svg-line-awesome.umd.min.js +1 -1
  30. package/dist/icon-set/svg-material-icons-outlined.umd.min.js +1 -1
  31. package/dist/icon-set/svg-material-icons-round.umd.min.js +1 -1
  32. package/dist/icon-set/svg-material-icons-sharp.umd.min.js +1 -1
  33. package/dist/icon-set/svg-material-icons.umd.min.js +1 -1
  34. package/dist/icon-set/svg-material-symbols-outlined.umd.min.js +6 -0
  35. package/dist/icon-set/svg-material-symbols-rounded.umd.min.js +6 -0
  36. package/dist/icon-set/svg-material-symbols-sharp.umd.min.js +6 -0
  37. package/dist/icon-set/svg-mdi-v4.umd.min.js +1 -1
  38. package/dist/icon-set/svg-mdi-v5.umd.min.js +1 -1
  39. package/dist/icon-set/svg-mdi-v6.umd.min.js +1 -1
  40. package/dist/icon-set/svg-themify.umd.min.js +1 -1
  41. package/dist/icon-set/themify.umd.min.js +1 -1
  42. package/dist/lang/ar.umd.min.js +1 -1
  43. package/dist/lang/az-latn.umd.min.js +1 -1
  44. package/dist/lang/bg.umd.min.js +1 -1
  45. package/dist/lang/ca.umd.min.js +1 -1
  46. package/dist/lang/cs.umd.min.js +1 -1
  47. package/dist/lang/da.umd.min.js +1 -1
  48. package/dist/lang/de.umd.min.js +1 -1
  49. package/dist/lang/el.umd.min.js +1 -1
  50. package/dist/lang/en-gb.umd.min.js +1 -1
  51. package/dist/lang/en-us.umd.min.js +1 -1
  52. package/dist/lang/eo.umd.min.js +1 -1
  53. package/dist/lang/es.umd.min.js +1 -1
  54. package/dist/lang/et.umd.min.js +1 -1
  55. package/dist/lang/eu.umd.min.js +1 -1
  56. package/dist/lang/fa-ir.umd.min.js +1 -1
  57. package/dist/lang/fa.umd.min.js +1 -1
  58. package/dist/lang/fi.umd.min.js +1 -1
  59. package/dist/lang/fr.umd.min.js +1 -1
  60. package/dist/lang/gn.umd.min.js +1 -1
  61. package/dist/lang/he.umd.min.js +1 -1
  62. package/dist/lang/hr.umd.min.js +1 -1
  63. package/dist/lang/hu.umd.min.js +1 -1
  64. package/dist/lang/id.umd.min.js +1 -1
  65. package/dist/lang/is.umd.min.js +1 -1
  66. package/dist/lang/it.umd.min.js +1 -1
  67. package/dist/lang/ja.umd.min.js +1 -1
  68. package/dist/lang/km.umd.min.js +1 -1
  69. package/dist/lang/ko-kr.umd.min.js +1 -1
  70. package/dist/lang/kur-ckb.umd.min.js +1 -1
  71. package/dist/lang/kz.umd.min.js +1 -1
  72. package/dist/lang/lu.umd.min.js +1 -1
  73. package/dist/lang/lv.umd.min.js +1 -1
  74. package/dist/lang/ml.umd.min.js +1 -1
  75. package/dist/lang/mm.umd.min.js +6 -0
  76. package/dist/lang/ms.umd.min.js +1 -1
  77. package/dist/lang/my.umd.min.js +1 -1
  78. package/dist/lang/nb-no.umd.min.js +1 -1
  79. package/dist/lang/nl.umd.min.js +1 -1
  80. package/dist/lang/pl.umd.min.js +1 -1
  81. package/dist/lang/pt-br.umd.min.js +1 -1
  82. package/dist/lang/pt.umd.min.js +1 -1
  83. package/dist/lang/ro.umd.min.js +1 -1
  84. package/dist/lang/ru.umd.min.js +1 -1
  85. package/dist/lang/sk.umd.min.js +1 -1
  86. package/dist/lang/sl.umd.min.js +1 -1
  87. package/dist/lang/sr.umd.min.js +1 -1
  88. package/dist/lang/sv.umd.min.js +1 -1
  89. package/dist/lang/ta.umd.min.js +1 -1
  90. package/dist/lang/th.umd.min.js +1 -1
  91. package/dist/lang/tr.umd.min.js +1 -1
  92. package/dist/lang/ug.umd.min.js +1 -1
  93. package/dist/lang/uk.umd.min.js +1 -1
  94. package/dist/lang/vi.umd.min.js +1 -1
  95. package/dist/lang/zh-hans.umd.min.js +1 -1
  96. package/dist/lang/zh-hant.umd.min.js +1 -1
  97. package/dist/quasar.addon.css +1 -1
  98. package/dist/quasar.addon.rtl.css +1 -1
  99. package/dist/quasar.common.js +2 -2
  100. package/dist/quasar.css +5 -2
  101. package/dist/quasar.esm.js +2 -2
  102. package/dist/quasar.ie.polyfills.js +1 -1
  103. package/dist/quasar.ie.polyfills.umd.min.js +1 -1
  104. package/dist/quasar.min.css +1 -1
  105. package/dist/quasar.rtl.css +5 -2
  106. package/dist/quasar.rtl.min.css +1 -1
  107. package/dist/quasar.sass +8 -3
  108. package/dist/quasar.styl +4 -2
  109. package/dist/quasar.umd.js +157 -111
  110. package/dist/quasar.umd.min.js +2 -2
  111. package/dist/quasar.umd.modern.js +152 -107
  112. package/dist/quasar.umd.modern.min.js +2 -2
  113. package/dist/types/extras/icon-set.d.ts +6 -0
  114. package/dist/types/index.d.ts +15 -1
  115. package/dist/vetur/quasar-attributes.json +12 -0
  116. package/dist/vetur/quasar-tags.json +4 -1
  117. package/dist/web-types/web-types.json +31 -1
  118. package/icon-set/material-symbols-outlined.js +128 -0
  119. package/icon-set/material-symbols-rounded.js +128 -0
  120. package/icon-set/material-symbols-sharp.js +128 -0
  121. package/icon-set/svg-material-symbols-outlined.js +202 -0
  122. package/icon-set/svg-material-symbols-rounded.js +202 -0
  123. package/icon-set/svg-material-symbols-sharp.js +202 -0
  124. package/lang/index.json +4 -0
  125. package/lang/mm.js +93 -0
  126. package/package.json +1 -1
  127. package/src/components/btn/QBtn.js +2 -2
  128. package/src/components/dialog/QDialog.js +7 -7
  129. package/src/components/dialog/QDialog.json +10 -1
  130. package/src/components/dialog-plugin/DialogPlugin.js +6 -6
  131. package/src/components/editor/QEditor.js +12 -30
  132. package/src/components/editor/editor-caret.js +1 -1
  133. package/src/components/field/QField.js +1 -0
  134. package/src/components/icon/QIcon.js +24 -1
  135. package/src/components/icon/QIcon.sass +4 -1
  136. package/src/components/infinite-scroll/QInfiniteScroll.js +10 -10
  137. package/src/components/input/QInput.js +3 -0
  138. package/src/components/layout/QLayout.js +1 -0
  139. package/src/components/menu/QMenu.js +3 -2
  140. package/src/components/select/QSelect.js +1 -1
  141. package/src/components/tooltip/QTooltip.js +2 -1
  142. package/src/components/uploader/QUploaderBase.js +22 -18
  143. package/src/components/video/QVideo.js +18 -2
  144. package/src/components/video/QVideo.json +36 -0
  145. package/src/components/virtual-scroll/QVirtualScroll.sass +4 -1
  146. package/src/components/virtual-scroll/QVirtualScroll.styl +4 -1
  147. package/src/mixins/portal.js +9 -2
  148. package/src/mixins/virtual-scroll.js +20 -21
  149. package/src/utils/patterns.js +7 -0
@@ -320,11 +320,11 @@ export default Vue.extend({
320
320
  if (this.loading === true && this.percentage !== void 0) {
321
321
  child.push(
322
322
  h('span', {
323
- staticClass: 'q-btn__progress absolute-full overflow-hidden'
323
+ staticClass: 'q-btn__progress absolute-full overflow-hidden',
324
+ class: this.darkPercentage === true ? 'q-btn__progress--dark' : ''
324
325
  }, [
325
326
  h('span', {
326
327
  staticClass: 'q-btn__progress-indicator fit block',
327
- class: this.darkPercentage === true ? 'q-btn__progress--dark' : '',
328
328
  style: this.percentageStyle
329
329
  })
330
330
  ])
@@ -151,7 +151,7 @@ export default Vue.extend({
151
151
  },
152
152
 
153
153
  methods: {
154
- focus () {
154
+ focus (selector) {
155
155
  addFocusFn(() => {
156
156
  let node = this.__getInnerNode()
157
157
 
@@ -159,7 +159,7 @@ export default Vue.extend({
159
159
  return
160
160
  }
161
161
 
162
- node = node.querySelector('[autofocus], [data-autofocus]') || node
162
+ node = node.querySelector(selector || '[autofocus], [data-autofocus]') || node
163
163
  node.focus({ preventScroll: true })
164
164
  })
165
165
  },
@@ -245,7 +245,7 @@ export default Vue.extend({
245
245
  }
246
246
 
247
247
  this.animating = false
248
- this.__showPortal(true)
248
+ this.__showPortal(true) // done showing
249
249
  this.$emit('show', evt)
250
250
  }, 300)
251
251
  },
@@ -253,6 +253,7 @@ export default Vue.extend({
253
253
  __hide (evt) {
254
254
  this.__removeHistory()
255
255
  this.__cleanup(true)
256
+ this.__hidePortal()
256
257
  this.animating = true
257
258
 
258
259
  // check null for IE
@@ -264,7 +265,7 @@ export default Vue.extend({
264
265
  this.$el.dispatchEvent(create('popup-hide', { bubbles: true }))
265
266
 
266
267
  this.__setTimeout(() => {
267
- this.__hidePortal()
268
+ this.__hidePortal(true) // done hiding, now destroy
268
269
  this.animating = false
269
270
  this.$emit('hide', evt)
270
271
  }, 300)
@@ -327,11 +328,10 @@ export default Vue.extend({
327
328
  __onFocusChange (e) {
328
329
  // the focus is not in a vue child component
329
330
  if (
330
- this.showing === true &&
331
- this.__portal !== void 0 &&
331
+ this.__portalIsAccessible === true &&
332
332
  childHasFocus(this.__portal.$el, e.target) !== true
333
333
  ) {
334
- this.focus()
334
+ this.focus('[tabindex]:not([tabindex="-1"])')
335
335
  }
336
336
  },
337
337
 
@@ -123,7 +123,16 @@
123
123
 
124
124
  "methods": {
125
125
  "focus": {
126
- "desc": "Focus dialog; if you have content with autofocus attribute, it will directly focus it"
126
+ "desc": "Focus dialog; if you have content with autofocus attribute, it will directly focus it",
127
+ "params": {
128
+ "selector": {
129
+ "type": "String",
130
+ "required": false,
131
+ "desc": "Optional CSS selector to override default focusable element",
132
+ "examples": [ "[tabindex]:not([tabindex=\"-1\"])" ],
133
+ "addedIn": "v1.18.9"
134
+ }
135
+ }
127
136
  },
128
137
 
129
138
  "shake": {
@@ -210,18 +210,18 @@ export default Vue.extend({
210
210
  getButtons (h) {
211
211
  const child = []
212
212
 
213
- this.ok && child.push(h(QBtn, {
214
- props: this.okProps,
215
- attrs: { 'data-autofocus': this.focus === 'ok' && this.hasForm !== true },
216
- on: cache(this, 'ok', { click: this.onOk })
217
- }))
218
-
219
213
  this.cancel && child.push(h(QBtn, {
220
214
  props: this.cancelProps,
221
215
  attrs: { 'data-autofocus': this.focus === 'cancel' && this.hasForm !== true },
222
216
  on: cache(this, 'cancel', { click: this.onCancel })
223
217
  }))
224
218
 
219
+ this.ok && child.push(h(QBtn, {
220
+ props: this.okProps,
221
+ attrs: { 'data-autofocus': this.focus === 'ok' && this.hasForm !== true },
222
+ on: cache(this, 'ok', { click: this.onOk })
223
+ }))
224
+
225
225
  if (child.length > 0) {
226
226
  return h(QCardActions, {
227
227
  staticClass: this.stackButtons === true ? 'items-end' : null,
@@ -379,33 +379,14 @@ export default Vue.extend({
379
379
  }
380
380
  },
381
381
 
382
- __onMousedown () {
382
+ // mousedown, touchstart
383
+ __onPointerStart (e) {
383
384
  this.__offsetBottom = void 0
385
+ this.qListeners[e.type] !== void 0 && this.$emit(e.type, e)
384
386
  },
385
387
 
386
- __onMouseup (e) {
388
+ __onSelectionchange () {
387
389
  this.caret.save()
388
- if (this.qListeners.mouseup !== void 0) {
389
- this.$emit('mouseup', e)
390
- }
391
- },
392
-
393
- __onKeyup (e) {
394
- this.caret.save()
395
- if (this.qListeners.keyup !== void 0) {
396
- this.$emit('keyup', e)
397
- }
398
- },
399
-
400
- __onTouchstart () {
401
- this.__offsetBottom = void 0
402
- },
403
-
404
- __onTouchend (e) {
405
- this.caret.save()
406
- if (this.qListeners.touchend !== void 0) {
407
- this.$emit('touchend', e)
408
- }
409
390
  },
410
391
 
411
392
  runCmd (cmd, param, update = true) {
@@ -468,6 +449,12 @@ export default Vue.extend({
468
449
  this.caret = new Caret(this.$refs.content, this)
469
450
  this.__setContent(this.value)
470
451
  this.refreshToolbar()
452
+
453
+ document.addEventListener('selectionchange', this.__onSelectionchange)
454
+ },
455
+
456
+ beforeDestroy () {
457
+ document.removeEventListener('selectionchange', this.__onSelectionchange)
471
458
  },
472
459
 
473
460
  render (h) {
@@ -505,13 +492,8 @@ export default Vue.extend({
505
492
  focus: this.__onFocus,
506
493
 
507
494
  // clean saved scroll position
508
- mousedown: this.__onMousedown,
509
- touchstart: this.__onTouchstart,
510
-
511
- // save caret
512
- mouseup: this.__onMouseup,
513
- keyup: this.__onKeyup,
514
- touchend: this.__onTouchend
495
+ mousedown: this.__onPointerStart,
496
+ touchstart: this.__onPointerStart
515
497
  }
516
498
 
517
499
  return h('div', {
@@ -198,7 +198,7 @@ export class Caret {
198
198
  return false
199
199
  }
200
200
 
201
- if (el !== null && list.includes(el.nodeName.toLowerCase()) === true) {
201
+ if (list.includes(el.nodeName.toLowerCase()) === true) {
202
202
  return true
203
203
  }
204
204
 
@@ -365,6 +365,7 @@ export default Vue.extend({
365
365
  ref: 'target',
366
366
  staticClass: 'q-field__native row',
367
367
  attrs: {
368
+ tabindex: -1,
368
369
  ...this.qAttrs,
369
370
  'data-autofocus': this.autofocus
370
371
  }
@@ -30,8 +30,15 @@ const matMap = {
30
30
  s_: '-sharp'
31
31
  }
32
32
 
33
+ const symMap = {
34
+ sym_o_: '-outlined',
35
+ sym_r_: '-rounded',
36
+ sym_s_: '-sharp'
37
+ }
38
+
33
39
  const libRE = new RegExp('^(' + Object.keys(libMap).join('|') + ')')
34
40
  const matRE = new RegExp('^(' + Object.keys(matMap).join('|') + ')')
41
+ const symRE = new RegExp('^(' + Object.keys(symMap).join('|') + ')')
35
42
  const mRE = /^[Mm]\s?[-+]?\.?\d/
36
43
  const imgRE = /^img:/
37
44
  const svgUseRE = /^svguse:/
@@ -136,6 +143,22 @@ export default Vue.extend({
136
143
  else if (ionRE.test(icon) === true) {
137
144
  cls = `ionicons ion-${this.$q.platform.is.ios === true ? 'ios' : 'md'}${icon.substr(3)}`
138
145
  }
146
+ else if (symRE.test(icon) === true) {
147
+ // "notranslate" class is for Google Translate
148
+ // to avoid tampering with Material Symbols ligature font
149
+ //
150
+ // Caution: To be able to add suffix to the class name,
151
+ // keep the 'material-symbols' at the end of the string.
152
+ cls = 'notranslate material-symbols'
153
+
154
+ const matches = icon.match(symRE)
155
+ if (matches !== null) {
156
+ icon = icon.substring(6)
157
+ cls += symMap[ matches[ 1 ] ]
158
+ }
159
+
160
+ content = icon
161
+ }
139
162
  else {
140
163
  // "notranslate" class is for Google Translate
141
164
  // to avoid tampering with Material Icons ligature font
@@ -187,7 +210,7 @@ export default Vue.extend({
187
210
  return h('span', data, mergeSlot([
188
211
  h('svg', {
189
212
  attrs: {
190
- viewBox: this.type.viewBox,
213
+ viewBox: this.type.viewBox || '0 0 24 24',
191
214
  focusable: 'false' /* needed for IE11 */
192
215
  }
193
216
  }, this.type.nodes)
@@ -28,7 +28,10 @@
28
28
  .material-icons,
29
29
  .material-icons-outlined,
30
30
  .material-icons-round,
31
- .material-icons-sharp
31
+ .material-icons-sharp,
32
+ .material-symbols-outlined,
33
+ .material-symbols-rounded,
34
+ .material-symbols-sharp
32
35
  user-select: none
33
36
  cursor: inherit
34
37
  font-size: inherit
@@ -150,6 +150,16 @@ export default Vue.extend({
150
150
 
151
151
  if (this.isWorking === true) {
152
152
  this.__scrollTarget.addEventListener('scroll', this.poll, passive)
153
+
154
+ if (this.reverse === true) {
155
+ const
156
+ scrollHeight = getScrollHeight(this.__scrollTarget),
157
+ containerHeight = height(this.__scrollTarget)
158
+
159
+ setScrollPosition(this.__scrollTarget, scrollHeight - containerHeight)
160
+ }
161
+
162
+ this.immediatePoll()
153
163
  }
154
164
  },
155
165
 
@@ -181,16 +191,6 @@ export default Vue.extend({
181
191
  this.__setDebounce(this.debounce)
182
192
 
183
193
  this.updateScrollTarget()
184
-
185
- if (this.reverse === true) {
186
- const
187
- scrollHeight = getScrollHeight(this.__scrollTarget),
188
- containerHeight = height(this.__scrollTarget)
189
-
190
- setScrollPosition(this.__scrollTarget, scrollHeight - containerHeight)
191
- }
192
-
193
- this.immediatePoll()
194
194
  },
195
195
 
196
196
  activated () {
@@ -285,13 +285,16 @@ export default Vue.extend({
285
285
  const inp = this.$refs.input
286
286
  if (inp !== void 0) {
287
287
  const parentStyle = inp.parentNode.style
288
+ const { overflow } = inp.style
288
289
 
289
290
  // reset height of textarea to a small size to detect the real height
290
291
  // but keep the total control size the same
291
292
  parentStyle.marginBottom = (inp.scrollHeight - 1) + 'px'
292
293
  inp.style.height = '1px'
294
+ inp.style.overflow = 'hidden'
293
295
 
294
296
  inp.style.height = inp.scrollHeight + 'px'
297
+ inp.style.overflow = overflow
295
298
  parentStyle.marginBottom = ''
296
299
  }
297
300
  },
@@ -137,6 +137,7 @@ export default Vue.extend({
137
137
  const layout = h('div', {
138
138
  class: this.classes,
139
139
  style: this.style,
140
+ attrs: { tabindex: -1 },
140
141
  on: { ...this.qListeners }
141
142
  }, mergeSlot([
142
143
  h(QScrollObserver, {
@@ -199,13 +199,14 @@ export default Vue.extend({
199
199
  }
200
200
 
201
201
  this.updatePosition()
202
- this.__showPortal(true)
202
+ this.__showPortal(true) // done showing
203
203
  this.$emit('show', evt)
204
204
  }, 300)
205
205
  },
206
206
 
207
207
  __hide (evt) {
208
208
  this.__anchorCleanup(true)
209
+ this.__hidePortal()
209
210
 
210
211
  // check null for IE
211
212
  if (
@@ -225,7 +226,7 @@ export default Vue.extend({
225
226
  this.$el.dispatchEvent(create('popup-hide', { bubbles: true }))
226
227
 
227
228
  this.__setTimeout(() => {
228
- this.__hidePortal()
229
+ this.__hidePortal(true) // done hiding, now destroy
229
230
  this.$emit('hide', evt)
230
231
  }, 300)
231
232
  },
@@ -408,7 +408,7 @@ export default Vue.extend({
408
408
 
409
409
  virtualScrollItemSizeComputed () {
410
410
  return this.virtualScrollItemSize === void 0
411
- ? (this.dense === true ? 24 : 48)
411
+ ? (this.optionsDense === true ? 24 : 48)
412
412
  : this.virtualScrollItemSize
413
413
  },
414
414
 
@@ -106,9 +106,10 @@ export default Vue.extend({
106
106
 
107
107
  __hide (evt) {
108
108
  this.__anchorCleanup()
109
+ this.__hidePortal()
109
110
 
110
111
  this.__setTimeout(() => {
111
- this.__hidePortal()
112
+ this.__hidePortal(true) // done hiding, now destroy
112
113
  this.$emit('hide', evt)
113
114
  }, 300)
114
115
  },
@@ -316,28 +316,32 @@ export default Vue.extend({
316
316
 
317
317
  return [
318
318
  h('div', {
319
- staticClass: 'q-uploader__header-content flex flex-center no-wrap q-gutter-xs'
319
+ staticClass: 'q-uploader__header-content column'
320
320
  }, [
321
- this.__getBtn(h, this.queuedFiles.length > 0, 'removeQueue', this.removeQueuedFiles),
322
- this.__getBtn(h, this.uploadedFiles.length > 0, 'removeUploaded', this.removeUploadedFiles),
323
-
324
- this.isUploading === true
325
- ? h(QSpinner, { staticClass: 'q-uploader__spinner' })
326
- : null,
327
-
328
- h('div', { staticClass: 'col column justify-center' }, [
329
- this.label !== void 0
330
- ? h('div', { staticClass: 'q-uploader__title' }, [ this.label ])
321
+ h('div', {
322
+ staticClass: 'flex flex-center no-wrap q-gutter-xs'
323
+ }, [
324
+ this.__getBtn(h, this.queuedFiles.length > 0, 'removeQueue', this.removeQueuedFiles),
325
+ this.__getBtn(h, this.uploadedFiles.length > 0, 'removeUploaded', this.removeUploadedFiles),
326
+
327
+ this.isUploading === true
328
+ ? h(QSpinner, { staticClass: 'q-uploader__spinner' })
331
329
  : null,
332
330
 
333
- h('div', { staticClass: 'q-uploader__subtitle' }, [
334
- this.uploadSizeLabel + ' / ' + this.uploadProgressLabel
335
- ])
336
- ]),
331
+ h('div', { staticClass: 'col column justify-center' }, [
332
+ this.label !== void 0
333
+ ? h('div', { staticClass: 'q-uploader__title' }, [ this.label ])
334
+ : null,
335
+
336
+ h('div', { staticClass: 'q-uploader__subtitle' }, [
337
+ this.uploadSizeLabel + ' / ' + this.uploadProgressLabel
338
+ ])
339
+ ]),
337
340
 
338
- this.__getBtn(h, this.canAddFiles, 'add', this.pickFiles),
339
- this.__getBtn(h, this.hideUploadBtn === false && this.canUpload === true, 'upload', this.upload),
340
- this.__getBtn(h, this.isUploading, 'clear', this.abort)
341
+ this.__getBtn(h, this.canAddFiles, 'add', this.pickFiles),
342
+ this.__getBtn(h, this.hideUploadBtn === false && this.canUpload === true, 'upload', this.upload),
343
+ this.__getBtn(h, this.isUploading, 'clear', this.abort)
344
+ ])
341
345
  ])
342
346
  ]
343
347
  },
@@ -14,7 +14,20 @@ export default Vue.extend({
14
14
  required: true
15
15
  },
16
16
 
17
- title: String
17
+ title: String,
18
+
19
+ fetchpriority: {
20
+ type: String,
21
+ default: 'auto'
22
+ },
23
+ loading: {
24
+ type: String,
25
+ default: 'eager'
26
+ },
27
+ referrerpolicy: {
28
+ type: String,
29
+ default: 'strict-origin-when-cross-origin'
30
+ }
18
31
  },
19
32
 
20
33
  computed: {
@@ -24,7 +37,10 @@ export default Vue.extend({
24
37
  src: this.src,
25
38
  frameborder: '0',
26
39
  title: this.title,
27
- allowfullscreen: true
40
+ allowfullscreen: true,
41
+ fetchpriority: this.fetchpriority,
42
+ loading: this.loading,
43
+ referrerpolicy: this.referrerpolicy
28
44
  }
29
45
  }
30
46
  },
@@ -33,6 +33,42 @@
33
33
  ],
34
34
  "category": "accessibility",
35
35
  "addedIn": "v1.17.0"
36
+ },
37
+
38
+ "fetchpriority": {
39
+ "type": "String",
40
+ "desc": "Provides a hint of the relative priority to use when fetching the iframe document",
41
+ "default": "auto",
42
+ "values": [ "high", "low", "auto" ],
43
+ "category": "behavior",
44
+ "addedIn": "v1.18.10"
45
+ },
46
+
47
+ "loading": {
48
+ "type": "String",
49
+ "desc": "Indicates how the browser should load the iframe",
50
+ "default": "eager",
51
+ "values": [ "eager", "lazy" ],
52
+ "category": "behavior",
53
+ "addedIn": "v1.18.10"
54
+ },
55
+
56
+ "referrerpolicy": {
57
+ "type": "String",
58
+ "desc": "Indicates which referrer to send when fetching the frame's resource",
59
+ "default": "strict-origin-when-cross-origin",
60
+ "values": [
61
+ "no-referrer",
62
+ "no-referrer-when-downgrade",
63
+ "origin",
64
+ "origin-when-cross-origin",
65
+ "same-origin",
66
+ "strict-origin",
67
+ "strict-origin-when-cross-origin",
68
+ "unsafe-url"
69
+ ],
70
+ "category": "behavior",
71
+ "addedIn": "v1.18.10"
36
72
  }
37
73
  }
38
74
  }
@@ -6,9 +6,12 @@
6
6
  outline: none
7
7
  contain: content
8
8
 
9
- *
9
+ > *
10
10
  overflow-anchor: none
11
11
 
12
+ > [data-q-vs-anchor]
13
+ overflow-anchor: auto
14
+
12
15
  &__padding
13
16
  background: linear-gradient(rgba(255,255,255,0), rgba(255,255,255,0) 20%, rgba(128, 128, 128, .03) 20%, rgba(128, 128, 128, .08) 50%, rgba(128, 128, 128, .03) 80%, rgba(255,255,255,0) 80%, rgba(255,255,255,0)) #{"/* rtl:ignore */"}
14
17
  background-size: 100% 50px #{"/* rtl:ignore */"}
@@ -6,9 +6,12 @@
6
6
  outline: none
7
7
  contain: content
8
8
 
9
- *
9
+ > *
10
10
  overflow-anchor: none
11
11
 
12
+ > [data-q-vs-anchor]
13
+ overflow-anchor: auto
14
+
12
15
  &__padding
13
16
  background: linear-gradient(rgba(255,255,255,0), rgba(255,255,255,0) 20%, rgba(128, 128, 128, .03) 20%, rgba(128, 128, 128, .08) 50%, rgba(128, 128, 128, .03) 80%, rgba(255,255,255,0) 80%, rgba(255,255,255,0)) /* rtl:ignore */
14
17
  background-size: 100% 50px /* rtl:ignore */
@@ -79,9 +79,12 @@ const Portal = {
79
79
  __showPortal (isReady) {
80
80
  if (isReady === true) {
81
81
  removeFocusWaitFlag(this.focusObj)
82
+ this.__portalIsAccessible = true
82
83
  return
83
84
  }
84
85
 
86
+ this.__portalIsAccessible = false
87
+
85
88
  if (this.__portalIsActive === true) { return }
86
89
  this.__portalIsActive = true
87
90
 
@@ -118,7 +121,11 @@ const Portal = {
118
121
  }
119
122
  },
120
123
 
121
- __hidePortal () {
124
+ __hidePortal (isReady) {
125
+ this.__portalIsAccessible = false
126
+
127
+ if (isReady !== true) { return }
128
+
122
129
  this.__portalIsActive = false
123
130
  removeFocusWaitFlag(this.focusObj)
124
131
 
@@ -170,7 +177,7 @@ const Portal = {
170
177
  },
171
178
 
172
179
  beforeDestroy () {
173
- this.__hidePortal()
180
+ this.__hidePortal(true)
174
181
  }
175
182
  }
176
183
 
@@ -185,9 +185,7 @@ const commonVirtScrollProps = {
185
185
  tableColspan: [ Number, String ]
186
186
  }
187
187
 
188
- let id = 1
189
-
190
- function setOverflowAnchor (id, index) {
188
+ function setOverflowAnchor (contentEl, index) {
191
189
  if (setOverflowAnchor.isSupported === void 0) {
192
190
  setOverflowAnchor.isSupported = window.getComputedStyle(document.body).overflowAnchor !== void 0
193
191
  }
@@ -196,21 +194,25 @@ function setOverflowAnchor (id, index) {
196
194
  return
197
195
  }
198
196
 
199
- const ssId = id + '_ss'
197
+ requestAnimationFrame(() => {
198
+ if (contentEl === void 0) {
199
+ return
200
+ }
200
201
 
201
- let styleSheet = document.getElementById(ssId)
202
+ const children = contentEl.children || []
202
203
 
203
- if (styleSheet === null) {
204
- styleSheet = document.createElement('style')
205
- styleSheet.type = 'text/css'
206
- styleSheet.id = ssId
207
- document.head.appendChild(styleSheet)
208
- }
204
+ filterProto
205
+ .call(children, el => el.dataset && el.dataset.qVsAnchor !== void 0)
206
+ .forEach(el => {
207
+ delete el.dataset.qVsAnchor
208
+ })
209
209
 
210
- if (styleSheet.qChildIndex !== index) {
211
- styleSheet.qChildIndex = index
212
- styleSheet.innerHTML = `#${id} > *:nth-child(${index}) { overflow-anchor: auto }`
213
- }
210
+ const el = children[index]
211
+
212
+ if (el && el.dataset) {
213
+ el.dataset.qVsAnchor = ''
214
+ }
215
+ })
214
216
  }
215
217
 
216
218
  export const commonVirtPropsList = Object.keys(commonVirtScrollProps)
@@ -223,8 +225,7 @@ export default {
223
225
 
224
226
  data () {
225
227
  return {
226
- virtualScrollSliceRange: { from: 0, to: 0 },
227
- id: 'qvs_' + id++
228
+ virtualScrollSliceRange: { from: 0, to: 0 }
228
229
  }
229
230
  },
230
231
 
@@ -423,7 +424,7 @@ export default {
423
424
  })
424
425
  }
425
426
 
426
- setOverflowAnchor(this.id, toIndex - from + 1)
427
+ setOverflowAnchor(contentEl, toIndex - from)
427
428
 
428
429
  const sizeBefore = alignEnd !== void 0 ? this.virtualScrollSizes.slice(from, toIndex).reduce(sumFn, 0) : 0
429
430
 
@@ -643,7 +644,7 @@ export default {
643
644
  staticClass: 'q-virtual-scroll__content',
644
645
  key: 'content',
645
646
  ref: 'content',
646
- attrs: { id: this.id, tabindex: -1 }
647
+ attrs: { tabindex: -1 }
647
648
  }, content),
648
649
 
649
650
  tag === 'tbody'
@@ -720,7 +721,5 @@ export default {
720
721
 
721
722
  beforeDestroy () {
722
723
  this.__onVirtualScrollEvt.cancel()
723
- const styleSheet = document.getElementById(this.id + '_ss')
724
- styleSheet !== null && styleSheet.remove()
725
724
  }
726
725
  }
@@ -13,6 +13,13 @@ export const testPattern = {
13
13
  fulltime: v => /^([0-1]?\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(v),
14
14
  timeOrFulltime: v => /^([0-1]?\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/.test(v),
15
15
 
16
+ // -- RFC 5322 --
17
+ // -- Added in v2.6.6 --
18
+ // This is a basic helper validation.
19
+ // For something more complex (like RFC 822) you should write and use your own rule.
20
+ // We won't be accepting PRs to enhance the one below because of the reason above.
21
+ email: v => /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(v),
22
+
16
23
  hexColor: v => hex.test(v),
17
24
  hexaColor: v => hexa.test(v),
18
25
  hexOrHexaColor: v => hexOrHexa.test(v),