quasar 2.8.2 → 2.8.4

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 (285) hide show
  1. package/dist/api/Loading.json +0 -1
  2. package/dist/api/QBtnDropdown.json +9 -0
  3. package/dist/api/QChip.json +9 -0
  4. package/dist/api/QCircularProgress.json +6 -0
  5. package/dist/api/QExpansionItem.json +59 -0
  6. package/dist/api/QField.json +2 -1
  7. package/dist/api/QFile.json +2 -1
  8. package/dist/api/QInput.json +2 -1
  9. package/dist/api/QSelect.json +2 -1
  10. package/dist/api/QTable.json +2 -2
  11. package/dist/api/QUploader.json +4 -0
  12. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  13. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  14. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  15. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  16. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  17. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  18. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  19. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  20. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  21. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  22. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  23. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  24. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  25. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  26. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  27. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  28. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  29. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  30. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  44. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  45. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  46. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  47. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  48. package/dist/icon-set/themify.umd.prod.js +1 -1
  49. package/dist/lang/ar-TN.umd.prod.js +2 -2
  50. package/dist/lang/ar.umd.prod.js +2 -2
  51. package/dist/lang/az-Latn.umd.prod.js +2 -2
  52. package/dist/lang/bg.umd.prod.js +2 -2
  53. package/dist/lang/bn.umd.prod.js +2 -2
  54. package/dist/lang/ca.umd.prod.js +2 -2
  55. package/dist/lang/cs.umd.prod.js +2 -2
  56. package/dist/lang/da.umd.prod.js +2 -2
  57. package/dist/lang/de.umd.prod.js +2 -2
  58. package/dist/lang/el.umd.prod.js +2 -2
  59. package/dist/lang/en-GB.umd.prod.js +2 -2
  60. package/dist/lang/en-US.umd.prod.js +2 -2
  61. package/dist/lang/eo.umd.prod.js +2 -2
  62. package/dist/lang/es.umd.prod.js +2 -2
  63. package/dist/lang/et.umd.prod.js +2 -2
  64. package/dist/lang/eu.umd.prod.js +2 -2
  65. package/dist/lang/fa-IR.umd.prod.js +2 -2
  66. package/dist/lang/fa.umd.prod.js +2 -2
  67. package/dist/lang/fi.umd.prod.js +2 -2
  68. package/dist/lang/fr.umd.prod.js +2 -2
  69. package/dist/lang/gn.umd.prod.js +2 -2
  70. package/dist/lang/he.umd.prod.js +2 -2
  71. package/dist/lang/hr.umd.prod.js +2 -2
  72. package/dist/lang/hu.umd.prod.js +2 -2
  73. package/dist/lang/id.umd.prod.js +2 -2
  74. package/dist/lang/is.umd.prod.js +2 -2
  75. package/dist/lang/it.umd.prod.js +2 -2
  76. package/dist/lang/ja.umd.prod.js +2 -2
  77. package/dist/lang/km.umd.prod.js +2 -2
  78. package/dist/lang/ko-KR.umd.prod.js +2 -2
  79. package/dist/lang/kur-CKB.umd.prod.js +2 -2
  80. package/dist/lang/kz.umd.prod.js +2 -2
  81. package/dist/lang/lt.umd.prod.js +2 -2
  82. package/dist/lang/lu.umd.prod.js +2 -2
  83. package/dist/lang/lv.umd.prod.js +2 -2
  84. package/dist/lang/ml.umd.prod.js +2 -2
  85. package/dist/lang/mm.umd.prod.js +2 -2
  86. package/dist/lang/ms.umd.prod.js +2 -2
  87. package/dist/lang/my.umd.prod.js +2 -2
  88. package/dist/lang/nb-NO.umd.prod.js +2 -2
  89. package/dist/lang/nl.umd.prod.js +2 -2
  90. package/dist/lang/pl.umd.prod.js +2 -2
  91. package/dist/lang/pt-BR.umd.prod.js +2 -2
  92. package/dist/lang/pt.umd.prod.js +2 -2
  93. package/dist/lang/ro.umd.prod.js +2 -2
  94. package/dist/lang/ru.umd.prod.js +2 -2
  95. package/dist/lang/sk.umd.prod.js +2 -2
  96. package/dist/lang/sl.umd.prod.js +2 -2
  97. package/dist/lang/sm.umd.prod.js +2 -2
  98. package/dist/lang/sr-CYR.umd.prod.js +2 -2
  99. package/dist/lang/sr.umd.prod.js +2 -2
  100. package/dist/lang/sv.umd.prod.js +2 -2
  101. package/dist/lang/ta.umd.prod.js +2 -2
  102. package/dist/lang/th.umd.prod.js +2 -2
  103. package/dist/lang/tr.umd.prod.js +2 -2
  104. package/dist/lang/ug.umd.prod.js +2 -2
  105. package/dist/lang/uk.umd.prod.js +2 -2
  106. package/dist/lang/uz-Cyrl.umd.prod.js +2 -2
  107. package/dist/lang/uz-Latn.umd.prod.js +2 -2
  108. package/dist/lang/vi.umd.prod.js +2 -2
  109. package/dist/lang/zh-CN.umd.prod.js +2 -2
  110. package/dist/lang/zh-TW.umd.prod.js +2 -2
  111. package/dist/quasar.cjs.prod.js +2 -2
  112. package/dist/quasar.esm.js +15676 -15431
  113. package/dist/quasar.esm.prod.js +2 -2
  114. package/dist/quasar.sass +1 -1
  115. package/dist/quasar.umd.js +15879 -15632
  116. package/dist/quasar.umd.prod.js +2 -2
  117. package/dist/transforms/import-map.json +2 -0
  118. package/dist/types/api/qloading.d.ts +5 -0
  119. package/dist/types/api/validation.d.ts +22 -2
  120. package/dist/types/api.d.ts +1 -0
  121. package/dist/types/index.d.ts +45 -9
  122. package/dist/types/utils/is.d.ts +67 -0
  123. package/dist/types/utils/run-sequential-promises.d.ts +119 -0
  124. package/dist/types/utils.d.ts +9 -0
  125. package/dist/vetur/quasar-attributes.json +21 -1
  126. package/dist/vetur/quasar-tags.json +6 -1
  127. package/dist/web-types/web-types.json +53 -6
  128. package/lang/ar-TN.js +3 -1
  129. package/lang/ar-TN.mjs +3 -1
  130. package/lang/ar.js +3 -1
  131. package/lang/ar.mjs +3 -1
  132. package/lang/az-Latn.js +3 -1
  133. package/lang/az-Latn.mjs +3 -1
  134. package/lang/bg.js +3 -1
  135. package/lang/bg.mjs +3 -1
  136. package/lang/bn.js +3 -1
  137. package/lang/bn.mjs +3 -1
  138. package/lang/ca.js +3 -1
  139. package/lang/ca.mjs +3 -1
  140. package/lang/cs.js +3 -1
  141. package/lang/cs.mjs +3 -1
  142. package/lang/da.js +3 -1
  143. package/lang/da.mjs +3 -1
  144. package/lang/de.js +3 -1
  145. package/lang/de.mjs +3 -1
  146. package/lang/el.js +3 -1
  147. package/lang/el.mjs +3 -1
  148. package/lang/en-GB.js +3 -1
  149. package/lang/en-GB.mjs +3 -1
  150. package/lang/en-US.js +3 -1
  151. package/lang/en-US.mjs +3 -1
  152. package/lang/eo.js +3 -1
  153. package/lang/eo.mjs +3 -1
  154. package/lang/es.js +3 -1
  155. package/lang/es.mjs +3 -1
  156. package/lang/et.js +3 -1
  157. package/lang/et.mjs +3 -1
  158. package/lang/eu.js +3 -1
  159. package/lang/eu.mjs +3 -1
  160. package/lang/fa-IR.js +5 -3
  161. package/lang/fa-IR.mjs +5 -3
  162. package/lang/fa.js +5 -3
  163. package/lang/fa.mjs +5 -3
  164. package/lang/fi.js +3 -1
  165. package/lang/fi.mjs +3 -1
  166. package/lang/fr.js +3 -1
  167. package/lang/fr.mjs +3 -1
  168. package/lang/gn.js +3 -1
  169. package/lang/gn.mjs +3 -1
  170. package/lang/he.js +3 -1
  171. package/lang/he.mjs +3 -1
  172. package/lang/hr.js +3 -1
  173. package/lang/hr.mjs +3 -1
  174. package/lang/hu.js +3 -1
  175. package/lang/hu.mjs +3 -1
  176. package/lang/id.js +3 -1
  177. package/lang/id.mjs +3 -1
  178. package/lang/is.js +3 -1
  179. package/lang/is.mjs +3 -1
  180. package/lang/it.js +3 -1
  181. package/lang/it.mjs +3 -1
  182. package/lang/ja.js +3 -1
  183. package/lang/ja.mjs +3 -1
  184. package/lang/km.js +3 -1
  185. package/lang/km.mjs +3 -1
  186. package/lang/ko-KR.js +3 -1
  187. package/lang/ko-KR.mjs +3 -1
  188. package/lang/kur-CKB.js +3 -1
  189. package/lang/kur-CKB.mjs +3 -1
  190. package/lang/kz.js +3 -1
  191. package/lang/kz.mjs +3 -1
  192. package/lang/lt.js +3 -1
  193. package/lang/lt.mjs +3 -1
  194. package/lang/lu.js +3 -1
  195. package/lang/lu.mjs +3 -1
  196. package/lang/lv.js +3 -1
  197. package/lang/lv.mjs +3 -1
  198. package/lang/ml.js +3 -1
  199. package/lang/ml.mjs +3 -1
  200. package/lang/mm.js +4 -1
  201. package/lang/mm.mjs +4 -1
  202. package/lang/ms.js +3 -1
  203. package/lang/ms.mjs +3 -1
  204. package/lang/my.js +3 -1
  205. package/lang/my.mjs +3 -1
  206. package/lang/nb-NO.js +3 -1
  207. package/lang/nb-NO.mjs +3 -1
  208. package/lang/nl.js +3 -1
  209. package/lang/nl.mjs +3 -1
  210. package/lang/pl.js +3 -1
  211. package/lang/pl.mjs +3 -1
  212. package/lang/pt-BR.js +3 -1
  213. package/lang/pt-BR.mjs +3 -1
  214. package/lang/pt.js +3 -1
  215. package/lang/pt.mjs +3 -1
  216. package/lang/ro.js +3 -1
  217. package/lang/ro.mjs +3 -1
  218. package/lang/ru.js +3 -1
  219. package/lang/ru.mjs +3 -1
  220. package/lang/sk.js +3 -1
  221. package/lang/sk.mjs +3 -1
  222. package/lang/sl.js +3 -1
  223. package/lang/sl.mjs +3 -1
  224. package/lang/sm.js +3 -1
  225. package/lang/sm.mjs +3 -1
  226. package/lang/sr-CYR.js +3 -1
  227. package/lang/sr-CYR.mjs +3 -1
  228. package/lang/sr.js +3 -1
  229. package/lang/sr.mjs +3 -1
  230. package/lang/sv.js +3 -1
  231. package/lang/sv.mjs +3 -1
  232. package/lang/ta.js +3 -1
  233. package/lang/ta.mjs +3 -1
  234. package/lang/th.js +3 -1
  235. package/lang/th.mjs +3 -1
  236. package/lang/tr.js +3 -1
  237. package/lang/tr.mjs +3 -1
  238. package/lang/ug.js +5 -3
  239. package/lang/ug.mjs +5 -3
  240. package/lang/uk.js +3 -1
  241. package/lang/uk.mjs +3 -1
  242. package/lang/uz-Cyrl.js +3 -1
  243. package/lang/uz-Cyrl.mjs +3 -1
  244. package/lang/uz-Latn.js +3 -1
  245. package/lang/uz-Latn.mjs +3 -1
  246. package/lang/vi.js +3 -1
  247. package/lang/vi.mjs +3 -1
  248. package/lang/zh-CN.js +3 -1
  249. package/lang/zh-CN.mjs +3 -1
  250. package/lang/zh-TW.js +3 -1
  251. package/lang/zh-TW.mjs +3 -1
  252. package/package.json +4 -5
  253. package/src/components/btn-dropdown/QBtnDropdown.js +10 -2
  254. package/src/components/btn-dropdown/QBtnDropdown.json +8 -0
  255. package/src/components/chip/QChip.js +9 -2
  256. package/src/components/chip/QChip.json +8 -0
  257. package/src/components/chip/__tests__/QChip.spec.js +359 -46
  258. package/src/components/circular-progress/QCircularProgress.js +4 -2
  259. package/src/components/circular-progress/QCircularProgress.json +7 -0
  260. package/src/components/circular-progress/use-circular-progress.js +1 -0
  261. package/src/components/dialog/QDialog.js +1 -0
  262. package/src/components/expansion-item/QExpansionItem.js +37 -8
  263. package/src/components/expansion-item/QExpansionItem.json +67 -0
  264. package/src/components/fab/QFab.js +20 -1
  265. package/src/components/form/QForm.js +35 -40
  266. package/src/components/form/QFormChildMixin.js +3 -1
  267. package/src/components/input/QInput.js +22 -17
  268. package/src/components/menu/QMenu.js +1 -0
  269. package/src/components/page/QPage.js +1 -1
  270. package/src/components/select/QSelect.js +1 -4
  271. package/src/components/table/QTable.js +1 -1
  272. package/src/components/table/QTable.json +2 -2
  273. package/src/components/tabs/QTabs.js +2 -1
  274. package/src/components/time/QTime.js +2 -2
  275. package/src/components/uploader/QUploader.json +5 -0
  276. package/src/components/uploader/uploader-core.js +2 -3
  277. package/src/composables/private/use-file.js +7 -5
  278. package/src/composables/private/use-validate.js +8 -14
  279. package/src/composables/private/use-validate.json +2 -1
  280. package/src/composables/use-form-child.js +6 -4
  281. package/src/plugins/Loading.json +0 -1
  282. package/src/utils/EventBus.js +64 -0
  283. package/src/utils/private/vm.js +4 -0
  284. package/src/utils/run-sequential-promises.js +115 -0
  285. package/src/utils.js +4 -0
