quasar 2.8.3 → 2.9.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 (314) hide show
  1. package/dist/api/QBreadcrumbsEl.json +52 -0
  2. package/dist/api/QBtn.json +41 -6
  3. package/dist/api/QBtnDropdown.json +9 -0
  4. package/dist/api/QChip.json +9 -0
  5. package/dist/api/QCircularProgress.json +6 -0
  6. package/dist/api/QEditor.json +7 -0
  7. package/dist/api/QExpansionItem.json +59 -0
  8. package/dist/api/QItem.json +52 -0
  9. package/dist/api/QRating.json +13 -0
  10. package/dist/api/QRouteTab.json +42 -6
  11. package/dist/api/QTable.json +2 -2
  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 +16157 -15723
  113. package/dist/quasar.esm.prod.js +2 -2
  114. package/dist/quasar.sass +1 -1
  115. package/dist/quasar.umd.js +16290 -15854
  116. package/dist/quasar.umd.prod.js +2 -2
  117. package/dist/transforms/import-map.json +2 -0
  118. package/dist/types/api/qeditor.d.ts +17 -0
  119. package/dist/types/api/qloading.d.ts +5 -0
  120. package/dist/types/api.d.ts +2 -0
  121. package/dist/types/index.d.ts +133 -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 +25 -1
  126. package/dist/vetur/quasar-tags.json +7 -1
  127. package/dist/web-types/web-types.json +108 -10
  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 +6 -5
  253. package/src/components/breadcrumbs/QBreadcrumbsEl.js +6 -7
  254. package/src/components/breadcrumbs/QBreadcrumbsEl.json +53 -0
  255. package/src/components/btn/QBtn.js +19 -19
  256. package/src/components/btn/QBtn.json +41 -6
  257. package/src/components/btn/use-btn.js +6 -4
  258. package/src/components/btn-dropdown/QBtnDropdown.js +10 -2
  259. package/src/components/btn-dropdown/QBtnDropdown.json +8 -0
  260. package/src/components/checkbox/QCheckbox.js +1 -2
  261. package/src/components/checkbox/use-checkbox.js +2 -1
  262. package/src/components/chip/QChip.js +9 -2
  263. package/src/components/chip/QChip.json +8 -0
  264. package/src/components/chip/__tests__/QChip.spec.js +359 -46
  265. package/src/components/circular-progress/QCircularProgress.js +4 -2
  266. package/src/components/circular-progress/QCircularProgress.json +7 -0
  267. package/src/components/circular-progress/use-circular-progress.js +1 -0
  268. package/src/components/dialog/QDialog.js +7 -4
  269. package/src/components/drawer/QDrawer.js +7 -4
  270. package/src/components/editor/QEditor.json +9 -0
  271. package/src/components/expansion-item/QExpansionItem.js +37 -8
  272. package/src/components/expansion-item/QExpansionItem.json +67 -0
  273. package/src/components/fab/QFab.js +20 -1
  274. package/src/components/form/QForm.js +35 -40
  275. package/src/components/form/QFormChildMixin.js +3 -1
  276. package/src/components/item/QItem.js +4 -5
  277. package/src/components/item/QItem.json +53 -0
  278. package/src/components/menu/QMenu.js +5 -5
  279. package/src/components/menu/__tests__/QMenu.spec.js +7 -0
  280. package/src/components/page/QPage.js +1 -1
  281. package/src/components/popup-edit/QPopupEdit.js +2 -5
  282. package/src/components/radio/QRadio.js +3 -3
  283. package/src/components/rating/QRating.js +48 -10
  284. package/src/components/rating/QRating.json +11 -0
  285. package/src/components/select/QSelect.js +1 -4
  286. package/src/components/stepper/QStep.js +5 -3
  287. package/src/components/table/QTable.js +4 -6
  288. package/src/components/table/QTable.json +2 -2
  289. package/src/components/tabs/QRouteTab.js +6 -4
  290. package/src/components/tabs/QRouteTab.json +42 -6
  291. package/src/components/tabs/QTabs.js +188 -107
  292. package/src/components/tabs/use-tab.js +62 -38
  293. package/src/components/time/QTime.js +2 -2
  294. package/src/components/tooltip/QTooltip.js +7 -13
  295. package/src/components/tree/QTree.js +1 -1
  296. package/src/components/uploader/uploader-core.js +2 -3
  297. package/src/composables/private/__tests__/use-model-toggle.spec.js +2 -0
  298. package/src/composables/private/__tests__/use-transition.spec.js +4 -0
  299. package/src/composables/private/use-file.js +1 -1
  300. package/src/composables/private/use-router-link.js +80 -43
  301. package/src/composables/private/use-tick.js +15 -9
  302. package/src/composables/private/use-timeout.js +20 -7
  303. package/src/composables/private/use-validate.js +7 -13
  304. package/src/composables/use-form-child.js +6 -4
  305. package/src/directives/TouchPan.js +1 -1
  306. package/src/directives/TouchRepeat.js +1 -1
  307. package/src/directives/TouchSwipe.js +1 -1
  308. package/src/utils/EventBus.js +64 -0
  309. package/src/utils/extend.js +19 -19
  310. package/src/utils/private/inject-obj-prop.js +2 -0
  311. package/src/utils/private/rtl.js +10 -7
  312. package/src/utils/private/vm.js +4 -0
  313. package/src/utils/run-sequential-promises.js +115 -0
  314. package/src/utils.js +4 -0
