quasar 2.21.4 → 2.23.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 (193) hide show
  1. package/README.md +1 -1
  2. package/dist/api/Mutation.json +1 -1
  3. package/dist/api/QLinearProgress.json +1 -1
  4. package/dist/api/QUploader.json +1 -1
  5. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  6. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  7. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  10. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  11. package/dist/icon-set/fontawesome-v7-pro.umd.prod.js +1 -1
  12. package/dist/icon-set/fontawesome-v7.umd.prod.js +1 -1
  13. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  14. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  16. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  17. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  18. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  19. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  20. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  21. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  24. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  25. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  26. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-fontawesome-v7.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-ionicons-v7.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-ionicons-v8.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  44. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  45. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  46. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  47. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  48. package/dist/icon-set/themify.umd.prod.js +1 -1
  49. package/dist/lang/ar-TN.umd.prod.js +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/bs-BA.umd.prod.js +1 -1
  55. package/dist/lang/ca.umd.prod.js +1 -1
  56. package/dist/lang/cs.umd.prod.js +1 -1
  57. package/dist/lang/da.umd.prod.js +1 -1
  58. package/dist/lang/de-CH.umd.prod.js +1 -1
  59. package/dist/lang/de-DE.umd.prod.js +1 -1
  60. package/dist/lang/de.umd.prod.js +1 -1
  61. package/dist/lang/el.umd.prod.js +1 -1
  62. package/dist/lang/en-GB.umd.prod.js +1 -1
  63. package/dist/lang/en-US.umd.prod.js +1 -1
  64. package/dist/lang/eo.umd.prod.js +1 -1
  65. package/dist/lang/es.umd.prod.js +1 -1
  66. package/dist/lang/et.umd.prod.js +1 -1
  67. package/dist/lang/eu.umd.prod.js +1 -1
  68. package/dist/lang/fa-IR.umd.prod.js +1 -1
  69. package/dist/lang/fa.umd.prod.js +1 -1
  70. package/dist/lang/fi.umd.prod.js +1 -1
  71. package/dist/lang/fr.umd.prod.js +1 -1
  72. package/dist/lang/gn.umd.prod.js +1 -1
  73. package/dist/lang/he.umd.prod.js +1 -1
  74. package/dist/lang/hi.umd.prod.js +1 -1
  75. package/dist/lang/hr.umd.prod.js +1 -1
  76. package/dist/lang/hu.umd.prod.js +1 -1
  77. package/dist/lang/id.umd.prod.js +1 -1
  78. package/dist/lang/is.umd.prod.js +1 -1
  79. package/dist/lang/it.umd.prod.js +1 -1
  80. package/dist/lang/ja.umd.prod.js +1 -1
  81. package/dist/lang/kk.umd.prod.js +1 -1
  82. package/dist/lang/km.umd.prod.js +1 -1
  83. package/dist/lang/ko-KR.umd.prod.js +1 -1
  84. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  85. package/dist/lang/lb.umd.prod.js +1 -1
  86. package/dist/lang/lt.umd.prod.js +1 -1
  87. package/dist/lang/lu.umd.prod.js +1 -1
  88. package/dist/lang/lv.umd.prod.js +1 -1
  89. package/dist/lang/mk.umd.prod.js +1 -1
  90. package/dist/lang/ml.umd.prod.js +1 -1
  91. package/dist/lang/mm.umd.prod.js +1 -1
  92. package/dist/lang/ms-MY.umd.prod.js +1 -1
  93. package/dist/lang/ms.umd.prod.js +1 -1
  94. package/dist/lang/my.umd.prod.js +1 -1
  95. package/dist/lang/nb-NO.umd.prod.js +1 -1
  96. package/dist/lang/nl.umd.prod.js +1 -1
  97. package/dist/lang/pl.umd.prod.js +1 -1
  98. package/dist/lang/pt-BR.umd.prod.js +1 -1
  99. package/dist/lang/pt.umd.prod.js +1 -1
  100. package/dist/lang/ro.umd.prod.js +1 -1
  101. package/dist/lang/ru.umd.prod.js +1 -1
  102. package/dist/lang/sk.umd.prod.js +1 -1
  103. package/dist/lang/sl.umd.prod.js +1 -1
  104. package/dist/lang/sm.umd.prod.js +1 -1
  105. package/dist/lang/sq.umd.prod.js +1 -1
  106. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  107. package/dist/lang/sr.umd.prod.js +1 -1
  108. package/dist/lang/sv.umd.prod.js +1 -1
  109. package/dist/lang/ta.umd.prod.js +1 -1
  110. package/dist/lang/th.umd.prod.js +1 -1
  111. package/dist/lang/tl.umd.prod.js +1 -1
  112. package/dist/lang/tr.umd.prod.js +1 -1
  113. package/dist/lang/ug.umd.prod.js +1 -1
  114. package/dist/lang/uk.umd.prod.js +1 -1
  115. package/dist/lang/ur-PK.umd.prod.js +1 -1
  116. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  117. package/dist/lang/uz-Latn.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.client.js +654 -207
  122. package/dist/quasar.css +20 -11
  123. package/dist/quasar.prod.css +1 -1
  124. package/dist/quasar.rtl.css +25 -20
  125. package/dist/quasar.rtl.prod.css +1 -1
  126. package/dist/quasar.sass +21 -12
  127. package/dist/quasar.server.prod.cjs +35 -35
  128. package/dist/quasar.server.prod.js +25 -25
  129. package/dist/quasar.umd.js +654 -206
  130. package/dist/quasar.umd.prod.js +19 -19
  131. package/dist/transforms/import-map.json +1 -1
  132. package/dist/types/composables.d.ts +15 -5
  133. package/dist/types/index.d.ts +5 -5
  134. package/dist/web-types/web-types.json +1 -1
  135. package/package.json +6 -6
  136. package/src/components/btn/QBtn.js +1 -1
  137. package/src/components/carousel/QCarousel.js +2 -0
  138. package/src/components/chip/QChip.js +20 -4
  139. package/src/components/date/QDate.js +9 -2
  140. package/src/components/dialog/QDialog.js +9 -2
  141. package/src/components/editor/QEditor.js +18 -3
  142. package/src/components/expansion-item/QExpansionItem.js +6 -1
  143. package/src/components/fab/QFab.sass +11 -9
  144. package/src/components/input/QInput.js +42 -1
  145. package/src/components/input/QInput.json +7 -0
  146. package/src/components/input/use-mask.js +12 -4
  147. package/src/components/item/QItem.js +10 -1
  148. package/src/components/linear-progress/QLinearProgress.js +4 -11
  149. package/src/components/linear-progress/QLinearProgress.json +1 -1
  150. package/src/components/linear-progress/QLinearProgress.sass +7 -2
  151. package/src/components/menu/QMenu.js +9 -2
  152. package/src/components/range/QRange.js +2 -1
  153. package/src/components/rating/QRating.js +27 -8
  154. package/src/components/rating/QRating.sass +4 -0
  155. package/src/components/resize-observer/QResizeObserver.js +14 -3
  156. package/src/components/scroll-area/QScrollArea.js +69 -17
  157. package/src/components/slide-item/QSlideItem.js +3 -2
  158. package/src/components/slider/use-slider.js +7 -3
  159. package/src/components/stepper/StepHeader.js +11 -2
  160. package/src/components/table/QTable.js +11 -9
  161. package/src/components/table/QTh.js +20 -1
  162. package/src/components/table/table-column-selection.js +9 -1
  163. package/src/components/table/table-pagination.js +5 -2
  164. package/src/components/table/table-row-selection.js +10 -10
  165. package/src/components/tabs/QTabs.js +5 -6
  166. package/src/components/time/QTime.js +35 -10
  167. package/src/components/tooltip/QTooltip.js +112 -6
  168. package/src/components/tree/QTree.js +124 -4
  169. package/src/components/uploader/uploader-core.js +19 -4
  170. package/src/components/uploader/xhr-uploader-plugin.js +93 -43
  171. package/src/components/uploader/xhr-uploader-plugin.json +4 -4
  172. package/src/composables/private.use-field/use-field.js +2 -0
  173. package/src/composables/private.use-file/use-file.js +21 -12
  174. package/src/composables/private.use-fullscreen/use-fullscreen.js +71 -11
  175. package/src/composables/private.use-fullscreen/use-fullscreen.test.js +158 -0
  176. package/src/composables/private.use-model-toggle/use-model-toggle.js +2 -0
  177. package/src/composables/private.use-panel/use-panel.js +6 -2
  178. package/src/composables/use-animation-frame/use-animation-frame.js +47 -0
  179. package/src/composables/use-animation-frame/use-animation-frame.test.js +122 -0
  180. package/src/composables/use-interval/use-interval.js +8 -0
  181. package/src/composables/use-render-cache/use-render-cache.js +15 -10
  182. package/src/composables/use-timeout/use-timeout.js +8 -0
  183. package/src/composables.js +1 -1
  184. package/src/directives/intersection/Intersection.js +2 -2
  185. package/src/directives/mutation/Mutation.json +1 -1
  186. package/src/directives/touch-repeat/TouchRepeat.js +3 -1
  187. package/src/plugins/cookies/Cookies.js +29 -13
  188. package/src/plugins/meta/Meta.js +57 -9
  189. package/src/utils/extend/extend.js +4 -0
  190. package/src/utils/extend/extend.test.js +29 -0
  191. package/src/utils/private.click-outside/click-outside.js +27 -12
  192. package/src/utils/private.click-outside/click-outside.test.js +132 -0
  193. package/src/utils/scroll/prevent-scroll.js +4 -4
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quasar",
3
- "version": "2.21.4",
4
- "description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time",
3
+ "version": "2.23.0",
4
+ "description": "Build high-performance Vue.js user interfaces (SPA, PWA, SSR, SSG, Mobile and Desktop) in record time",
5
5
  "keywords": [
6
6
  "desktop",
7
7
  "electron",
@@ -65,15 +65,15 @@
65
65
  "diff": "^9.0.0",
66
66
  "fs-extra": "^11.3.6",
67
67
  "kolorist": "^1.8.0",
68
- "lightningcss": "^1.32.0",
68
+ "lightningcss": "^1.33.0",
69
69
  "open": "^11.0.0",
70
- "postcss": "^8.5.16",
70
+ "postcss": "^8.5.20",
71
71
  "postcss-rtlcss": "^6.0.0",
72
- "rolldown": "^1.1.5",
72
+ "rolldown": "^1.2.0",
73
73
  "sass-embedded": "^1.100.0",
74
74
  "table": "^6.8.2",
75
75
  "tinyglobby": "^0.2.17",
76
- "vue": "^3.5.39",
76
+ "vue": "^3.5.40",
77
77
  "webpack-merge": "^6.0.1",
78
78
  "@quasar/extras": "2.0.2"
79
79
  },