@@ -33,6 +33,14 @@
33
33
  "category": "style"
34
34
  },
35
35
 
36
+ "toggle-aria-label": {
37
+ "type": "String",
38
+ "desc": "aria-label to be used on the expansion toggle element",
39
+ "examples": [ "Open details" ],
40
+ "category": "content",
41
+ "addedIn": "v2.8.4"
42
+ },
43
+
36
44
  "label": {
37
45
  "type": "String",
38
46
  "desc": "Header label (unless using 'header' slot)",
@@ -103,6 +111,13 @@
103
111
  "category": "behavior"
104
112
  },
105
113
 
114
+ "hide-expand-icon": {
115
+ "type": "Boolean",
116
+ "desc": "Do not show the expand icon",
117
+ "category": "content",
118
+ "addedIn": "v2.8.4"
119
+ },
120
+
106
121
  "expand-icon-toggle": {
107
122
  "type": "Boolean",
108
123
  "desc": "Applies the expansion events to the expand icon only and not to the whole header",
@@ -169,6 +184,58 @@
169
184
  "type": "Boolean",
170
185
  "desc": "QExpansionItem expanded status",
171
186
  "addedIn": "v2.7.6"
187
+ },
188
+
189
+ "detailsId": {
190
+ "type": "String",
191
+ "desc": "QExpansionItem details panel id (for use in aria-controls)",
192
+ "__exemption": [ "examples" ],
193
+ "addedIn": "v2.8.4"
194
+ },
195
+
196
+ "show": {
197
+ "type": "Function",
198
+ "desc": "Triggers component to show",
199
+ "params": {
200
+ "evt": {
201
+ "type": "Object",
202
+ "required": false,
203
+ "desc": "JS event object",
204
+ "__exemption": [ "examples" ]
205
+ }
206
+ },
207
+ "returns": null,
208
+ "addedIn": "v2.8.4"
209
+ },
210
+
211
+ "hide": {
212
+ "type": "Function",
213
+ "desc": "Triggers component to hide",
214
+ "params": {
215
+ "evt": {
216
+ "type": "Object",
217
+ "required": false,
218
+ "desc": "JS event object",
219
+ "__exemption": [ "examples" ]
220
+ }
221
+ },
222
+ "returns": null,
223
+ "addedIn": "v2.8.4"
224
+ },
225
+
226
+ "toggle": {
227
+ "type": "Function",
228
+ "desc": "Triggers component to toggle between show/hide",
229
+ "params": {
230
+ "evt": {
231
+ "type": "Object",
232
+ "required": false,
233
+ "desc": "JS event object",
234
+ "__exemption": [ "examples" ]
235
+ }
236
+ },
237
+ "returns": null,
238
+ "addedIn": "v2.8.4"
172
239
  }
