quasar 2.3.4 → 2.4.3

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 (238) hide show
  1. package/dist/api/BottomSheet.json +1 -1
  2. package/dist/api/Loading.json +2 -6
  3. package/dist/api/Notify.json +5 -5
  4. package/dist/api/QAvatar.json +1 -1
  5. package/dist/api/QBreadcrumbsEl.json +32 -11
  6. package/dist/api/QBtn.json +32 -16
  7. package/dist/api/QBtnDropdown.json +33 -17
  8. package/dist/api/QBtnToggle.json +4 -1
  9. package/dist/api/QCarousel.json +4 -4
  10. package/dist/api/QChatMessage.json +4 -12
  11. package/dist/api/QChip.json +4 -4
  12. package/dist/api/QExpansionItem.json +34 -13
  13. package/dist/api/QFab.json +32 -2
  14. package/dist/api/QFabAction.json +9 -1
  15. package/dist/api/QField.json +1 -0
  16. package/dist/api/QFile.json +1 -0
  17. package/dist/api/QInput.json +1 -0
  18. package/dist/api/QItem.json +31 -10
  19. package/dist/api/QLinearProgress.json +1 -1
  20. package/dist/api/QOptionGroup.json +74 -4
  21. package/dist/api/QPagination.json +4 -4
  22. package/dist/api/QPullToRefresh.json +1 -1
  23. package/dist/api/QRange.json +592 -107
  24. package/dist/api/QRating.json +3 -3
  25. package/dist/api/QRouteTab.json +32 -12
  26. package/dist/api/QSelect.json +4 -7
  27. package/dist/api/QSlider.json +504 -39
  28. package/dist/api/QStep.json +4 -4
  29. package/dist/api/QStepper.json +4 -4
  30. package/dist/api/QTab.json +1 -1
  31. package/dist/api/QTable.json +4 -4
  32. package/dist/api/QTimelineEntry.json +1 -1
  33. package/dist/api/QToggle.json +1 -1
  34. package/dist/api/QTree.json +1 -1
  35. package/dist/api/QUploader.json +16 -2
  36. package/dist/api/QVideo.json +11 -1
  37. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  38. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  39. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  40. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  41. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  42. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  43. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  44. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  45. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  46. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  47. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  48. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  49. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  50. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  51. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  52. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  53. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  54. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  55. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  56. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  57. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  58. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  59. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  60. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  61. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  62. package/dist/icon-set/svg-mdi-v4.umd.prod.js +1 -1
  63. package/dist/icon-set/svg-mdi-v5.umd.prod.js +1 -1
  64. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  65. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  66. package/dist/icon-set/themify.umd.prod.js +1 -1
  67. package/dist/lang/ar.umd.prod.js +1 -1
  68. package/dist/lang/az-Latn.umd.prod.js +1 -1
  69. package/dist/lang/bg.umd.prod.js +1 -1
  70. package/dist/lang/bn.umd.prod.js +1 -1
  71. package/dist/lang/ca.umd.prod.js +1 -1
  72. package/dist/lang/cs.umd.prod.js +1 -1
  73. package/dist/lang/da.umd.prod.js +1 -1
  74. package/dist/lang/de.umd.prod.js +1 -1
  75. package/dist/lang/el.umd.prod.js +1 -1
  76. package/dist/lang/en-GB.umd.prod.js +1 -1
  77. package/dist/lang/en-US.umd.prod.js +1 -1
  78. package/dist/lang/eo.umd.prod.js +1 -1
  79. package/dist/lang/es.umd.prod.js +1 -1
  80. package/dist/lang/et.umd.prod.js +1 -1
  81. package/dist/lang/fa-IR.umd.prod.js +1 -1
  82. package/dist/lang/fa.umd.prod.js +1 -1
  83. package/dist/lang/fi.umd.prod.js +1 -1
  84. package/dist/lang/fr.umd.prod.js +1 -1
  85. package/dist/lang/gn.umd.prod.js +1 -1
  86. package/dist/lang/he.umd.prod.js +1 -1
  87. package/dist/lang/hr.umd.prod.js +1 -1
  88. package/dist/lang/hu.umd.prod.js +1 -1
  89. package/dist/lang/id.umd.prod.js +1 -1
  90. package/dist/lang/is.umd.prod.js +1 -1
  91. package/dist/lang/it.umd.prod.js +1 -1
  92. package/dist/lang/ja.umd.prod.js +1 -1
  93. package/dist/lang/km.umd.prod.js +1 -1
  94. package/dist/lang/ko-KR.umd.prod.js +1 -1
  95. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  96. package/dist/lang/lt.umd.prod.js +1 -1
  97. package/dist/lang/lu.umd.prod.js +1 -1
  98. package/dist/lang/lv.umd.prod.js +1 -1
  99. package/dist/lang/ml.umd.prod.js +1 -1
  100. package/dist/lang/ms.umd.prod.js +1 -1
  101. package/dist/lang/nb-NO.umd.prod.js +1 -1
  102. package/dist/lang/nl.umd.prod.js +1 -1
  103. package/dist/lang/pl.umd.prod.js +1 -1
  104. package/dist/lang/pt-BR.umd.prod.js +1 -1
  105. package/dist/lang/pt.umd.prod.js +1 -1
  106. package/dist/lang/ro.umd.prod.js +1 -1
  107. package/dist/lang/ru.umd.prod.js +1 -1
  108. package/dist/lang/sk.umd.prod.js +1 -1
  109. package/dist/lang/sl.umd.prod.js +1 -1
  110. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  111. package/dist/lang/sr.umd.prod.js +1 -1
  112. package/dist/lang/sv.umd.prod.js +1 -1
  113. package/dist/lang/ta.umd.prod.js +1 -1
  114. package/dist/lang/th.umd.prod.js +1 -1
  115. package/dist/lang/tr.umd.prod.js +1 -1
  116. package/dist/lang/ug.umd.prod.js +1 -1
  117. package/dist/lang/uk.umd.prod.js +1 -1
  118. package/dist/lang/vi.umd.prod.js +1 -1
  119. package/dist/lang/zh-CN.umd.prod.js +1 -1
  120. package/dist/lang/zh-TW.umd.prod.js +1 -1
  121. package/dist/quasar.cjs.prod.js +2 -2
  122. package/dist/quasar.css +277 -196
  123. package/dist/quasar.esm.prod.js +2 -2
  124. package/dist/quasar.prod.css +1 -1
  125. package/dist/quasar.rtl.css +344 -275
  126. package/dist/quasar.rtl.prod.css +1 -1
  127. package/dist/quasar.sass +243 -189
  128. package/dist/quasar.umd.js +16670 -16294
  129. package/dist/quasar.umd.prod.js +2 -2
  130. package/dist/ssr-directives/Morph.js +1 -1
  131. package/dist/transforms/loader-asset-urls.json +20 -0
  132. package/dist/types/api/slider.d.ts +46 -0
  133. package/dist/types/api/validation.d.ts +4 -0
  134. package/dist/types/api.d.ts +2 -0
  135. package/dist/types/composables.d.ts +3 -3
  136. package/dist/types/index.d.ts +599 -121
  137. package/dist/types/utils/date.d.ts +2 -1
  138. package/dist/vetur/quasar-attributes.json +254 -82
  139. package/dist/vetur/quasar-tags.json +61 -18
  140. package/dist/web-types/web-types.json +635 -197
  141. package/package.json +1 -1
  142. package/src/api.extends.json +1 -2
  143. package/src/components/breadcrumbs/QBreadcrumbs.js +7 -2
  144. package/src/components/breadcrumbs/QBreadcrumbs.sass +0 -3
  145. package/src/components/breadcrumbs/QBreadcrumbsEl.js +14 -8
  146. package/src/components/btn/QBtn.js +5 -5
  147. package/src/components/btn/use-btn.js +21 -21
  148. package/src/components/btn/use-btn.json +22 -13
  149. package/src/components/btn-toggle/QBtnToggle.json +3 -0
  150. package/src/components/checkbox/use-checkbox.js +1 -1
  151. package/src/components/color/QColor.js +32 -26
  152. package/src/components/color/QColor.sass +10 -23
  153. package/src/components/date/QDate.sass +2 -0
  154. package/src/components/dialog/QDialog.js +7 -5
  155. package/src/components/drawer/QDrawer.js +18 -15
  156. package/src/components/editor/QEditor.js +1 -1
  157. package/src/components/editor/QEditor.sass +10 -1
  158. package/src/components/expansion-item/QExpansionItem.js +4 -1
  159. package/src/components/fab/QFab.js +18 -12
  160. package/src/components/fab/QFab.json +33 -0
  161. package/src/components/fab/QFab.sass +1 -1
  162. package/src/components/fab/QFabAction.js +14 -7
  163. package/src/components/fab/QFabAction.json +10 -0
  164. package/src/components/file/QFile.js +12 -5
  165. package/src/components/file/QFile.sass +4 -2
  166. package/src/components/footer/QFooter.js +1 -1
  167. package/src/components/header/QHeader.js +1 -1
  168. package/src/components/icon/QIcon.js +1 -1
  169. package/src/components/infinite-scroll/QInfiniteScroll.js +4 -5
  170. package/src/components/item/QItem.js +2 -3
  171. package/src/components/linear-progress/QLinearProgress.json +1 -1
  172. package/src/components/menu/QMenu.js +6 -2
  173. package/src/components/option-group/QOptionGroup.js +3 -0
  174. package/src/components/option-group/QOptionGroup.json +48 -2
  175. package/src/components/parallax/QParallax.js +4 -2
  176. package/src/components/popup-edit/QPopupEdit.js +2 -5
  177. package/src/components/radio/QRadio.js +2 -7
  178. package/src/components/range/QRange.js +132 -273
  179. package/src/components/range/QRange.json +11 -121
  180. package/src/components/rating/QRating.json +3 -3
  181. package/src/components/resize-observer/QResizeObserver.js +11 -10
  182. package/src/components/scroll-area/QScrollArea.js +8 -2
  183. package/src/components/scroll-observer/QScrollObserver.js +2 -0
  184. package/src/components/select/QSelect.js +4 -1
  185. package/src/components/slider/QSlider.js +61 -137
  186. package/src/components/slider/QSlider.json +1 -121
  187. package/src/components/slider/QSlider.sass +203 -138
  188. package/src/components/slider/use-slider.js +454 -107
  189. package/src/components/slider/use-slider.json +546 -0
  190. package/src/components/stepper/QStepper.js +3 -3
  191. package/src/components/stepper/QStepper.sass +24 -26
  192. package/src/components/table/QTable.js +26 -46
  193. package/src/components/tabs/QRouteTab.js +1 -2
  194. package/src/components/tabs/QRouteTab.json +0 -7
  195. package/src/components/tabs/QTabs.js +91 -24
  196. package/src/components/tabs/use-tab.js +26 -13
  197. package/src/components/tooltip/QTooltip.js +1 -2
  198. package/src/components/tree/QTree.js +14 -12
  199. package/src/components/uploader/QUploader.json +14 -2
  200. package/src/components/uploader/uploader-core.js +16 -9
  201. package/src/components/video/QVideo.js +4 -1
  202. package/src/components/video/QVideo.json +12 -1
  203. package/src/components/virtual-scroll/QVirtualScroll.sass +1 -0
  204. package/src/components/virtual-scroll/use-virtual-scroll.js +30 -17
  205. package/src/composables/private/use-field.js +18 -20
  206. package/src/composables/private/use-file.js +20 -5
  207. package/src/composables/private/use-form.js +2 -3
  208. package/src/composables/private/use-fullscreen.js +15 -4
  209. package/src/composables/private/use-model-toggle.js +1 -1
  210. package/src/composables/private/use-portal.js +9 -7
  211. package/src/composables/private/use-router-link.js +44 -23
  212. package/src/composables/private/use-router-link.json +26 -10
  213. package/src/composables/private/use-split-attrs.js +4 -4
  214. package/src/composables/private/use-tick.js +7 -14
  215. package/src/composables/private/use-validate.js +21 -15
  216. package/src/composables/private/use-validate.json +1 -0
  217. package/src/css/core/helpers.sass +3 -0
  218. package/src/css/core/positioning.sass +5 -0
  219. package/src/css/variables.sass +4 -6
  220. package/src/directives/ScrollFire.js +1 -0
  221. package/src/icon-set.js +2 -4
  222. package/src/plugins/AppFullscreen.js +70 -53
  223. package/src/plugins/AppVisibility.js +2 -3
  224. package/src/plugins/BottomSheet.js +3 -5
  225. package/src/plugins/Dialog.js +3 -5
  226. package/src/plugins/LoadingBar.js +17 -18
  227. package/src/plugins/Notify.js +296 -295
  228. package/src/plugins/Platform.js +14 -14
  229. package/src/utils/clone.js +53 -4
  230. package/src/utils/date.js +4 -4
  231. package/src/utils/dom.js +2 -2
  232. package/src/utils/open-url.js +2 -2
  233. package/src/utils/patterns.js +1 -0
  234. package/src/utils/private/define-reactive-plugin.js +10 -8
  235. package/src/utils/private/focus-manager.js +8 -10
  236. package/src/utils/private/global-dialog.js +6 -8
  237. package/src/utils/private/inject-obj-prop.js +13 -0
  238. 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)",
