quasar 2.14.7 → 2.15.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 (156) hide show
  1. package/dist/api/QDialog.json +1 -1
  2. package/dist/api/QImg.json +1 -1
  3. package/dist/api/QSelect.json +1 -1
  4. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  5. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  6. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  7. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  10. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  11. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  12. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  13. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  14. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  16. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  17. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  18. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  19. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  20. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  21. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  24. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  25. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  26. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  42. package/dist/icon-set/themify.umd.prod.js +1 -1
  43. package/dist/lang/ar-TN.umd.prod.js +1 -1
  44. package/dist/lang/ar.umd.prod.js +1 -1
  45. package/dist/lang/az-Latn.umd.prod.js +1 -1
  46. package/dist/lang/bg.umd.prod.js +1 -1
  47. package/dist/lang/bn.umd.prod.js +1 -1
  48. package/dist/lang/ca.umd.prod.js +1 -1
  49. package/dist/lang/cs.umd.prod.js +1 -1
  50. package/dist/lang/da.umd.prod.js +1 -1
  51. package/dist/lang/de-CH.umd.prod.js +1 -1
  52. package/dist/lang/de-DE.umd.prod.js +1 -1
  53. package/dist/lang/de.umd.prod.js +1 -1
  54. package/dist/lang/el.umd.prod.js +1 -1
  55. package/dist/lang/en-GB.umd.prod.js +1 -1
  56. package/dist/lang/en-US.umd.prod.js +1 -1
  57. package/dist/lang/eo.umd.prod.js +1 -1
  58. package/dist/lang/es.umd.prod.js +1 -1
  59. package/dist/lang/et.umd.prod.js +1 -1
  60. package/dist/lang/eu.umd.prod.js +1 -1
  61. package/dist/lang/fa-IR.umd.prod.js +1 -1
  62. package/dist/lang/fa.umd.prod.js +1 -1
  63. package/dist/lang/fi.umd.prod.js +1 -1
  64. package/dist/lang/fr.umd.prod.js +1 -1
  65. package/dist/lang/gn.umd.prod.js +1 -1
  66. package/dist/lang/he.umd.prod.js +1 -1
  67. package/dist/lang/hi.umd.prod.js +1 -1
  68. package/dist/lang/hr.umd.prod.js +1 -1
  69. package/dist/lang/hu.umd.prod.js +1 -1
  70. package/dist/lang/id.umd.prod.js +1 -1
  71. package/dist/lang/is.umd.prod.js +1 -1
  72. package/dist/lang/it.umd.prod.js +1 -1
  73. package/dist/lang/ja.umd.prod.js +1 -1
  74. package/dist/lang/kk.umd.prod.js +1 -1
  75. package/dist/lang/km.umd.prod.js +1 -1
  76. package/dist/lang/ko-KR.umd.prod.js +1 -1
  77. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  78. package/dist/lang/lt.umd.prod.js +1 -1
  79. package/dist/lang/lu.umd.prod.js +1 -1
  80. package/dist/lang/lv.umd.prod.js +1 -1
  81. package/dist/lang/mk.umd.prod.js +1 -1
  82. package/dist/lang/ml.umd.prod.js +1 -1
  83. package/dist/lang/mm.umd.prod.js +1 -1
  84. package/dist/lang/ms-MY.umd.prod.js +1 -1
  85. package/dist/lang/ms.umd.prod.js +1 -1
  86. package/dist/lang/my.umd.prod.js +1 -1
  87. package/dist/lang/nb-NO.umd.prod.js +1 -1
  88. package/dist/lang/nl.umd.prod.js +1 -1
  89. package/dist/lang/pl.umd.prod.js +1 -1
  90. package/dist/lang/pt-BR.umd.prod.js +1 -1
  91. package/dist/lang/pt.umd.prod.js +1 -1
  92. package/dist/lang/ro.umd.prod.js +1 -1
  93. package/dist/lang/ru.umd.prod.js +1 -1
  94. package/dist/lang/sk.umd.prod.js +1 -1
  95. package/dist/lang/sl.umd.prod.js +1 -1
  96. package/dist/lang/sm.umd.prod.js +1 -1
  97. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  98. package/dist/lang/sr.umd.prod.js +1 -1
  99. package/dist/lang/sv.umd.prod.js +1 -1
  100. package/dist/lang/ta.umd.prod.js +1 -1
  101. package/dist/lang/th.umd.prod.js +1 -1
  102. package/dist/lang/tl.umd.prod.js +1 -1
  103. package/dist/lang/tr.umd.prod.js +1 -1
  104. package/dist/lang/ug.umd.prod.js +1 -1
  105. package/dist/lang/uk.umd.prod.js +1 -1
  106. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  107. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  108. package/dist/lang/vi.umd.prod.js +1 -1
  109. package/dist/lang/zh-CN.umd.prod.js +1 -1
  110. package/dist/lang/zh-TW.umd.prod.js +1 -1
  111. package/dist/quasar.cjs.prod.js +59 -59
  112. package/dist/quasar.esm.js +959 -930
  113. package/dist/quasar.esm.prod.js +53 -53
  114. package/dist/quasar.sass +1 -1
  115. package/dist/quasar.umd.js +146 -117
  116. package/dist/quasar.umd.prod.js +55 -55
  117. package/dist/transforms/import-map.json +1 -1
  118. package/dist/transforms/loader-asset-urls.json +1 -1
  119. package/dist/types/composables.d.ts +33 -0
  120. package/dist/types/index.d.ts +12 -0
  121. package/dist/vetur/quasar-attributes.json +1 -1
  122. package/dist/vetur/quasar-tags.json +1 -1
  123. package/dist/web-types/web-types.json +1 -1
  124. package/package.json +1 -1
  125. package/src/components/btn-dropdown/QBtnDropdown.js +1 -1
  126. package/src/components/color/QColor.js +19 -13
  127. package/src/components/date/QDate.js +2 -2
  128. package/src/components/dialog/QDialog.js +15 -3
  129. package/src/components/dialog/QDialog.json +19 -0
  130. package/src/components/drawer/QDrawer.js +1 -1
  131. package/src/components/editor/QEditor.js +4 -4
  132. package/src/components/expansion-item/QExpansionItem.js +1 -1
  133. package/src/components/fab/QFab.js +1 -1
  134. package/src/components/img/QImg.js +76 -56
  135. package/src/components/img/QImg.json +20 -6
  136. package/src/components/menu/QMenu.js +2 -2
  137. package/src/components/no-ssr/QNoSsr.js +3 -3
  138. package/src/components/resize-observer/QResizeObserver.js +3 -3
  139. package/src/components/select/QSelect.js +3 -0
  140. package/src/components/select/QSelect.json +7 -0
  141. package/src/components/slide-item/QSlideItem.js +3 -3
  142. package/src/components/stepper/QStep.js +3 -3
  143. package/src/components/tabs/QTabs.js +2 -2
  144. package/src/components/tooltip/QTooltip.js +2 -2
  145. package/src/composables/private/use-field.js +9 -12
  146. package/src/composables/private/use-panel.js +3 -3
  147. package/src/composables/use-hydration.js +16 -0
  148. package/src/composables/use-id.js +50 -0
  149. package/src/composables/use-render-cache.js +40 -0
  150. package/src/composables/{private/use-split-attrs.js → use-split-attrs.js} +4 -2
  151. package/src/composables/{private/use-tick.js → use-tick.js} +1 -1
  152. package/src/composables/{private/use-timeout.js → use-timeout.js} +1 -1
  153. package/src/composables.js +15 -1
  154. package/src/composables/private/use-cache.js +0 -21
  155. package/src/composables/private/use-can-render.js +0 -16
  156. package/src/composables/private/use-id.js +0 -34
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar",
3
- "version": "2.14.7",
3
+ "version": "2.15.0",
4
4
  "description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time",