173
240
  }
174
241
  }
@@ -9,6 +9,7 @@ import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../
9
9
  import { createComponent } from '../../utils/private/create.js'
10
10
  import { hSlot, hMergeSlot } from '../../utils/private/render.js'
11
11
  import { fabKey } from '../../utils/private/symbols.js'
12
+ import uid from '../../utils/uid.js'
12
13
 
13
14
  const directions = [ 'up', 'right', 'down', 'left' ]
14
15
  const alignValues = [ 'left', 'center', 'right' ]
@@ -48,6 +49,7 @@ export default createComponent({
48
49
  setup (props, { slots }) {
49
50
  const triggerRef = ref(null)
50
51
  const showing = ref(props.modelValue === true)
52
+ const targetUid = uid()
51
53
 
52
54
  const { proxy: { $q } } = getCurrentInstance()
53
55
  const { formClass, labelProps } = useFab(props, showing)
@@ -73,6 +75,21 @@ export default createComponent({
73
75
  + ` q-fab__actions--${ showing.value === true ? 'opened' : 'closed' }`
74
76
  )
75
77
 
78
+ const actionAttrs = computed(() => {
79
+ const attrs = {
80
+ id: targetUid
81
+ }
82
+
83
+ if (showing.value === true) {
84
+ attrs.role = 'menu'
85
+ }
86
+ else {
87
+ attrs[ 'aria-hidden' ] = 'true'
88
+ }
89
+
90
+ return attrs
91
+ })
92
+
76
93
  const iconHolderClass = computed(() =>
77
94
  'q-fab__icon-holder '
78
95
  + ` q-fab__icon-holder--${ showing.value === true ? 'opened' : 'closed' }`
@@ -134,10 +151,12 @@ export default createComponent({
134
151
  fab: true,
135
152
  'aria-expanded': showing.value === true ? 'true' : 'false',
136
153
  'aria-haspopup': 'true',
154
+ 'aria-controls': targetUid,
155
+ 'aria-owns': targetUid,
137
156
  onClick: toggle
138
157
  }, getTriggerContent),
139
158
 
140
- h('div', { class: actionClass.value }, hSlot(slots.default))
159
+ h('div', { class: actionClass.value, ...actionAttrs.value }, hSlot(slots.default))
141
160
  ])
142
161
  }
143
162
  })
