quasar 2.8.3 → 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 (274) hide show
  1. package/dist/api/QBtnDropdown.json +9 -0
  2. package/dist/api/QChip.json +9 -0
  3. package/dist/api/QCircularProgress.json +6 -0
  4. package/dist/api/QExpansionItem.json +59 -0
  5. package/dist/api/QTable.json +2 -2
  6. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  7. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  10. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  11. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  12. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  13. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  14. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  16. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  17. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  18. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  19. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  20. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  21. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  24. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  25. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  26. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  42. package/dist/icon-set/themify.umd.prod.js +1 -1
  43. package/dist/lang/ar-TN.umd.prod.js +2 -2
  44. package/dist/lang/ar.umd.prod.js +2 -2
  45. package/dist/lang/az-Latn.umd.prod.js +2 -2
  46. package/dist/lang/bg.umd.prod.js +2 -2
  47. package/dist/lang/bn.umd.prod.js +2 -2
  48. package/dist/lang/ca.umd.prod.js +2 -2
  49. package/dist/lang/cs.umd.prod.js +2 -2
  50. package/dist/lang/da.umd.prod.js +2 -2
  51. package/dist/lang/de.umd.prod.js +2 -2
  52. package/dist/lang/el.umd.prod.js +2 -2
  53. package/dist/lang/en-GB.umd.prod.js +2 -2
  54. package/dist/lang/en-US.umd.prod.js +2 -2
  55. package/dist/lang/eo.umd.prod.js +2 -2
  56. package/dist/lang/es.umd.prod.js +2 -2
  57. package/dist/lang/et.umd.prod.js +2 -2
  58. package/dist/lang/eu.umd.prod.js +2 -2
  59. package/dist/lang/fa-IR.umd.prod.js +2 -2
  60. package/dist/lang/fa.umd.prod.js +2 -2
  61. package/dist/lang/fi.umd.prod.js +2 -2
  62. package/dist/lang/fr.umd.prod.js +2 -2
  63. package/dist/lang/gn.umd.prod.js +2 -2
  64. package/dist/lang/he.umd.prod.js +2 -2
  65. package/dist/lang/hr.umd.prod.js +2 -2
  66. package/dist/lang/hu.umd.prod.js +2 -2
  67. package/dist/lang/id.umd.prod.js +2 -2
  68. package/dist/lang/is.umd.prod.js +2 -2
  69. package/dist/lang/it.umd.prod.js +2 -2
  70. package/dist/lang/ja.umd.prod.js +2 -2
  71. package/dist/lang/km.umd.prod.js +2 -2
  72. package/dist/lang/ko-KR.umd.prod.js +2 -2
  73. package/dist/lang/kur-CKB.umd.prod.js +2 -2
  74. package/dist/lang/kz.umd.prod.js +2 -2
  75. package/dist/lang/lt.umd.prod.js +2 -2
  76. package/dist/lang/lu.umd.prod.js +2 -2
  77. package/dist/lang/lv.umd.prod.js +2 -2
  78. package/dist/lang/ml.umd.prod.js +2 -2
  79. package/dist/lang/mm.umd.prod.js +2 -2
  80. package/dist/lang/ms.umd.prod.js +2 -2
  81. package/dist/lang/my.umd.prod.js +2 -2
  82. package/dist/lang/nb-NO.umd.prod.js +2 -2
  83. package/dist/lang/nl.umd.prod.js +2 -2
  84. package/dist/lang/pl.umd.prod.js +2 -2
  85. package/dist/lang/pt-BR.umd.prod.js +2 -2
  86. package/dist/lang/pt.umd.prod.js +2 -2
  87. package/dist/lang/ro.umd.prod.js +2 -2
  88. package/dist/lang/ru.umd.prod.js +2 -2
  89. package/dist/lang/sk.umd.prod.js +2 -2
  90. package/dist/lang/sl.umd.prod.js +2 -2
  91. package/dist/lang/sm.umd.prod.js +2 -2
  92. package/dist/lang/sr-CYR.umd.prod.js +2 -2
  93. package/dist/lang/sr.umd.prod.js +2 -2
  94. package/dist/lang/sv.umd.prod.js +2 -2
  95. package/dist/lang/ta.umd.prod.js +2 -2
  96. package/dist/lang/th.umd.prod.js +2 -2
  97. package/dist/lang/tr.umd.prod.js +2 -2
  98. package/dist/lang/ug.umd.prod.js +2 -2
  99. package/dist/lang/uk.umd.prod.js +2 -2
  100. package/dist/lang/uz-Cyrl.umd.prod.js +2 -2
  101. package/dist/lang/uz-Latn.umd.prod.js +2 -2
  102. package/dist/lang/vi.umd.prod.js +2 -2
  103. package/dist/lang/zh-CN.umd.prod.js +2 -2
  104. package/dist/lang/zh-TW.umd.prod.js +2 -2
  105. package/dist/quasar.cjs.prod.js +2 -2
  106. package/dist/quasar.esm.js +15693 -15455
  107. package/dist/quasar.esm.prod.js +2 -2
  108. package/dist/quasar.sass +1 -1
  109. package/dist/quasar.umd.js +15866 -15626
  110. package/dist/quasar.umd.prod.js +2 -2
  111. package/dist/transforms/import-map.json +2 -0
  112. package/dist/types/api/qloading.d.ts +5 -0
  113. package/dist/types/api.d.ts +1 -0
  114. package/dist/types/index.d.ts +40 -1
  115. package/dist/types/utils/is.d.ts +67 -0
  116. package/dist/types/utils/run-sequential-promises.d.ts +119 -0
  117. package/dist/types/utils.d.ts +9 -0
  118. package/dist/vetur/quasar-attributes.json +21 -1
  119. package/dist/vetur/quasar-tags.json +6 -1
  120. package/dist/web-types/web-types.json +49 -2
  121. package/lang/ar-TN.js +3 -1
  122. package/lang/ar-TN.mjs +3 -1
  123. package/lang/ar.js +3 -1
  124. package/lang/ar.mjs +3 -1
  125. package/lang/az-Latn.js +3 -1
  126. package/lang/az-Latn.mjs +3 -1
  127. package/lang/bg.js +3 -1
  128. package/lang/bg.mjs +3 -1
  129. package/lang/bn.js +3 -1
  130. package/lang/bn.mjs +3 -1
  131. package/lang/ca.js +3 -1
  132. package/lang/ca.mjs +3 -1
  133. package/lang/cs.js +3 -1
  134. package/lang/cs.mjs +3 -1
  135. package/lang/da.js +3 -1
  136. package/lang/da.mjs +3 -1
  137. package/lang/de.js +3 -1
  138. package/lang/de.mjs +3 -1
  139. package/lang/el.js +3 -1
  140. package/lang/el.mjs +3 -1
  141. package/lang/en-GB.js +3 -1
  142. package/lang/en-GB.mjs +3 -1
  143. package/lang/en-US.js +3 -1
  144. package/lang/en-US.mjs +3 -1
  145. package/lang/eo.js +3 -1
  146. package/lang/eo.mjs +3 -1
  147. package/lang/es.js +3 -1
  148. package/lang/es.mjs +3 -1
  149. package/lang/et.js +3 -1
  150. package/lang/et.mjs +3 -1
  151. package/lang/eu.js +3 -1
  152. package/lang/eu.mjs +3 -1
  153. package/lang/fa-IR.js +5 -3
  154. package/lang/fa-IR.mjs +5 -3
  155. package/lang/fa.js +5 -3
  156. package/lang/fa.mjs +5 -3
  157. package/lang/fi.js +3 -1
  158. package/lang/fi.mjs +3 -1
  159. package/lang/fr.js +3 -1
  160. package/lang/fr.mjs +3 -1
  161. package/lang/gn.js +3 -1
  162. package/lang/gn.mjs +3 -1
  163. package/lang/he.js +3 -1
  164. package/lang/he.mjs +3 -1
  165. package/lang/hr.js +3 -1
  166. package/lang/hr.mjs +3 -1
  167. package/lang/hu.js +3 -1
  168. package/lang/hu.mjs +3 -1
  169. package/lang/id.js +3 -1
  170. package/lang/id.mjs +3 -1
  171. package/lang/is.js +3 -1
  172. package/lang/is.mjs +3 -1
  173. package/lang/it.js +3 -1
  174. package/lang/it.mjs +3 -1
  175. package/lang/ja.js +3 -1
  176. package/lang/ja.mjs +3 -1
  177. package/lang/km.js +3 -1
  178. package/lang/km.mjs +3 -1
  179. package/lang/ko-KR.js +3 -1
  180. package/lang/ko-KR.mjs +3 -1
  181. package/lang/kur-CKB.js +3 -1
  182. package/lang/kur-CKB.mjs +3 -1
  183. package/lang/kz.js +3 -1
  184. package/lang/kz.mjs +3 -1
  185. package/lang/lt.js +3 -1
  186. package/lang/lt.mjs +3 -1
  187. package/lang/lu.js +3 -1
  188. package/lang/lu.mjs +3 -1
  189. package/lang/lv.js +3 -1
  190. package/lang/lv.mjs +3 -1
  191. package/lang/ml.js +3 -1
  192. package/lang/ml.mjs +3 -1
  193. package/lang/mm.js +4 -1
  194. package/lang/mm.mjs +4 -1
  195. package/lang/ms.js +3 -1
  196. package/lang/ms.mjs +3 -1
  197. package/lang/my.js +3 -1
  198. package/lang/my.mjs +3 -1
  199. package/lang/nb-NO.js +3 -1
  200. package/lang/nb-NO.mjs +3 -1
  201. package/lang/nl.js +3 -1
  202. package/lang/nl.mjs +3 -1
  203. package/lang/pl.js +3 -1
  204. package/lang/pl.mjs +3 -1
  205. package/lang/pt-BR.js +3 -1
  206. package/lang/pt-BR.mjs +3 -1
  207. package/lang/pt.js +3 -1
  208. package/lang/pt.mjs +3 -1
  209. package/lang/ro.js +3 -1
  210. package/lang/ro.mjs +3 -1
  211. package/lang/ru.js +3 -1
  212. package/lang/ru.mjs +3 -1
  213. package/lang/sk.js +3 -1
  214. package/lang/sk.mjs +3 -1
  215. package/lang/sl.js +3 -1
  216. package/lang/sl.mjs +3 -1
  217. package/lang/sm.js +3 -1
  218. package/lang/sm.mjs +3 -1
  219. package/lang/sr-CYR.js +3 -1
  220. package/lang/sr-CYR.mjs +3 -1
  221. package/lang/sr.js +3 -1
  222. package/lang/sr.mjs +3 -1
  223. package/lang/sv.js +3 -1
  224. package/lang/sv.mjs +3 -1
  225. package/lang/ta.js +3 -1
  226. package/lang/ta.mjs +3 -1
  227. package/lang/th.js +3 -1
  228. package/lang/th.mjs +3 -1
  229. package/lang/tr.js +3 -1
  230. package/lang/tr.mjs +3 -1
  231. package/lang/ug.js +5 -3
  232. package/lang/ug.mjs +5 -3
  233. package/lang/uk.js +3 -1
  234. package/lang/uk.mjs +3 -1
  235. package/lang/uz-Cyrl.js +3 -1
  236. package/lang/uz-Cyrl.mjs +3 -1
  237. package/lang/uz-Latn.js +3 -1
  238. package/lang/uz-Latn.mjs +3 -1
  239. package/lang/vi.js +3 -1
  240. package/lang/vi.mjs +3 -1
  241. package/lang/zh-CN.js +3 -1
  242. package/lang/zh-CN.mjs +3 -1
  243. package/lang/zh-TW.js +3 -1
  244. package/lang/zh-TW.mjs +3 -1
  245. package/package.json +4 -5
  246. package/src/components/btn-dropdown/QBtnDropdown.js +10 -2
  247. package/src/components/btn-dropdown/QBtnDropdown.json +8 -0
  248. package/src/components/chip/QChip.js +9 -2
  249. package/src/components/chip/QChip.json +8 -0
  250. package/src/components/chip/__tests__/QChip.spec.js +359 -46
  251. package/src/components/circular-progress/QCircularProgress.js +4 -2
  252. package/src/components/circular-progress/QCircularProgress.json +7 -0
  253. package/src/components/circular-progress/use-circular-progress.js +1 -0
  254. package/src/components/dialog/QDialog.js +1 -0
  255. package/src/components/expansion-item/QExpansionItem.js +37 -8
  256. package/src/components/expansion-item/QExpansionItem.json +67 -0
  257. package/src/components/fab/QFab.js +20 -1
  258. package/src/components/form/QForm.js +35 -40
  259. package/src/components/form/QFormChildMixin.js +3 -1
  260. package/src/components/menu/QMenu.js +1 -0
  261. package/src/components/page/QPage.js +1 -1
  262. package/src/components/select/QSelect.js +1 -4
  263. package/src/components/table/QTable.js +1 -1
  264. package/src/components/table/QTable.json +2 -2
  265. package/src/components/tabs/QTabs.js +2 -1
  266. package/src/components/time/QTime.js +2 -2
  267. package/src/components/uploader/uploader-core.js +2 -3
  268. package/src/composables/private/use-file.js +1 -1
  269. package/src/composables/private/use-validate.js +7 -13
  270. package/src/composables/use-form-child.js +6 -4
  271. package/src/utils/EventBus.js +64 -0
  272. package/src/utils/private/vm.js +4 -0
  273. package/src/utils/run-sequential-promises.js +115 -0
  274. 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
  }