@@ -37,6 +37,7 @@ export default createComponent({
37
37
 
38
38
  dense: Boolean,
39
39
 
40
+ toggleAriaLabel: String,
40
41
  expandIcon: String,
41
42
  expandedIcon: String,
42
43
  expandIconClass: [ Array, String, Object ],
@@ -47,6 +48,7 @@ export default createComponent({
47
48
 
48
49
  expandSeparator: Boolean,
49
50
  defaultOpened: Boolean,
51
+ hideExpandIcon: Boolean,
50
52
  expandIconToggle: Boolean,
51
53
  switchToggleSide: Boolean,
52
54
  denseToggle: Boolean,
@@ -73,8 +75,9 @@ export default createComponent({
73
75
  )
74
76
 
75
77
  const blurTargetRef = ref(null)
78
+ const targetUid = uid()
76
79
 
77
- const { hide, toggle } = useModelToggle({ showing })
80
+ const { show, hide, toggle } = useModelToggle({ showing })
78
81
 
79
82
  let uniqueId, exitGroup
80
83
 
@@ -124,6 +127,28 @@ export default createComponent({
124
127
  props.disable !== true && (hasLink.value === true || props.expandIconToggle === true)
125
128
  )
126
129
 
130
+ const headerSlotScope = computed(() => ({
131
+ expanded: showing.value === true,
132
+ detailsId: props.targetUid,
133
+ toggle,
134
+ show,
135
+ hide
136
+ }))
137
+
138
+ const toggleAriaAttrs = computed(() => {
139
+ const toggleAriaLabel = props.toggleAriaLabel !== void 0
140
+ ? props.toggleAriaLabel
141
+ : $q.lang.label[ showing.value === true ? 'collapse' : 'expand' ](props.label)
142
+
143
+ return {
144
+ role: 'button',
145
+ 'aria-expanded': showing.value === true ? 'true' : 'false',
146
+ 'aria-owns': targetUid,
147
+ 'aria-controls': targetUid,
148
+ 'aria-label': toggleAriaLabel
149
+ }
150
+ })
151
+
127
152
  watch(() => props.group, name => {
128
153
  exitGroup !== void 0 && exitGroup()
129
154
  name !== void 0 && enterGroup()
@@ -215,6 +240,7 @@ export default createComponent({
215
240
  if (activeToggleIcon.value === true) {
216
241
  Object.assign(data, {
217
242
  tabindex: 0,
243
+ ...toggleAriaAttrs.value,
218
244
  onClick: toggleIcon,
219
245
  onKeyup: toggleIconKeyboard
220
246
  })
@@ -235,7 +261,7 @@ export default createComponent({
235
261
  let child
236
262
 
237
263
  if (slots.header !== void 0) {
238
- child = [].concat(slots.header({ expanded: showing.value === true }))
264
+ child = [].concat(slots.header(headerSlotScope.value))
239
265
  }
240
266
  else {
241
267
  child = [
@@ -256,9 +282,11 @@ export default createComponent({
256
282
  )
257
283
  }
258
284
 
259
- props.disable !== true && child[ props.switchToggleSide === true ? 'unshift' : 'push' ](
260
- getToggleIcon()
261
- )
285
+ if (props.disable !== true && props.hideExpandIcon !== true) {
286
+ child[ props.switchToggleSide === true ? 'unshift' : 'push' ](
287
+ getToggleIcon()
288
+ )
289
+ }
262
290
 
263
291
  return child
264
292
  }
@@ -278,9 +306,9 @@ export default createComponent({
278
306
  data.clickable = true
279
307
  data.onClick = onHeaderClick
280
308
 
281
- hasLink.value === true && Object.assign(
309
+ Object.assign(
282
310
  data,
283
- linkProps.value
311
+ hasLink.value === true ? linkProps.value : toggleAriaAttrs.value
284
312
  )
285
313
  }
286
314
 
@@ -292,7 +320,8 @@ export default createComponent({
292
320
  h('div', {
293
321
  key: 'e-content',
294
322
  class: 'q-expansion-item__content relative-position',
295
- style: contentStyle.value
323
+ style: contentStyle.value,
324
+ id: targetUid
296
325
  }, hSlot(slots.default)),
297
326
  [ [
298
327
  vShow,
@@ -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": "accessibility",
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
  }
@@ -41,7 +41,7 @@ export default createComponent({
41
41
  const { proxy: { $q } } = getCurrentInstance()
42
42
 
43
43
  const isDark = useDark(props, $q)
44
- const { hasRouterLink, hasLink, linkProps, linkClass, linkTag, navigateToRouterLink } = useRouterLink()
44
+ const { hasLink, linkAttrs, linkClass, linkTag, navigateOnClick } = useRouterLink()
45
45
 
46
46
  const rootRef = ref(null)
47
47
  const blurTargetRef = ref(null)
@@ -65,7 +65,7 @@ export default createComponent({
65
65
  ? linkClass.value
66
66
  : (
67
67
  props.active === true
68
- ? `${ props.activeClass !== void 0 ? ` ${ props.activeClass }` : '' } q-item--active`
68
+ ? ` q-item--active${ props.activeClass !== void 0 ? ` ${ props.activeClass }` : '' }`
69
69
  : ''
70
70
  )
71
71
  )
@@ -101,8 +101,7 @@ export default createComponent({
101
101
  }
102
102
  }
103
103
 
104
- hasRouterLink.value === true && navigateToRouterLink(e)
105
- emit('click', e)
104
+ navigateOnClick(e)
106
105
  }
107
106
  }
108
107
 
@@ -143,7 +142,7 @@ export default createComponent({
143
142
 
144
143
  if (isClickable.value === true) {
145
144
  data.tabindex = props.tabindex || '0'
146
- Object.assign(data, linkProps.value)
145
+ Object.assign(data, linkAttrs.value)
147
146
  }
148
147
  else if (isActionable.value === true) {
149
148
  data[ 'aria-disabled' ] = 'true'
@@ -62,5 +62,58 @@
62
62
  "default": {
63
63
  "desc": "This is where QItem's content goes"
64
64
  }
65
+ },
66
+
67
+ "events": {
68
+ "click": {
69
+ "desc": "Emitted when the component is clicked",
70
+ "params": {
71
+ "evt": {
72
+ "extends": "evt",
73
+ "desc": "JS event object; If you are using route navigation ('to'/'replace' props) and you want to cancel navigation then call evt.preventDefault() synchronously in your event handler"
74
+ },
75
+ "go": {
76
+ "type": "Function",
77
+ "desc": "Available ONLY if you are using route navigation ('to'/'replace' props); When you need to control the time at which the component should trigger the route navigation then call evt.preventDefault() synchronously and then call this function at your convenience; Useful if you have async work to be done before the actual route navigation or if you want to redirect somewhere else",
78
+ "required": false,
79
+ "addedIn": "v2.9",
80
+ "params": {
81
+ "opts": {
82
+ "type": "Object",
83
+ "desc": "Optional options",
84
+ "required": false,
85
+ "definition": {
86
+ "to": {
87
+ "type": [ "String", "Object" ],
88
+ "desc": "Equivalent to Vue Router <router-link> 'to' property; Specify it explicitly otherwise it will be set with same value as component's 'to' prop",
89
+ "required": false,
90
+ "examples": [
91
+ "/home/dashboard",
92
+ "{ name: 'my-route-name' }"
93
+ ]
94
+ },
95
+
96
+ "replace": {
97
+ "type": "Boolean",
98
+ "desc": "Equivalent to Vue Router <router-link> 'replace' property; Specify it explicitly otherwise it will be set with same value as component's 'replace' prop",
99
+ "required": false
100
+ },
101
+
102
+ "returnRouterError": {
103
+ "type": "Boolean",
104
+ "desc": "Return the router error, if any; Otherwise the returned Promise will always fulfill",
105
+ "required": false
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "returns": {
111
+ "type": "Promise<any>",
112
+ "desc": "Returns the router's navigation promise",
113
+ "__exemption": [ "examples" ]
114
+ }
115
+ }
116
+ }
117
+ }
65
118
  }
66
119
  }
@@ -99,7 +99,7 @@ export default createComponent({
99
99
 
100
100
  const isDark = useDark(props, $q)
101
101
  const { registerTick, removeTick } = useTick()
102
- const { registerTimeout, removeTimeout } = useTimeout()
102
+ const { registerTimeout } = useTimeout()
103
103
  const { transition, transitionStyle } = useTransition(props, showing)
104
104
  const { localScrollTarget, changeScrollEvent, unconfigureScrollTarget } = useScrollTarget(props, configureScrollTarget)
105
105
 
@@ -187,9 +187,6 @@ export default createComponent({
187
187
  }
188
188
 
189
189
  function handleShow (evt) {
190
- removeTick()
191
- removeTimeout()
192
-
193
190
  refocusTarget = props.noRefocus === false
194
191
  ? document.activeElement
195
192
  : null
@@ -221,11 +218,13 @@ export default createComponent({
221
218
  document.activeElement.blur()
222
219
  }
223
220
 
221
+ // should removeTick() if this gets removed
224
222
  registerTick(() => {
225
223
  updatePosition()
226
224
  props.noFocus !== true && focus()
227
225
  })
228
226
 
227
+ // should removeTimeout() if this gets removed
229
228
  registerTimeout(() => {
230
229
  // required in order to avoid the "double-tap needed" issue
231
230
  if ($q.platform.is.ios === true) {
@@ -243,7 +242,6 @@ export default createComponent({
243
242
 
244
243
  function handleHide (evt) {
245
244
  removeTick()
246
- removeTimeout()
247
245
  hidePortal()
248
246
 
249
247
  anchorCleanup(true)
@@ -261,6 +259,7 @@ export default createComponent({
261
259
  refocusTarget = null
262
260
  }
263
261
 
262
+ // should removeTimeout() if this gets removed
264
263
  registerTimeout(() => {
265
264
  hidePortal(true) // done hiding, now destroy
266
265
  emit('hide', evt)
@@ -350,6 +349,7 @@ export default createComponent({
350
349
  () => (
351
350
  showing.value === true
352
351
  ? h('div', {
352
+ role: 'menu',
353
353
  ...attrs,
354
354
  ref: innerRef,
355
355
  tabindex: -1,
@@ -80,6 +80,7 @@ describe('Menu API', () => {
80
80
  .click()
81
81
  cy.dataCy('menu')
82
82
  .should('exist')
83
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
83
84
  cy.get('body')
84
85
  .click(499, 0)
85
86
  .wait(300) // Await menu animation otherwise it always passes
@@ -98,6 +99,7 @@ describe('Menu API', () => {
98
99
  .click()
99
100
  cy.dataCy('menu')
100
101
  .should('exist')
102
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
101
103
  cy.get('body')
102
104
  .type('{esc}')
103
105
  .wait(300) // Await menu animation otherwise it always passes
@@ -118,6 +120,7 @@ describe('Menu API', () => {
118
120
 
119
121
  cy.dataCy('wrapper')
120
122
  .click()
123
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
121
124
  cy.dataCy('menu')
122
125
  .should('exist')
123
126
  .dataCy('keep-open')
@@ -136,6 +139,7 @@ describe('Menu API', () => {
136
139
 
137
140
  cy.dataCy('wrapper')
138
141
  .click()
142
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
139
143
  cy.dataCy('menu')
140
144
  .should('exist')
141
145
  .dataCy('keep-open')
@@ -161,6 +165,7 @@ describe('Menu API', () => {
161
165
  .focus()
162
166
  .should('have.focus')
163
167
  .click()
168
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
164
169
  cy.dataCy('menu')
165
170
  .should('exist')
166
171
  .should('have.focus')
@@ -183,6 +188,7 @@ describe('Menu API', () => {
183
188
  .focus()
184
189
  .should('have.focus')
185
190
  .click()
191
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
186
192
  cy.dataCy('menu')
187
193
  .should('exist')
188
194
  .should('have.focus')
@@ -529,6 +535,7 @@ describe('Menu API', () => {
529
535
  let bottom = null
530
536
  let left = null
531
537
 
538
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
532
539
  cy.dataCy('wrapper')
533
540
  .click()
534
541
  .wait(300)
@@ -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', {
@@ -58,16 +58,13 @@ export default createComponent({
58
58
  let validated = false
59
59
 
60
60
  const scope = computed(() => {
61
- const acc = {
61
+ return injectProp({
62
62
  initialValue: initialValue.value,
63
63
  validate: props.validate,
64
64
  set,
65
65
  cancel,
66
66
  updatePosition
67
- }
68
-
69
- injectProp(acc, 'value', () => currentModel.value, val => { currentModel.value = val })
70
- return acc
67
+ }, 'value', () => currentModel.value, val => { currentModel.value = val })
71
68
  })
72
69
 
73
70
  function set () {
@@ -15,8 +15,7 @@ import { hSlot, hMergeSlot } from '../../utils/private/render.js'
15
15
  const svg = h('svg', {
16
16
  key: 'svg',
17
17
  class: 'q-radio__bg absolute non-selectable',
18
- viewBox: '0 0 24 24',
19
- 'aria-hidden': 'true'
18
+ viewBox: '0 0 24 24'
20
19
  }, [
21
20
  h('path', {
22
21
  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'
@@ -161,7 +160,8 @@ export default createComponent({
161
160
  const child = [
162
161
  h('div', {
163
162
  class: innerClass.value,
164
- style: sizeStyle.value
163
+ style: sizeStyle.value,
164
+ 'aria-hidden': 'true'
165
165
  }, content)
166
166
  ]
167
167