@@ -5,6 +5,7 @@ import { stopAndPrevent } from '../../utils/event.js'
5
5
  import { addFocusFn } from '../../utils/private/focus-manager.js'
6
6
  import { hSlot } from '../../utils/private/render.js'
7
7
  import { formKey } from '../../utils/private/symbols.js'
8
+ import { vmIsDestroyed } from '../../utils/private/vm.js'
8
9
 
9
10
  export default createComponent({
10
11
  name: 'QForm',
@@ -28,7 +29,6 @@ export default createComponent({
28
29
  const registeredComponents = []
29
30
 
30
31
  function validate (shouldFocus) {
31
- const promises = []
32
32
  const focus = typeof shouldFocus === 'boolean'
33
33
  ? shouldFocus
34
34
  : props.noErrorFocus !== true
@@ -39,60 +39,55 @@ export default createComponent({
39
39
  emit('validation-' + (res === true ? 'success' : 'error'), ref)
40
40
  }
41
41
 
42
- for (let i = 0; i < registeredComponents.length; i++) {
43
- const comp = registeredComponents[ i ]
42
+ const validateComponent = comp => {
44
43
  const valid = comp.validate()
45
44
 
46
- if (typeof valid.then === 'function') {
47
- promises.push(
48
- valid.then(
49
- valid => ({ valid, comp }),
50
- err => ({ valid: false, comp, err })
51
- )
45
+ return typeof valid.then === 'function'
46
+ ? valid.then(
47
+ valid => ({ valid, comp }),
48
+ err => ({ valid: false, comp, err })
52
49
  )
53
- }
54
- else if (valid !== true) {
55
- if (props.greedy === false) {
56
- emitEvent(false, comp)
57
-
58
- if (focus === true && typeof comp.focus === 'function') {
59
- comp.focus()
60
- }
61
-
62
- return Promise.resolve(false)
63
- }
64
-
65
- promises.push({ valid: false, comp })
66
- }
50
+ : Promise.resolve({ valid, comp })
67
51
  }
68
52
 
69
- if (promises.length === 0) {
70
- emitEvent(true)
71
- return Promise.resolve(true)
72
- }
73
-
74
- return Promise.all(promises).then(res => {
75
- const errors = res.filter(r => r.valid !== true)
53
+ const errorsPromise = props.greedy === true
54
+ ? Promise
55
+ .all(registeredComponents.map(validateComponent))
56
+ .then(res => res.filter(r => r.valid !== true))
57
+ : registeredComponents
58
+ .reduce(
59
+ (acc, comp) => acc.then(() => {
60
+ return validateComponent(comp).then(r => {
61
+ if (r.valid === false) { return Promise.reject(r) }
62
+ })
63
+ }),
64
+ Promise.resolve()
65
+ )
66
+ .catch(error => [ error ])
76
67
 
77
- if (errors.length === 0) {
68
+ return errorsPromise.then(errors => {
69
+ if (errors === void 0 || errors.length === 0) {
78
70
  index === validateIndex && emitEvent(true)
79
71
  return true
80
72
  }
81
73
 
82
- const { valid, comp, err } = errors[ 0 ]
83
-
84
74
  // if not outdated already
85
75
  if (index === validateIndex) {
86
- err !== void 0 && console.error(err)
76
+ const { comp, err } = errors[ 0 ]
87
77
 
78
+ err !== void 0 && console.error(err)
88
79
  emitEvent(false, comp)
89
80
 
90
- if (
91
- focus === true
92
- && valid !== true
93
- && typeof comp.focus === 'function'
94
- ) {
95
- comp.focus()
81
+ if (focus === true) {
82
+ // Try to focus first mounted and active component
83
+ const activeError = errors.find(({ comp }) => (
84
+ typeof comp.focus === 'function'
85
+ && vmIsDestroyed(comp.$) === false
86
+ ))
87
+
88
+ if (activeError !== void 0) {
89
+ activeError.comp.focus()
90
+ }
96
91
  }
97
92
  }
98
93
 
@@ -28,12 +28,14 @@ export default {
28
28
  resetValidation () {}
29
29
  },
30
30
 
31
- created () {
31
+ mounted () {
32
+ // register to parent QForm
32
33
  const $form = this.$.provides[ formKey ]
33
34
  $form !== void 0 && this.disable !== true && $form.bindComponent(this)
34
35
  },
35
36
 
36
37
  beforeUnmount () {
38
+ // un-register from parent QForm
37
39
  const $form = this.$.provides[ formKey ]
38
40
  $form !== void 0 && this.disable !== true && $form.unbindComponent(this)
39
41
  }
@@ -43,6 +43,9 @@ export default createComponent({
43
43
  ],
44
44
 
45
45
  setup (props, { emit, attrs }) {
46
+ const { proxy } = getCurrentInstance()
47
+ const { $q } = proxy
48
+
46
49
  const temp = {}
47
50
  let emitCachedValue = NaN, typedNumber, stopValueWatcher, emitTimer, emitValueFn
48
51
 
@@ -289,21 +292,24 @@ export default createComponent({
289
292
 
290
293
  // textarea only
291
294
  function adjustHeight () {
292
- const inp = inputRef.value
293
- if (inp !== null) {
294
- const parentStyle = inp.parentNode.style
295
- const { overflow } = inp.style
296
-
297
- // reset height of textarea to a small size to detect the real height
298
- // but keep the total control size the same
299
- parentStyle.marginBottom = (inp.scrollHeight - 1) + 'px'
300
- inp.style.height = '1px'
301
- inp.style.overflow = 'hidden'
302
-
303
- inp.style.height = inp.scrollHeight + 'px'
304
- inp.style.overflow = overflow
305
- parentStyle.marginBottom = ''
306
- }
295
+ requestAnimationFrame(() => {
296
+ const inp = inputRef.value
297
+ if (inp !== null) {
298
+ const parentStyle = inp.parentNode.style
299
+ const { overflow } = inp.style
300
+
301
+ // reset height of textarea to a small size to detect the real height
302
+ // but keep the total control size the same
303
+ // Firefox rulez #14263, #14344
304
+ $q.platform.is.firefox !== true && (inp.style.overflow = 'hidden')
305
+ inp.style.height = '1px'
306
+ parentStyle.marginBottom = (inp.scrollHeight - 1) + 'px'
307
+
308
+ inp.style.height = inp.scrollHeight + 'px'
309
+ inp.style.overflow = overflow
310
+ parentStyle.marginBottom = ''
311
+ }
312
+ })
307
313
  }
308
314
 
309
315
  function onChange (e) {
@@ -406,8 +412,7 @@ export default createComponent({
406
412
  const renderFn = useField(state)
407
413
 
408
414
  // expose public methods
409
- const vm = getCurrentInstance()
410
- Object.assign(vm.proxy, {
415
+ Object.assign(proxy, {
411
416
  focus,
412
417
  select,
413
418
  getNativeElement: () => inputRef.value
@@ -350,6 +350,7 @@ export default createComponent({
350
350
  () => (
351
351
  showing.value === true
352
352
  ? h('div', {
353
+ role: 'menu',
353
354
  ...attrs,
354
355
  ref: innerRef,
355
356
  tabindex: -1,
@@ -45,7 +45,7 @@ export default createComponent({
45
45
  })
46
46
 
47
47
  const classes = computed(() =>
48
- `q-page ${ props.padding === true ? ' q-layout-padding' : '' }`
48
+ `q-page${ props.padding === true ? ' q-layout-padding' : '' }`
49
49
  )
50
50
 
51
51
  return () => h('main', {
@@ -273,16 +273,13 @@ export default createComponent({
273
273
  tabindex: props.tabindex,
274
274
  role: 'combobox',
275
275
  'aria-label': props.label,
276
+ 'aria-readonly': props.readonly === true ? 'true' : 'false',
276
277
  'aria-autocomplete': props.useInput === true ? 'list' : 'none',
277
278
  'aria-expanded': menu.value === true ? 'true' : 'false',
278
279
  'aria-owns': `${ state.targetUid.value }_lb`,
279
280
  'aria-controls': `${ state.targetUid.value }_lb`
280
281
  }
281
282
 
282
- if (optionIndex.value >= 0) {
283
- attrs[ 'aria-activedescendant' ] = `${ state.targetUid.value }_${ optionIndex.value }`
284
- }
285
-
286
283
  return attrs
287
284
  })
288
285
 
@@ -348,7 +348,7 @@ export default createComponent({
348
348
 
349
349
  if (rowEl !== null) {
350
350
  const scrollTarget = rootRef.value.querySelector('.q-table__middle.scroll')
351
- const { offsetTop } = rowEl
351
+ const offsetTop = rowEl.offsetTop - props.virtualScrollStickySizeStart
352
352
  const direction = offsetTop < scrollTarget.scrollTop ? 'decrease' : 'increase'
353
353
 
354
354
  scrollTarget.scrollTop = offsetTop
@@ -77,10 +77,10 @@
77
77
 
78
78
  "virtual-scroll-sticky-size-start": {
79
79
  "type": [ "Number", "String" ],
80
- "desc": "Size in pixels of the sticky header (if using one); A correct value will improve scroll precision",
80
+ "desc": "Size in pixels of the sticky header (if using one); A correct value will improve scroll precision; Will be also used for non-virtual-scroll tables for fixing top alignment when using scrollTo method",
81
81
  "default": "0",
82
82
  "examples": [ "virtual-scroll-sticky-size-start=\"48\"" ],
83
- "category": "virtual-scroll"
83
+ "category": "virtual-scroll|behavior"
84
84
  },
85
85
 
86
86
  "virtual-scroll-sticky-size-end": {
@@ -11,6 +11,7 @@ import { noop } from '../../utils/event.js'
11
11
  import { hSlot } from '../../utils/private/render.js'
12
12
  import { tabsKey } from '../../utils/private/symbols.js'
13
13
  import { rtlHasScrollBug } from '../../utils/private/rtl.js'
14
+ import { vmIsDestroyed } from '../../utils/private/vm.js'
14
15
 
15
16
  function getIndicatorClass (color, top, vertical) {
16
17
  const pos = vertical === true
@@ -180,7 +181,7 @@ export default createComponent({
180
181
 
181
182
  function recalculateScroll () {
182
183
  registerScrollTick(() => {
183
- if (vm.isDeactivated !== true && vm.isUnmounted !== true) {
184
+ if (vmIsDestroyed(vm) === false) {
184
185
  updateContainer({
185
186
  width: rootRef.value.offsetWidth,
186
187
  height: rootRef.value.offsetHeight
@@ -12,6 +12,7 @@ import { hSlot } from '../../utils/private/render.js'
12
12
  import { formatDate, __splitDate } from '../../utils/date.js'
13
13
  import { position } from '../../utils/event.js'
14
14
  import { pad } from '../../utils/format.js'
15
+ import { vmIsDestroyed } from '../../utils/private/vm.js'
15
16
 
16
17
  function getViewByModel (model, withSeconds) {
17
18
  if (model.hour !== null) {
@@ -386,8 +387,7 @@ export default createComponent({
386
387
  }
387
388
 
388
389
  function shouldAbortInteraction () {
389
- return vm.isDeactivated === true
390
- || vm.isUnmounted === true
390
+ return vmIsDestroyed(vm) === true
391
391
  // if we have limited options, can we actually set any?
392
392
  || (
393
393
  viewValidOptions.value !== null
@@ -258,6 +258,11 @@
258
258
  "isBusy": {
259
259
  "type": "Boolean",
260
260
  "desc": "The component state is set as busy; User should not be able to interact with the component"
261
+ },
262
+
263
+ "isUploading": {
264
+ "type": "Boolean",
265
+ "desc": "The component is uploading files"
261
266
  }
262
267
  }
263
268
  }
@@ -12,6 +12,7 @@ import { stop } from '../../utils/event.js'
12
12
  import { humanStorageSize } from '../../utils/format.js'
13
13
  import { uploaderKey } from '../../utils/private/symbols.js'
14
14
  import { injectProp, injectMultipleProps } from '../../utils/private/inject-obj-prop.js'
15
+ import { vmIsDestroyed } from '../../utils/private/vm.js'
15
16
 
16
17
  function getProgressLabel (p) {
17
18
  return (p * 100).toFixed(2) + '%'
@@ -90,9 +91,7 @@ export function getRenderer (getPlugin) {
90
91
  uploadedSize: ref(0),
91
92
 
92
93
  updateFileStatus,
93
- isAlive () {
94
- return vm.isDeactivated !== true && vm.isUnmounted !== true
95
- }
94
+ isAlive: () => vmIsDestroyed(vm) === false
96
95
  }
97
96
 
98
97
  const {
@@ -129,11 +129,13 @@ export default function ({
129
129
  file.__key = file.webkitRelativePath + file.lastModified + file.name + file.size
130
130
  })
131
131
 
132
- // Avoid duplicate files
133
- const filenameMap = currentFileList.map(entry => entry.__key)
134
- files = filterFiles(files, rejectedFiles, 'duplicate', file => {
135
- return filenameMap.includes(file.__key) === false
136
- })
132
+ if (append === true) {
133
+ // Avoid duplicate files
134
+ const filenameMap = currentFileList.map(entry => entry.__key)
135
+ files = filterFiles(files, rejectedFiles, 'duplicate', file => {
136
+ return filenameMap.includes(file.__key) === false
137
+ })
138
+ }
137
139
 
138
140
  if (files.length === 0) { return done() }
139
141
 
@@ -2,7 +2,7 @@ import { ref, computed, watch, onBeforeUnmount, getCurrentInstance } from 'vue'
2
2
 
3
3
  import useFormChild from '../use-form-child.js'
4
4
  import { testPattern } from '../../utils/patterns.js'
5
- import { debounce } from '../../utils.js'
5
+ import debounce from '../../utils/debounce.js'
6
6
  import { injectProp } from '../../utils/private/inject-obj-prop.js'
7
7
 
8
8
  const lazyRulesValues = [ true, false, 'ondemand' ]
@@ -119,21 +119,15 @@ export default function (focused, innerLoading) {
119
119
 
120
120
  const index = ++validateIndex
121
121
 
122
- if (innerLoading.value !== true && props.lazyRules !== true) {
123
- isDirtyModel.value = true
124
- }
122
+ const setDirty = innerLoading.value !== true
123
+ ? () => { isDirtyModel.value = true }
124
+ : () => {}
125
125
 
126
126
  const update = (err, msg) => {
127
- if (innerError.value !== err) {
128
- innerError.value = err
129
- }
130
-
131
- const m = msg || void 0
132
-
133
- if (innerErrorMessage.value !== m) {
134
- innerErrorMessage.value = m
135
- }
127
+ err === true && setDirty()
136
128
 
129
+ innerError.value = err
130
+ innerErrorMessage.value = msg || null
137
131
  innerLoading.value = false
138
132
  }
139
133
 
@@ -144,7 +138,7 @@ export default function (focused, innerLoading) {
144
138
  let res
145
139
 
146
140
  if (typeof rule === 'function') {
147
- res = rule(val)
141
+ res = rule(val, testPattern)
148
142
  }
149
143
  else if (typeof rule === 'string' && testPattern[ rule ] !== void 0) {
150
144
  res = testPattern[ rule ](val)
@@ -32,7 +32,8 @@
32
32
  "desc": "Array of Functions/Strings; If String, then it must be a name of one of the embedded validation rules",
33
33
  "examples": [
34
34
  ":rules=\"[ val => val.length <= 3 || 'Please use maximum 3 characters' ]\"",
35
- ":rules=\"[ 'fulltime' ]\""
35
+ ":rules=\"[ 'fulltime' ]\"",
36
+ ":rules=\"[ (val, rules) => rules.email(val) || 'Please enter a valid email address' ]\""
36
37
  ],
37
38
  "category": "behavior"
38
39
  },
@@ -1,4 +1,4 @@
1
- import { inject, watch, onBeforeUnmount, getCurrentInstance } from 'vue'
1
+ import { inject, watch, getCurrentInstance, onMounted, onBeforeUnmount } from 'vue'
2
2
 
3
3
  import { formKey } from '../utils/private/symbols.js'
4
4
 
@@ -21,11 +21,13 @@ export default function ({ validate, resetValidation, requiresQForm }) {
21
21
  }
22
22
  })
23
23
 
24
- // register component to parent QForm
25
- props.disable !== true && $form.bindComponent(proxy)
24
+ onMounted(() => {
25
+ // register to parent QForm
26
+ props.disable !== true && $form.bindComponent(proxy)
27
+ })
26
28
 
27
29
  onBeforeUnmount(() => {
28
- // unregister component
30
+ // un-register from parent QForm
29
31
  props.disable !== true && $form.unbindComponent(proxy)
30
32
  })
31
33
  }
@@ -74,7 +74,6 @@
74
74
 
75
75
  "methods": {
76
76
  "show": {
77
- "tsInjectionPoint": true,
78
77
  "desc": "Activate and show",
79
78
  "params": {
80
79
  "opts": {
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Forked from tiny-emitter
3
+ * Copyright (c) 2017 Scott Corgan
4
+ */
5
+
6
+ export default class EventBus {
7
+ constructor () {
8
+ this.__stack = {}
9
+ }
10
+
11
+ on (name, callback, ctx) {
12
+ (this.__stack[ name ] || (this.__stack[ name ] = [])).push({
13
+ fn: callback,
14
+ ctx
15
+ })
16
+
17
+ return this // chainable
18
+ }
19
+
20
+ once (name, callback, ctx) {
21
+ const listener = () => {
22
+ this.off(name, listener)
23
+ callback.apply(ctx, arguments)
24
+ }
25
+
26
+ listener.__callback = callback
27
+ return this.on(name, listener, ctx) // chainable
28
+ }
29
+
30
+ emit (name) {
31
+ const list = this.__stack[ name ]
32
+
33
+ if (list !== void 0) {
34
+ const params = [].slice.call(arguments, 1)
35
+ list.forEach(entry => {
36
+ entry.fn.apply(entry.ctx, params)
37
+ })
38
+ }
39
+
40
+ return this // chainable
41
+ }
42
+
43
+ off (name, callback) {
44
+ const list = this.__stack[ name ]
45
+ const liveEvents = []
46
+
47
+ if (list !== void 0 && callback) {
48
+ list.forEach(entry => {
49
+ if (entry.fn !== callback && entry.fn.__callback !== callback) {
50
+ liveEvents.push(entry)
51
+ }
52
+ })
53
+
54
+ if (liveEvents.length !== 0) {
55
+ this.__stack[ name ] = liveEvents
56
+ }
57
+ else {
58
+ delete this.__stack[ name ]
59
+ }
60
+ }
61
+
62
+ return this // chainable
63
+ }
64
+ }
@@ -43,3 +43,7 @@ export function getNormalizedVNodes (vnodes) {
43
43
  export function vmHasRouter (vm) {
44
44
  return vm.appContext.config.globalProperties.$router !== void 0
45
45
  }
46
+
47
+ export function vmIsDestroyed (vm) {
48
+ return vm.isUnmounted === true || vm.isDeactivated === true
49
+ }