@@ -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
@@ -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,7 +129,7 @@ export default function ({
129
129
  file.__key = file.webkitRelativePath + file.lastModified + file.name + file.size
130
130
  })
131
131
 
132
- if (append !== true) {
132
+ if (append === true) {
133
133
  // Avoid duplicate files
134
134
  const filenameMap = currentFileList.map(entry => entry.__key)
135
135
  files = filterFiles(files, rejectedFiles, 'duplicate', file => {
@@ -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
 
@@ -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
  }
@@ -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
+ }
@@ -0,0 +1,115 @@
1
+
2
+ function parsePromises (sequentialPromises) {
3
+ const isList = Array.isArray(sequentialPromises)
4
+
5
+ if (isList === true) {
6
+ const totalJobs = sequentialPromises.length
7
+ return {
8
+ isList,
9
+ totalJobs,
10
+ resultAggregator: Array(totalJobs).fill(null)
11
+ }
12
+ }
13
+
14
+ const resultKeys = Object.keys(sequentialPromises)
15
+ const resultAggregator = {}
16
+ resultKeys.forEach(keyName => { resultAggregator[ keyName ] = null })
17
+
18
+ return {
19
+ isList,
20
+ totalJobs: resultKeys.length,
21
+ resultAggregator,
22
+ resultKeys
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Run a list of Promises sequentially, optionally on multiple threads.
28
+ *
29
+ * @param {*} sequentialPromises - Array of Functions or Object with Functions as values
30
+ * Array of Function form: [ (resultAggregator: Array) => Promise<any>, ... ]
31
+ * Object form: { [key: string]: (resultAggregator: object) => Promise<any>, ... }
32
+ * @param {*} opts - Optional options Object
33
+ * Object form: { threadsNumber?: number, abortOnFail?: boolean }
34
+ * Default: { threadsNumber: 1, abortOnFail: true }
35
+ * When configuring threadsNumber AND using http requests, be
36
+ * aware of the maximum threads that the hosting browser
37
+ * supports (usually 3); any number of threads above that
38
+ * won't add any real benefits
39
+ * @returns Promise<Array<Object> | Object>
40
+ * With opts.abortOnFail set to true (which is default):
41
+ * When sequentialPromises param is Array:
42
+ * The Promise resolves with an Array of Objects of the following form:
43
+ * [ { key: number, status: 'fulfilled', value: any }, ... ]
44
+ * The Promise rejects with an Object of the following form:
45
+ * { key: number, status: 'rejected', reason: Error, resultAggregator: array }
46
+ * When sequentialPromises param is Object:
47
+ * The Promise resolves with an Object of the following form:
48
+ * { [key: string]: { key: string, status: 'fulfilled', value: any }, ... }
49
+ * The Promise rejects with an Object of the following form:
50
+ * { key: string, status: 'rejected', reason: Error, resultAggregator: object }
51
+ * With opts.abortOnFail set to false:
52
+ * The Promise is never rejected (no catch() needed)
53
+ * The Promise resolves with:
54
+ * An Array of Objects (when sequentialPromises param is also an Array) of the following form:
55
+ * [ { key: number, status: 'fulfilled', value: any } | { status: 'rejected', reason: Error }, ... ]
56
+ * An Object (when sequentialPromises param is also an Object) of the following form:
57
+ * { [key: string]: { key: string, status: 'fulfilled', value: any } | { key: string, status: 'rejected', reason: Error }, ... }
58
+ */
59
+ export default function runSequentialPromises (
60
+ sequentialPromises,
61
+ { threadsNumber = 1, abortOnFail = true } = {}
62
+ ) {
63
+ let jobIndex = -1, hasAborted = false
64
+
65
+ const { isList, totalJobs, resultAggregator, resultKeys } = parsePromises(sequentialPromises)
66
+
67
+ const getPromiseThread = () => new Promise((resolve, reject) => {
68
+ function runNextPromise () {
69
+ const currentJobIndex = ++jobIndex
70
+
71
+ if (hasAborted === true || currentJobIndex >= totalJobs) {
72
+ resolve()
73
+ return
74
+ }
75
+
76
+ const key = isList === true ? currentJobIndex : resultKeys[ currentJobIndex ]
77
+
78
+ sequentialPromises[ key ](resultAggregator)
79
+ .then(value => {
80
+ if (hasAborted === true) {
81
+ resolve()
82
+ return // early exit
83
+ }
84
+
85
+ resultAggregator[ key ] = { key, status: 'fulfilled', value }
86
+
87
+ // timeout so it doesn't interfere with the .catch() below
88
+ setTimeout(runNextPromise)
89
+ })
90
+ .catch(reason => {
91
+ if (hasAborted === true) {
92
+ resolve()
93
+ return // early exit
94
+ }
95
+
96
+ const result = { key, status: 'rejected', reason }
97
+ resultAggregator[ key ] = result
98
+
99
+ if (abortOnFail === true) {
100
+ hasAborted = true
101
+ reject({ ...result, resultAggregator })
102
+ return // early exit
103
+ }
104
+
105
+ // timeout so no interference
106
+ setTimeout(runNextPromise)
107
+ })
108
+ }
109
+
110
+ runNextPromise()
111
+ })
112
+
113
+ const threads = Array(threadsNumber).fill(getPromiseThread())
114
+ return Promise.all(threads).then(() => resultAggregator)
115
+ }
package/src/utils.js CHANGED
@@ -6,6 +6,7 @@ import createUploaderComponent from './utils/create-uploader-component.js'
6
6
  import date from './utils/date.js'
7
7
  import debounce from './utils/debounce.js'
8
8
  import dom from './utils/dom.js'
9
+ import EventBus from './utils/EventBus.js'
9
10
  import event, { noop } from './utils/event.js'
10
11
  import exportFile from './utils/export-file.js'
11
12
  import extend from './utils/extend.js'
@@ -16,6 +17,7 @@ import is from './utils/is.js'
16
17
  import morph from './utils/morph.js'
17
18
  import openURL from './utils/open-url.js'
18
19
  import patterns from './utils/patterns.js'
20
+ import runSequentialPromises from './utils/run-sequential-promises.js'
19
21
  import scroll from './utils/scroll.js'
20
22
  import setCssVar from './utils/set-css-var.js'
21
23
  import throttle from './utils/throttle.js'
@@ -30,6 +32,7 @@ export {
30
32
  date,
31
33
  debounce,
32
34
  dom,
35
+ EventBus,
33
36
  event,
34
37
  exportFile,
35
38
  extend,
@@ -41,6 +44,7 @@ export {
41
44
  morph,
42
45
  openURL,
43
46
  patterns,
47
+ runSequentialPromises,
44
48
  scroll,
45
49
  setCssVar,
46
50
  throttle,