quasar 1.17.7 → 1.18.2

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 (131) hide show
  1. package/dist/api/QCheckbox.json +27 -0
  2. package/dist/api/QRadio.json +18 -0
  3. package/dist/api/QToggle.json +24 -25
  4. package/dist/icon-set/bootstrap-icons.umd.min.js +1 -1
  5. package/dist/icon-set/eva-icons.umd.min.js +1 -1
  6. package/dist/icon-set/fontawesome-v5-pro.umd.min.js +1 -1
  7. package/dist/icon-set/fontawesome-v5.umd.min.js +1 -1
  8. package/dist/icon-set/ionicons-v4.umd.min.js +1 -1
  9. package/dist/icon-set/line-awesome.umd.min.js +1 -1
  10. package/dist/icon-set/material-icons-outlined.umd.min.js +1 -1
  11. package/dist/icon-set/material-icons-round.umd.min.js +1 -1
  12. package/dist/icon-set/material-icons-sharp.umd.min.js +1 -1
  13. package/dist/icon-set/material-icons.umd.min.js +1 -1
  14. package/dist/icon-set/mdi-v3.umd.min.js +1 -1
  15. package/dist/icon-set/mdi-v4.umd.min.js +1 -1
  16. package/dist/icon-set/mdi-v5.umd.min.js +1 -1
  17. package/dist/icon-set/mdi-v6.umd.min.js +1 -1
  18. package/dist/icon-set/svg-bootstrap-icons.umd.min.js +1 -1
  19. package/dist/icon-set/svg-eva-icons.umd.min.js +1 -1
  20. package/dist/icon-set/svg-fontawesome-v5.umd.min.js +1 -1
  21. package/dist/icon-set/svg-ionicons-v4.umd.min.js +1 -1
  22. package/dist/icon-set/svg-ionicons-v5.umd.min.js +1 -1
  23. package/dist/icon-set/svg-ionicons-v6.umd.min.js +1 -1
  24. package/dist/icon-set/svg-line-awesome.umd.min.js +1 -1
  25. package/dist/icon-set/svg-material-icons-outlined.umd.min.js +1 -1
  26. package/dist/icon-set/svg-material-icons-round.umd.min.js +1 -1
  27. package/dist/icon-set/svg-material-icons-sharp.umd.min.js +1 -1
  28. package/dist/icon-set/svg-material-icons.umd.min.js +1 -1
  29. package/dist/icon-set/svg-mdi-v4.umd.min.js +1 -1
  30. package/dist/icon-set/svg-mdi-v5.umd.min.js +1 -1
  31. package/dist/icon-set/svg-mdi-v6.umd.min.js +1 -1
  32. package/dist/icon-set/svg-themify.umd.min.js +1 -1
  33. package/dist/icon-set/themify.umd.min.js +1 -1
  34. package/dist/lang/ar.umd.min.js +1 -1
  35. package/dist/lang/az-latn.umd.min.js +1 -1
  36. package/dist/lang/bg.umd.min.js +1 -1
  37. package/dist/lang/ca.umd.min.js +1 -1
  38. package/dist/lang/cs.umd.min.js +1 -1
  39. package/dist/lang/da.umd.min.js +1 -1
  40. package/dist/lang/de.umd.min.js +1 -1
  41. package/dist/lang/el.umd.min.js +1 -1
  42. package/dist/lang/en-gb.umd.min.js +1 -1
  43. package/dist/lang/en-us.umd.min.js +1 -1
  44. package/dist/lang/eo.umd.min.js +1 -1
  45. package/dist/lang/es.umd.min.js +1 -1
  46. package/dist/lang/et.umd.min.js +1 -1
  47. package/dist/lang/fa-ir.umd.min.js +1 -1
  48. package/dist/lang/fa.umd.min.js +1 -1
  49. package/dist/lang/fi.umd.min.js +1 -1
  50. package/dist/lang/fr.umd.min.js +1 -1
  51. package/dist/lang/gn.umd.min.js +1 -1
  52. package/dist/lang/he.umd.min.js +1 -1
  53. package/dist/lang/hr.umd.min.js +1 -1
  54. package/dist/lang/hu.umd.min.js +1 -1
  55. package/dist/lang/id.umd.min.js +1 -1
  56. package/dist/lang/is.umd.min.js +1 -1
  57. package/dist/lang/it.umd.min.js +1 -1
  58. package/dist/lang/ja.umd.min.js +1 -1
  59. package/dist/lang/km.umd.min.js +1 -1
  60. package/dist/lang/ko-kr.umd.min.js +1 -1
  61. package/dist/lang/kur-ckb.umd.min.js +1 -1
  62. package/dist/lang/lu.umd.min.js +1 -1
  63. package/dist/lang/lv.umd.min.js +1 -1
  64. package/dist/lang/ml.umd.min.js +1 -1
  65. package/dist/lang/ms.umd.min.js +1 -1
  66. package/dist/lang/my.umd.min.js +1 -1
  67. package/dist/lang/nb-no.umd.min.js +1 -1
  68. package/dist/lang/nl.umd.min.js +1 -1
  69. package/dist/lang/pl.umd.min.js +1 -1
  70. package/dist/lang/pt-br.umd.min.js +1 -1
  71. package/dist/lang/pt.umd.min.js +1 -1
  72. package/dist/lang/ro.umd.min.js +1 -1
  73. package/dist/lang/ru.umd.min.js +1 -1
  74. package/dist/lang/sk.umd.min.js +1 -1
  75. package/dist/lang/sl.umd.min.js +1 -1
  76. package/dist/lang/sr.umd.min.js +1 -1
  77. package/dist/lang/sv.umd.min.js +1 -1
  78. package/dist/lang/ta.umd.min.js +1 -1
  79. package/dist/lang/th.umd.min.js +1 -1
  80. package/dist/lang/tr.umd.min.js +1 -1
  81. package/dist/lang/ug.umd.min.js +1 -1
  82. package/dist/lang/uk.umd.min.js +1 -1
  83. package/dist/lang/vi.umd.min.js +1 -1
  84. package/dist/lang/zh-hans.umd.min.js +1 -1
  85. package/dist/lang/zh-hant.umd.min.js +1 -1
  86. package/dist/quasar.addon.css +1 -1
  87. package/dist/quasar.addon.rtl.css +1 -1
  88. package/dist/quasar.common.js +2 -2
  89. package/dist/quasar.css +45 -11
  90. package/dist/quasar.esm.js +2 -2
  91. package/dist/quasar.ie.polyfills.js +1 -1
  92. package/dist/quasar.ie.polyfills.umd.min.js +1 -1
  93. package/dist/quasar.min.css +1 -1
  94. package/dist/quasar.rtl.css +58 -24
  95. package/dist/quasar.rtl.min.css +1 -1
  96. package/dist/quasar.sass +31 -11
  97. package/dist/quasar.styl +31 -11
  98. package/dist/quasar.umd.js +329 -195
  99. package/dist/quasar.umd.min.js +2 -2
  100. package/dist/quasar.umd.modern.js +319 -193
  101. package/dist/quasar.umd.modern.min.js +2 -2
  102. package/dist/types/index.d.ts +32 -12
  103. package/dist/types/utils/date.d.ts +28 -13
  104. package/dist/vetur/quasar-attributes.json +32 -12
  105. package/dist/vetur/quasar-tags.json +8 -3
  106. package/dist/web-types/web-types.json +73 -28
  107. package/package.json +1 -1
  108. package/src/components/checkbox/QCheckbox.js +48 -22
  109. package/src/components/checkbox/QCheckbox.json +17 -0
  110. package/src/components/checkbox/QCheckbox.sass +17 -5
  111. package/src/components/checkbox/QCheckbox.styl +17 -5
  112. package/src/components/field/QField.sass +2 -0
  113. package/src/components/field/QField.styl +2 -0
  114. package/src/components/form/QForm.js +17 -14
  115. package/src/components/input/QInput.js +9 -0
  116. package/src/components/radio/QRadio.js +43 -19
  117. package/src/components/radio/QRadio.json +16 -0
  118. package/src/components/radio/QRadio.sass +17 -5
  119. package/src/components/radio/QRadio.styl +17 -5
  120. package/src/components/select/QSelect.js +3 -2
  121. package/src/components/stepper/QStep.js +1 -1
  122. package/src/components/toggle/QToggle.js +0 -3
  123. package/src/components/toggle/QToggle.json +3 -13
  124. package/src/components/tree/QTree.js +6 -8
  125. package/src/mixins/checkbox.js +4 -0
  126. package/src/mixins/checkbox.json +18 -0
  127. package/src/mixins/validate.js +19 -16
  128. package/src/mixins/virtual-scroll.js +6 -4
  129. package/src/plugins/Meta.js +1 -1
  130. package/src/plugins/Screen.js +15 -9
  131. package/src/utils/date.js +151 -94
