quasar 2.3.4 → 2.4.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 (204) hide show
  1. package/dist/api/Loading.json +2 -6
  2. package/dist/api/QBreadcrumbsEl.json +31 -10
  3. package/dist/api/QBtn.json +30 -14
  4. package/dist/api/QBtnDropdown.json +30 -14
  5. package/dist/api/QBtnToggle.json +3 -0
  6. package/dist/api/QChatMessage.json +4 -12
  7. package/dist/api/QExpansionItem.json +31 -10
  8. package/dist/api/QFab.json +30 -0
  9. package/dist/api/QFabAction.json +8 -0
  10. package/dist/api/QField.json +1 -0
  11. package/dist/api/QFile.json +1 -0
  12. package/dist/api/QInput.json +1 -0
  13. package/dist/api/QItem.json +31 -10
  14. package/dist/api/QOptionGroup.json +74 -4
  15. package/dist/api/QRange.json +592 -107
  16. package/dist/api/QRouteTab.json +31 -11
  17. package/dist/api/QSelect.json +3 -6
  18. package/dist/api/QSlider.json +504 -39
  19. package/dist/api/QUploader.json +16 -2
  20. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  21. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  22. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  23. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  24. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  25. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  26. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  27. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  28. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  29. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  30. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  31. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  32. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  33. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  44. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  45. package/dist/icon-set/svg-mdi-v4.umd.prod.js +1 -1
  46. package/dist/icon-set/svg-mdi-v5.umd.prod.js +1 -1
  47. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  48. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  49. package/dist/icon-set/themify.umd.prod.js +1 -1
  50. package/dist/lang/ar.umd.prod.js +1 -1
  51. package/dist/lang/az-Latn.umd.prod.js +1 -1
  52. package/dist/lang/bg.umd.prod.js +1 -1
  53. package/dist/lang/bn.umd.prod.js +1 -1
  54. package/dist/lang/ca.umd.prod.js +1 -1
  55. package/dist/lang/cs.umd.prod.js +1 -1
  56. package/dist/lang/da.umd.prod.js +1 -1
  57. package/dist/lang/de.umd.prod.js +1 -1
  58. package/dist/lang/el.umd.prod.js +1 -1
  59. package/dist/lang/en-GB.umd.prod.js +1 -1
  60. package/dist/lang/en-US.umd.prod.js +1 -1
  61. package/dist/lang/eo.umd.prod.js +1 -1
  62. package/dist/lang/es.umd.prod.js +1 -1
  63. package/dist/lang/et.umd.prod.js +1 -1
  64. package/dist/lang/fa-IR.umd.prod.js +1 -1
  65. package/dist/lang/fa.umd.prod.js +1 -1
  66. package/dist/lang/fi.umd.prod.js +1 -1
  67. package/dist/lang/fr.umd.prod.js +1 -1
  68. package/dist/lang/gn.umd.prod.js +1 -1
  69. package/dist/lang/he.umd.prod.js +1 -1
  70. package/dist/lang/hr.umd.prod.js +1 -1
  71. package/dist/lang/hu.umd.prod.js +1 -1
  72. package/dist/lang/id.umd.prod.js +1 -1
  73. package/dist/lang/is.umd.prod.js +1 -1
  74. package/dist/lang/it.umd.prod.js +1 -1
  75. package/dist/lang/ja.umd.prod.js +1 -1
  76. package/dist/lang/km.umd.prod.js +1 -1
  77. package/dist/lang/ko-KR.umd.prod.js +1 -1
  78. package/dist/lang/kur-CKB.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/ms.umd.prod.js +1 -1
  84. package/dist/lang/nb-NO.umd.prod.js +1 -1
  85. package/dist/lang/nl.umd.prod.js +1 -1
  86. package/dist/lang/pl.umd.prod.js +1 -1
  87. package/dist/lang/pt-BR.umd.prod.js +1 -1
  88. package/dist/lang/pt.umd.prod.js +1 -1
  89. package/dist/lang/ro.umd.prod.js +1 -1
  90. package/dist/lang/ru.umd.prod.js +1 -1
  91. package/dist/lang/sk.umd.prod.js +1 -1
  92. package/dist/lang/sl.umd.prod.js +1 -1
  93. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  94. package/dist/lang/sr.umd.prod.js +1 -1
  95. package/dist/lang/sv.umd.prod.js +1 -1
  96. package/dist/lang/ta.umd.prod.js +1 -1
  97. package/dist/lang/th.umd.prod.js +1 -1
  98. package/dist/lang/tr.umd.prod.js +1 -1
  99. package/dist/lang/ug.umd.prod.js +1 -1
  100. package/dist/lang/uk.umd.prod.js +1 -1
  101. package/dist/lang/vi.umd.prod.js +1 -1
  102. package/dist/lang/zh-CN.umd.prod.js +1 -1
  103. package/dist/lang/zh-TW.umd.prod.js +1 -1
  104. package/dist/quasar.cjs.prod.js +2 -2
  105. package/dist/quasar.css +264 -183
  106. package/dist/quasar.esm.prod.js +2 -2
  107. package/dist/quasar.prod.css +1 -1
  108. package/dist/quasar.rtl.css +331 -262
  109. package/dist/quasar.rtl.prod.css +1 -1
  110. package/dist/quasar.sass +235 -178
  111. package/dist/quasar.umd.js +16537 -16226
  112. package/dist/quasar.umd.prod.js +2 -2
  113. package/dist/ssr-directives/Morph.js +1 -1
  114. package/dist/transforms/loader-asset-urls.json +20 -0
  115. package/dist/types/api/slider.d.ts +46 -0
  116. package/dist/types/api/validation.d.ts +4 -0
  117. package/dist/types/api.d.ts +2 -0
  118. package/dist/types/composables.d.ts +3 -3
  119. package/dist/types/index.d.ts +594 -120
  120. package/dist/vetur/quasar-attributes.json +250 -82
  121. package/dist/vetur/quasar-tags.json +59 -17
  122. package/dist/web-types/web-types.json +578 -149
  123. package/package.json +1 -1
  124. package/src/api.extends.json +0 -1
  125. package/src/components/breadcrumbs/QBreadcrumbs.js +7 -2
  126. package/src/components/breadcrumbs/QBreadcrumbs.sass +0 -3
  127. package/src/components/breadcrumbs/QBreadcrumbsEl.js +14 -8
  128. package/src/components/btn/QBtn.js +5 -5
  129. package/src/components/btn/use-btn.js +21 -21
  130. package/src/components/btn/use-btn.json +22 -13
  131. package/src/components/btn-toggle/QBtnToggle.json +3 -0
  132. package/src/components/checkbox/use-checkbox.js +1 -1
  133. package/src/components/color/QColor.js +32 -26
  134. package/src/components/color/QColor.sass +10 -23
  135. package/src/components/date/QDate.sass +2 -0
  136. package/src/components/drawer/QDrawer.js +18 -15
  137. package/src/components/editor/QEditor.js +1 -1
  138. package/src/components/editor/QEditor.sass +10 -1
  139. package/src/components/expansion-item/QExpansionItem.js +4 -1
  140. package/src/components/fab/QFab.js +18 -12
  141. package/src/components/fab/QFab.json +33 -0
  142. package/src/components/fab/QFab.sass +1 -1
  143. package/src/components/fab/QFabAction.js +14 -7
  144. package/src/components/fab/QFabAction.json +10 -0
  145. package/src/components/file/QFile.js +12 -5
  146. package/src/components/file/QFile.sass +4 -2
  147. package/src/components/footer/QFooter.js +1 -1
  148. package/src/components/header/QHeader.js +1 -1
  149. package/src/components/icon/QIcon.js +1 -1
  150. package/src/components/infinite-scroll/QInfiniteScroll.js +4 -5
  151. package/src/components/item/QItem.js +2 -3
  152. package/src/components/option-group/QOptionGroup.js +3 -0
  153. package/src/components/option-group/QOptionGroup.json +48 -2
  154. package/src/components/parallax/QParallax.js +4 -2
  155. package/src/components/popup-edit/QPopupEdit.js +2 -5
  156. package/src/components/radio/QRadio.js +2 -7
  157. package/src/components/range/QRange.js +103 -222
  158. package/src/components/range/QRange.json +11 -121
  159. package/src/components/scroll-area/QScrollArea.js +3 -1
  160. package/src/components/slider/QSlider.js +46 -132
  161. package/src/components/slider/QSlider.json +1 -121
  162. package/src/components/slider/QSlider.sass +198 -132
  163. package/src/components/slider/use-slider.js +453 -109
  164. package/src/components/slider/use-slider.json +546 -0
  165. package/src/components/stepper/QStepper.js +3 -3
  166. package/src/components/stepper/QStepper.sass +24 -26
  167. package/src/components/table/QTable.js +26 -46
  168. package/src/components/tabs/QRouteTab.js +1 -2
  169. package/src/components/tabs/QRouteTab.json +0 -7
  170. package/src/components/tabs/QTabs.js +71 -20
  171. package/src/components/tabs/use-tab.js +26 -13
  172. package/src/components/tree/QTree.js +14 -12
  173. package/src/components/uploader/QUploader.json +14 -2
  174. package/src/components/uploader/uploader-core.js +16 -9
  175. package/src/components/virtual-scroll/QVirtualScroll.sass +1 -0
  176. package/src/components/virtual-scroll/use-virtual-scroll.js +30 -17
  177. package/src/composables/private/use-field.js +5 -5
  178. package/src/composables/private/use-file.js +20 -5
  179. package/src/composables/private/use-form.js +2 -3
  180. package/src/composables/private/use-fullscreen.js +15 -4
  181. package/src/composables/private/use-router-link.js +44 -23
  182. package/src/composables/private/use-router-link.json +26 -10
  183. package/src/composables/private/use-split-attrs.js +4 -4
  184. package/src/composables/private/use-validate.js +21 -15
  185. package/src/composables/private/use-validate.json +1 -0
  186. package/src/css/core/helpers.sass +3 -0
  187. package/src/css/core/positioning.sass +5 -0
  188. package/src/directives/ScrollFire.js +1 -0
  189. package/src/icon-set.js +2 -4
  190. package/src/plugins/AppFullscreen.js +70 -53
  191. package/src/plugins/AppVisibility.js +2 -3
  192. package/src/plugins/BottomSheet.js +3 -5
  193. package/src/plugins/Dialog.js +3 -5
  194. package/src/plugins/LoadingBar.js +17 -18
  195. package/src/plugins/Notify.js +296 -295
  196. package/src/plugins/Platform.js +14 -14
  197. package/src/utils/date.js +4 -4
  198. package/src/utils/dom.js +2 -2
  199. package/src/utils/open-url.js +2 -2
  200. package/src/utils/patterns.js +1 -0
  201. package/src/utils/private/define-reactive-plugin.js +10 -8
  202. package/src/utils/private/global-dialog.js +6 -8
  203. package/src/utils/private/inject-obj-prop.js +13 -0
  204. package/src/utils/private/is.js +2 -2