5
5
  "main": "dist/quasar.cjs.prod.js",
6
6
  "module": "dist/quasar.esm.prod.js",
@@ -6,7 +6,7 @@ import QBtnGroup from '../btn-group/QBtnGroup.js'
6
6
  import QMenu from '../menu/QMenu.js'
7
7
 
8
8
  import { getBtnDesignAttr, useBtnProps } from '../btn/use-btn.js'
9
- import useId from '../../composables/private/use-id.js'
9
+ import useId from '../../composables/use-id.js'
10
10
  import { useTransitionProps } from '../../composables/private/use-transition.js'
11
11
 
12
12
  import { createComponent } from '../../utils/private/create.js'
@@ -11,7 +11,7 @@ import QTabPanels from '../tab-panels/QTabPanels.js'
11
11
  import QTabPanel from '../tab-panels/QTabPanel.js'
12
12
 
13
13
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
14
- import useCache from '../../composables/private/use-cache.js'
14
+ import useRenderCache from '../../composables/use-render-cache.js'
15
15
  import { useFormInject, useFormProps } from '../../composables/private/use-form.js'
16
16
 
17
17
  import { createComponent } from '../../utils/private/create.js'
@@ -80,7 +80,7 @@ export default createComponent({
80
80
  const { $q } = proxy
81
81
 
82
82
  const isDark = useDark(props, $q)
83
- const { getCache } = useCache()
83
+ const { getCache } = useRenderCache()
84
84
 
85
85
  const spectrumRef = ref(null)
86
86
  const errorIconRef = ref(null)
@@ -290,7 +290,7 @@ export default createComponent({
290
290
  updateModel(rgb, change)
291
291
  }
292
292
 
293
- function onHueChange (val, change) {
293
+ function onHue (val, change) {
294
294
  const h = Math.round(val)
295
295
  const rgb = hsvToRgb({
296
296
  h,
@@ -303,6 +303,10 @@ export default createComponent({
303
303
  updateModel(rgb, change)
304
304
  }
305
305
 
306
+ function onHueChange (val) {
307
+ onHueChange(val, true)
308
+ }
309
+
306
310
  function onNumericChange (value, formatModel, max, evt, change) {
307
311
  evt !== void 0 && stop(evt)
308
312
 
@@ -494,6 +498,10 @@ export default createComponent({
494
498
  }
495
499
  }
496
500
 
501
+ function setTopView (val) {
502
+ topView.value = val
503
+ }
504
+
497
505
  function getHeader () {
498
506
  const child = []
499
507
 
@@ -503,9 +511,7 @@ export default createComponent({
503
511
  modelValue: topView.value,
504
512
  dense: true,
505
513
  align: 'justify',
506
- ...getCache('topVTab', {
507
- 'onUpdate:modelValue': val => { topView.value = val }
508
- })
514
+ 'onUpdate:modelValue': setTopView
509
515
  }, () => [
510
516
  h(QTab, {
511
517
  label: 'HEX' + (hasAlpha.value === true ? 'A' : ''),
@@ -586,6 +592,10 @@ export default createComponent({
586
592
  ])
587
593
  }
588
594
 
595
+ function setView (val) {
596
+ view.value = val
597
+ }
598
+
589
599
  function getFooter () {
590
600
  return h('div', {
591
601
  class: 'q-color-picker__footer relative-position overflow-hidden'
@@ -595,9 +605,7 @@ export default createComponent({
595
605
  modelValue: view.value,
596
606
  dense: true,
597
607
  align: 'justify',
598
- ...getCache('ftIn', {
599
- 'onUpdate:modelValue': val => { view.value = val }
600
- })
608
+ 'onUpdate:modelValue': setView
601
609
  }, () => [
602
610
  h(QTab, {
603
611
  icon: $q.iconSet.colorPicker.spectrum,
@@ -660,10 +668,8 @@ export default createComponent({
660
668
  selectionColor: 'transparent',
661
669
  readonly: editable.value !== true,
662
670
  thumbPath,
663
- 'onUpdate:modelValue': onHueChange,
664
- ...getCache('lazyhue', {
665
- onChange: val => onHueChange(val, true)
666
- })
671
+ 'onUpdate:modelValue': onHue,
672
+ onChange: onHueChange
667
673
  })
668
674
  ]
669
675
 
@@ -3,7 +3,7 @@ import { h, ref, computed, watch, Transition, nextTick, getCurrentInstance } fro
3
3
  import QBtn from '../btn/QBtn.js'
4
4
 
5
5
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
6
- import useCache from '../../composables/private/use-cache.js'
6
+ import useRenderCache from '../../composables/use-render-cache.js'
7
7
  import { useFormProps, useFormAttrs, useFormInject } from '../../composables/private/use-form.js'
8
8
  import useDatetime, { useDatetimeProps, useDatetimeEmits, getDayHash } from './use-datetime.js'
9
9
 
@@ -90,7 +90,7 @@ export default createComponent({
90
90
  const { $q } = proxy
91
91
 
92
92
  const isDark = useDark(props, $q)
93
- const { getCache } = useCache()
93
+ const { getCache } = useRenderCache()
94
94
  const { tabindex, headerClass, getLocale, getCurrentDate } = useDatetime(props, $q)
95
95
 
96
96
  let lastEmitValue
@@ -1,8 +1,8 @@
1
1
  import { h, ref, computed, watch, onBeforeUnmount, Transition, getCurrentInstance } from 'vue'
2
2
 
3
3
  import useHistory from '../../composables/private/use-history.js'
4
- import useTimeout from '../../composables/private/use-timeout.js'
5
- import useTick from '../../composables/private/use-tick.js'
4
+ import useTimeout from '../../composables/use-timeout.js'
5
+ import useTick from '../../composables/use-tick.js'
6
6
  import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'
7
7
  import useTransition, { useTransitionProps } from '../../composables/private/use-transition.js'
8
8
  import usePortal from '../../composables/private/use-portal.js'
@@ -64,6 +64,8 @@ export default createComponent({
64
64
 
65
65
  square: Boolean,
66
66
 
67
+ backdropFilter: String,
68
+
67
69
  position: {
68
70
  type: String,
69
71
  default: 'standard',
@@ -102,6 +104,16 @@ export default createComponent({
102
104
  () => defaultTransitions[ props.position ][ 1 ]
103
105
  )
104
106
 
107
+ const backdropStyle = computed(() => (
108
+ transitionStyle.value
109
+ + (
110
+ props.backdropFilter !== void 0
111
+ // Safari requires the -webkit prefix
112
+ ? `;backdrop-filter:${ props.backdropFilter };-webkit-backdrop-filter:${ props.backdropFilter }`
113
+ : ''
114
+ )
115
+ ))
116
+
105
117
  const { showPortal, hidePortal, portalIsAccessible, renderPortal } = usePortal(
106
118
  vm, innerRef, renderPortalContent, 'dialog'
107
119
  )
@@ -384,7 +396,7 @@ export default createComponent({
384
396
  useBackdrop.value === true
385
397
  ? h('div', {
386
398
  class: 'q-dialog__backdrop fixed-full',
387
- style: transitionStyle.value,
399
+ style: backdropStyle.value,
388
400
  'aria-hidden': 'true',
389
401
  tabindex: -1,
390
402
  onClick: onBackdropClick
@@ -42,6 +42,25 @@
42
42
  "category": "content"
43
43
  },
44
44
 
45
+ "backdrop-filter": {
46
+ "type": "String",
47
+ "desc": "Apply a backdrop filter; The value needs to be the same as in the CSS specs for backdrop-filter; The examples are not an exhaustive list",
48
+ "examples": [
49
+ "blur(4px)",
50
+ "blur(4px) saturate(150%)",
51
+ "brightness(60%)",
52
+ "invert(70%)",
53
+ "grayscale(100%)",
54
+ "contrast(40%)",
55
+ "hue-rotate(120deg)",
56
+ "sepia(90%)",
57
+ "saturate(80%)",
58
+ "none"
59
+ ],
60
+ "category": "style",
61
+ "addedIn": "v2.15"
62
+ },
63
+
45
64
  "maximized": {
46
65
  "type": "Boolean",
47
66
  "desc": "Put Dialog into maximized mode",
@@ -3,7 +3,7 @@ import { h, withDirectives, ref, computed, watch, onMounted, onBeforeUnmount, ne
3
3
  import useHistory from '../../composables/private/use-history.js'
4
4
  import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'
5
5
  import usePreventScroll from '../../composables/private/use-prevent-scroll.js'
6
- import useTimeout from '../../composables/private/use-timeout.js'
6
+ import useTimeout from '../../composables/use-timeout.js'
7
7
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
8
8
 
9
9
  import TouchPan from '../../directives/TouchPan.js'
@@ -5,7 +5,7 @@ import { getToolbar, getFonts, getLinkEditor } from './editor-utils.js'
5
5
 
6
6
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
7
7
  import useFullscreen, { useFullscreenProps, useFullscreenEmits } from '../../composables/private/use-fullscreen.js'
8
- import useSplitAttrs from '../../composables/private/use-split-attrs.js'
8
+ import useSplitAttrs from '../../composables/use-split-attrs.js'
9
9
 
10
10
  import { createComponent } from '../../utils/private/create.js'
11
11
  import { stopAndPrevent } from '../../utils/event.js'
@@ -85,13 +85,13 @@ export default createComponent({
85
85
  'linkHide'
86
86
  ],
87
87
 
88
- setup (props, { slots, emit, attrs }) {
89
- const { proxy, vnode } = getCurrentInstance()
88
+ setup (props, { slots, emit }) {
89
+ const { proxy } = getCurrentInstance()
90
90
  const { $q } = proxy
91
91
 
92
92
  const isDark = useDark(props, $q)
93
93
  const { inFullscreen, toggleFullscreen } = useFullscreen()
94
- const splitAttrs = useSplitAttrs(attrs, vnode)
94
+ const splitAttrs = useSplitAttrs()
95
95
 
96
96
  const rootRef = ref(null)
97
97
  const contentRef = ref(null)
@@ -8,7 +8,7 @@ import QSlideTransition from '../slide-transition/QSlideTransition.js'
8
8
  import QSeparator from '../separator/QSeparator.js'
9
9
 
10
10
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
11
- import useId from '../../composables/private/use-id.js'
11
+ import useId from '../../composables/use-id.js'
12
12
  import { useRouterLinkProps } from '../../composables/private/use-router-link.js'
13
13
  import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'
14
14
 
@@ -4,7 +4,7 @@ import QBtn from '../btn/QBtn.js'
4
4
  import QIcon from '../icon/QIcon.js'
5
5
 
6
6
  import useFab, { useFabProps } from './use-fab.js'
7
- import useId from '../../composables/private/use-id.js'
7
+ import useId from '../../composables/use-id.js'
8
8
  import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'
9
9
 
10
10
  import { createComponent } from '../../utils/private/create.js'
@@ -2,14 +2,15 @@ import { h, ref, computed, watch, onMounted, Transition, getCurrentInstance } fr
2
2
 
3
3
  import QSpinner from '../spinner/QSpinner.js'
4
4
 
5
+ import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js'
5
6
  import useRatio, { useRatioProps } from '../../composables/private/use-ratio.js'
6
7
 
7
8
  import { createComponent } from '../../utils/private/create.js'
8
9
  import { hSlot } from '../../utils/private/render.js'
9
10
  import { vmIsDestroyed } from '../../utils/private/vm.js'
10
- import useTimeout from '../../composables/private/use-timeout.js'
11
+ import useTimeout from '../../composables/use-timeout.js'
11
12
 
12
- const defaultRatio = 16 / 9
13
+ const defaultRatio = 1.7778 /* 16/9 */
13
14
 
14
15
  export default createComponent({
15
16
  name: 'QImg',
@@ -49,6 +50,7 @@ export default createComponent({
49
50
  },
50
51
 
51
52
  placeholderSrc: String,
53
+ errorSrc: String,
52
54
 
53
55
  fit: {
54
56
  type: String,
@@ -80,9 +82,21 @@ export default createComponent({
80
82
  const { registerTimeout: registerLoadTimeout, removeTimeout: removeLoadTimeout } = useTimeout()
81
83
  const { registerTimeout: registerLoadShowTimeout, removeTimeout: removeLoadShowTimeout } = useTimeout()
82
84
 
85
+ const placeholderImg = computed(() => (
86
+ props.placeholderSrc !== void 0
87
+ ? { src: props.placeholderSrc }
88
+ : null
89
+ ))
90
+
91
+ const errorImg = computed(() => (
92
+ props.errorSrc !== void 0
93
+ ? { src: props.errorSrc, __qerror: true }
94
+ : null
95
+ ))
96
+
83
97
  const images = [
84
98
  ref(null),
85
- ref(getPlaceholderSrc())
99
+ ref(placeholderImg.value)
86
100
  ]
87
101
 
88
102
  const position = ref(0)
@@ -102,6 +116,7 @@ export default createComponent({
102
116
  const imgClass = computed(() =>
103
117
  `q-img__image ${ props.imgClass !== void 0 ? props.imgClass + ' ' : '' }`
104
118
  + `q-img__image--with${ props.noTransition === true ? 'out' : '' }-transition`
119
+ + ' q-img__image--'
105
120
  )
106
121
 
107
122
  const imgStyle = computed(() => ({
@@ -110,8 +125,6 @@ export default createComponent({
110
125
  objectPosition: props.position
111
126
  }))
112
127
 
113
- watch(() => getCurrentSrc(), addImage)
114
-
115
128
  function setLoading () {
116
129
  removeLoadShowTimeout()
117
130
 
@@ -130,37 +143,6 @@ export default createComponent({
130
143
  isLoading.value = false
131
144
  }
132
145
 
133
- function getCurrentSrc () {
134
- return props.src || props.srcset || props.sizes
135
- ? {
136
- src: props.src,
137
- srcset: props.srcset,
138
- sizes: props.sizes
139
- }
140
- : null
141
- }
142
-
143
- function getPlaceholderSrc () {
144
- return props.placeholderSrc !== void 0
145
- ? { src: props.placeholderSrc }
146
- : null
147
- }
148
-
149
- function addImage (imgProps) {
150
- removeLoadTimeout()
151
- hasError.value = false
152
-
153
- if (imgProps === null) {
154
- clearLoading()
155
- images[ position.value ^ 1 ].value = getPlaceholderSrc()
156
- }
157
- else {
158
- setLoading()
159
- }
160
-
161
- images[ position.value ].value = imgProps
162
- }
163
-
164
146
  function onLoad ({ target }) {
165
147
  if (vmIsDestroyed(vm) === false) {
166
148
  removeLoadTimeout()
@@ -187,14 +169,19 @@ export default createComponent({
187
169
  }
188
170
  }
189
171
 
190
- function onReady (img) {
172
+ function onReady (target) {
191
173
  if (vmIsDestroyed(vm) === true) return
192
174
 
193
175
  position.value = position.value ^ 1
194
176
  images[ position.value ].value = null
177
+
195
178
  clearLoading()
196
- hasError.value = false
197
- emit('load', img.currentSrc || img.src)
179
+
180
+ if (target.getAttribute('__qerror') !== 'true') {
181
+ hasError.value = false
182
+ }
183
+
184
+ emit('load', target.currentSrc || target.src)
198
185
  }
199
186
 
200
187
  function onError (err) {
@@ -202,8 +189,8 @@ export default createComponent({
202
189
  clearLoading()
203
190
 
204
191
  hasError.value = true
205
- images[ position.value ].value = null
206
- images[ position.value ^ 1 ].value = getPlaceholderSrc()
192
+ images[ position.value ].value = errorImg.value
193
+ images[ position.value ^ 1 ].value = placeholderImg.value
207
194
 
208
195
  emit('error', err)
209
196
  }
@@ -229,11 +216,14 @@ export default createComponent({
229
216
  }
230
217
 
231
218
  if (position.value === index) {
232
- data.class += ' q-img__image--waiting'
233
- Object.assign(data, { onLoad, onError })
219
+ Object.assign(data, {
220
+ class: data.class + 'current',
221
+ onLoad,
222
+ onError
223
+ })
234
224
  }
235
225
  else {
236
- data.class += ' q-img__image--loaded'
226
+ data.class += 'loaded'
237
227
  }
238
228
 
239
229
  return h(
@@ -271,13 +261,40 @@ export default createComponent({
271
261
  }
272
262
 
273
263
  if (__QUASAR_SSR_SERVER__ !== true) {
274
- if (__QUASAR_SSR_CLIENT__) {
275
- onMounted(() => {
276
- addImage(getCurrentSrc())
277
- })
264
+ function watchSrc () {
265
+ watch(
266
+ () => (
267
+ props.src || props.srcset || props.sizes
268
+ ? {
269
+ src: props.src,
270
+ srcset: props.srcset,
271
+ sizes: props.sizes
272
+ }
273
+ : null
274
+ ),
275
+ imgProps => {
276
+ removeLoadTimeout()
277
+ hasError.value = false
278
+
279
+ if (imgProps === null) {
280
+ clearLoading()
281
+ images[ position.value ^ 1 ].value = placeholderImg.value
282
+ }
283
+ else {
284
+ setLoading()
285
+ }
286
+
287
+ images[ position.value ].value = imgProps
288
+ },
289
+ { immediate: true }
290
+ )
291
+ }
292
+
293
+ if (isRuntimeSsrPreHydration.value === true) {
294
+ onMounted(watchSrc)
278
295
  }
279
296
  else {
280
- addImage(getCurrentSrc())
297
+ watchSrc()
281
298
  }
282
299
  }
283
300
 
@@ -290,14 +307,16 @@ export default createComponent({
290
307
  )
291
308
  }
292
309
 
293
- if (hasError.value !== true) {
294
- if (images[ 0 ].value !== null) {
295
- content.push(getImage(0))
296
- }
310
+ if (images[ 0 ].value !== null) {
311
+ content.push(
312
+ getImage(0)
313
+ )
314
+ }
297
315
 
298
- if (images[ 1 ].value !== null) {
299
- content.push(getImage(1))
300
- }
316
+ if (images[ 1 ].value !== null) {
317
+ content.push(
318
+ getImage(1)
319
+ )
301
320
  }
302
321
 
303
322
  content.push(
@@ -305,6 +324,7 @@ export default createComponent({
305
324
  )
306
325
 
307
326
  return h('div', {
327
+ key: 'main',
308
328
  class: classes.value,
309
329
  style: style.value,
310
330
  role: 'img',
@@ -44,14 +44,28 @@
44
44
  "desc": "While waiting for your image to load, you can use a placeholder image",
45
45
  "transformAssetUrls": true,
46
46
  "examples": [
47
- "(public folder) src=\"img/some-placeholder.png\"",
48
- "(assets folder) src=\"~assets/my-placeholder.gif\"",
49
- "(relative path format) :src=\"require('./placeholder.jpg')\"",
50
- "(URL) src=\"https://picsum.photos/500/300\""
47
+ "(public folder) placeholder-src=\"img/some-placeholder.png\"",
48
+ "(assets folder) placeholder-src=\"~assets/my-placeholder.gif\"",
49
+ "(relative path format) :placeholder-src=\"require('./placeholder.jpg')\"",
50
+ "(URL) placeholder-src=\"https://picsum.photos/500/300\""
51
51
  ],
52
52
  "category": "model"
53
53
  },
54
54
 
55
+ "error-src": {
56
+ "type": "String",
57
+ "desc": "In case your image fails to load, you can use an error image",
58
+ "transformAssetUrls": true,
59
+ "examples": [
60
+ "(public folder) error-src=\"img/some-placeholder.png\"",
61
+ "(assets folder) error-src=\"~assets/my-placeholder.gif\"",
62
+ "(relative path format) :error-src=\"require('./placeholder.jpg')\"",
63
+ "(URL) error-src=\"https://picsum.photos/500/300\""
64
+ ],
65
+ "category": "model",
66
+ "addedIn": "v2.15"
67
+ },
68
+
55
69
  "ratio": {
56
70
  "desc": "Force the component to maintain an aspect ratio",
57
71
  "examples": [
@@ -167,13 +181,13 @@
167
181
  "type": "String",
168
182
  "desc": "Specifies an alternate text for the image, if the image cannot be displayed",
169
183
  "examples": [ "Two cats" ],
170
- "category": "content"
184
+ "category": "miscellaneous"
171
185
  },
172
186
 
173
187
  "draggable": {
174
188
  "type": "Boolean",
175
189
  "desc": "Adds the native 'draggable' attribute",
176
- "category": "behavior"
190
+ "category": "miscellaneous"
177
191
  },
178
192
 
179
193
  "img-class": {
@@ -6,8 +6,8 @@ import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../
6
6
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
7
7
  import usePortal from '../../composables/private/use-portal.js'
8
8
  import useTransition, { useTransitionProps } from '../../composables/private/use-transition.js'
9
- import useTick from '../../composables/private/use-tick.js'
10
- import useTimeout from '../../composables/private/use-timeout.js'
9
+ import useTick from '../../composables/use-tick.js'
10
+ import useTimeout from '../../composables/use-timeout.js'
11
11
 
12
12
  import { createComponent } from '../../utils/private/create.js'
13
13
  import { closePortalMenus } from '../../utils/private/portal.js'
@@ -1,6 +1,6 @@
1
1
  import { h } from 'vue'
2
2
 
3
- import useCanRender from '../../composables/private/use-can-render.js'
3
+ import useHydration from '../../composables/use-hydration.js'
4
4
 
5
5
  import { createComponent } from '../../utils/private/create.js'
6
6
  import { hSlot } from '../../utils/private/render.js'
@@ -18,10 +18,10 @@ export default createComponent({
18
18
  },
19
19
 
20
20
  setup (props, { slots }) {
21
- const canRender = useCanRender()
21
+ const { isHydrated } = useHydration()
22
22
 
23
23
  return () => {
24
- if (canRender.value === true) {
24
+ if (isHydrated.value === true) {
25
25
  const node = hSlot(slots.default)
26
26
  return node === void 0
27
27
  ? node
@@ -1,6 +1,6 @@
1
1
  import { h, onMounted, onBeforeUnmount, getCurrentInstance, nextTick } from 'vue'
2
2
 
3
- import useCanRender from '../../composables/private/use-can-render.js'
3
+ import useHydration from '../../composables/use-hydration.js'
4
4
 
5
5
  import { createComponent } from '../../utils/private/create.js'
6
6
  import { listenOpts, noop } from '../../utils/event.js'
@@ -95,7 +95,7 @@ export default createComponent({
95
95
  return noop
96
96
  }
97
97
  else { // no observer, so fallback to old iframe method
98
- const canRender = useCanRender()
98
+ const { isHydrated } = useHydration()
99
99
 
100
100
  let curDocView
101
101
 
@@ -134,7 +134,7 @@ export default createComponent({
134
134
  onBeforeUnmount(cleanup)
135
135
 
136
136
  return () => {
137
- if (canRender.value === true) {
137
+ if (isHydrated.value === true) {
138
138
  return h('object', {
139
139
  class: 'q--avoid-card-border',
140
140
  style: resizeProps.style,
@@ -79,6 +79,7 @@ export default createComponent({
79
79
 
80
80
  popupContentClass: String,
81
81
  popupContentStyle: [ String, Array, Object ],
82
+ popupNoRouteDismiss: Boolean,
82
83
 
83
84
  useInput: Boolean,
84
85
  useChips: Boolean,
@@ -1186,6 +1187,7 @@ export default createComponent({
1186
1187
  noParentEvent: true,
1187
1188
  noRefocus: true,
1188
1189
  noFocus: true,
1190
+ noRouteDismiss: props.popupNoRouteDismiss,
1189
1191
  square: squaredMenu.value,
1190
1192
  transitionShow: props.transitionShow,
1191
1193
  transitionHide: props.transitionHide,
@@ -1263,6 +1265,7 @@ export default createComponent({
1263
1265
  transitionShow: transitionShowComputed,
1264
1266
  transitionHide: props.transitionHide,
1265
1267
  transitionDuration: props.transitionDuration,
1268
+ noRouteDismiss: props.popupNoRouteDismiss,
1266
1269
  onBeforeShow: onControlPopupShow,
1267
1270
  onBeforeHide: onDialogBeforeHide,
1268
1271
  onHide: onDialogHide,
@@ -232,6 +232,13 @@
232
232
  "category": "style"
233
233
  },
234
234
 
235
+ "popup-no-route-dismiss": {
236
+ "type": "Boolean",
237
+ "desc": "Changing route app won't dismiss the popup (menu or dialog)",
238
+ "category": "behavior",
239
+ "addedIn": "v2.15"
240
+ },
241
+
235
242
  "use-input": {
236
243
  "type": "Boolean",
237
244
  "desc": "Use an input tag where users can type",
@@ -3,7 +3,7 @@ import { h, ref, computed, withDirectives, onBeforeUnmount, onBeforeUpdate, getC
3
3
  import TouchPan from '../../directives/TouchPan.js'
4
4
 
5
5
  import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
6
- import useCache from '../../composables/private/use-cache.js'
6
+ import useRenderCache from '../../composables/use-render-cache.js'
7
7
 
8
8
  import { createComponent } from '../../utils/private/create.js'
9
9
  import { hSlot } from '../../utils/private/render.js'
@@ -36,7 +36,7 @@ export default createComponent({
36
36
  const { $q } = proxy
37
37
 
38
38
  const isDark = useDark(props, $q)
39
- const { getCacheWithFn } = useCache()
39
+ const { getCache } = useRenderCache()
40
40
 
41
41
  const contentRef = ref(null)
42
42
 
@@ -209,7 +209,7 @@ export default createComponent({
209
209
  }
210
210
  else {
211
211
  content.push(
212
- withDirectives(node, getCacheWithFn('dir#' + dirs.join(''), () => {
212
+ withDirectives(node, getCache('dir#' + dirs.join(''), () => {
213
213
  const modifiers = {
214
214
  prevent: true,
215
215
  stop: true,