@@ -49,7 +49,7 @@ export default Vue.extend({
49
49
  ? shouldFocus
50
50
  : this.noErrorFocus !== true
51
51
 
52
- this.validateIndex++
52
+ const index = ++this.validateIndex
53
53
 
54
54
  const components = this.getValidationComponents().filter(c => c.disable !== true)
55
55
 
@@ -65,7 +65,7 @@ export default Vue.extend({
65
65
  promises.push(
66
66
  valid.then(
67
67
  valid => ({ valid, comp }),
68
- error => ({ valid: false, comp, error })
68
+ err => ({ valid: false, comp, err })
69
69
  )
70
70
  )
71
71
  }
@@ -89,19 +89,19 @@ export default Vue.extend({
89
89
  return Promise.resolve(true)
90
90
  }
91
91
 
92
- const index = this.validateIndex
93
-
94
92
  return Promise.all(promises).then(
95
93
  res => {
96
- if (index === this.validateIndex) {
97
- const errors = res.filter(r => r.valid !== true)
94
+ const errors = res.filter(r => r.valid !== true)
98
95
 
99
- if (errors.length === 0) {
100
- emit(true)
101
- return true
102
- }
96
+ if (errors.length === 0) {
97
+ index === this.validateIndex && emit(true)
98
+ return true
99
+ }
103
100
 
104
- const { valid, comp } = errors[0]
101
+ const { valid, comp, err } = errors[0]
102
+
103
+ if (index === this.validateIndex) {
104
+ err !== void 0 && console.error(err)
105
105
 
106
106
  emit(false, comp)
107
107
 
@@ -112,9 +112,9 @@ export default Vue.extend({
112
112
  ) {
113
113
  comp.focus()
114
114
  }
115
-
116
- return false
117
115
  }
116
+
117
+ return false
118
118
  }
119
119
  )
120
120
  },
@@ -130,8 +130,11 @@ export default Vue.extend({
130
130
  submit (evt) {
131
131
  evt !== void 0 && stopAndPrevent(evt)
132
132
 
133
+ const index = this.validateIndex + 1
134
+
133
135
  this.validate().then(val => {
134
- if (val === true) {
136
+ // if not outdated && validation succeeded
137
+ if (index === this.validateIndex && val === true) {
135
138
  if (this.qListeners.submit !== void 0) {
136
139
  this.$emit('submit', evt)
137
140
  }
@@ -71,6 +71,15 @@ export default Vue.extend({
71
71
  this.autogrow === true && this.$nextTick(this.__adjustHeight)
72
72
  },
73
73
 
74
+ // some browsers lose the native input value
75
+ // so we need to reattach it dynamically
76
+ // (like type="password" <-> type="text"; see #12078)
77
+ type () {
78
+ if (this.$refs.input) {
79
+ this.$refs.input.value = this.value
80
+ }
81
+ },
82
+
74
83
  autogrow (autogrow) {
75
84
  // textarea only
76
85
  if (autogrow === true) {
@@ -1,5 +1,7 @@
1
1
  import Vue from 'vue'
2
2
 
3
+ import QIcon from '../icon/QIcon.js'
4
+
3
5
  import DarkMixin from '../../mixins/dark.js'
4
6
  import OptionSizeMixin from '../../mixins/option-size.js'
5
7
  import FormMixin from '../../mixins/form.js'
@@ -25,6 +27,9 @@ export default Vue.extend({
25
27
  label: String,
26
28
  leftLabel: Boolean,
27
29
 
30
+ checkedIcon: String,
31
+ uncheckedIcon: String,
32
+
28
33
  color: String,
29
34
  keepColor: Boolean,
30
35
  dense: Boolean,
@@ -57,6 +62,12 @@ export default Vue.extend({
57
62
  return `q-radio__inner--${this.isTrue === true ? 'truthy' : 'falsy'}${color}`
58
63
  },
59
64
 
65
+ computedIcon () {
66
+ return this.isTrue === true
67
+ ? this.checkedIcon
68
+ : this.uncheckedIcon
69
+ },
70
+
60
71
  computedTabindex () {
61
72
  return this.disable === true ? -1 : this.tabindex || 0
62
73
  },
@@ -108,25 +119,38 @@ export default Vue.extend({
108
119
  },
109
120
 
110
121
  render (h) {
111
- const content = [
112
- h('svg', {
113
- staticClass: 'q-radio__bg absolute non-selectable',
114
- attrs: { focusable: 'false' /* needed for IE11 */, viewBox: '0 0 24 24', 'aria-hidden': 'true' }
115
- }, [
116
- h('path', {
117
- attrs: {
118
- d: 'M12,22a10,10 0 0 1 -10,-10a10,10 0 0 1 10,-10a10,10 0 0 1 10,10a10,10 0 0 1 -10,10m0,-22a12,12 0 0 0 -12,12a12,12 0 0 0 12,12a12,12 0 0 0 12,-12a12,12 0 0 0 -12,-12'
119
- }
120
- }),
121
-
122
- h('path', {
123
- staticClass: 'q-radio__check',
124
- attrs: {
125
- d: 'M12,6a6,6 0 0 0 -6,6a6,6 0 0 0 6,6a6,6 0 0 0 6,-6a6,6 0 0 0 -6,-6'
126
- }
127
- })
128
- ])
129
- ]
122
+ const content = this.computedIcon !== void 0
123
+ ? [
124
+ h('div', {
125
+ key: 'icon',
126
+ staticClass: 'q-radio__icon-container absolute flex flex-center no-wrap'
127
+ }, [
128
+ h(QIcon, {
129
+ staticClass: 'q-radio__icon',
130
+ props: { name: this.computedIcon }
131
+ })
132
+ ])
133
+ ]
134
+ : [
135
+ h('svg', {
136
+ key: 'svg',
137
+ staticClass: 'q-radio__bg absolute non-selectable',
138
+ attrs: { focusable: 'false' /* needed for IE11 */, viewBox: '0 0 24 24', 'aria-hidden': 'true' }
139
+ }, [
140
+ h('path', {
141
+ attrs: {
142
+ d: 'M12,22a10,10 0 0 1 -10,-10a10,10 0 0 1 10,-10a10,10 0 0 1 10,10a10,10 0 0 1 -10,10m0,-22a12,12 0 0 0 -12,12a12,12 0 0 0 12,12a12,12 0 0 0 12,-12a12,12 0 0 0 -12,-12'
143
+ }
144
+ }),
145
+
146
+ h('path', {
147
+ staticClass: 'q-radio__check',
148
+ attrs: {
149
+ d: 'M12,6a6,6 0 0 0 -6,6a6,6 0 0 0 6,6a6,6 0 0 0 6,-6a6,6 0 0 0 -6,-6'
150
+ }
151
+ })
152
+ ])
153
+ ]
130
154
 
131
155
  this.disable !== true && this.__injectFormInput(
132
156
  content,
@@ -35,6 +35,22 @@
35
35
  "category": "label"
36
36
  },
37
37
 
38
+ "checked-icon": {
39
+ "type": "String",
40
+ "desc": "The icon to be used when selected (instead of the default design)",
41
+ "examples": [ "visibility" ],
42
+ "category": "icons",
43
+ "addedIn": "v1.18"
44
+ },
45
+
46
+ "unchecked-icon": {
47
+ "type": "String",
48
+ "desc": "The icon to be used when un-selected (instead of the default design)",
49
+ "examples": [ "visibility_off" ],
50
+ "category": "icons",
51
+ "addedIn": "v1.18"
52
+ },
53
+
38
54
  "color": {
39
55
  "extends": "color"
40
56
  },
@@ -3,19 +3,27 @@ $radio-transition: .22s cubic-bezier(0,0,.2,1) 0ms
3
3
  .q-radio
4
4
  vertical-align: middle
5
5
 
6
- &__bg
6
+ &__native
7
+ width: 1px
8
+ height: 1px
9
+
10
+ &__bg,
11
+ &__icon-container
7
12
  top: 25%
8
13
  left: 25%
9
14
  width: 50%
10
15
  height: 50%
16
+ user-select: none
17
+
18
+ &__bg
11
19
  -webkit-print-color-adjust: exact
12
20
 
13
21
  path
14
22
  fill: currentColor
15
23
 
16
- &__native
17
- width: 1px
18
- height: 1px
24
+ &__icon
25
+ color: currentColor
26
+ font-size: .6em
19
27
 
20
28
  &__check
21
29
  transform-origin: 50% 50%
@@ -51,12 +59,16 @@ $radio-transition: .22s cubic-bezier(0,0,.2,1) 0ms
51
59
 
52
60
  &--dense
53
61
 
62
+ .q-checkbox__icon
63
+ font-size: .6em
64
+
54
65
  .q-radio__inner
55
66
  width: .5em
56
67
  min-width: .5em
57
68
  height: .5em
58
69
 
59
- .q-radio__bg
70
+ .q-radio__bg,
71
+ .q-radio__icon-container
60
72
  left: 0
61
73
  top: 0
62
74
  width: 100%
@@ -3,19 +3,27 @@ $radio-transition = .22s cubic-bezier(0,0,.2,1) 0ms
3
3
  .q-radio
4
4
  vertical-align: middle
5
5
 
6
- &__bg
6
+ &__native
7
+ width: 1px
8
+ height: 1px
9
+
10
+ &__bg,
11
+ &__icon-container
7
12
  top: 25%
8
13
  left: 25%
9
14
  width: 50%
10
15
  height: 50%
16
+ user-select: none
17
+
18
+ &__bg
11
19
  -webkit-print-color-adjust: exact
12
20
 
13
21
  path
14
22
  fill: currentColor
15
23
 
16
- &__native
17
- width: 1px
18
- height: 1px
24
+ &__icon
25
+ color: currentColor
26
+ font-size: .6em
19
27
 
20
28
  &__check
21
29
  transform-origin: 50% 50%
@@ -51,12 +59,16 @@ $radio-transition = .22s cubic-bezier(0,0,.2,1) 0ms
51
59
 
52
60
  &--dense
53
61
 
62
+ .q-checkbox__icon
63
+ font-size: .6em
64
+
54
65
  .q-radio__inner
55
66
  width: .5em
56
67
  min-width: .5em
57
68
  height: .5em
58
69
 
59
- .q-radio__bg
70
+ .q-radio__bg,
71
+ .q-radio__icon-container
60
72
  left: 0
61
73
  top: 0
62
74
  width: 100%
@@ -270,7 +270,7 @@ export default Vue.extend({
270
270
  const { options, optionEls } = this.__optionScopeCache
271
271
 
272
272
  return this.options.slice(from, to).map((opt, i) => {
273
- const disable = this.isOptionDisabled(opt) === true
273
+ const disable = this.isOptionDisabled(opt)
274
274
  const index = from + i
275
275
 
276
276
  const itemProps = {
@@ -368,7 +368,8 @@ export default Vue.extend({
368
368
  // returns method to tell if an option is disabled;
369
369
  // takes into account 'option-disable' prop
370
370
  isOptionDisabled () {
371
- return this.__getPropValueFn('optionDisable', 'disable')
371
+ const fn = this.__getPropValueFn('optionDisable', 'disable')
372
+ return (...args) => fn.apply(null, args) === true
372
373
  },
373
374
 
374
375
  inputControlEvents () {
@@ -67,7 +67,7 @@ export default Vue.extend({
67
67
  onEvents () {
68
68
  return this.isActive !== true ||
69
69
  this.stepper.vertical !== true ||
70
- (this.$q.platform.is.ios !== true && this.$q.platform.is.safari !== true && this.$q.platform.is.ie !== true)
70
+ (this.$q.platform.is.ios !== true && this.$q.platform.is.chrome === true)
71
71
  ? { ...this.qListeners }
72
72
  : { ...this.qListeners, scroll: this.__keepScroll }
73
73
  }
@@ -10,9 +10,6 @@ export default Vue.extend({
10
10
 
11
11
  props: {
12
12
  icon: String,
13
- checkedIcon: String,
14
- uncheckedIcon: String,
15
- indeterminateIcon: String,
16
13
 
17
14
  iconColor: String
18
15
  },
@@ -11,25 +11,15 @@
11
11
  },
12
12
 
13
13
  "checked-icon": {
14
- "type": "String",
15
- "desc": "The icon to be used when the toggle is on",
16
- "examples": [ "visibility" ],
17
- "category": "content"
14
+ "desc": "The icon to be used when the toggle is on"
18
15
  },
19
16
 
20
17
  "unchecked-icon": {
21
- "type": "String",
22
- "desc": "The icon to be used when the toggle is off",
23
- "examples": [ "visibility_off" ],
24
- "category": "content"
18
+ "desc": "The icon to be used when the toggle is off"
25
19
  },
26
20
 
27
21
  "indeterminate-icon": {
28
- "type": "String",
29
- "desc": "The icon to be used when the model is indeterminate",
30
- "examples": [ "help" ],
31
- "category": "content",
32
- "addedIn": "v1.8.0"
22
+ "desc": "The icon to be used when the model is indeterminate"
33
23
  },
34
24
 
35
25
  "icon-color": {
@@ -604,14 +604,12 @@ export default Vue.extend({
604
604
  __onClick (node, meta, e, keyboard) {
605
605
  keyboard !== true && this.__blur(meta.key)
606
606
 
607
- if (this.hasSelection) {
608
- if (meta.selectable) {
609
- if (this.noSelectionUnset === false) {
610
- this.$emit('update:selected', meta.key !== this.selected ? meta.key : null)
611
- }
612
- else if (meta.key !== this.selected) {
613
- this.$emit('update:selected', meta.key || null)
614
- }
607
+ if (this.hasSelection && meta.selectable) {
608
+ if (this.noSelectionUnset === false) {
609
+ this.$emit('update:selected', meta.key !== this.selected ? meta.key : null)
610
+ }
611
+ else if (meta.key !== this.selected) {
612
+ this.$emit('update:selected', meta.key || null)
615
613
  }
616
614
  }
617
615
  else {
@@ -22,6 +22,10 @@ export default {
22
22
  falseValue: { default: false },
23
23
  indeterminateValue: { default: null },
24
24
 
25
+ checkedIcon: String,
26
+ uncheckedIcon: String,
27
+ indeterminateIcon: String,
28
+
25
29
  toggleOrder: {
26
30
  type: String,
27
31
  validator: v => v === 'tf' || v === 'ft'
@@ -73,6 +73,24 @@
73
73
  "category": "label"
74
74
  },
75
75
 
76
+ "checked-icon": {
77
+ "type": "String",
78
+ "examples": [ "visibility" ],
79
+ "category": "icons"
80
+ },
81
+
82
+ "unchecked-icon": {
83
+ "type": "String",
84
+ "examples": [ "visibility_off" ],
85
+ "category": "icons"
86
+ },
87
+
88
+ "indeterminate-icon": {
89
+ "type": "String",
90
+ "examples": [ "help" ],
91
+ "category": "icons"
92
+ },
93
+
76
94
  "color": {
77
95
  "extends": "color"
78
96
  },
@@ -70,7 +70,14 @@ export default {
70
70
  else if (this.isDirty === false) {
71
71
  this.isDirty = true
72
72
 
73
- if (this.hasRules === true && this.lazyRules !== 'ondemand') {
73
+ if (
74
+ this.hasActiveRules === true &&
75
+ this.lazyRules !== 'ondemand' &&
76
+ // Don't re-trigger if it's already in progress;
77
+ // It might mean that focus switched to submit btn and
78
+ // QForm's submit() has been called already (ENTER key)
79
+ this.innerLoading === false
80
+ ) {
74
81
  this.debouncedValidate()
75
82
  }
76
83
  }
@@ -84,12 +91,15 @@ export default {
84
91
 
85
92
  computed: {
86
93
  hasRules () {
87
- return this.disable !== true &&
88
- this.rules !== void 0 &&
94
+ return this.rules !== void 0 &&
89
95
  this.rules !== null &&
90
96
  this.rules.length > 0
91
97
  },
92
98
 
99
+ hasActiveRules () {
100
+ return this.disable !== true && this.hasRules === true
101
+ },
102
+
93
103
  hasError () {
94
104
  return this.error === true || this.innerError === true
95
105
  },
@@ -127,11 +137,11 @@ export default {
127
137
  * - Promise (pending async validation)
128
138
  */
129
139
  validate (val = this.value) {
130
- if (this.hasRules !== true) {
140
+ if (this.hasActiveRules !== true) {
131
141
  return true
132
142
  }
133
143
 
134
- this.validateIndex++
144
+ const index = ++this.validateIndex
135
145
 
136
146
  if (this.innerLoading !== true && this.lazyRules !== true) {
137
147
  this.isDirty = true
@@ -184,31 +194,24 @@ export default {
184
194
  this.innerLoading = true
185
195
  }
186
196
 
187
- const index = this.validateIndex
188
-
189
197
  return Promise.all(promises).then(
190
198
  res => {
191
- if (index !== this.validateIndex) {
192
- return true
193
- }
194
-
195
199
  if (res === void 0 || Array.isArray(res) === false || res.length === 0) {
196
- update(false)
200
+ index === this.validateIndex && update(false)
197
201
  return true
198
202
  }
199
203
 
200
204
  const msg = res.find(r => r === false || typeof r === 'string')
201
- update(msg !== void 0, msg)
205
+ index === this.validateIndex && update(msg !== void 0, msg)
202
206
  return msg === void 0
203
207
  },
204
208
  e => {
205
209
  if (index === this.validateIndex) {
206
210
  console.error(e)
207
211
  update(true)
208
- return false
209
212
  }
210
213
 
211
- return true
214
+ return false
212
215
  }
213
216
  )
214
217
  },
@@ -223,7 +226,7 @@ export default {
223
226
 
224
227
  __validateIfNeeded (changedRules) {
225
228
  if (
226
- this.hasRules === true &&
229
+ this.hasActiveRules === true &&
227
230
  this.lazyRules !== 'ondemand' &&
228
231
  (this.isDirty === true || (this.lazyRules !== true && changedRules !== true))
229
232
  ) {
@@ -591,7 +591,9 @@ export default {
591
591
 
592
592
  this.__scrollViewSize = scrollViewSize
593
593
 
594
- const multiplier = 1 + this.virtualScrollSliceRatioBefore + this.virtualScrollSliceRatioAfter
594
+ const virtualScrollSliceRatioBefore = parseFloat(this.virtualScrollSliceRatioBefore) || 0
595
+ const virtualScrollSliceRatioAfter = parseFloat(this.virtualScrollSliceRatioAfter) || 0
596
+ const multiplier = 1 + virtualScrollSliceRatioBefore + virtualScrollSliceRatioAfter
595
597
  const view = scrollViewSize === void 0 || scrollViewSize <= 0
596
598
  ? 1
597
599
  : Math.ceil(scrollViewSize / this.virtualScrollItemSizeComputed)
@@ -603,9 +605,9 @@ export default {
603
605
 
604
606
  this.virtualScrollSliceSizeComputed = {
605
607
  total: Math.ceil(baseSize * multiplier),
606
- start: Math.ceil(baseSize * this.virtualScrollSliceRatioBefore),
607
- center: Math.ceil(baseSize * (0.5 + this.virtualScrollSliceRatioBefore)),
608
- end: Math.ceil(baseSize * (1 + this.virtualScrollSliceRatioBefore)),
608
+ start: Math.ceil(baseSize * virtualScrollSliceRatioBefore),
609
+ center: Math.ceil(baseSize * (0.5 + virtualScrollSliceRatioBefore)),
610
+ end: Math.ceil(baseSize * (1 + virtualScrollSliceRatioBefore)),
609
611
  view
610
612
  }
611
613
  },
@@ -180,7 +180,7 @@ function updateClient () {
180
180
  function getAttr (seed) {
181
181
  return att => {
182
182
  const val = seed[att]
183
- return att + (val !== void 0 ? `="${val}"` : '')
183
+ return att + (val !== true && val !== void 0 ? `="${val}"` : '')
184
184
  }
185
185
  }
186
186
 
@@ -1,6 +1,6 @@
1
1
  import Vue from 'vue'
2
2
 
3
- import { isSSR, fromSSR } from './Platform.js'
3
+ import { isSSR, fromSSR, client } from './Platform.js'
4
4
  import { listenOpts, noop } from '../utils/event.js'
5
5
  import debounce from '../utils/debounce.js'
6
6
 
@@ -47,12 +47,22 @@ export default {
47
47
  return
48
48
  }
49
49
 
50
+ const { visualViewport } = window
51
+ const getSize = visualViewport === void 0 || client.is.mobile === true
52
+ ? () => [
53
+ Math.max(window.innerWidth, document.scrollingElement.clientWidth),
54
+ Math.max(window.innerHeight, document.scrollingElement.clientHeight)
55
+ ]
56
+ : () => [
57
+ visualViewport.width * visualViewport.scale + window.innerWidth - document.scrollingElement.clientWidth,
58
+ visualViewport.height * visualViewport.scale + window.innerHeight - document.scrollingElement.clientHeight
59
+ ]
60
+
61
+ const target = visualViewport || window
50
62
  const classes = cfg.screen !== void 0 && cfg.screen.bodyClasses === true
51
63
 
52
64
  const update = force => {
53
- const
54
- w = window.innerWidth,
55
- h = window.innerHeight
65
+ const [ w, h ] = getSize()
56
66
 
57
67
  if (h !== this.height) {
58
68
  this.height = h
@@ -110,11 +120,7 @@ export default {
110
120
  }
111
121
 
112
122
  const start = () => {
113
- const
114
- style = getComputedStyle(document.body),
115
- target = window.visualViewport !== void 0
116
- ? window.visualViewport
117
- : window
123
+ const style = getComputedStyle(document.body)
118
124
 
119
125
  // if css props available
120
126
  if (style.getPropertyValue('--q-size-sm')) {