quasar 2.2.3 → 2.3.2

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 (169) hide show
  1. package/dist/api/BottomSheet.json +17 -2
  2. package/dist/api/Dialog.json +17 -2
  3. package/dist/api/LocalStorage.json +8 -0
  4. package/dist/api/QCircularProgress.json +14 -0
  5. package/dist/api/QDate.json +46 -0
  6. package/dist/api/QEditor.json +7 -2
  7. package/dist/api/QFooter.json +1 -1
  8. package/dist/api/QHeader.json +1 -1
  9. package/dist/api/QIntersection.json +14 -0
  10. package/dist/api/QLinearProgress.json +14 -0
  11. package/dist/api/QRouteTab.json +1 -24
  12. package/dist/api/QScrollArea.json +3 -0
  13. package/dist/api/QSelect.json +62 -0
  14. package/dist/api/QSkeleton.json +1 -1
  15. package/dist/api/QTable.json +62 -5
  16. package/dist/api/QTree.json +6 -0
  17. package/dist/api/QUploader.json +81 -1
  18. package/dist/api/SessionStorage.json +8 -0
  19. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  20. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  21. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  22. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  23. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  24. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  25. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  26. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  27. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  28. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  29. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  30. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  31. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  32. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +6 -0
  39. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  44. package/dist/icon-set/svg-mdi-v4.umd.prod.js +1 -1
  45. package/dist/icon-set/svg-mdi-v5.umd.prod.js +1 -1
  46. package/dist/icon-set/svg-mdi-v6.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.umd.prod.js +1 -1
  50. package/dist/lang/az-Latn.umd.prod.js +1 -1
  51. package/dist/lang/bg.umd.prod.js +1 -1
  52. package/dist/lang/bn.umd.prod.js +1 -1
  53. package/dist/lang/ca.umd.prod.js +1 -1
  54. package/dist/lang/cs.umd.prod.js +1 -1
  55. package/dist/lang/da.umd.prod.js +1 -1
  56. package/dist/lang/de.umd.prod.js +1 -1
  57. package/dist/lang/el.umd.prod.js +1 -1
  58. package/dist/lang/en-GB.umd.prod.js +1 -1
  59. package/dist/lang/en-US.umd.prod.js +1 -1
  60. package/dist/lang/eo.umd.prod.js +1 -1
  61. package/dist/lang/es.umd.prod.js +1 -1
  62. package/dist/lang/et.umd.prod.js +1 -1
  63. package/dist/lang/fa-IR.umd.prod.js +1 -1
  64. package/dist/lang/fa.umd.prod.js +1 -1
  65. package/dist/lang/fi.umd.prod.js +1 -1
  66. package/dist/lang/fr.umd.prod.js +1 -1
  67. package/dist/lang/gn.umd.prod.js +1 -1
  68. package/dist/lang/he.umd.prod.js +1 -1
  69. package/dist/lang/hr.umd.prod.js +1 -1
  70. package/dist/lang/hu.umd.prod.js +1 -1
  71. package/dist/lang/id.umd.prod.js +1 -1
  72. package/dist/lang/is.umd.prod.js +1 -1
  73. package/dist/lang/it.umd.prod.js +1 -1
  74. package/dist/lang/ja.umd.prod.js +1 -1
  75. package/dist/lang/km.umd.prod.js +1 -1
  76. package/dist/lang/ko-KR.umd.prod.js +1 -1
  77. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  78. package/dist/lang/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/ml.umd.prod.js +1 -1
  82. package/dist/lang/ms.umd.prod.js +1 -1
  83. package/dist/lang/nb-NO.umd.prod.js +1 -1
  84. package/dist/lang/nl.umd.prod.js +1 -1
  85. package/dist/lang/pl.umd.prod.js +1 -1
  86. package/dist/lang/pt-BR.umd.prod.js +1 -1
  87. package/dist/lang/pt.umd.prod.js +1 -1
  88. package/dist/lang/ro.umd.prod.js +1 -1
  89. package/dist/lang/ru.umd.prod.js +1 -1
  90. package/dist/lang/sk.umd.prod.js +1 -1
  91. package/dist/lang/sl.umd.prod.js +1 -1
  92. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  93. package/dist/lang/sr.umd.prod.js +1 -1
  94. package/dist/lang/sv.umd.prod.js +1 -1
  95. package/dist/lang/ta.umd.prod.js +1 -1
  96. package/dist/lang/th.umd.prod.js +1 -1
  97. package/dist/lang/tr.umd.prod.js +1 -1
  98. package/dist/lang/ug.umd.prod.js +1 -1
  99. package/dist/lang/uk.umd.prod.js +1 -1
  100. package/dist/lang/vi.umd.prod.js +1 -1
  101. package/dist/lang/zh-CN.umd.prod.js +1 -1
  102. package/dist/lang/zh-TW.umd.prod.js +1 -1
  103. package/dist/quasar.cjs.prod.js +2 -2
  104. package/dist/quasar.css +57 -3
  105. package/dist/quasar.esm.prod.js +2 -2
  106. package/dist/quasar.prod.css +1 -1
  107. package/dist/quasar.rtl.css +124 -3
  108. package/dist/quasar.rtl.prod.css +1 -1
  109. package/dist/quasar.sass +47 -5
  110. package/dist/quasar.umd.js +206 -125
  111. package/dist/quasar.umd.prod.js +2 -2
  112. package/dist/ssr-directives/Morph.js +1 -1
  113. package/dist/types/composables.d.ts +5 -1
  114. package/dist/types/extras/icon-set.d.ts +1 -0
  115. package/dist/types/index.d.ts +374 -141
  116. package/dist/vetur/quasar-attributes.json +18 -2
  117. package/dist/vetur/quasar-tags.json +6 -2
  118. package/dist/web-types/web-types.json +44 -3
  119. package/icon-set/svg-ionicons-v6.js +225 -0
  120. package/package.json +5 -2
  121. package/src/api.extends.json +7 -0
  122. package/src/body.js +14 -4
  123. package/src/components/circular-progress/QCircularProgress.js +6 -1
  124. package/src/components/circular-progress/QCircularProgress.json +6 -0
  125. package/src/components/date/QDate.json +34 -0
  126. package/src/components/editor/QEditor.js +2 -2
  127. package/src/components/editor/QEditor.json +6 -2
  128. package/src/components/footer/QFooter.json +1 -1
  129. package/src/components/header/QHeader.json +1 -1
  130. package/src/components/icon/QIcon.js +1 -1
  131. package/src/components/infinite-scroll/QInfiniteScroll.js +48 -31
  132. package/src/components/intersection/QIntersection.js +9 -1
  133. package/src/components/intersection/QIntersection.json +9 -0
  134. package/src/components/linear-progress/QLinearProgress.js +10 -1
  135. package/src/components/linear-progress/QLinearProgress.json +6 -0
  136. package/src/components/linear-progress/QLinearProgress.sass +2 -1
  137. package/src/components/popup-proxy/QPopupProxy.js +6 -15
  138. package/src/components/scroll-area/QScrollArea.js +1 -1
  139. package/src/components/scroll-area/QScrollArea.json +4 -1
  140. package/src/components/select/QSelect.js +15 -21
  141. package/src/components/select/QSelect.json +47 -0
  142. package/src/components/skeleton/QSkeleton.json +1 -4
  143. package/src/components/slider/use-slider.js +3 -3
  144. package/src/components/table/QTable.json +51 -5
  145. package/src/components/table/table-pagination.js +2 -2
  146. package/src/components/tabs/QRouteTab.json +1 -23
  147. package/src/components/tabs/QTabs.js +1 -1
  148. package/src/components/time/QTime.js +6 -5
  149. package/src/components/tree/QTree.js +9 -5
  150. package/src/components/tree/QTree.json +5 -0
  151. package/src/components/tree/QTree.sass +52 -4
  152. package/src/components/uploader/uploader-core.js +2 -7
  153. package/src/components/uploader/xhr-uploader-plugin.json +97 -1
  154. package/src/components/virtual-scroll/use-virtual-scroll.js +17 -1
  155. package/src/composables/private/use-field.js +4 -4
  156. package/src/composables/private/use-file.js +8 -0
  157. package/src/composables/private/use-model-toggle.js +1 -1
  158. package/src/composables/private/use-refocus-target.js +12 -3
  159. package/src/composables/private/use-split-attrs.js +7 -1
  160. package/src/composables/use-dialog-plugin-component.js +7 -1
  161. package/src/css/core/transitions.sass +3 -1
  162. package/src/install-quasar.js +1 -0
  163. package/src/utils/create-uploader-component.js +6 -4
  164. package/src/utils/date.js +1 -1
  165. package/src/utils/private/get-emits-object.js +11 -0
  166. package/src/utils/private/global-dialog.json +10 -2
  167. package/src/utils/private/vm.js +3 -3
  168. package/src/utils/private/web-storage.json +10 -0
  169. package/wrappers/index.js +4 -0