@@ -23,6 +23,7 @@ import { useTableRowSelection, useTableRowSelectionProps, useTableRowSelectionEm
23
23
  import { useTableRowExpand, useTableRowExpandProps, useTableRowExpandEmits } from './table-row-expand.js'
24
24
  import { useTableColumnSelection, useTableColumnSelectionProps } from './table-column-selection.js'
25
25
 
26
+ import { injectProp, injectMultipleProps } from '../../utils/private/inject-obj-prop.js'
26
27
  import { createComponent } from '../../utils/private/create.js'
27
28
 
28
29
  const bottomClass = 'q-table__bottom row items-center'
@@ -477,11 +478,7 @@ export default createComponent({
477
478
 
478
479
  data.cols = data.cols.map(col => {
479
480
  const c = { ...col }
480
- Object.defineProperty(c, 'value', {
481
- get: () => getCellValue(col, data.row),
482
- configurable: true,
483
- enumerable: true
484
- })
481
+ injectProp(c, 'value', () => getCellValue(col, data.row))
485
482
  return c
486
483
  })
487
484
 
@@ -490,13 +487,7 @@ export default createComponent({
490
487
 
491
488
  function getBodyCellScope (data) {
492
489
  injectBodyCommonScope(data)
493
-
494
- Object.defineProperty(data, 'value', {
495
- get: () => getCellValue(data.col, data.row),
496
- configurable: true,
497
- enumerable: true
498
- })
499
-
490
+ injectProp(data, 'value', () => getCellValue(data.col, data.row))
500
491
  return data
501
492
  }
502
493
 
@@ -516,23 +507,21 @@ export default createComponent({
516
507
  dense: props.dense
517
508
  })
518
509
 
519
- hasSelectionMode.value === true && Object.defineProperty(data, 'selected', {
520
- get: () => isRowSelected(data.key),
521
- set: (adding, evt) => {
510
+ hasSelectionMode.value === true && injectProp(
511
+ data,
512
+ 'selected',
513
+ () => isRowSelected(data.key),
514
+ (adding, evt) => {
522
515
  updateSelection([ data.key ], [ data.row ], adding, evt)
523
- },
524
- configurable: true,
525
- enumerable: true
526
- })
516
+ }
517
+ )
527
518
 
528
- Object.defineProperty(data, 'expand', {
529
- get: () => isRowExpanded(data.key),
530
- set: adding => {
531
- updateExpanded(data.key, adding)
532
- },
533
- configurable: true,
534
- enumerable: true
535
- })
519
+ injectProp(
520
+ data,
521
+ 'expand',
522
+ () => isRowExpanded(data.key),
523
+ adding => { updateExpanded(data.key, adding) }
524
+ )
536
525
  }
537
526
 
538
527
  function getCellValue (col, row) {
@@ -704,12 +693,12 @@ export default createComponent({
704
693
  })
705
694
 
706
695
  if (multipleSelection.value === true) {
707
- Object.defineProperty(data, 'selected', {
708
- get: () => headerSelectedValue.value,
709
- set: onMultipleSelectionSet,
710
- configurable: true,
711
- enumerable: true
712
- })
696
+ injectProp(
697
+ data,
698
+ 'selected',
699
+ () => headerSelectedValue.value,
700
+ onMultipleSelectionSet
701
+ )
713
702
  }
714
703
 
715
704
  return data
@@ -1024,19 +1013,10 @@ export default createComponent({
1024
1013
  getCellValue
1025
1014
  })
1026
1015
 
1027
- Object.defineProperty(vm.proxy, 'filteredSortedRows', {
1028
- get: () => filteredSortedRows.value,
1029
- enumerable: true
1030
- })
1031
-
1032
- Object.defineProperty(vm.proxy, 'computedRows', {
1033
- get: () => computedRows.value,
1034
- enumerable: true
1035
- })
1036
-
1037
- Object.defineProperty(vm.proxy, 'computedRowsNumber', {
1038
- get: () => computedRowsNumber.value,
1039
- enumerable: true
1016
+ injectMultipleProps(vm.proxy, {
1017
+ filteredSortedRows: () => filteredSortedRows.value,
1018
+ computedRows: () => computedRows.value,
1019
+ computedRowsNumber: () => computedRowsNumber.value
1040
1020
  })
1041
1021
 
1042
1022
  return () => {
@@ -10,8 +10,7 @@ export default createComponent({
10
10
 
11
11
  props: {
12
12
  ...useRouterLinkProps,
13
- ...useTabProps,
14
- to: { required: true }
13
+ ...useTabProps
15
14
  },
16
15
 
17
16
  emits: useTabEmits,
@@ -5,13 +5,6 @@
5
5
 
6
6
  "mixins": [ "components/tabs/QTab", "composables/private/use-router-link" ],
7
7
 
8
- "props": {
9
- "to": {
10
- "required": true,
11
- "category": "general"
12
- }
13
- },
14
-
15
8
  "events": {
16
9
  "click": {
17
10
  "desc": "Emitted when component is clicked (activated)",
@@ -87,6 +87,7 @@ export default createComponent({
87
87
  )
88
88
 
89
89
  const tabList = []
90
+ const hasFocus = ref(false)
90
91
 
91
92
  let localFromRoute = false, animateTimer, scrollTimer, unwatchRoute
92
93
  let localUpdateArrows = arrowsEnabled.value === true
@@ -126,7 +127,7 @@ export default createComponent({
126
127
  )
127
128
 
128
129
  const innerClass = computed(() =>
129
- 'q-tabs__content row no-wrap items-center self-stretch hide-scrollbar '
130
+ 'q-tabs__content row no-wrap items-center self-stretch hide-scrollbar relative-position '
130
131
  + alignClass.value
131
132
  + (props.contentClass !== void 0 ? ` ${ props.contentClass }` : '')
132
133
  + ($q.platform.is.mobile === true ? ' scroll' : '')
@@ -201,7 +202,7 @@ export default createComponent({
201
202
  contentRef.value[ domProps.value.scroll ],
202
203
  Array.prototype.reduce.call(
203
204
  contentRef.value.children,
204
- (acc, el) => acc + el[ domProps.value.content ],
205
+ (acc, el) => acc + (el[ domProps.value.content ] || 0),
205
206
  0
206
207
  )
207
208
  ),
@@ -260,23 +261,27 @@ export default createComponent({
260
261
  }
261
262
 
262
263
  if (newTab && scrollable.value === true) {
263
- const
264
- { left, width, top, height } = contentRef.value.getBoundingClientRect(),
265
- newPos = newTab.rootRef.value.getBoundingClientRect()
264
+ scrollToTabEl(newTab.rootRef.value)
265
+ }
266
+ }
266
267
 
267
- let offset = props.vertical === true ? newPos.top - top : newPos.left - left
268
+ function scrollToTabEl (el) {
269
+ const
270
+ { left, width, top, height } = contentRef.value.getBoundingClientRect(),
271
+ newPos = el.getBoundingClientRect()
268
272
 
269
- if (offset < 0) {
270
- contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.floor(offset)
271
- localUpdateArrows()
272
- return
273
- }
273
+ let offset = props.vertical === true ? newPos.top - top : newPos.left - left
274
274
 
275
- offset += props.vertical === true ? newPos.height - height : newPos.width - width
276
- if (offset > 0) {
277
- contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.ceil(offset)
278
- localUpdateArrows()
279
- }
275
+ if (offset < 0) {
276
+ contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.floor(offset)
277
+ localUpdateArrows()
278
+ return
279
+ }
280
+
281
+ offset += props.vertical === true ? newPos.height - height : newPos.width - width
282
+ if (offset > 0) {
283
+ contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.ceil(offset)
284
+ localUpdateArrows()
280
285
  }
281
286
  }
282
287
 
@@ -312,17 +317,56 @@ export default createComponent({
312
317
  }
313
318
 
314
319
  function scrollToStart () {
315
- animScrollTo(rtlPosCorrection.value === true ? 9999 : 0)
320
+ animScrollTo(rtlPosCorrection.value === true ? Number.MAX_SAFE_INTEGER : 0)
316
321
  }
317
322
 
318
323
  function scrollToEnd () {
319
- animScrollTo(rtlPosCorrection.value === true ? 0 : 9999)
324
+ animScrollTo(rtlPosCorrection.value === true ? 0 : Number.MAX_SAFE_INTEGER)
320
325
  }
321
326
 
322
327
  function stopAnimScroll () {
323
328
  clearInterval(scrollTimer)
324
329
  }
325
330
 
331
+ function onKbdNavigate (keyCode, fromEl) {
332
+ const tabs = Array.prototype.filter.call(
333
+ contentRef.value.children,
334
+ el => el === fromEl || (el.matches && el.matches('.q-tab.q-focusable') === true)
335
+ )
336
+
337
+ const len = tabs.length
338
+ if (len === 0) { return }
339
+
340
+ if (keyCode === 36) { // Home
341
+ scrollToTabEl(tabs[ 0 ])
342
+ return true
343
+ }
344
+ if (keyCode === 35) { // End
345
+ scrollToTabEl(tabs[ len - 1 ])
346
+ return true
347
+ }
348
+
349
+ const dirPrev = (props.vertical === true && keyCode === 38 /* ArrowUp */)
350
+ || (props.vertical !== true && keyCode === 37 /* ArrowLeft */)
351
+
352
+ const dirNext = (props.vertical === true && keyCode === 40 /* ArrowDown */)
353
+ || (props.vertical !== true && keyCode === 39 /* ArrowRight */)
354
+
355
+ const dir = dirPrev === true ? -1 : (dirNext === true ? 1 : void 0)
356
+
357
+ if (dir !== void 0) {
358
+ const rtlDir = isRTL.value === true ? -1 : 1
359
+ const index = tabs.indexOf(fromEl) + dir * rtlDir
360
+
361
+ if (index >= 0 && index < len) {
362
+ scrollToTabEl(tabs[ index ])
363
+ tabs[ index ].focus({ preventScroll: true })
364
+ }
365
+
366
+ return true
367
+ }
368
+ }
369
+
326
370
  // let's speed up execution of time-sensitive scrollTowards()
327
371
  // with a computed variable by directly applying the minimal
328
372
  // number of instructions on get/set functions
@@ -368,7 +412,7 @@ export default createComponent({
368
412
  }
369
413
 
370
414
  function getRouteList () {
371
- return tabList.filter(tab => tab.routerProps !== void 0 && tab.routerProps.hasLink.value === true)
415
+ return tabList.filter(tab => tab.routerProps !== void 0 && tab.routerProps.hasRouterLink.value === true)
372
416
  }
373
417
 
374
418
  // do not use directly; use verifyRouteModel() instead
@@ -440,6 +484,9 @@ export default createComponent({
440
484
  }
441
485
  }
442
486
 
487
+ function onFocusin () { hasFocus.value = true }
488
+ function onFocusout () { hasFocus.value = false }
489
+
443
490
  function verifyRouteModel () {
444
491
  if ($tabs.avoidRouteWatcher !== true) {
445
492
  registerTimeout(updateActiveRoute)
@@ -485,6 +532,7 @@ export default createComponent({
485
532
  const $tabs = {
486
533
  currentModel,
487
534
  tabProps,
535
+ hasFocus,
488
536
 
489
537
  registerTab,
490
538
  unregisterTab,
@@ -492,6 +540,7 @@ export default createComponent({
492
540
  verifyRouteModel,
493
541
  updateModel,
494
542
  recalculateScroll,
543
+ onKbdNavigate,
495
544
 
496
545
  avoidRouteWatcher: false
497
546
  }
@@ -543,7 +592,9 @@ export default createComponent({
543
592
  return h('div', {
544
593
  ref: rootRef,
545
594
  class: classes.value,
546
- role: 'tablist'
595
+ role: 'tablist',
596
+ onFocusin,
597
+ onFocusout
547
598
  }, child)
548
599
  }
549
600
  }
@@ -1,16 +1,17 @@
1
- import { h, ref, computed, inject, onBeforeUnmount, onMounted, withDirectives } from 'vue'
1
+ import { h, ref, computed, inject, onBeforeUnmount, onMounted, withDirectives, getCurrentInstance } from 'vue'
2
2
 
3
3
  import QIcon from '../icon/QIcon.js'
4
4
 
5
5
  import Ripple from '../../directives/Ripple.js'
6
6
 
7
7
  import { hMergeSlot } from '../../utils/private/render.js'
8
- import { isKeyCode } from '../../utils/private/key-composition.js'
8
+ import { isKeyCode, shouldIgnoreKey } from '../../utils/private/key-composition.js'
9
9
  import { tabsKey } from '../../utils/private/symbols.js'
10
+ import { stopAndPrevent } from '../../utils/event.js'
10
11
 
11
12
  let uid = 0
12
13
 
13
- export const useTabEmits = [ 'click', 'keyup' ]
14
+ export const useTabEmits = [ 'click', 'keydown' ]
14
15
 
15
16
  export const useTabProps = {
16
17
  icon: String,
@@ -42,14 +43,19 @@ export default function (props, slots, emit, routerProps) {
42
43
  console.error('QTab/QRouteTab component needs to be child of QTabs')
43
44
  })
44
45
 
46
+ const { proxy } = getCurrentInstance()
47
+
45
48
  const blurTargetRef = ref(null)
46
49
  const rootRef = ref(null)
47
50
  const tabIndicatorRef = ref(null)
48
51
 
49
52
  const ripple = computed(() => (
50
- props.disable === true
53
+ props.disable === true || props.ripple === false
51
54
  ? false
52
- : props.ripple
55
+ : Object.assign(
56
+ { keyCodes: [ 13, 32 ], early: true },
57
+ props.ripple === true ? {} : props.ripple
58
+ )
53
59
  ))
54
60
 
55
61
  const isActive = computed(() => $tabs.currentModel.value === props.name)
@@ -79,7 +85,9 @@ export default function (props, slots, emit, routerProps) {
79
85
  )
80
86
 
81
87
  const tabIndex = computed(() => (
82
- props.disable === true || isActive.value === true ? -1 : props.tabindex || 0
88
+ props.disable === true || $tabs.hasFocus.value === true
89
+ ? -1
90
+ : props.tabindex || 0
83
91
  ))
84
92
 
85
93
  function onClick (e, keyboard) {
@@ -89,12 +97,12 @@ export default function (props, slots, emit, routerProps) {
89
97
  let go
90
98
 
91
99
  if (routerProps !== void 0) {
92
- if (routerProps.hasLink.value === true) {
100
+ if (routerProps.hasRouterLink.value === true) {
93
101
  go = () => {
94
102
  e.__qNavigate = true
95
103
  $tabs.avoidRouteWatcher = true
96
104
 
97
- const res = routerProps.navigateToLink(e)
105
+ const res = routerProps.navigateToRouterLink(e)
98
106
 
99
107
  if (res === false) {
100
108
  $tabs.avoidRouteWatcher = false
@@ -123,9 +131,14 @@ export default function (props, slots, emit, routerProps) {
123
131
  }
124
132
  }
125
133
 
126
- function onKeyup (e) {
127
- isKeyCode(e, 13) === true && onClick(e, true)
128
- emit('keyup', e)
134
+ function onKeydown (e) {
135
+ if (isKeyCode(e, [ 13, 32 ])) {
136
+ onClick(e, true)
137
+ }
138
+ else if (shouldIgnoreKey(e) !== true && e.keyCode >= 35 && e.keyCode <= 40) {
139
+ $tabs.onKbdNavigate(e.keyCode, proxy.$el) === true && stopAndPrevent(e)
140
+ }
141
+ emit('keydown', e)
129
142
  }
130
143
 
131
144
  function getContent () {
@@ -201,10 +214,10 @@ export default function (props, slots, emit, routerProps) {
201
214
  class: classes.value,
202
215
  tabindex: tabIndex.value,
203
216
  role: 'tab',
204
- 'aria-selected': isActive.value,
217
+ 'aria-selected': isActive.value === true ? 'true' : 'false',
205
218
  'aria-disabled': props.disable === true ? 'true' : void 0,
206
219
  onClick,
207
- onKeyup,
220
+ onKeydown,
208
221
  ...customData
209
222
  }
210
223
 
@@ -13,6 +13,7 @@ import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
13
13
  import { createComponent } from '../../utils/private/create.js'
14
14
  import { stopAndPrevent } from '../../utils/event.js'
15
15
  import { shouldIgnoreKey } from '../../utils/private/key-composition.js'
16
+ import { injectProp } from '../../utils/private/inject-obj-prop.js'
16
17
 
17
18
  const tickStrategyOptions = [ 'none', 'strict', 'leaf', 'leaf-filtered' ]
18
19
 
@@ -431,18 +432,19 @@ export default createComponent({
431
432
  function getSlotScope (node, meta, key) {
432
433
  const scope = { tree: proxy, node, key, color: props.color, dark: isDark.value }
433
434
 
434
- Object.defineProperty(scope, 'expanded', {
435
- get: () => { return meta.expanded },
436
- set: val => { val !== meta.expanded && setExpanded(key, val) },
437
- configurable: true,
438
- enumerable: true
439
- })
440
- Object.defineProperty(scope, 'ticked', {
441
- get: () => { return meta.ticked },
442
- set: val => { val !== meta.ticked && setTicked([ key ], val) },
443
- configurable: true,
444
- enumerable: true
445
- })
435
+ injectProp(
436
+ scope,
437
+ 'expanded',
438
+ () => { return meta.expanded },
439
+ val => { val !== meta.expanded && setExpanded(key, val) }
440
+ )
441
+
442
+ injectProp(
443
+ scope,
444
+ 'ticked',
445
+ () => { return meta.ticked },
446
+ val => { val !== meta.ticked && setTicked([ key ], val) }
447
+ )
446
448
 
447
449
  return scope
448
450
  }
@@ -67,12 +67,24 @@
67
67
  "slots": {
68
68
  "header": {
69
69
  "desc": "Slot for custom header; Scope is the QUploader instance itself",
70
- "__exemption": ["scope"]
70
+ "scope": {
71
+ "...self": {
72
+ "type": "Component",
73
+ "tsType": "QUploader",
74
+ "desc": "QUploader instance"
75
+ }
76
+ }
71
77
  },
72
78
 
73
79
  "list": {
74
80
  "desc": "Slot for custom list; Scope is the QUploader instance itself",
75
- "__exemption": ["scope"]
81
+ "scope": {
82
+ "...self": {
83
+ "type": "Component",
84
+ "tsType": "QUploader",
85
+ "desc": "QUploader instance"
86
+ }
87
+ }
76
88
  }
77
89
  },
78
90
 
@@ -210,7 +210,7 @@ export function getRenderer (getPlugin) {
210
210
  removed.size += f.size
211
211
  removed.files.push(f)
212
212
 
213
- f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)
213
+ f.__img !== void 0 && window.URL.revokeObjectURL(f.__img.src)
214
214
 
215
215
  return false
216
216
  })
@@ -226,7 +226,7 @@ export function getRenderer (getPlugin) {
226
226
  if (props.disable) { return }
227
227
 
228
228
  if (file.__status === 'uploaded') {
229
- state.uploadedFiles.value = state.uploadedFiles.value.filter(f => f.name !== file.name)
229
+ state.uploadedFiles.value = state.uploadedFiles.value.filter(f => f.__key !== file.__key)
230
230
  }
231
231
  else if (file.__status === 'uploading') {
232
232
  file.__abort()
@@ -236,21 +236,22 @@ export function getRenderer (getPlugin) {
236
236
  }
237
237
 
238
238
  state.files.value = state.files.value.filter(f => {
239
- if (f.name !== file.name) {
239
+ if (f.__key !== file.__key) {
240
240
  return true
241
241
  }
242
242
 
243
- f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)
243
+ f.__img !== void 0 && window.URL.revokeObjectURL(f.__img.src)
244
244
 
245
245
  return false
246
246
  })
247
- state.queuedFiles.value = state.queuedFiles.value.filter(f => f.name !== file.name)
247
+
248
+ state.queuedFiles.value = state.queuedFiles.value.filter(f => f.__key !== file.__key)
248
249
  emit('removed', [ file ])
249
250
  }
250
251
 
251
252
  function revokeImgURLs () {
252
253
  state.files.value.forEach(f => {
253
- f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)
254
+ f.__img !== void 0 && window.URL.revokeObjectURL(f.__img.src)
254
255
  })
255
256
  }
256
257
 
@@ -303,6 +304,7 @@ export function getRenderer (getPlugin) {
303
304
  let child = void 0
304
305
 
305
306
  if (icon === 'add') {
307
+ data.onClick = pickFiles
306
308
  child = renderInput
307
309
  }
308
310
  else {
@@ -324,6 +326,7 @@ export function getRenderer (getPlugin) {
324
326
  multiple: props.multiple === true ? 'multiple' : void 0,
325
327
  capture: props.capture,
326
328
  onMousedown: stop, // need to stop refocus from QBtn
329
+ onClick: pickFiles,
327
330
  onChange: addFilesToQueue
328
331
  })
329
332
  }
@@ -367,7 +370,7 @@ export function getRenderer (getPlugin) {
367
370
  }
368
371
 
369
372
  return state.files.value.map(file => h('div', {
370
- key: file.name,
373
+ key: file.__key,
371
374
  class: 'q-uploader__file relative-position'
372
375
  + (props.noThumbnails !== true && file.__img !== void 0 ? ' q-uploader__file--img' : '')
373
376
  + (
@@ -441,11 +444,15 @@ export function getRenderer (getPlugin) {
441
444
  uploadProgressLabel: uploadProgressLabel.value
442
445
  }
443
446
 
444
- Object.keys(state).forEach(key => {
447
+ for (const key in state) {
445
448
  acc[ key ] = isRef(state[ key ]) === true
446
449
  ? state[ key ].value
447
450
  : state[ key ]
448
- })
451
+ }
452
+
453
+ // TODO: (Qv3) Put the QUploader instance under `ref`
454
+ // property for consistency and flexibility
455
+ // return { ref: { ...acc, ...publicMethods } }
449
456
  return { ...acc, ...publicMethods }
450
457
  })
451
458
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  &__content
6
6
  outline: none
7
+ contain: content
7
8
 
8
9
  *
9
10
  overflow-anchor: none