@@ -290,7 +290,7 @@ export default createComponent({
290
290
  blurTarget !== document.activeElement
291
291
  ) {
292
292
  blurTarget.setAttribute('tabindex', -1)
293
- blurTarget.focus()
293
+ blurTarget.focus({ preventScroll: true })
294
294
  }
295
295
 
296
296
  if (touchTarget === rootRef.value) {
@@ -89,6 +89,7 @@ export default createComponent({
89
89
 
90
90
  const {
91
91
  updatePanelsList,
92
+ updatePanelIndex,
92
93
  getPanelContent,
93
94
  panelDirectives,
94
95
  goToPanel,
@@ -322,6 +323,7 @@ export default createComponent({
322
323
 
323
324
  return () => {
324
325
  panelsLen = updatePanelsList(slots)
326
+ updatePanelIndex()
325
327
 
326
328
  return h(
327
329
  'div',
@@ -15,6 +15,10 @@ import { createComponent } from '../../utils/private.create/create.js'
15
15
  import { stopAndPrevent } from '../../utils/event/event.js'
16
16
  import { hDir, hMergeSlotSafely } from '../../utils/private.render/render.js'
17
17
 
18
+ function preventSpace(e) {
19
+ if (e.keyCode === 32) stopAndPrevent(e)
20
+ }
21
+
18
22
  export const defaultSizes = {
19
23
  xs: 8,
20
24
  sm: 10,
@@ -116,7 +120,11 @@ export default createComponent({
116
120
  const attributes = computed(() => {
117
121
  const chip = props.disable
118
122
  ? { tabindex: -1, 'aria-disabled': 'true' }
119
- : { tabindex: props.tabindex || 0 }
123
+ : {
124
+ tabindex: props.tabindex || 0,
125
+ role: 'button',
126
+ 'aria-pressed': props.selected ? 'true' : 'false'
127
+ }
120
128
 
121
129
  const remove = {
122
130
  ...chip,
@@ -129,7 +137,10 @@ export default createComponent({
129
137
  })
130
138
 
131
139
  function onKeyup(e) {
132
- if (e.keyCode === 13 /* ENTER */) onClick(e)
140
+ if ([13, 32].includes(e.keyCode)) {
141
+ onClick(e)
142
+ stopAndPrevent(e)
143
+ }
133
144
  }
134
145
 
135
146
  function onClick(e) {
@@ -140,7 +151,7 @@ export default createComponent({
140
151
  }
141
152
 
142
153
  function onRemove(e) {
143
- if (e.keyCode === void 0 || e.keyCode === 13) {
154
+ if (e.keyCode === void 0 || [13, 32].includes(e.keyCode)) {
144
155
  stopAndPrevent(e)
145
156
  if (!props.disable) {
146
157
  emit('update:modelValue', false)
@@ -196,6 +207,7 @@ export default createComponent({
196
207
  name: removeIcon.value,
197
208
  ...attributes.value.remove,
198
209
  onClick: onRemove,
210
+ onKeydown: preventSpace,
199
211
  onKeyup: onRemove
200
212
  })
201
213
  )
@@ -213,7 +225,11 @@ export default createComponent({
213
225
  }
214
226
 
215
227
  if (isClickable.value) {
216
- Object.assign(data, attributes.value.chip, { onClick, onKeyup })
228
+ Object.assign(data, attributes.value.chip, {
229
+ onClick,
230
+ onKeydown: preventSpace,
231
+ onKeyup
232
+ })
217
233
  }
218
234
 
219
235
  return hDir(
@@ -14,6 +14,7 @@ import useDark, {
14
14
  useDarkProps
15
15
  } from '../../composables/private.use-dark/use-dark.js'
16
16
  import useRenderCache from '../../composables/use-render-cache/use-render-cache.js'
17
+ import useHydration from '../../composables/use-hydration/use-hydration.js'
17
18
  import {
18
19
  useFormAttrs,
19
20
  useFormInject,
@@ -124,6 +125,7 @@ export default createComponent({
124
125
 
125
126
  const isDark = useDark(props, $q)
126
127
  const { getCache } = useRenderCache()
128
+ const { isHydrated } = useHydration()
127
129
  const { tabindex, headerClass, getLocale, getCurrentDate } = useDatetime(
128
130
  props,
129
131
  $q
@@ -736,6 +738,7 @@ export default createComponent({
736
738
  }
737
739
 
738
740
  if (
741
+ isHydrated.value &&
739
742
  viewModel.value.year === today.value.year &&
740
743
  viewModel.value.month === today.value.month
741
744
  ) {
@@ -1478,7 +1481,8 @@ export default createComponent({
1478
1481
  ],
1479
1482
 
1480
1483
  Months() {
1481
- const currentYear = viewModel.value.year === today.value.year
1484
+ const currentYear =
1485
+ isHydrated.value && viewModel.value.year === today.value.year
1482
1486
  const isDisabled = month =>
1483
1487
  (minNav.value !== null &&
1484
1488
  viewModel.value.year === minNav.value.year &&
@@ -1565,7 +1569,10 @@ export default createComponent({
1565
1569
  [
1566
1570
  h(QBtn, {
1567
1571
  key: 'yr' + i,
1568
- class: today.value.year === i ? 'q-date__today' : null,
1572
+ class:
1573
+ isHydrated.value && today.value.year === i
1574
+ ? 'q-date__today'
1575
+ : null,
1569
1576
  flat: !active,
1570
1577
  label: i,
1571
1578
  dense: true,
@@ -138,6 +138,7 @@ export default createComponent({
138
138
  hideOnRouteChange,
139
139
  handleShow,
140
140
  handleHide,
141
+ handleRouteChange,
141
142
  processOnMount: true
142
143
  })
143
144
 
@@ -253,13 +254,15 @@ export default createComponent({
253
254
  hidePortal()
254
255
 
255
256
  if (refocusTarget !== null) {
256
- ;(
257
+ const target =
257
258
  (evt?.type.indexOf('key') === 0
258
259
  ? refocusTarget.closest('[tabindex]:not([tabindex^="-"])')
259
260
  : void 0) || refocusTarget
260
- ).focus()
261
261
 
262
262
  refocusTarget = null
263
+ addFocusFn(() => {
264
+ if (target.isConnected) target.focus()
265
+ })
263
266
  }
264
267
 
265
268
  // should removeTimeout() if this gets removed
@@ -270,6 +273,10 @@ export default createComponent({
270
273
  }, props.transitionDuration)
271
274
  }
272
275
 
276
+ function handleRouteChange() {
277
+ refocusTarget = null
278
+ }
279
+
273
280
  function focus(selector) {
274
281
  addFocusFn(() => {
275
282
  let node = innerRef.value
@@ -21,6 +21,8 @@ import useFullscreen, {
21
21
  } from '../../composables/private.use-fullscreen/use-fullscreen.js'
22
22
  import useSplitAttrs from '../../composables/use-split-attrs/use-split-attrs.js'
23
23
 
24
+ import { isRuntimeSsrPreHydration } from '../../plugins/platform/Platform.js'
25
+
24
26
  import { createComponent } from '../../utils/private.create/create.js'
25
27
  import { stopAndPrevent } from '../../utils/event/event.js'
26
28
  import extend from '../../utils/extend/extend.js'
@@ -113,8 +115,12 @@ export default createComponent({
113
115
 
114
116
  const editable = computed(() => !props.readonly && !props.disable)
115
117
 
116
- let defaultFont, offsetBottom
118
+ let defaultFont,
119
+ offsetBottom,
120
+ refreshToolbarTimer = null
117
121
  let lastEmit = props.modelValue
122
+ const renderInitialContent =
123
+ __QUASAR_SSR_SERVER__ || isRuntimeSsrPreHydration.value
118
124
 
119
125
  if (!__QUASAR_SSR_SERVER__) {
120
126
  document.execCommand(
@@ -648,7 +654,12 @@ export default createComponent({
648
654
  }
649
655
 
650
656
  function refreshToolbar() {
651
- setTimeout(() => {
657
+ if (refreshToolbarTimer !== null) {
658
+ clearTimeout(refreshToolbarTimer)
659
+ }
660
+
661
+ refreshToolbarTimer = setTimeout(() => {
662
+ refreshToolbarTimer = null
652
663
  editLinkUrl.value = null
653
664
  proxy.$forceUpdate()
654
665
  }, 1)
@@ -673,6 +684,10 @@ export default createComponent({
673
684
  })
674
685
 
675
686
  onBeforeUnmount(() => {
687
+ if (refreshToolbarTimer !== null) {
688
+ clearTimeout(refreshToolbarTimer)
689
+ }
690
+
676
691
  document.removeEventListener('selectionchange', onSelectionchange)
677
692
  })
678
693
 
@@ -745,7 +760,7 @@ export default createComponent({
745
760
  class: innerClass.value,
746
761
  contenteditable: editable.value,
747
762
  placeholder: props.placeholder,
748
- ...(__QUASAR_SSR_SERVER__ ? { innerHTML: props.modelValue } : {}),
763
+ ...(renderInitialContent ? { innerHTML: props.modelValue } : {}),
749
764
  ...splitAttrs.listeners.value,
750
765
  onInput,
751
766
  onKeydown,
@@ -33,6 +33,10 @@ import { hSlot } from '../../utils/private.render/render.js'
33
33
  import uid from '../../utils/uid/uid.js'
34
34
 
35
35
  const itemGroups = shallowReactive({})
36
+
37
+ function preventSpace(e) {
38
+ if (e.keyCode === 32) stopAndPrevent(e)
39
+ }
36
40
  const LINK_PROPS = Object.keys(useRouterLinkProps)
37
41
 
38
42
  export default createComponent({
@@ -176,7 +180,7 @@ export default createComponent({
176
180
  }
177
181
 
178
182
  function toggleIconKeyboard(e) {
179
- if (e.keyCode === 13) toggleIcon(e, true)
183
+ if ([13, 32].includes(e.keyCode)) toggleIcon(e, true)
180
184
  }
181
185
 
182
186
  function toggleIcon(e, keyboard) {
@@ -259,6 +263,7 @@ export default createComponent({
259
263
  tabindex: 0,
260
264
  ...toggleAriaAttrs.value,
261
265
  onClick: toggleIcon,
266
+ onKeydown: preventSpace,
262
267
  onKeyup: toggleIconKeyboard
263
268
  })
264
269
 
@@ -100,20 +100,22 @@
100
100
  .q-btn
101
101
  margin: 5px
102
102
 
103
+ // physical direction, not text-based: don't let rtlcss mirror it
103
104
  &--right
104
- transform-origin: 0 50%
105
- transform: scale(.4) translateX(-62px)
105
+ transform-origin: 0 50% #{"/* rtl:ignore */"}
106
+ transform: scale(.4) translateX(-62px) #{"/* rtl:ignore */"}
106
107
  height: 56px
107
- left: 100%
108
- margin-left: 9px
108
+ left: 100% #{"/* rtl:ignore */"}
109
+ margin-left: 9px #{"/* rtl:ignore */"}
110
+ flex-direction: row #{"/* rtl:row-reverse */"}
109
111
 
110
112
  &--left
111
- transform-origin: 100% 50%
112
- transform: scale(.4) translateX(62px)
113
+ transform-origin: 100% 50% #{"/* rtl:ignore */"}
114
+ transform: scale(.4) translateX(62px) #{"/* rtl:ignore */"}
113
115
  height: 56px
114
- right: 100%
115
- margin-right: 9px
116
- flex-direction: row-reverse
116
+ right: 100% #{"/* rtl:ignore */"}
117
+ margin-right: 9px #{"/* rtl:ignore */"}
118
+ flex-direction: row-reverse #{"/* rtl:row */"}
117
119
 
118
120
  &--up
119
121
  transform-origin: 50% 100%
@@ -42,6 +42,7 @@ export default createComponent({
42
42
  modelValue: __QUASAR_SSR_SERVER__
43
43
  ? {} // SSR does not know about FileList
44
44
  : [String, Number, FileList],
45
+ modelModifiers: Object,
45
46
 
46
47
  shadowText: String,
47
48
 
@@ -179,6 +180,13 @@ export default createComponent({
179
180
  watch(
180
181
  () => props.modelValue,
181
182
  v => {
183
+ if (emitTimer !== null) {
184
+ cancelPendingValueEmission()
185
+ typedNumber = false
186
+ stopValueWatcher = false
187
+ delete temp.value
188
+ }
189
+
182
190
  if (hasMask.value) {
183
191
  if (stopValueWatcher) {
184
192
  stopValueWatcher = false
@@ -196,6 +204,14 @@ export default createComponent({
196
204
  delete temp.value
197
205
  }
198
206
  }
207
+
208
+ if (
209
+ props.modelModifiers?.trim === true &&
210
+ Object.hasOwn(temp, 'value') &&
211
+ (typeof temp.value !== 'string' || temp.value.trim() !== v)
212
+ ) {
213
+ delete temp.value
214
+ }
199
215
  }
200
216
 
201
217
  // textarea only
@@ -268,6 +284,10 @@ export default createComponent({
268
284
  if (hasMask.value) {
269
285
  updateMaskValue(val, false, e.inputType)
270
286
  } else {
287
+ if (props.modelModifiers?.trim === true) {
288
+ temp.value = val
289
+ }
290
+
271
291
  emitValue(val)
272
292
 
273
293
  if (isTypeText.value && e.target === document.activeElement) {
@@ -300,7 +320,11 @@ export default createComponent({
300
320
  emitValueFn = () => {
301
321
  emitTimer = null
302
322
 
303
- if (props.type !== 'number' && Object.hasOwn(temp, 'value')) {
323
+ if (
324
+ props.type !== 'number' &&
325
+ (props.modelModifiers?.trim !== true || hasMask.value) &&
326
+ Object.hasOwn(temp, 'value')
327
+ ) {
304
328
  delete temp.value
305
329
  }
306
330
 
@@ -332,6 +356,22 @@ export default createComponent({
332
356
  }
333
357
  }
334
358
 
359
+ function cancelPendingValueEmission() {
360
+ if (emitTimer !== null) {
361
+ clearTimeout(emitTimer)
362
+ emitTimer = null
363
+ }
364
+
365
+ emitValueFn = void 0
366
+ }
367
+
368
+ function onClear() {
369
+ cancelPendingValueEmission()
370
+ typedNumber = false
371
+ stopValueWatcher = false
372
+ delete temp.value
373
+ }
374
+
335
375
  // textarea only
336
376
  function adjustHeight() {
337
377
  requestAnimationFrame(() => {
@@ -445,6 +485,7 @@ export default createComponent({
445
485
  inputRef,
446
486
 
447
487
  emitValue,
488
+ onClear,
448
489
 
449
490
  hasValue,
450
491
 
@@ -17,6 +17,13 @@
17
17
  "examples": ["# v-model=\"myText\""]
18
18
  },
19
19
 
20
+ "model-modifiers": {
21
+ "type": "Object",
22
+ "desc": "Modifiers supplied by Vue for the component's v-model binding",
23
+ "examples": ["{ trim: true }"],
24
+ "internal": true
25
+ },
26
+
20
27
  "shadow-text": {
21
28
  "type": "String",
22
29
  "desc": "Text to be displayed as shadow at the end of the text in the control; Does NOT applies to type=file",
@@ -148,6 +148,14 @@ export default function useMask(props, emit, emitValue, inputRef) {
148
148
  }
149
149
  )
150
150
 
151
+ watch(
152
+ () => props.maskTokens,
153
+ () => {
154
+ if (hasMask.value) updateMaskValue(innerValue.value, true)
155
+ },
156
+ { deep: true }
157
+ )
158
+
151
159
  function getInitialMaskedValue() {
152
160
  updateMaskInternals()
153
161
 
@@ -311,8 +319,8 @@ export default function useMask(props, emit, emitValue, inputRef) {
311
319
 
312
320
  function updateMaskValue(rawVal, updateMaskInternalsFlag, inputType) {
313
321
  const inp = inputRef.value,
314
- end = inp.selectionEnd,
315
- endReverse = inp.value.length - end,
322
+ end = inp?.selectionEnd ?? 0,
323
+ endReverse = inp === null ? 0 : inp.value.length - end,
316
324
  unmasked = unmaskValue(rawVal)
317
325
 
318
326
  // Update here so unmask uses the original fillChar
@@ -323,11 +331,11 @@ export default function useMask(props, emit, emitValue, inputRef) {
323
331
  changed = innerValue.value !== masked
324
332
 
325
333
  // We want to avoid "flickering" so we set value immediately
326
- if (inp.value !== masked) inp.value = masked
334
+ if (inp !== null && inp.value !== masked) inp.value = masked
327
335
 
328
336
  if (changed) innerValue.value = masked
329
337
 
330
- if (document.activeElement === inp) {
338
+ if (inp !== null && document.activeElement === inp) {
331
339
  nextTick(() => {
332
340
  if (masked === maskReplaced) {
333
341
  const cursor = props.reverseFillMask ? maskReplaced.length : 0
@@ -118,6 +118,10 @@ export default createComponent({
118
118
  emit('keyup', e)
119
119
  }
120
120
 
121
+ function onKeydown(e) {
122
+ if (isClickable.value && e.keyCode === 32) stopAndPrevent(e)
123
+ }
124
+
121
125
  function getContent() {
122
126
  const child = hUniqueSlot(slots.default, [])
123
127
 
@@ -139,8 +143,13 @@ export default createComponent({
139
143
  ref: rootRef,
140
144
  class: classes.value,
141
145
  style: style.value,
142
- role: 'listitem',
146
+ role: hasLink.value
147
+ ? void 0
148
+ : isClickable.value
149
+ ? 'button'
150
+ : 'listitem',
143
151
  onClick,
152
+ onKeydown,
144
153
  onKeyup
145
154
  }
146
155
 
@@ -18,11 +18,9 @@ const defaultSizes = {
18
18
  xl: 14
19
19
  }
20
20
 
21
- function width(val, reverse, $q) {
21
+ function width(val) {
22
22
  return {
23
- transform: reverse
24
- ? `translateX(${$q.lang.rtl ? '-' : ''}100%) scale3d(${-val},1,1)`
25
- : `scale3d(${val},1,1)`
23
+ transform: `scale3d(${val},1,1)`
26
24
  }
27
25
  }
28
26
 
@@ -62,7 +60,6 @@ export default createComponent({
62
60
  const sizeStyle = useSize(props, defaultSizes)
63
61
 
64
62
  const motion = computed(() => props.indeterminate || props.query)
65
- const widthReverse = computed(() => props.reverse !== props.query)
66
63
  const style = computed(() => ({
67
64
  ...(sizeStyle.value !== null ? sizeStyle.value : {}),
68
65
  '--q-linear-progress-speed': `${props.animationSpeed}ms`
@@ -77,11 +74,7 @@ export default createComponent({
77
74
  )
78
75
 
79
76
  const trackStyle = computed(() =>
80
- width(
81
- props.buffer !== void 0 ? props.buffer : 1,
82
- widthReverse.value,
83
- proxy.$q
84
- )
77
+ width(props.buffer !== void 0 ? props.buffer : 1)
85
78
  )
86
79
  const transitionSuffix = computed(
87
80
  () => `with${props.instantFeedback ? 'out' : ''}-transition`
@@ -96,7 +89,7 @@ export default createComponent({
96
89
  )
97
90
 
98
91
  const modelStyle = computed(() =>
99
- width(motion.value ? 1 : props.value, widthReverse.value, proxy.$q)
92
+ width(motion.value ? 1 : props.value)
100
93
  )
101
94
  const modelClass = computed(
102
95
  () =>
@@ -34,7 +34,7 @@
34
34
 
35
35
  "reverse": {
36
36
  "type": "Boolean",
37
- "desc": "Reverse direction of progress",
37
+ "desc": "Reverse direction of progress (has no effect for query behaviour)",
38
38
  "category": "behavior"
39
39
  },
40
40
 
@@ -16,8 +16,13 @@
16
16
 
17
17
  &--reverse
18
18
  .q-linear-progress
19
- &__model, &__track
20
- transform-origin: 0 100%
19
+ &__model--determinate, &__track
20
+ transform-origin: 100% 0
21
+
22
+ // motion modes span the full width, so anchoring cannot reverse them: mirror them in place
23
+ &__model--indeterminate, &__model--query
24
+ transform-origin: 50% 0
25
+ scale: -1 1
21
26
 
22
27
  &__model
23
28
 
@@ -137,6 +137,7 @@ export default createComponent({
137
137
  canShow,
138
138
  handleShow,
139
139
  handleHide,
140
+ handleRouteChange,
140
141
  hideOnRouteChange,
141
142
  processOnMount: true
142
143
  })
@@ -297,13 +298,15 @@ export default createComponent({
297
298
  // menu was not closed from a mouse or touch clickOutside
298
299
  !evt.qClickOutside)
299
300
  ) {
300
- ;(
301
+ const target =
301
302
  (evt?.type.indexOf('key') === 0
302
303
  ? refocusTarget.closest('[tabindex]:not([tabindex^="-"])')
303
304
  : void 0) || refocusTarget
304
- ).focus()
305
305
 
306
306
  refocusTarget = null
307
+ addFocusFn(() => {
308
+ if (target.isConnected) target.focus()
309
+ })
307
310
  }
308
311
 
309
312
  // should removeTimeout() if this gets removed
@@ -313,6 +316,10 @@ export default createComponent({
313
316
  }, props.transitionDuration)
314
317
  }
315
318
 
319
+ function handleRouteChange() {
320
+ refocusTarget = null
321
+ }
322
+
316
323
  function anchorCleanup(hiding) {
317
324
  absoluteOffset = void 0
318
325
 
@@ -191,6 +191,7 @@ export default createComponent({
191
191
 
192
192
  const maxEvents = computed(() => getEvents('max'))
193
193
  const getMaxThumb = methods.getThumbRenderFn({
194
+ injectFormInput: false,
194
195
  focusValue: 'max',
195
196
  getNodeData: () => ({
196
197
  ...maxEvents.value,
@@ -349,7 +350,7 @@ export default createComponent({
349
350
  // If either of the values to be emitted are null, set them to the defaults the user has entered.
350
351
  model.value =
351
352
  model.value.min === null || model.value.max === null
352
- ? { min: pos.min || props.min, max: pos.max || props.max }
353
+ ? { min: pos.min ?? props.min, max: pos.max ?? props.max }
353
354
  : { min: pos.min, max: pos.max }
354
355
 
355
356
  if (!props.snap || props.step === 0) {