@@ -70,7 +70,8 @@ export default createComponent({
70
70
  const vm = getCurrentInstance()
71
71
  const { proxy: { $q } } = vm
72
72
 
73
- const { registerTick, prepareTick } = useTick()
73
+ const { registerTick: registerScrollTick } = useTick()
74
+ const { registerTimeout: registerFocusTimeout, removeTimeout: removeFocusTimeout } = useTimeout()
74
75
  const { registerTimeout } = useTimeout()
75
76
 
76
77
  const rootRef = ref(null)
@@ -87,6 +88,7 @@ export default createComponent({
87
88
  )
88
89
 
89
90
  const tabList = []
91
+ const hasFocus = ref(false)
90
92
 
91
93
  let localFromRoute = false, animateTimer, scrollTimer, unwatchRoute
92
94
  let localUpdateArrows = arrowsEnabled.value === true
@@ -126,7 +128,7 @@ export default createComponent({
126
128
  )
127
129
 
128
130
  const innerClass = computed(() =>
129
- 'q-tabs__content row no-wrap items-center self-stretch hide-scrollbar '
131
+ 'q-tabs__content row no-wrap items-center self-stretch hide-scrollbar relative-position '
130
132
  + alignClass.value
131
133
  + (props.contentClass !== void 0 ? ` ${ props.contentClass }` : '')
132
134
  + ($q.platform.is.mobile === true ? ' scroll' : '')
@@ -177,7 +179,7 @@ export default createComponent({
177
179
  }
178
180
 
179
181
  function recalculateScroll () {
180
- registerTick(() => {
182
+ registerScrollTick(() => {
181
183
  if (vm.isDeactivated !== true && vm.isUnmounted !== true) {
182
184
  updateContainer({
183
185
  width: rootRef.value.offsetWidth,
@@ -185,8 +187,6 @@ export default createComponent({
185
187
  })
186
188
  }
187
189
  })
188
-
189
- prepareTick()
190
190
  }
191
191
 
192
192
  function updateContainer (domSize) {
@@ -201,7 +201,7 @@ export default createComponent({
201
201
  contentRef.value[ domProps.value.scroll ],
202
202
  Array.prototype.reduce.call(
203
203
  contentRef.value.children,
204
- (acc, el) => acc + el[ domProps.value.content ],
204
+ (acc, el) => acc + (el[ domProps.value.content ] || 0),
205
205
  0
206
206
  )
207
207
  ),
@@ -260,23 +260,27 @@ export default createComponent({
260
260
  }
261
261
 
262
262
  if (newTab && scrollable.value === true) {
263
- const
264
- { left, width, top, height } = contentRef.value.getBoundingClientRect(),
265
- newPos = newTab.rootRef.value.getBoundingClientRect()
263
+ scrollToTabEl(newTab.rootRef.value)
264
+ }
265
+ }
266
266
 
267
- let offset = props.vertical === true ? newPos.top - top : newPos.left - left
267
+ function scrollToTabEl (el) {
268
+ const
269
+ { left, width, top, height } = contentRef.value.getBoundingClientRect(),
270
+ newPos = el.getBoundingClientRect()
268
271
 
269
- if (offset < 0) {
270
- contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.floor(offset)
271
- localUpdateArrows()
272
- return
273
- }
272
+ let offset = props.vertical === true ? newPos.top - top : newPos.left - left
274
273
 
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
- }
274
+ if (offset < 0) {
275
+ contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.floor(offset)
276
+ localUpdateArrows()
277
+ return
278
+ }
279
+
280
+ offset += props.vertical === true ? newPos.height - height : newPos.width - width
281
+ if (offset > 0) {
282
+ contentRef.value[ props.vertical === true ? 'scrollTop' : 'scrollLeft' ] += Math.ceil(offset)
283
+ localUpdateArrows()
280
284
  }
281
285
  }
282
286
 
@@ -312,17 +316,53 @@ export default createComponent({
312
316
  }
313
317
 
314
318
  function scrollToStart () {
315
- animScrollTo(rtlPosCorrection.value === true ? 9999 : 0)
319
+ animScrollTo(rtlPosCorrection.value === true ? Number.MAX_SAFE_INTEGER : 0)
316
320
  }
317
321
 
318
322
  function scrollToEnd () {
319
- animScrollTo(rtlPosCorrection.value === true ? 0 : 9999)
323
+ animScrollTo(rtlPosCorrection.value === true ? 0 : Number.MAX_SAFE_INTEGER)
320
324
  }
321
325
 
322
326
  function stopAnimScroll () {
323
327
  clearInterval(scrollTimer)
324
328
  }
325
329
 
330
+ function onKbdNavigate (keyCode, fromEl) {
331
+ const tabs = Array.prototype.filter.call(
332
+ contentRef.value.children,
333
+ el => el === fromEl || (el.matches && el.matches('.q-tab.q-focusable') === true)
334
+ )
335
+
336
+ const len = tabs.length
337
+ if (len === 0) { return }
338
+
339
+ if (keyCode === 36) { // Home
340
+ scrollToTabEl(tabs[ 0 ])
341
+ return true
342
+ }
343
+ if (keyCode === 35) { // End
344
+ scrollToTabEl(tabs[ len - 1 ])
345
+ return true
346
+ }
347
+
348
+ const dirPrev = keyCode === (props.vertical === true ? 38 /* ArrowUp */ : 37 /* ArrowLeft */)
349
+ const dirNext = keyCode === (props.vertical === true ? 40 /* ArrowDown */ : 39 /* ArrowRight */)
350
+
351
+ const dir = dirPrev === true ? -1 : (dirNext === true ? 1 : void 0)
352
+
353
+ if (dir !== void 0) {
354
+ const rtlDir = isRTL.value === true ? -1 : 1
355
+ const index = tabs.indexOf(fromEl) + dir * rtlDir
356
+
357
+ if (index >= 0 && index < len) {
358
+ scrollToTabEl(tabs[ index ])
359
+ tabs[ index ].focus({ preventScroll: true })
360
+ }
361
+
362
+ return true
363
+ }
364
+ }
365
+
326
366
  // let's speed up execution of time-sensitive scrollTowards()
327
367
  // with a computed variable by directly applying the minimal
328
368
  // number of instructions on get/set functions
@@ -368,7 +408,7 @@ export default createComponent({
368
408
  }
369
409
 
370
410
  function getRouteList () {
371
- return tabList.filter(tab => tab.routerProps !== void 0 && tab.routerProps.hasLink.value === true)
411
+ return tabList.filter(tab => tab.routerProps !== void 0 && tab.routerProps.hasRouterLink.value === true)
372
412
  }
373
413
 
374
414
  // do not use directly; use verifyRouteModel() instead
@@ -440,6 +480,29 @@ export default createComponent({
440
480
  }
441
481
  }
442
482
 
483
+ function onFocusin (e) {
484
+ removeFocusTimeout()
485
+
486
+ if (
487
+ hasFocus.value !== true
488
+ && rootRef.value !== null
489
+ && e.target
490
+ && typeof e.target.closest === 'function'
491
+ ) {
492
+ const tab = e.target.closest('.q-tab')
493
+
494
+ // if the target is contained by a QTab/QRouteTab
495
+ // (it might be other elements focused, like additional QBtn)
496
+ if (tab && rootRef.value.contains(tab) === true) {
497
+ hasFocus.value = true
498
+ }
499
+ }
500
+ }
501
+
502
+ function onFocusout () {
503
+ registerFocusTimeout(() => { hasFocus.value = false }, 30)
504
+ }
505
+
443
506
  function verifyRouteModel () {
444
507
  if ($tabs.avoidRouteWatcher !== true) {
445
508
  registerTimeout(updateActiveRoute)
@@ -485,6 +548,7 @@ export default createComponent({
485
548
  const $tabs = {
486
549
  currentModel,
487
550
  tabProps,
551
+ hasFocus,
488
552
 
489
553
  registerTab,
490
554
  unregisterTab,
@@ -492,6 +556,7 @@ export default createComponent({
492
556
  verifyRouteModel,
493
557
  updateModel,
494
558
  recalculateScroll,
559
+ onKbdNavigate,
495
560
 
496
561
  avoidRouteWatcher: false
497
562
  }
@@ -543,7 +608,9 @@ export default createComponent({
543
608
  return h('div', {
544
609
  ref: rootRef,
545
610
  class: classes.value,
546
- role: 'tablist'
611
+ role: 'tablist',
612
+ onFocusin,
613
+ onFocusout
547
614
  }, child)
548
615
  }
549
616
  }
@@ -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
 
@@ -92,7 +92,7 @@ export default createComponent({
92
92
  const selfOrigin = computed(() => parsePosition(props.self, $q.lang.rtl))
93
93
  const hideOnRouteChange = computed(() => props.persistent !== true)
94
94
 
95
- const { registerTick, removeTick, prepareTick } = useTick()
95
+ const { registerTick, removeTick } = useTick()
96
96
  const { registerTimeout, removeTimeout } = useTimeout()
97
97
  const { transition, transitionStyle } = useTransition(props, showing)
98
98
  const { localScrollTarget, changeScrollEvent, unconfigureScrollTarget } = useScrollTarget(props, configureScrollTarget)
@@ -158,7 +158,6 @@ export default createComponent({
158
158
  updatePosition()
159
159
  configureScrollTarget()
160
160
  })
161
- prepareTick()
162
161
 
163
162
  if (unwatchPosition === void 0) {
164
163
  unwatchPosition = watch(
@@ -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
 
@@ -13,7 +13,9 @@ export default createComponent({
13
13
  src: {
14
14
  type: String,
15
15
  required: true
16
- }
16
+ },
17
+
18
+ title: String
17
19
  },
18
20
 
19
21
  setup (props) {
@@ -30,6 +32,7 @@ export default createComponent({
30
32
  }, [
31
33
  h('iframe', {
32
34
  src: props.src,
35
+ title: props.title,
33
36
  frameborder: '0',
34
37
  allowfullscreen: true
35
38
  })
@@ -11,9 +11,20 @@
11
11
  "desc": "The source url to display in an iframe",
12
12
  "required": true,
13
13
  "examples": [
14
- "src=\"https://www.youtube.com/embed/k3_tw44QsZQ\""
14
+ "https://www.youtube.com/embed/k3_tw44QsZQ"
15
15
  ],
16
16
  "category": "model"
17
+ },
18
+
19
+ "title": {
20
+ "type": "String",
21
+ "desc": "(Accessibility) Set the native 'title' attribute value of the inner iframe being used",
22
+ "required": false,
23
+ "examples": [
24
+ "My Daily Marathon"
25
+ ],
26
+ "category": "accessibility",
27
+ "addedIn": "v2.4.3"
17
28
  }
18
29
  }
19
30
  }
@@ -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