quasar 2.8.4 → 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 (165) hide show
  1. package/dist/api/QBreadcrumbsEl.json +52 -0
  2. package/dist/api/QBtn.json +41 -6
  3. package/dist/api/QBtnDropdown.json +1 -1
  4. package/dist/api/QChip.json +1 -1
  5. package/dist/api/QEditor.json +7 -0
  6. package/dist/api/QExpansionItem.json +1 -1
  7. package/dist/api/QItem.json +52 -0
  8. package/dist/api/QRating.json +13 -0
  9. package/dist/api/QRouteTab.json +42 -6
  10. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  11. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  12. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  13. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  14. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  15. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  16. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  17. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  18. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  19. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  20. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  21. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  22. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  23. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  24. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  25. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  26. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  27. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  28. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  44. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  45. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  46. package/dist/icon-set/themify.umd.prod.js +1 -1
  47. package/dist/lang/ar-TN.umd.prod.js +1 -1
  48. package/dist/lang/ar.umd.prod.js +1 -1
  49. package/dist/lang/az-Latn.umd.prod.js +1 -1
  50. package/dist/lang/bg.umd.prod.js +1 -1
  51. package/dist/lang/bn.umd.prod.js +1 -1
  52. package/dist/lang/ca.umd.prod.js +1 -1
  53. package/dist/lang/cs.umd.prod.js +1 -1
  54. package/dist/lang/da.umd.prod.js +1 -1
  55. package/dist/lang/de.umd.prod.js +1 -1
  56. package/dist/lang/el.umd.prod.js +1 -1
  57. package/dist/lang/en-GB.umd.prod.js +1 -1
  58. package/dist/lang/en-US.umd.prod.js +1 -1
  59. package/dist/lang/eo.umd.prod.js +1 -1
  60. package/dist/lang/es.umd.prod.js +1 -1
  61. package/dist/lang/et.umd.prod.js +1 -1
  62. package/dist/lang/eu.umd.prod.js +1 -1
  63. package/dist/lang/fa-IR.umd.prod.js +1 -1
  64. package/dist/lang/fa.umd.prod.js +1 -1
  65. package/dist/lang/fi.umd.prod.js +1 -1
  66. package/dist/lang/fr.umd.prod.js +1 -1
  67. package/dist/lang/gn.umd.prod.js +1 -1
  68. package/dist/lang/he.umd.prod.js +1 -1
  69. package/dist/lang/hr.umd.prod.js +1 -1
  70. package/dist/lang/hu.umd.prod.js +1 -1
  71. package/dist/lang/id.umd.prod.js +1 -1
  72. package/dist/lang/is.umd.prod.js +1 -1
  73. package/dist/lang/it.umd.prod.js +1 -1
  74. package/dist/lang/ja.umd.prod.js +1 -1
  75. package/dist/lang/km.umd.prod.js +1 -1
  76. package/dist/lang/ko-KR.umd.prod.js +1 -1
  77. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  78. package/dist/lang/kz.umd.prod.js +1 -1
  79. package/dist/lang/lt.umd.prod.js +1 -1
  80. package/dist/lang/lu.umd.prod.js +1 -1
  81. package/dist/lang/lv.umd.prod.js +1 -1
  82. package/dist/lang/ml.umd.prod.js +1 -1
  83. package/dist/lang/mm.umd.prod.js +1 -1
  84. package/dist/lang/ms.umd.prod.js +1 -1
  85. package/dist/lang/my.umd.prod.js +1 -1
  86. package/dist/lang/nb-NO.umd.prod.js +1 -1
  87. package/dist/lang/nl.umd.prod.js +2 -2
  88. package/dist/lang/pl.umd.prod.js +1 -1
  89. package/dist/lang/pt-BR.umd.prod.js +1 -1
  90. package/dist/lang/pt.umd.prod.js +1 -1
  91. package/dist/lang/ro.umd.prod.js +1 -1
  92. package/dist/lang/ru.umd.prod.js +1 -1
  93. package/dist/lang/sk.umd.prod.js +1 -1
  94. package/dist/lang/sl.umd.prod.js +1 -1
  95. package/dist/lang/sm.umd.prod.js +1 -1
  96. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  97. package/dist/lang/sr.umd.prod.js +1 -1
  98. package/dist/lang/sv.umd.prod.js +1 -1
  99. package/dist/lang/ta.umd.prod.js +1 -1
  100. package/dist/lang/th.umd.prod.js +1 -1
  101. package/dist/lang/tr.umd.prod.js +1 -1
  102. package/dist/lang/ug.umd.prod.js +1 -1
  103. package/dist/lang/uk.umd.prod.js +1 -1
  104. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  105. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  106. package/dist/lang/vi.umd.prod.js +1 -1
  107. package/dist/lang/zh-CN.umd.prod.js +1 -1
  108. package/dist/lang/zh-TW.umd.prod.js +1 -1
  109. package/dist/quasar.cjs.prod.js +2 -2
  110. package/dist/quasar.esm.js +533 -337
  111. package/dist/quasar.esm.prod.js +2 -2
  112. package/dist/quasar.sass +1 -1
  113. package/dist/quasar.umd.js +532 -336
  114. package/dist/quasar.umd.prod.js +2 -2
  115. package/dist/types/api/qeditor.d.ts +17 -0
  116. package/dist/types/api.d.ts +1 -0
  117. package/dist/types/index.d.ts +93 -8
  118. package/dist/types/utils/run-sequential-promises.d.ts +1 -1
  119. package/dist/vetur/quasar-attributes.json +4 -0
  120. package/dist/vetur/quasar-tags.json +1 -0
  121. package/dist/web-types/web-types.json +60 -9
  122. package/lang/nl.js +2 -2
  123. package/lang/nl.mjs +2 -2
  124. package/package.json +5 -3
  125. package/src/components/breadcrumbs/QBreadcrumbsEl.js +6 -7
  126. package/src/components/breadcrumbs/QBreadcrumbsEl.json +53 -0
  127. package/src/components/btn/QBtn.js +19 -19
  128. package/src/components/btn/QBtn.json +41 -6
  129. package/src/components/btn/use-btn.js +6 -4
  130. package/src/components/btn-dropdown/QBtnDropdown.json +1 -1
  131. package/src/components/checkbox/QCheckbox.js +1 -2
  132. package/src/components/checkbox/use-checkbox.js +2 -1
  133. package/src/components/chip/QChip.json +1 -1
  134. package/src/components/dialog/QDialog.js +6 -4
  135. package/src/components/drawer/QDrawer.js +7 -4
  136. package/src/components/editor/QEditor.json +9 -0
  137. package/src/components/expansion-item/QExpansionItem.json +1 -1
  138. package/src/components/item/QItem.js +4 -5
  139. package/src/components/item/QItem.json +53 -0
  140. package/src/components/menu/QMenu.js +4 -5
  141. package/src/components/menu/__tests__/QMenu.spec.js +7 -0
  142. package/src/components/popup-edit/QPopupEdit.js +2 -5
  143. package/src/components/radio/QRadio.js +3 -3
  144. package/src/components/rating/QRating.js +48 -10
  145. package/src/components/rating/QRating.json +11 -0
  146. package/src/components/stepper/QStep.js +5 -3
  147. package/src/components/table/QTable.js +3 -5
  148. package/src/components/tabs/QRouteTab.js +6 -4
  149. package/src/components/tabs/QRouteTab.json +42 -6
  150. package/src/components/tabs/QTabs.js +188 -108
  151. package/src/components/tabs/use-tab.js +62 -38
  152. package/src/components/tooltip/QTooltip.js +7 -13
  153. package/src/components/tree/QTree.js +1 -1
  154. package/src/composables/private/__tests__/use-model-toggle.spec.js +2 -0
  155. package/src/composables/private/__tests__/use-transition.spec.js +4 -0
  156. package/src/composables/private/use-router-link.js +80 -43
  157. package/src/composables/private/use-tick.js +15 -9
  158. package/src/composables/private/use-timeout.js +20 -7
  159. package/src/directives/TouchPan.js +1 -1
  160. package/src/directives/TouchRepeat.js +1 -1
  161. package/src/directives/TouchSwipe.js +1 -1
  162. package/src/utils/extend.js +19 -19
  163. package/src/utils/private/inject-obj-prop.js +2 -0
  164. package/src/utils/private/rtl.js +10 -7
  165. package/src/utils/run-sequential-promises.js +1 -1