@@ -24,29 +24,7 @@
24
24
  "navigateFn": {
25
25
  "type": "Function",
26
26
  "desc": "When you need to control the time at which the tab should trigger the route navigation then set 'evt.navigate' to false and call this function; Useful if you have async work to be done before the actual route navigation",
27
- "params": {
28
- "to": {
29
- "type": [ "String", "Object" ],
30
- "desc": "Equivalent to Vue Router <router-link> 'to' property",
31
- "examples": [
32
- "/home/dashboard",
33
- "{ name: 'my-route-name' }"
34
- ],
35
- "default": "Tab's 'to' property"
36
- },
37
-
38
- "append": {
39
- "type": "Boolean",
40
- "desc": "Equivalent to Vue Router <router-link> 'append' property",
41
- "default": "Tab's 'append' property"
42
- },
43
-
44
- "replace": {
45
- "type": "Boolean",
46
- "desc": "Equivalent to Vue Router <router-link> 'replace' property",
47
- "default": "Tab's 'replace' property"
48
- }
49
- },
27
+ "params": null,
50
28
  "returns": null
51
29
  }
52
30
  }
@@ -63,7 +63,7 @@ export default createComponent({
63
63
 
64
64
  contentClass: String,
65
65
 
66
- 'onUpdate:modelValue': Function
66
+ 'onUpdate:modelValue': [ Function, Array ]
67
67
  },
68
68
 
69
69
  setup (props, { slots, emit }) {
@@ -659,21 +659,22 @@ export default createComponent({
659
659
  function setHour (hour) {
660
660
  if (innerModel.value.hour !== hour) {
661
661
  innerModel.value.hour = hour
662
- innerModel.value.minute = null
663
- innerModel.value.second = null
662
+ verifyAndUpdate()
664
663
  }
665
664
  }
666
665
 
667
666
  function setMinute (minute) {
668
667
  if (innerModel.value.minute !== minute) {
669
668
  innerModel.value.minute = minute
670
- innerModel.value.second = null
671
- props.withSeconds !== true && updateValue({ minute })
669
+ verifyAndUpdate()
672
670
  }
673
671
  }
674
672
 
675
673
  function setSecond (second) {
676
- innerModel.value.second !== second && updateValue({ second })
674
+ if (innerModel.value.second !== second) {
675
+ innerModel.value.second = second
676
+ verifyAndUpdate()
677
+ }
677
678
  }
678
679
 
679
680
  const setModel = {
@@ -14,6 +14,8 @@ 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
16
 
17
+ const tickStrategyOptions = [ 'none', 'strict', 'leaf', 'leaf-filtered' ]
18
+
17
19
  export default createComponent({
18
20
  name: 'QTree',
19
21
 
@@ -37,6 +39,8 @@ export default createComponent({
37
39
  default: 'children'
38
40
  },
39
41
 
42
+ dense: Boolean,
43
+
40
44
  color: String,
41
45
  controlColor: String,
42
46
  textColor: String,
@@ -47,7 +51,7 @@ export default createComponent({
47
51
  tickStrategy: {
48
52
  type: String,
49
53
  default: 'none',
50
- validator: v => [ 'none', 'strict', 'leaf', 'leaf-filtered' ].includes(v)
54
+ validator: v => tickStrategyOptions.includes(v)
51
55
  },
52
56
  ticked: Array, // v-model:ticked
53
57
  expanded: Array, // v-model:expanded
@@ -92,7 +96,7 @@ export default createComponent({
92
96
  })
93
97
 
94
98
  const classes = computed(() =>
95
- 'q-tree'
99
+ `q-tree q-tree--${ props.dense === true ? 'dense' : 'standard' }`
96
100
  + (props.noConnectors === true ? ' q-tree--no-connectors' : '')
97
101
  + (isDark.value === true ? ' q-tree--dark' : '')
98
102
  + (props.color !== void 0 ? ` text-${ props.color }` : '')
@@ -534,13 +538,13 @@ export default createComponent({
534
538
 
535
539
  m.lazy === 'loading'
536
540
  ? h(QSpinner, {
537
- class: 'q-tree__spinner q-mr-xs',
541
+ class: 'q-tree__spinner',
538
542
  color: computedControlColor.value
539
543
  })
540
544
  : (
541
545
  isParent === true
542
546
  ? h(QIcon, {
543
- class: 'q-tree__arrow q-mr-xs'
547
+ class: 'q-tree__arrow'
544
548
  + (m.expanded === true ? ' q-tree__arrow--rotate' : ''),
545
549
  name: computedIcon.value,
546
550
  onClick (e) { onExpandClick(node, m, e) }
@@ -550,7 +554,7 @@ export default createComponent({
550
554
 
551
555
  m.hasTicking === true && m.noTick !== true
552
556
  ? h(QCheckbox, {
553
- class: 'q-mr-xs',
557
+ class: 'q-tree__tickbox',
554
558
  modelValue: m.indeterminate === true ? null : m.ticked,
555
559
  color: computedControlColor.value,
556
560
  dark: isDark.value,
@@ -61,6 +61,11 @@
61
61
  "desc": "Color name for selected nodes (from the Quasar Color Palette)"
62
62
  },
63
63
 
64
+ "dense": {
65
+ "extends": "dense",
66
+ "addedIn": "v2.2.4"
67
+ },
68
+
64
69
  "dark": {
65
70
  "extends": "dark"
66
71
  },
@@ -39,7 +39,7 @@
39
39
  position: absolute
40
40
  top: -3px
41
41
  bottom: 50%
42
- width: 35px
42
+ width: 31px
43
43
  left: -35px
44
44
  border-left: 1px solid currentColor
45
45
  border-bottom: 1px solid currentColor
@@ -84,11 +84,13 @@
84
84
  &__node--selected .q-tree__node-header-content
85
85
  color: $grey
86
86
 
87
- &__icon, &__node-header-content .q-icon, &__spinner
87
+ &__icon,
88
+ &__node-header-content .q-icon
88
89
  font-size: 21px
89
90
 
90
91
  &__img
91
92
  height: 42px
93
+ border-radius: 2px
92
94
 
93
95
  &__avatar, &__node-header-content .q-avatar
94
96
  font-size: 28px
@@ -96,15 +98,20 @@
96
98
  width: 28px
97
99
  height: 28px
98
100
 
99
- &__arrow, &__spinner
101
+ &__arrow,
102
+ &__spinner
100
103
  font-size: 16px
101
104
 
102
105
  &__arrow
103
106
  transition: transform .3s
107
+ margin-right: 4px
104
108
 
105
109
  &--rotate
106
110
  transform: rotate3d(0, 0, 1, 90deg)
107
111
 
112
+ &__tickbox
113
+ margin-right: 4px
114
+
108
115
  // remove connectors before root
109
116
  > .q-tree__node
110
117
  padding: 0
@@ -123,10 +130,51 @@
123
130
  .q-tree__node-body:after
124
131
  display: none !important
125
132
 
133
+ &--dense .q-tree
134
+ &__arrow,
135
+ &__spinner
136
+ margin-right: 1px
137
+
138
+ &__img
139
+ height: 32px
140
+
141
+ &__tickbox
142
+ margin-right: 3px
143
+
144
+ &__node
145
+ padding: 0
146
+ &:after
147
+ top: 0
148
+ left: -8px
149
+
150
+ &__node-header
151
+ margin-top: 0
152
+ padding: 1px
153
+ &:before
154
+ top: 0
155
+ left: -8px
156
+ width: 8px
157
+
158
+ &__node--child
159
+ padding-left: 17px
160
+ > .q-tree__node-header:before
161
+ left: -25px
162
+ width: 21px
163
+
164
+ &__node-body
165
+ padding: 0 0 2px
166
+
167
+ &__node--parent > .q-tree__node-collapsible > .q-tree__node-body
168
+ padding: 0 0 2px 20px
169
+ &:after
170
+ left: 8px
171
+
172
+ &__children
173
+ padding-left: 16px
174
+
126
175
  [dir=rtl]
127
176
  .q-tree__arrow
128
177
  transform: rotate3d(0, 0, 1, 180deg) #{"/* rtl:ignore */"}
129
178
 
130
179
  &--rotate
131
180
  transform: rotate3d(0, 0, 1, 90deg) #{"/* rtl:ignore */"}
132
-
@@ -260,20 +260,15 @@ export function getRenderer (getPlugin) {
260
260
  }
261
261
 
262
262
  function addFilesToQueue (e, fileList) {
263
- const processedFiles = processFiles(e, fileList, state.files.value, true)
263
+ const localFiles = processFiles(e, fileList, state.files.value, true)
264
264
 
265
- if (processedFiles === void 0) { return }
266
-
267
- const localFiles = processedFiles
268
- .filter(file => state.files.value.findIndex(f => file.name === f.name) === -1)
265
+ if (localFiles === void 0) { return }
269
266
 
270
267
  const fileInput = getFileInput()
271
268
  if (fileInput !== void 0 && fileInput !== null) {
272
269
  fileInput.value = ''
273
270
  }
274
271
 
275
- if (localFiles === void 0) { return }
276
-
277
272
  localFiles.forEach(file => {
278
273
  state.updateFileStatus(file, 'idle')
279
274
  uploadSize.value += file.size
@@ -11,7 +11,7 @@
11
11
  }
12
12
  },
13
13
  "returns": {
14
- "type": [ "Object", "Promise" ],
14
+ "type": [ "Object", "Promise<any>" ],
15
15
  "desc": "Optional configuration for the upload process; You can override QUploader props in this Object (url, method, headers, formFields, fieldName, withCredentials, sendRaw); Props of these Object can also be Functions with the form of (file[s]) => value",
16
16
  "__exemption": [ "examples" ]
17
17
  },
@@ -22,6 +22,18 @@
22
22
  "type": [ "String", "Function" ],
23
23
  "desc": "URL or path to the server which handles the upload. Takes String or factory function, which returns String. Function is called right before upload; If using a function then for best performance, reference it from your scope and do not define it inline",
24
24
  "examples": [ "https://example.com/path", "files => `https://example.com?count=${files.length}`" ],
25
+ "params": {
26
+ "files": {
27
+ "type": "Array",
28
+ "desc": "Uploaded files",
29
+ "__exemption": [ "examples" ]
30
+ }
31
+ },
32
+ "returns": {
33
+ "type": "String",
34
+ "desc": "URL or path to the server which handles the upload",
35
+ "__exemption": [ "examples" ]
36
+ },
25
37
  "category": "upload"
26
38
  },
27
39
 
@@ -31,6 +43,18 @@
31
43
  "desc": "HTTP method to use for upload; Takes String or factory function which returns a String; Function is called right before upload; If using a function then for best performance, reference it from your scope and do not define it inline",
32
44
  "values": [ "POST", "PUT" ],
33
45
  "examples": [ "POST", ":method=\"files => files.length > 10 ? 'POST' : 'PUT'\"" ],
46
+ "params": {
47
+ "files": {
48
+ "type": "Array",
49
+ "desc": "Uploaded files",
50
+ "__exemption": [ "examples" ]
51
+ }
52
+ },
53
+ "returns": {
54
+ "type": "String",
55
+ "desc": "HTTP method to use for upload",
56
+ "__exemption": [ "examples" ]
57
+ },
34
58
  "category": "upload"
35
59
  },
36
60
 
@@ -42,6 +66,18 @@
42
66
  "backgroundFile",
43
67
  ":field-name=\"(file) => 'background' + file.name\""
44
68
  ],
69
+ "params": {
70
+ "files": {
71
+ "type": "File",
72
+ "desc": "The current file being processed",
73
+ "__exemption": [ "examples" ]
74
+ }
75
+ },
76
+ "returns": {
77
+ "type": "String",
78
+ "desc": "Field name for the current file upload",
79
+ "__exemption": [ "examples" ]
80
+ },
45
81
  "category": "upload"
46
82
  },
47
83
 
@@ -67,6 +103,18 @@
67
103
  "() => [{name: 'X-Custom-Timestamp', value: Date.now()}]",
68
104
  "files => [{name: 'X-Custom-Count', value: files.length}]"
69
105
  ],
106
+ "params": {
107
+ "files": {
108
+ "type": "Array",
109
+ "desc": "Uploaded files",
110
+ "__exemption": [ "examples" ]
111
+ }
112
+ },
113
+ "returns": {
114
+ "type": "String",
115
+ "desc": "An array consists of objects with header definitions",
116
+ "__exemption": [ "examples" ]
117
+ },
70
118
  "category": "upload"
71
119
  },
72
120
 
@@ -92,6 +140,18 @@
92
140
  "() => [{name: 'my-field', value: 'my-value'}]",
93
141
  "files => [{name: 'my-field', value: 'my-value' + files.length}]"
94
142
  ],
143
+ "params": {
144
+ "files": {
145
+ "type": "Array",
146
+ "desc": "Uploaded files",
147
+ "__exemption": [ "examples" ]
148
+ }
149
+ },
150
+ "returns": {
151
+ "type": "String",
152
+ "desc": "An array consists of objects with additional fields definitions (used by Form to be uploaded)",
153
+ "__exemption": [ "examples" ]
154
+ },
95
155
  "category": "upload"
96
156
  },
97
157
 
@@ -99,6 +159,18 @@
99
159
  "type": [ "Boolean", "Function" ],
100
160
  "desc": "Sets withCredentials to true on the XHR that manages the upload; Takes boolean or factory function for Boolean; Function is called right before upload; If using a function then for best performance, reference it from your scope and do not define it inline",
101
161
  "examples": [ "with-credentials", ":with-credentials=\"files => ...\"" ],
162
+ "params": {
163
+ "files": {
164
+ "type": "Array",
165
+ "desc": "Uploaded files",
166
+ "__exemption": [ "examples" ]
167
+ }
168
+ },
169
+ "returns": {
170
+ "type": "Boolean",
171
+ "desc": "If true, withCredentials will be set to true on the XHR that manages the upload",
172
+ "__exemption": [ "examples" ]
173
+ },
102
174
  "category": "upload"
103
175
  },
104
176
 
@@ -106,6 +178,18 @@
106
178
  "type": [ "Boolean", "Function" ],
107
179
  "desc": "Send raw files without wrapping into a Form(); Takes boolean or factory function for Boolean; Function is called right before upload; If using a function then for best performance, reference it from your scope and do not define it inline",
108
180
  "examples": [ "send-raw", ":send-raw=\"files => ...\"" ],
181
+ "params": {
182
+ "files": {
183
+ "type": "Array",
184
+ "desc": "Uploaded files",
185
+ "__exemption": [ "examples" ]
186
+ }
187
+ },
188
+ "returns": {
189
+ "type": "Boolean",
190
+ "desc": "If true, raw files will get sent without wrapping into a Form()",
191
+ "__exemption": [ "examples" ]
192
+ },
109
193
  "category": "upload"
110
194
  },
111
195
 
@@ -113,6 +197,18 @@
113
197
  "type": [ "Boolean", "Function" ],
114
198
  "desc": "Upload files in batch (in one XHR request); Takes boolean or factory function for Boolean; Function is called right before upload; If using a function then for best performance, reference it from your scope and do not define it inline",
115
199
  "examples": [ "files => files.length > 10" ],
200
+ "params": {
201
+ "files": {
202
+ "type": "Array",
203
+ "desc": "Uploaded files",
204
+ "__exemption": [ "examples" ]
205
+ }
206
+ },
207
+ "returns": {
208
+ "type": "Boolean",
209
+ "desc": "If true, files will be uploaded in a batch (in one XHR request)",
210
+ "__exemption": [ "examples" ]
211
+ },
116
212
  "category": "upload"
117
213
  }
118
214
  },
@@ -1,4 +1,4 @@
1
- import { h, ref, computed, watch, onBeforeMount, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
1
+ import { h, ref, computed, watch, onActivated, onBeforeMount, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
2
2
 
3
3
  import debounce from '../../utils/debounce.js'
4
4
  import { noop } from '../../utils/event.js'
@@ -679,6 +679,22 @@ export function useVirtualScroll ({
679
679
  setVirtualScrollSize()
680
680
  })
681
681
 
682
+ onActivated(() => {
683
+ const scrollEl = getVirtualScrollTarget()
684
+
685
+ if (prevScrollStart !== void 0 && scrollEl !== void 0 && scrollEl !== null && scrollEl.nodeType !== 8) {
686
+ setScroll(
687
+ scrollEl,
688
+ prevScrollStart,
689
+ props.virtualScrollHorizontal,
690
+ $q.lang.rtl
691
+ )
692
+ }
693
+ else {
694
+ scrollTo(prevToIndex)
695
+ }
696
+ })
697
+
682
698
  setOverflowAnchor !== noop && onBeforeUnmount(() => {
683
699
  const styleSheet = document.getElementById(vsId + '_ss')
684
700
  styleSheet !== null && styleSheet.remove()
@@ -75,7 +75,7 @@ export const useFieldProps = {
75
75
  export const useFieldEmits = [ 'update:modelValue', 'clear', 'focus', 'blur', 'popup-show', 'popup-hide' ]
76
76
 
77
77
  export function useFieldState () {
78
- const { props, attrs, proxy } = getCurrentInstance()
78
+ const { props, attrs, proxy, vnode } = getCurrentInstance()
79
79
 
80
80
  const isDark = useDark(props, proxy.$q)
81
81
 
@@ -88,9 +88,9 @@ export function useFieldState () {
88
88
 
89
89
  innerLoading: ref(false),
90
90
  focused: ref(false),
91
- hasPopupOpen: ref(false),
91
+ hasPopupOpen: false,
92
92
 
93
- splitAttrs: useSplitAttrs(attrs),
93
+ splitAttrs: useSplitAttrs(attrs, vnode),
94
94
  targetUid: ref(getTargetUid(props.for)),
95
95
 
96
96
  rootRef: ref(null),
@@ -301,7 +301,7 @@ export default function (state) {
301
301
  focusoutTimer = setTimeout(() => {
302
302
  if (
303
303
  document.hasFocus() === true && (
304
- state.hasPopupOpen.value === true
304
+ state.hasPopupOpen === true
305
305
  || (
306
306
  state.controlRef !== void 0
307
307
  && (
@@ -112,6 +112,14 @@ export default function ({
112
112
  files = [ files[ 0 ] ]
113
113
  }
114
114
 
115
+ // Avoid duplicate files
116
+ const filenameMap = currentFileList.map(entry => entry.name)
117
+ files = filterFiles(files, rejectedFiles, 'duplicate', file => {
118
+ return filenameMap.includes(file.name) === false
119
+ })
120
+
121
+ if (files.length === 0) { return done() }
122
+
115
123
  if (props.maxTotalSize !== void 0) {
116
124
  let size = append === true
117
125
  ? currentFileList.reduce((total, file) => total + file.size, 0)
@@ -8,7 +8,7 @@ export const useModelToggleProps = {
8
8
  default: null
9
9
  },
10
10
 
11
- 'onUpdate:modelValue': Function
11
+ 'onUpdate:modelValue': [ Function, Array ]
12
12
  }
13
13
 
14
14
  export const useModelToggleEmits = [
@@ -16,12 +16,21 @@ export default function (props, rootRef) {
16
16
  })
17
17
 
18
18
  function refocusTarget (e) {
19
+ const root = rootRef.value
20
+
19
21
  if (e !== void 0 && e.type.indexOf('key') === 0) {
20
- if (document.activeElement !== rootRef.value && rootRef.value.contains(document.activeElement) === true) {
21
- rootRef.value.focus()
22
+ if (
23
+ root !== null
24
+ && document.activeElement !== root
25
+ && root.contains(document.activeElement) === true
26
+ ) {
27
+ root.focus()
22
28
  }
23
29
  }
24
- else if ((e === void 0 || rootRef.value.contains(e.target) === true) && refocusRef.value !== null) {
30
+ else if (
31
+ refocusRef.value !== null
32
+ && (e === void 0 || (root !== null && root.contains(e.target) === true))
33
+ ) {
25
34
  refocusRef.value.focus()
26
35
  }
27
36
  }
@@ -2,7 +2,7 @@ import { ref, onBeforeUpdate } from 'vue'
2
2
 
3
3
  const listenerRE = /^on[A-Z]/
4
4
 
5
- export default function (attrs) {
5
+ export default function (attrs, vnode) {
6
6
  const acc = {
7
7
  listeners: ref({}),
8
8
  attributes: ref({})
@@ -21,6 +21,12 @@ export default function (attrs) {
21
21
  }
22
22
  })
23
23
 
24
+ Object.keys(vnode.props).forEach(key => {
25
+ if (listenerRE.test(key) === true) {
26
+ listeners[ key ] = vnode.props[ key ]
27
+ }
28
+ })
29
+
24
30
  acc.listeners.value = listeners
25
31
  acc.attributes.value = attributes
26
32
  }
@@ -1,5 +1,7 @@
1
1
  import { ref, getCurrentInstance } from 'vue'
2
2
 
3
+ import getEmitsObject from '../utils/private/get-emits-object'
4
+
3
5
  // To be used for the custom component
4
6
  // used on a Dialog plugin
5
7
 
@@ -34,6 +36,10 @@ function useDialogPluginComponent () {
34
36
  }
35
37
  }
36
38
 
37
- useDialogPluginComponent.emits = [ 'ok', 'hide' ]
39
+ // Don't forget to update the types in "ui/types/composables.d.ts"
40
+ const emits = [ 'ok', 'hide' ]
41
+
42
+ useDialogPluginComponent.emits = emits
43
+ useDialogPluginComponent.emitsObject = getEmitsObject(emits)
38
44
 
39
45
  export default useDialogPluginComponent
@@ -1,4 +1,6 @@
1
- // default easing is easeOutCubic
1
+ // should not need this, but it's good as fallback
2
+ \:root
3
+ --q-transition-duration: .3s
2
4
 
3
5
  .q-transition
4
6
  &--slide-right,
@@ -84,6 +84,7 @@ export default __QUASAR_SSR_SERVER__
84
84
  _meta: {
85
85
  htmlAttrs: '',
86
86
  headTags: '',
87
+ endingHeadTags: '',
87
88
  bodyClasses: '',
88
89
  bodyAttrs: 'data-server-rendered',
89
90
  bodyTags: ''
@@ -1,6 +1,9 @@
1
1
  import { coreProps, coreEmits, getRenderer } from '../components/uploader/uploader-core.js'
2
2
 
3
3
  import { createComponent } from './private/create.js'
4
+ import getEmitsObject from './private/get-emits-object.js'
5
+
6
+ const coreEmitsObject = getEmitsObject(coreEmits)
4
7
 
5
8
  export default ({ name, props, emits, injectPlugin }) => createComponent({
6
9
  name,
@@ -10,10 +13,9 @@ export default ({ name, props, emits, injectPlugin }) => createComponent({
10
13
  ...props
11
14
  },
12
15
 
13
- emits: [
14
- ...coreEmits,
15
- ...emits
16
- ],
16
+ emits: Object(emits) === emits
17
+ ? { ...coreEmitsObject, ...emits }
18
+ : [ ...coreEmits, ...emits ],
17
19
 
18
20
  setup () {
19
21
  return getRenderer(injectPlugin)
package/src/utils/date.js CHANGED
@@ -403,7 +403,7 @@ export function __splitDate (str, mask, dateLocale, calendar, defaultModel) {
403
403
  }
404
404
  }
405
405
 
406
- date.dateHash = date.year + '/' + pad(date.month) + '/' + pad(date.day)
406
+ date.dateHash = pad(date.year, 6) + '/' + pad(date.month) + '/' + pad(date.day)
407
407
  date.timeHash = pad(date.hour) + ':' + pad(date.minute) + ':' + pad(date.second) + tzString
408
408
 
409
409
  return date
@@ -0,0 +1,11 @@
1
+ const trueFn = () => true
2
+
3
+ export default function (emitsArray) {
4
+ const emitsObject = {}
5
+
6
+ emitsArray.forEach(val => {
7
+ emitsObject[ val ] = trueFn
8
+ })
9
+
10
+ return emitsObject
11
+ }
@@ -35,8 +35,16 @@
35
35
  "type": "Function",
36
36
  "desc": "Tell what to do",
37
37
  "required": true,
38
- "params": null,
39
- "returns": null
38
+ "params": {
39
+ "payload": {
40
+ "type": "Any",
41
+ "desc": "The payload if called onDialogOK with the parameter or emitted one with the 'ok' event",
42
+ "required": false,
43
+ "examples": [ "'Quasar Framework'", "[ 1, 2, 6, 3 ]", "{ book: { id: 1, name: 'Lorem Ipsum' }, user: { name: 'Lorem J. Ipsum', role: 'admin' } }" ]
44
+ }
45
+ },
46
+ "returns": null,
47
+ "examples": [ "() => console.log('OK!')", "(payload) => Notify.create({ type: 'positive', message: `Successfully saved '${payload.book.name}' book!` })" ]
40
48
  }
41
49
  },
42
50
  "returns": {