@@ -125,7 +125,7 @@
125
125
  "type": "String",
126
126
  "desc": "aria-label to be used on the dropdown toggle element",
127
127
  "examples": [ "Open menu" ],
128
- "category": "content",
128
+ "category": "accessibility",
129
129
  "addedIn": "v2.8.4"
130
130
  }
131
131
  },
@@ -11,8 +11,7 @@ const bgNode = h('div', {
11
11
  }, [
12
12
  h('svg', {
13
13
  class: 'q-checkbox__svg fit absolute-full',
14
- viewBox: '0 0 24 24',
15
- 'aria-hidden': 'true'
14
+ viewBox: '0 0 24 24'
16
15
  }, [
17
16
  h('path', {
18
17
  class: 'q-checkbox__truthy',
@@ -211,7 +211,8 @@ export default function (type, getInner) {
211
211
  const child = [
212
212
  h('div', {
213
213
  class: innerClass.value,
214
- style: sizeStyle.value
214
+ style: sizeStyle.value,
215
+ 'aria-hidden': 'true'
215
216
  }, inner)
216
217
  ]
217
218
 
@@ -99,7 +99,7 @@
99
99
  "type": "String",
100
100
  "desc": "aria-label to be used on the remove icon",
101
101
  "examples": [ "Remove item" ],
102
- "category": "content",
102
+ "category": "accessibility",
103
103
  "addedIn": "v2.8.4"
104
104
  },
105
105
 
@@ -94,7 +94,7 @@ export default createComponent({
94
94
  )
95
95
 
96
96
  const { preventBodyScroll } = usePreventScroll()
97
- const { registerTimeout, removeTimeout } = useTimeout()
97
+ const { registerTimeout } = useTimeout()
98
98
  const { registerTick, removeTick } = useTick()
99
99
 
100
100
  const { showPortal, hidePortal, portalIsAccessible, renderPortal } = usePortal(
@@ -179,8 +179,6 @@ export default createComponent({
179
179
  })
180
180
 
181
181
  function handleShow (evt) {
182
- removeTimeout()
183
- removeTick()
184
182
  addToHistory()
185
183
 
186
184
  refocusTarget = props.noRefocus === false && document.activeElement !== null
@@ -195,7 +193,11 @@ export default createComponent({
195
193
  document.activeElement !== null && document.activeElement.blur()
196
194
  registerTick(focus)
197
195
  }
196
+ else {
197
+ removeTick()
198
+ }
198
199
 
200
+ // should removeTimeout() if this gets removed
199
201
  registerTimeout(() => {
200
202
  if (vm.proxy.$q.platform.is.ios === true) {
201
203
  if (props.seamless !== true && document.activeElement) {
@@ -231,7 +233,6 @@ export default createComponent({
231
233
  }
232
234
 
233
235
  function handleHide (evt) {
234
- removeTimeout()
235
236
  removeTick()
236
237
  removeFromHistory()
237
238
  cleanup(true)
@@ -243,6 +244,7 @@ export default createComponent({
243
244
  refocusTarget = null
244
245
  }
245
246
 
247
+ // should removeTimeout() if this gets removed
246
248
  registerTimeout(() => {
247
249
  hidePortal(true) // done hiding, now destroy
248
250
  animating.value = false
@@ -75,7 +75,7 @@ export default createComponent({
75
75
 
76
76
  const isDark = useDark(props, $q)
77
77
  const { preventBodyScroll } = usePreventScroll()
78
- const { registerTimeout } = useTimeout()
78
+ const { registerTimeout, removeTimeout } = useTimeout()
79
79
 
80
80
  const $layout = inject(layoutKey, () => {
81
81
  console.error('QDrawer needs to be child of QLayout')
@@ -145,9 +145,12 @@ export default createComponent({
145
145
 
146
146
  cleanup()
147
147
 
148
- noEvent !== true && registerTimeout(() => {
149
- emit('hide', evt)
150
- }, duration)
148
+ if (noEvent !== true) {
149
+ registerTimeout(() => { emit('hide', evt) }, duration)
150
+ }
151
+ else {
152
+ removeTimeout()
153
+ }
151
154
  }
152
155
 
153
156
  const { show, hide } = useModelToggle({
@@ -312,5 +312,14 @@
312
312
  "__exemption": [ "examples" ]
313
313
  }
314
314
  }
315
+ },
316
+
317
+ "computedProps": {
318
+ "caret": {
319
+ "type": "Object",
320
+ "tsType": "QEditorCaret",
321
+ "desc": "The current caret state",
322
+ "__exemption": [ "examples" ]
323
+ }
315
324
  }
316
325
  }
@@ -37,7 +37,7 @@
37
37
  "type": "String",
38
38
  "desc": "aria-label to be used on the expansion toggle element",
39
39
  "examples": [ "Open details" ],
40
- "category": "content",
40
+ "category": "accessibility",
41
41
  "addedIn": "v2.8.4"
42
42
  },
43
43
 
@@ -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)
@@ -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)
@@ -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
 
@@ -31,6 +31,8 @@ export default createComponent({
31
31
  iconHalf: [ String, Array ],
32
32
  iconSelected: [ String, Array ],
33
33
 
34
+ iconAriaLabel: [ String, Array ],
35
+
34
36
  color: [ String, Array ],
35
37
  colorHalf: [ String, Array ],
36
38
  colorSelected: [ String, Array ],
@@ -96,11 +98,29 @@ export default createComponent({
96
98
  }
97
99
  })
98
100
 
101
+ const iconLabel = computed(() => {
102
+ if (typeof props.iconAriaLabel === 'string') {
103
+ const label = props.iconAriaLabel.length > 0 ? `${ props.iconAriaLabel } ` : ''
104
+ return i => `${ label }${ i }`
105
+ }
106
+
107
+ if (Array.isArray(props.iconAriaLabel) === true) {
108
+ const iMax = props.iconAriaLabel.length
109
+
110
+ if (iMax > 0) {
111
+ return i => props.iconAriaLabel[ Math.min(i, iMax) - 1 ]
112
+ }
113
+ }
114
+
115
+ return (i, label) => `${ label } ${ i }`
116
+ })
117
+
99
118
  const stars = computed(() => {
100
119
  const
101
120
  acc = [],
102
121
  icons = iconData.value,
103
- ceil = Math.ceil(props.modelValue)
122
+ ceil = Math.ceil(props.modelValue),
123
+ tabindex = editable.value === true ? 0 : null
104
124
 
105
125
  const halfIndex = props.iconHalf === void 0 || ceil === props.modelValue
106
126
  ? -1
@@ -117,7 +137,16 @@ export default createComponent({
117
137
  icons.selColor !== void 0 && active === true
118
138
  ? (i <= icons.selColorLen ? props.colorSelected[ i - 1 ] : icons.selColor)
119
139
  : (i <= icons.colorLen ? props.color[ i - 1 ] : icons.color)
120
- )
140
+ ),
141
+ name = (
142
+ half === true
143
+ ? (i <= icons.halfIconLen ? props.iconHalf[ i - 1 ] : icons.halfIcon)
144
+ : (
145
+ icons.selIcon !== void 0 && (active === true || exSelected === true)
146
+ ? (i <= icons.selIconLen ? props.iconSelected[ i - 1 ] : icons.selIcon)
147
+ : (i <= icons.iconLen ? props.icon[ i - 1 ] : icons.icon)
148
+ )
149
+ ) || $q.iconSet.rating.icon
121
150
 
122
151
  acc.push({
123
152
  name: (
@@ -130,7 +159,14 @@ export default createComponent({
130
159
  )
131
160
  ) || $q.iconSet.rating.icon,
132
161
 
133
- classes: 'q-rating__icon'
162
+ attrs: {
163
+ tabindex,
164
+ role: 'radio',
165
+ 'aria-checked': props.modelValue === i ? 'true' : 'false',
166
+ 'aria-label': iconLabel.value(i, name)
167
+ },
168
+
169
+ iconClass: 'q-rating__icon'
134
170
  + (active === true || half === true ? ' q-rating__icon--active' : '')
135
171
  + (exSelected === true ? ' q-rating__icon--exselected' : '')
136
172
  + (mouseModel.value === i ? ' q-rating__icon--hovered' : '')
@@ -142,15 +178,17 @@ export default createComponent({
142
178
  })
143
179
 
144
180
  const attributes = computed(() => {
181
+ const attrs = { role: 'radiogroup' }
182
+
145
183
  if (props.disable === true) {
146
- return { 'aria-disabled': 'true' }
184
+ attrs[ 'aria-disabled' ] = 'true'
147
185
  }
148
186
  if (props.readonly === true) {
149
- return { 'aria-readonly': 'true' }
187
+ attrs[ 'aria-readonly' ] = 'true'
150
188
  }
151
- })
152
189
 
153
- const tabindex = computed(() => (editable.value === true ? 0 : null))
190
+ return attrs
191
+ })
154
192
 
155
193
  function set (value) {
156
194
  if (editable.value === true) {
@@ -201,7 +239,7 @@ export default createComponent({
201
239
  return () => {
202
240
  const child = []
203
241
 
204
- stars.value.forEach(({ classes, name }, index) => {
242
+ stars.value.forEach(({ iconClass, name, attrs }, index) => {
205
243
  const i = index + 1
206
244
 
207
245
  child.push(
@@ -209,7 +247,7 @@ export default createComponent({
209
247
  key: i,
210
248
  ref: vm => { iconRefs[ `rt${ i }` ] = vm },
211
249
  class: 'q-rating__icon-container flex flex-center',
212
- tabindex: tabindex.value,
250
+ ...attrs,
213
251
  onClick () { set(i) },
214
252
  onMouseover () { setHoverValue(i) },
215
253
  onMouseout: resetMouseModel,
@@ -218,7 +256,7 @@ export default createComponent({
218
256
  onKeyup (e) { onKeyup(e, i) }
219
257
  }, hMergeSlot(
220
258
  slots[ `tip-${ i }` ],
221
- [ h(QIcon, { class: classes, name }) ]
259
+ [ h(QIcon, { class: iconClass, name }) ]
222
260
  ))
223
261
  )
224
262
  })
@@ -56,6 +56,17 @@
56
56
  "category": "content"
57
57
  },
58
58
 
59
+ "icon-aria-label": {
60
+ "type": [ "String", "Array" ],
61
+ "desc": "Label to be set on aria-label for Icon; If an array is provided each rating value will use the corresponding aria-label in the array (0 based); If string value is provided the rating value will be appended; If not provided the name of the icon will be used",
62
+ "examples": [
63
+ "Rating",
64
+ "[\"Bad\", \"Normal\", \"Good\"]"
65
+ ],
66
+ "category": "accessibility",
67
+ "addedIn": "v1.20.3"
68
+ },
69
+
59
70
  "color": {
60
71
  "extends": "color",
61
72
  "type": [ "String", "Array" ],
@@ -53,10 +53,12 @@ export default createComponent({
53
53
  default: true
54
54
  },
55
55
  done: Boolean,
56
- error: Boolean
56
+ error: Boolean,
57
+
58
+ onScroll: [ Function, Array ]
57
59
  },
58
60
 
59
- setup (props, { attrs, slots }) {
61
+ setup (props, { slots, emit }) {
60
62
  const { proxy: { $q } } = getCurrentInstance()
61
63
 
62
64
  const $stepper = inject(stepperKey, () => {
@@ -80,7 +82,7 @@ export default createComponent({
80
82
  if (target.scrollTop > 0) {
81
83
  target.scrollTop = 0
82
84
  }
83
- attrs.onScroll !== void 0 && attrs.onScroll(e)
85
+ props.onScroll !== void 0 && emit('scroll', e)
84
86
  }
85
87
  }
86
88
  ))
@@ -479,11 +479,9 @@ export default createComponent({
479
479
  function getBodyScope (data) {
480
480
  injectBodyCommonScope(data)
481
481
 
482
- data.cols = data.cols.map(col => {
483
- const c = { ...col }
484
- injectProp(c, 'value', () => getCellValue(col, data.row))
485
- return c
486
- })
482
+ data.cols = data.cols.map(
483
+ col => injectProp({ ...col }, 'value', () => getCellValue(col, data.row))
484
+ )
487
485
 
488
486
  return data
489
487
  }
@@ -16,7 +16,9 @@ export default createComponent({
16
16
  emits: useTabEmits,
17
17
 
18
18
  setup (props, { slots, emit }) {
19
- const rData = useRouterLink()
19
+ const routeData = useRouterLink({
20
+ useDisableForRouterLinkProps: false
21
+ })
20
22
 
21
23
  const { renderTab, $tabs } = useTab(
22
24
  props,
@@ -24,14 +26,14 @@ export default createComponent({
24
26
  emit,
25
27
  {
26
28
  exact: computed(() => props.exact),
27
- ...rData
29
+ ...routeData
28
30
  }
29
31
  )
30
32
 
31
- watch(() => props.name + props.exact + (rData.linkRoute.value || {}).href, () => {
33
+ watch(() => `${ props.name } | ${ props.exact } | ${ (routeData.resolvedLink.value || {}).href }`, () => {
32
34
  $tabs.verifyRouteModel()
33
35
  })
34
36
 
35
- return () => renderTab(rData.linkTag.value, rData.linkProps.value)
37
+ return () => renderTab(routeData.linkTag.value, routeData.linkAttrs.value)
36
38
  }
37
39
  })
@@ -7,17 +7,53 @@
7
7
 
8
8
  "events": {
9
9
  "click": {
10
- "desc": "Emitted when component is clicked (activated)",
10
+ "desc": "Emitted when the component is clicked",
11
11
  "params": {
12
12
  "evt": {
13
13
  "extends": "evt",
14
- "desc": "JS event object; If you want to cancel navigation set synchronously 'evt.navigate' to false"
14
+ "desc": "JS event object; If you want to cancel navigation then call evt.preventDefault() synchronously in your event handler"
15
15
  },
16
- "navigateFn": {
16
+ "go": {
17
17
  "type": "Function",
18
- "desc": "When you need to control the time at which the tab should trigger the route navigation then set 'evt.navigate' to false and call this function; Useful if you have async work to be done before the actual route navigation",
19
- "params": null,
20
- "returns": null
18
+ "desc": "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",
19
+ "required": false,
20
+ "params": {
21
+ "opts": {
22
+ "type": "Object",
23
+ "desc": "Optional options",
24
+ "required": false,
25
+ "definition": {
26
+ "to": {
27
+ "type": [ "String", "Object" ],
28
+ "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",
29
+ "required": false,
30
+ "examples": [
31
+ "/home/dashboard",
32
+ "{ name: 'my-route-name' }"
33
+ ]
34
+ },
35
+
36
+ "replace": {
37
+ "type": "Boolean",
38
+ "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",
39
+ "required": false
40
+ },
41
+
42
+ "returnRouterError": {
43
+ "type": "Boolean",
44
+ "desc": "Return the router error, if any; Otherwise the returned Promise will always fulfill",
45
+ "required": false
46
+ }
47
+ },
48
+ "addedIn": "v2.9"
49
+ }
50
+ },
51
+ "returns": {
52
+ "type": "Promise<any>",
53
+ "desc": "Returns the router's navigation promise",
54
+ "__exemption": [ "examples" ],
55
+ "addedIn": "v2.9"
56
+ }
21
57
  }
22
58
  }
23
59
  }