quasar 2.12.7 → 2.13.1

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 (210) hide show
  1. package/dist/api/BottomSheet.json +7 -2
  2. package/dist/api/Dialog.json +7 -2
  3. package/dist/api/QBanner.json +7 -2
  4. package/dist/api/QBar.json +7 -2
  5. package/dist/api/QBtn.json +7 -2
  6. package/dist/api/QBtnDropdown.json +7 -2
  7. package/dist/api/QCard.json +7 -2
  8. package/dist/api/QCarousel.json +7 -2
  9. package/dist/api/QCheckbox.json +8 -3
  10. package/dist/api/QChip.json +13 -3
  11. package/dist/api/QColor.json +7 -2
  12. package/dist/api/QDate.json +7 -2
  13. package/dist/api/QDrawer.json +7 -2
  14. package/dist/api/QEditor.json +7 -2
  15. package/dist/api/QExpansionItem.json +7 -2
  16. package/dist/api/QFab.json +7 -2
  17. package/dist/api/QFabAction.json +7 -2
  18. package/dist/api/QField.json +28 -7
  19. package/dist/api/QFile.json +14 -4
  20. package/dist/api/QImg.json +1 -1
  21. package/dist/api/QInnerLoading.json +7 -2
  22. package/dist/api/QInput.json +16 -5
  23. package/dist/api/QIntersection.json +7 -2
  24. package/dist/api/QItem.json +12 -4
  25. package/dist/api/QLinearProgress.json +7 -2
  26. package/dist/api/QList.json +7 -2
  27. package/dist/api/QMarkupTable.json +7 -2
  28. package/dist/api/QMenu.json +21 -6
  29. package/dist/api/QOptionGroup.json +7 -2
  30. package/dist/api/QPagination.json +37 -11
  31. package/dist/api/QRadio.json +7 -2
  32. package/dist/api/QRange.json +7 -2
  33. package/dist/api/QScrollArea.json +14 -4
  34. package/dist/api/QSelect.json +24 -8
  35. package/dist/api/QSeparator.json +7 -2
  36. package/dist/api/QSkeleton.json +7 -2
  37. package/dist/api/QSlideItem.json +7 -2
  38. package/dist/api/QSlider.json +7 -2
  39. package/dist/api/QStepper.json +7 -2
  40. package/dist/api/QTabPanel.json +7 -2
  41. package/dist/api/QTable.json +124 -21
  42. package/dist/api/QTime.json +17 -6
  43. package/dist/api/QTimeline.json +7 -2
  44. package/dist/api/QToggle.json +8 -3
  45. package/dist/api/QTooltip.json +14 -4
  46. package/dist/api/QTree.json +7 -2
  47. package/dist/api/QUploader.json +7 -2
  48. package/dist/api/QVirtualScroll.json +2 -1
  49. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  50. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  51. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  52. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  53. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  54. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  55. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  56. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  57. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  58. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  59. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  60. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  61. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  62. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  63. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  64. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  65. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  66. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  67. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  68. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  69. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  70. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  71. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  72. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  73. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  74. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  75. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  76. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  77. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +2 -2
  78. package/dist/icon-set/svg-material-icons-round.umd.prod.js +2 -2
  79. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +2 -2
  80. package/dist/icon-set/svg-material-icons.umd.prod.js +2 -2
  81. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +2 -2
  82. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +2 -2
  83. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +2 -2
  84. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  85. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  86. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  87. package/dist/icon-set/themify.umd.prod.js +1 -1
  88. package/dist/lang/ar-TN.umd.prod.js +1 -1
  89. package/dist/lang/ar.umd.prod.js +1 -1
  90. package/dist/lang/az-Latn.umd.prod.js +1 -1
  91. package/dist/lang/bg.umd.prod.js +1 -1
  92. package/dist/lang/bn.umd.prod.js +1 -1
  93. package/dist/lang/ca.umd.prod.js +1 -1
  94. package/dist/lang/cs.umd.prod.js +1 -1
  95. package/dist/lang/da.umd.prod.js +1 -1
  96. package/dist/lang/de-CH.umd.prod.js +6 -0
  97. package/dist/lang/de-DE.umd.prod.js +6 -0
  98. package/dist/lang/de.umd.prod.js +1 -1
  99. package/dist/lang/el.umd.prod.js +1 -1
  100. package/dist/lang/en-GB.umd.prod.js +1 -1
  101. package/dist/lang/en-US.umd.prod.js +1 -1
  102. package/dist/lang/eo.umd.prod.js +1 -1
  103. package/dist/lang/es.umd.prod.js +1 -1
  104. package/dist/lang/et.umd.prod.js +1 -1
  105. package/dist/lang/eu.umd.prod.js +1 -1
  106. package/dist/lang/fa-IR.umd.prod.js +1 -1
  107. package/dist/lang/fa.umd.prod.js +1 -1
  108. package/dist/lang/fi.umd.prod.js +1 -1
  109. package/dist/lang/fr.umd.prod.js +1 -1
  110. package/dist/lang/gn.umd.prod.js +1 -1
  111. package/dist/lang/he.umd.prod.js +1 -1
  112. package/dist/lang/hi.umd.prod.js +1 -1
  113. package/dist/lang/hr.umd.prod.js +1 -1
  114. package/dist/lang/hu.umd.prod.js +1 -1
  115. package/dist/lang/id.umd.prod.js +1 -1
  116. package/dist/lang/is.umd.prod.js +1 -1
  117. package/dist/lang/it.umd.prod.js +1 -1
  118. package/dist/lang/ja.umd.prod.js +1 -1
  119. package/dist/lang/kk.umd.prod.js +1 -1
  120. package/dist/lang/km.umd.prod.js +1 -1
  121. package/dist/lang/ko-KR.umd.prod.js +1 -1
  122. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  123. package/dist/lang/lt.umd.prod.js +1 -1
  124. package/dist/lang/lu.umd.prod.js +1 -1
  125. package/dist/lang/lv.umd.prod.js +1 -1
  126. package/dist/lang/mk.umd.prod.js +2 -2
  127. package/dist/lang/ml.umd.prod.js +1 -1
  128. package/dist/lang/mm.umd.prod.js +1 -1
  129. package/dist/lang/ms.umd.prod.js +1 -1
  130. package/dist/lang/my.umd.prod.js +1 -1
  131. package/dist/lang/nb-NO.umd.prod.js +1 -1
  132. package/dist/lang/nl.umd.prod.js +1 -1
  133. package/dist/lang/pl.umd.prod.js +1 -1
  134. package/dist/lang/pt-BR.umd.prod.js +1 -1
  135. package/dist/lang/pt.umd.prod.js +1 -1
  136. package/dist/lang/ro.umd.prod.js +1 -1
  137. package/dist/lang/ru.umd.prod.js +1 -1
  138. package/dist/lang/sk.umd.prod.js +1 -1
  139. package/dist/lang/sl.umd.prod.js +1 -1
  140. package/dist/lang/sm.umd.prod.js +1 -1
  141. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  142. package/dist/lang/sr.umd.prod.js +1 -1
  143. package/dist/lang/sv.umd.prod.js +1 -1
  144. package/dist/lang/ta.umd.prod.js +1 -1
  145. package/dist/lang/th.umd.prod.js +1 -1
  146. package/dist/lang/tr.umd.prod.js +1 -1
  147. package/dist/lang/ug.umd.prod.js +1 -1
  148. package/dist/lang/uk.umd.prod.js +1 -1
  149. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  150. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  151. package/dist/lang/vi.umd.prod.js +1 -1
  152. package/dist/lang/zh-CN.umd.prod.js +1 -1
  153. package/dist/lang/zh-TW.umd.prod.js +1 -1
  154. package/dist/quasar.addon.prod.css +1 -1
  155. package/dist/quasar.addon.rtl.prod.css +1 -1
  156. package/dist/quasar.cjs.prod.js +2 -2
  157. package/dist/quasar.esm.js +136 -43
  158. package/dist/quasar.esm.prod.js +2 -2
  159. package/dist/quasar.prod.css +1 -1
  160. package/dist/quasar.rtl.prod.css +1 -1
  161. package/dist/quasar.sass +1 -1
  162. package/dist/quasar.umd.js +136 -43
  163. package/dist/quasar.umd.prod.js +2 -2
  164. package/dist/types/api/qtree.d.ts +115 -21
  165. package/dist/types/index.d.ts +98 -83
  166. package/dist/vetur/quasar-attributes.json +70 -66
  167. package/dist/vetur/quasar-tags.json +2 -1
  168. package/dist/web-types/web-types.json +134 -184
  169. package/lang/de-CH.js +98 -0
  170. package/lang/de-CH.mjs +93 -0
  171. package/lang/de-DE.js +98 -0
  172. package/lang/de-DE.mjs +93 -0
  173. package/lang/index.json +8 -0
  174. package/lang/mk.js +4 -4
  175. package/lang/mk.mjs +4 -4
  176. package/package.json +4 -3
  177. package/src/api.extends.json +2 -1
  178. package/src/components/btn/use-btn.json +2 -1
  179. package/src/components/checkbox/use-checkbox.json +1 -1
  180. package/src/components/chip/QChip.json +2 -1
  181. package/src/components/date/QDate.js +4 -4
  182. package/src/components/fab/use-fab.json +2 -1
  183. package/src/components/field/QField.js +14 -2
  184. package/src/components/field/QField.json +7 -0
  185. package/src/components/field/__tests__/QField.cy.js +156 -0
  186. package/src/components/img/QImg.json +1 -1
  187. package/src/components/input/QInput.json +2 -1
  188. package/src/components/input/use-mask.js +6 -1
  189. package/src/components/intersection/QIntersection.json +2 -1
  190. package/src/components/item/QItem.js +1 -1
  191. package/src/components/item/QItem.json +3 -3
  192. package/src/components/menu/QMenu.json +4 -0
  193. package/src/components/pagination/QPagination.json +9 -5
  194. package/src/components/scroll-area/QScrollArea.js +16 -1
  195. package/src/components/scroll-area/QScrollArea.json +2 -1
  196. package/src/components/select/QSelect.js +42 -17
  197. package/src/components/select/QSelect.json +3 -2
  198. package/src/components/select/__tests__/QSelect.cy.js +2 -1
  199. package/src/components/table/QTable.json +38 -1
  200. package/src/components/table/table-sort.js +5 -0
  201. package/src/components/time/QTime.js +16 -3
  202. package/src/components/time/QTime.json +4 -3
  203. package/src/components/tooltip/QTooltip.json +4 -0
  204. package/src/components/tree/QTree.js +8 -3
  205. package/src/components/virtual-scroll/use-virtual-scroll.json +1 -1
  206. package/src/composables/private/__tests__/FieldWrapper.vue +17 -2
  207. package/src/composables/private/__tests__/use-field.cy.js +334 -137
  208. package/src/composables/private/__tests__/use-validate.cy.js +162 -15
  209. package/src/composables/private/use-field.js +21 -8
  210. package/src/composables/private/use-validate.json +2 -1
@@ -0,0 +1,156 @@
1
+ import QField from '../QField'
2
+ import { vModelAdapter } from '@quasar/quasar-app-extension-testing-e2e-cypress'
3
+ import { ref } from 'vue'
4
+ import Icons from '../../../../icon-set/material-icons.mjs'
5
+
6
+ function getHostElement () {
7
+ return cy.get('.q-field')
8
+ }
9
+
10
+ function mountQField (options) {
11
+ return cy.mount(QField, options)
12
+ }
13
+
14
+ describe('Field API', () => {
15
+ describe('Props', () => {
16
+ describe('Category: model', () => {
17
+ describe('(prop): maxlength', () => {
18
+ it.skip(' ', () => {
19
+ // It is tricky to test this since it will require that we setup a control slot with v-model.
20
+ // This is already tested in QInput and others using use-field composable, so are not not testing it.
21
+ })
22
+ })
23
+ })
24
+ })
25
+
26
+ describe('Slots', () => {
27
+ describe('(slot): control', () => {
28
+ it('should use control slot as content of the field', () => {
29
+ const controlSlot = 'Hello there'
30
+ mountQField({
31
+ slots: {
32
+ control: () => controlSlot
33
+ }
34
+ })
35
+
36
+ getHostElement().get('.q-field__control-container').should('contain', controlSlot)
37
+ })
38
+ })
39
+ })
40
+
41
+ describe('Events', () => {
42
+ describe('(event): update:model-value', () => {
43
+ it('should emit onUpdate:modelValue event', () => {
44
+ const model = ref('text')
45
+ const fn = cy.stub()
46
+ mountQField({
47
+ props: {
48
+ ...vModelAdapter(model),
49
+ 'onUpdate:modelValue': fn,
50
+ clearable: true
51
+ }
52
+ })
53
+
54
+ getHostElement().get('button[type="button"]')
55
+ .contains(Icons.field.clear).click()
56
+ .then(() => {
57
+ expect(fn).to.be.calledWith()
58
+ })
59
+ })
60
+ })
61
+
62
+ describe('(event): focus', () => {
63
+ it('should emit the focus event', () => {
64
+ const fn = cy.stub()
65
+
66
+ mountQField({
67
+ props: {
68
+ onfocus: fn
69
+ },
70
+ slots: {
71
+ control: 'text'
72
+ }
73
+ })
74
+
75
+ getHostElement().click()
76
+
77
+ getHostElement().then(() => {
78
+ expect(fn).to.be.calledWith()
79
+ })
80
+ })
81
+ })
82
+
83
+ describe('(event): blur', () => {
84
+ it('should emit blur event', () => {
85
+ const fn = cy.stub()
86
+ mountQField({
87
+ props: {
88
+ onblur: fn
89
+ },
90
+ slots: {
91
+ control: 'text'
92
+ }
93
+ })
94
+
95
+ getHostElement()
96
+ .click()
97
+
98
+ getHostElement().then(() => {
99
+ Cypress.vueWrapper.vm.blur()
100
+ })
101
+
102
+ getHostElement()
103
+ .then(() => {
104
+ expect(fn).to.be.calledWith()
105
+ })
106
+ })
107
+ })
108
+ })
109
+
110
+ describe('Methods', () => {
111
+ describe('(method): focus', () => {
112
+ it('should focus the component', () => {
113
+ mountQField({
114
+ slots: {
115
+ control: 'text'
116
+ }
117
+ })
118
+
119
+ getHostElement()
120
+ .get('.q-field--focused')
121
+ .should('not.exist')
122
+
123
+ getHostElement()
124
+ .then(() => {
125
+ Cypress.vueWrapper.vm.focus()
126
+ })
127
+ getHostElement()
128
+ .get('.q-field--focused')
129
+ .should('exist')
130
+ })
131
+ })
132
+
133
+ describe('(method): blur', () => {
134
+ it('should blur the component', () => {
135
+ mountQField({
136
+ slots: {
137
+ control: 'text'
138
+ }
139
+ })
140
+
141
+ getHostElement().click()
142
+
143
+ getHostElement()
144
+ .get('.q-field--focused')
145
+ .should('exist')
146
+
147
+ getHostElement()
148
+ .then(() => {
149
+ Cypress.vueWrapper.vm.blur()
150
+ })
151
+
152
+ cy.get('.q-field--focused').should('not.exist')
153
+ })
154
+ })
155
+ })
156
+ })
@@ -246,7 +246,7 @@
246
246
  "error": {
247
247
  "desc": "Emitted when browser could not load the image",
248
248
  "params": {
249
- "src": {
249
+ "err": {
250
250
  "type": "Error",
251
251
  "desc": "JS Error object"
252
252
  }
@@ -26,7 +26,8 @@
26
26
  "default": "text",
27
27
  "values": [
28
28
  "text", "password", "textarea", "email", "search",
29
- "tel", "file", "number", "url", "time", "date"
29
+ "tel", "file", "number", "url", "time", "date",
30
+ "datetime-local"
30
31
  ],
31
32
  "category": "general"
32
33
  },
@@ -304,7 +304,12 @@ export default function (props, emit, emitValue, inputRef) {
304
304
  ? unmaskValue(masked)
305
305
  : masked
306
306
 
307
- String(props.modelValue) !== val && emitValue(val, true)
307
+ if (
308
+ String(props.modelValue) !== val
309
+ && (props.modelValue !== null || val !== '')
310
+ ) {
311
+ emitValue(val, true)
312
+ }
308
313
  }
309
314
 
310
315
  function moveCursorForPaste (inp, start, end) {
@@ -23,7 +23,8 @@
23
23
  },
24
24
 
25
25
  "root": {
26
- "type": "Element",
26
+ "type": [ "Element", "null" ],
27
+ "default": null,
27
28
  "desc": "[Intersection API root prop] Lets you define an alternative to the viewport as your root (through its DOM element); It is important to keep in mind that root needs to be an ancestor of the observed element",
28
29
  "examples": [ "$refs.myTable.$el", "getElementById(\"myTable\")" ],
29
30
  "category": "behavior"
@@ -106,7 +106,7 @@ export default createComponent({
106
106
  }
107
107
 
108
108
  function onKeyup (e) {
109
- if (isClickable.value === true && isKeyCode(e, 13) === true) {
109
+ if (isClickable.value === true && isKeyCode(e, [ 13, 32 ]) === true) {
110
110
  stopAndPrevent(e)
111
111
 
112
112
  // for ripple
@@ -7,10 +7,10 @@
7
7
 
8
8
  "props": {
9
9
  "active": {
10
- "type": "Boolean",
10
+ "type": [ "Boolean", "null" ],
11
+ "default": null,
11
12
  "desc": "Put item into 'active' state",
12
- "category": "state",
13
- "default": null
13
+ "category": "state"
14
14
  },
15
15
 
16
16
  "dark": {
@@ -105,12 +105,16 @@
105
105
 
106
106
  "max-height": {
107
107
  "extends": "size",
108
+ "type": [ "String", "null" ],
109
+ "default": null,
108
110
  "desc": "The maximum height of the menu; Size in CSS units, including unit name",
109
111
  "category": "style"
110
112
  },
111
113
 
112
114
  "max-width": {
113
115
  "extends": "size",
116
+ "type": [ "String", "null" ],
117
+ "default": null,
114
118
  "desc": "The maximum width of the menu; Size in CSS units, including unit name",
115
119
  "category": "style"
116
120
  }
@@ -80,25 +80,29 @@
80
80
  },
81
81
 
82
82
  "boundary-links": {
83
- "type": "Boolean",
83
+ "type": [ "Boolean", "null" ],
84
+ "default": null,
84
85
  "desc": "Show boundary button links",
85
86
  "category": "content"
86
87
  },
87
88
 
88
89
  "boundary-numbers": {
89
- "type": "Boolean",
90
+ "type": [ "Boolean", "null" ],
91
+ "default": null,
90
92
  "desc": "Always show first and last page buttons (if not using 'input')",
91
93
  "category": "content"
92
94
  },
93
95
 
94
96
  "direction-links": {
95
- "type": "Boolean",
97
+ "type": [ "Boolean", "null" ],
98
+ "default": null,
96
99
  "desc": "Show direction buttons",
97
100
  "category": "content"
98
101
  },
99
102
 
100
103
  "ellipses": {
101
- "type": "Boolean",
104
+ "type": [ "Boolean", "null" ],
105
+ "default": null,
102
106
  "desc": "Show ellipses (...) when pages are available",
103
107
  "category": "content"
104
108
  },
@@ -221,7 +225,7 @@
221
225
  },
222
226
 
223
227
  "ripple": {
224
- "type": [ "Boolean", "Object" ],
228
+ "type": [ "Boolean", "Object", "null" ],
225
229
  "desc": "Configure buttons material ripple (disable it by setting it to 'false' or supply a config object); Does not applies to boundary and ellipsis buttons",
226
230
  "default": true,
227
231
  "examples": [ false, "{ early: true, center: true, color: 'teal', keyCodes: [] }" ],
@@ -352,11 +352,26 @@ export default createComponent({
352
352
  targetRef.value[ dirProps[ axis ].scroll ] = offset
353
353
  }
354
354
 
355
+ let mouseEventTimer = null
356
+
355
357
  function onMouseenter () {
356
- hover.value = true
358
+ if (mouseEventTimer !== null) {
359
+ clearTimeout(mouseEventTimer)
360
+ }
361
+
362
+ // setTimeout needed for iOS; see ticket #16210
363
+ mouseEventTimer = setTimeout(() => {
364
+ mouseEventTimer = null
365
+ hover.value = true
366
+ }, proxy.$q.platform.is.ios ? 50 : 0)
357
367
  }
358
368
 
359
369
  function onMouseleave () {
370
+ if (mouseEventTimer !== null) {
371
+ clearTimeout(mouseEventTimer)
372
+ mouseEventTimer = null
373
+ }
374
+
360
375
  hover.value = false
361
376
  }
362
377
 
@@ -73,7 +73,8 @@
73
73
  },
74
74
 
75
75
  "visible": {
76
- "type": "Boolean",
76
+ "type": [ "Boolean", "null" ],
77
+ "default": null,
77
78
  "desc": "Manually control the visibility of the scrollbar; Overrides default mouse over/leave behavior",
78
79
  "category": "behavior"
79
80
  },
@@ -143,7 +143,8 @@ export default createComponent({
143
143
  const dialogFieldFocused = ref(false)
144
144
  const innerLoadingIndicator = ref(false)
145
145
 
146
- let inputTimer = null, innerValueCache,
146
+ let filterTimer = null, inputValueTimer = null,
147
+ innerValueCache,
147
148
  hasDialog, userInputValue, filterId = null, defaultInputValue,
148
149
  transitionShowComputed, searchBuffer, searchBufferExp
149
150
 
@@ -588,9 +589,11 @@ export default createComponent({
588
589
  scrollTo(index)
589
590
 
590
591
  if (skipInputValue !== true && props.useInput === true && props.fillInput === true) {
591
- setInputValue(index >= 0
592
- ? getOptionLabel.value(props.options[ index ])
593
- : defaultInputValue
592
+ setInputValue(
593
+ index >= 0
594
+ ? getOptionLabel.value(props.options[ index ])
595
+ : defaultInputValue,
596
+ true
594
597
  )
595
598
  }
596
599
  }
@@ -651,9 +654,13 @@ export default createComponent({
651
654
 
652
655
  e.target.value = ''
653
656
 
654
- if (inputTimer !== null) {
655
- clearTimeout(inputTimer)
656
- inputTimer = null
657
+ if (filterTimer !== null) {
658
+ clearTimeout(filterTimer)
659
+ filterTimer = null
660
+ }
661
+ if (inputValueTimer !== null) {
662
+ clearTimeout(inputValueTimer)
663
+ inputValueTimer = null
657
664
  }
658
665
 
659
666
  resetInputValue()
@@ -744,6 +751,10 @@ export default createComponent({
744
751
  // backspace
745
752
  if (
746
753
  e.keyCode === 8
754
+ && (
755
+ props.useChips === true
756
+ || props.clearable === true
757
+ )
747
758
  && props.hideSelected !== true
748
759
  && inputValue.value.length === 0
749
760
  ) {
@@ -838,7 +849,7 @@ export default createComponent({
838
849
  scrollTo(index)
839
850
 
840
851
  if (index >= 0 && props.useInput === true && props.fillInput === true) {
841
- setInputValue(getOptionLabel.value(props.options[ index ]))
852
+ setInputValue(getOptionLabel.value(props.options[ index ]), true)
842
853
  }
843
854
  })
844
855
  }
@@ -1024,9 +1035,13 @@ export default createComponent({
1024
1035
  }
1025
1036
 
1026
1037
  function onInput (e) {
1027
- if (inputTimer !== null) {
1028
- clearTimeout(inputTimer)
1029
- inputTimer = null
1038
+ if (filterTimer !== null) {
1039
+ clearTimeout(filterTimer)
1040
+ filterTimer = null
1041
+ }
1042
+ if (inputValueTimer !== null) {
1043
+ clearTimeout(inputValueTimer)
1044
+ inputValueTimer = null
1030
1045
  }
1031
1046
 
1032
1047
  if (e && e.target && e.target.qComposing === true) {
@@ -1047,17 +1062,26 @@ export default createComponent({
1047
1062
  }
1048
1063
 
1049
1064
  if (props.onFilter !== void 0) {
1050
- inputTimer = setTimeout(() => {
1051
- inputTimer = null
1065
+ filterTimer = setTimeout(() => {
1066
+ filterTimer = null
1052
1067
  filter(inputValue.value)
1053
1068
  }, props.inputDebounce)
1054
1069
  }
1055
1070
  }
1056
1071
 
1057
- function setInputValue (val) {
1072
+ function setInputValue (val, emitImmediately) {
1058
1073
  if (inputValue.value !== val) {
1059
1074
  inputValue.value = val
1060
- emit('inputValue', val)
1075
+
1076
+ if (emitImmediately === true || props.inputDebounce === 0 || props.inputDebounce === '0') {
1077
+ emit('inputValue', val)
1078
+ }
1079
+ else {
1080
+ inputValueTimer = setTimeout(() => {
1081
+ inputValueTimer = null
1082
+ emit('inputValue', val)
1083
+ }, props.inputDebounce)
1084
+ }
1061
1085
  }
1062
1086
  }
1063
1087
 
@@ -1065,7 +1089,7 @@ export default createComponent({
1065
1089
  userInputValue = internal !== true
1066
1090
 
1067
1091
  if (props.useInput === true) {
1068
- setInputValue(val)
1092
+ setInputValue(val, true)
1069
1093
 
1070
1094
  if (noFiltering === true || internal !== true) {
1071
1095
  defaultInputValue = val
@@ -1418,7 +1442,8 @@ export default createComponent({
1418
1442
  updatePreState()
1419
1443
 
1420
1444
  onBeforeUnmount(() => {
1421
- inputTimer !== null && clearTimeout(inputTimer)
1445
+ filterTimer !== null && clearTimeout(filterTimer)
1446
+ inputValueTimer !== null && clearTimeout(inputValueTimer)
1422
1447
  })
1423
1448
 
1424
1449
  // expose public methods
@@ -152,7 +152,8 @@
152
152
  },
153
153
 
154
154
  "options-dark": {
155
- "type": "Boolean",
155
+ "type": [ "Boolean", "null" ],
156
+ "default": null,
156
157
  "desc": "Options menu will be colored with a dark color",
157
158
  "category": "options"
158
159
  },
@@ -270,7 +271,7 @@
270
271
 
271
272
  "input-debounce": {
272
273
  "type": [ "Number", "String" ],
273
- "desc": "Debounce the input model update with an amount of milliseconds",
274
+ "desc": "Debounce the input model update with an amount of milliseconds (also affects the 'filter' event, if used)",
274
275
  "default": 500,
275
276
  "category": "content"
276
277
  },
@@ -1258,7 +1258,8 @@ describe('QSelect API', () => {
1258
1258
  props: {
1259
1259
  modelValue: null,
1260
1260
  onInputValue: fn,
1261
- useInput: true
1261
+ useInput: true,
1262
+ inputDebounce: 0
1262
1263
  }
1263
1264
  })
1264
1265
 
@@ -187,7 +187,7 @@
187
187
  },
188
188
  "sort": {
189
189
  "type": "Function",
190
- "desc": "Compare function if you have some custom data or want a specific way to compare two rows",
190
+ "desc": "Compare function if you have some custom data or want a specific way to compare two rows; rows with null/undefined values will get sorted without triggering this method (use 'rawSort' instead if you want to handle those values too)",
191
191
  "examples": ["(a, b, rowA, rowB) => parseInt(a, 10) - parseInt(b, 10)"],
192
192
  "params": {
193
193
  "a": {
@@ -221,6 +221,43 @@
221
221
  "examples": [ "-1", "0", "1" ]
222
222
  }
223
223
  },
224
+ "rawSort": {
225
+ "type": "Function",
226
+ "desc": "Compare function if you have some custom data or want a specific way to compare two rows; includes rows with null/undefined values (use 'sort' instead if you don't want that)",
227
+ "examples": ["(a, b, rowA, rowB) => parseInt(a, 10) - parseInt(b, 10)"],
228
+ "params": {
229
+ "a": {
230
+ "type": "Any",
231
+ "required": true,
232
+ "desc": "Value of the first comparison term",
233
+ "examples": [ 123, "abc" ]
234
+ },
235
+ "b": {
236
+ "type": "Any",
237
+ "required": true,
238
+ "desc": "Value of the second comparison term",
239
+ "examples": [ 123, "abc" ]
240
+ },
241
+ "rowA": {
242
+ "type": "Object",
243
+ "required": true,
244
+ "desc": "Full Row object in which is contained the first term",
245
+ "examples": [ "{ name: 'Potassium', value: 'K' }" ]
246
+ },
247
+ "rowB": {
248
+ "type": "Object",
249
+ "required": true,
250
+ "desc": "Full Row object in which is contained the second term",
251
+ "examples": [ "{ name: 'Fluorine', value: 'F' }" ]
252
+ }
253
+ },
254
+ "returns": {
255
+ "type": "Number",
256
+ "desc": "Comparison result of term 'a' with term 'b'. Less than 0 when 'a' should come first; greater than 0 if 'b' should come first; equal to 0 if their position must not be changed with respect to each other",
257
+ "examples": [ "-1", "0", "1" ]
258
+ },
259
+ "addedIn": "v2.13.0"
260
+ },
224
261
  "sortOrder": {
225
262
  "type": "String",
226
263
  "desc": "Set column sort order: 'ad' (ascending-descending) or 'da' (descending-ascending); Overrides the 'column-sort-order' prop",
@@ -42,6 +42,9 @@ export function useTableSort (props, computedPagination, colList, setPagination)
42
42
  A = val(a),
43
43
  B = val(b)
44
44
 
45
+ if (col.rawSort !== void 0) {
46
+ return col.rawSort(A, B, a, b) * dir
47
+ }
45
48
  if (A === null || A === void 0) {
46
49
  return -1 * dir
47
50
  }
@@ -49,6 +52,8 @@ export function useTableSort (props, computedPagination, colList, setPagination)
49
52
  return 1 * dir
50
53
  }
51
54
  if (col.sort !== void 0) {
55
+ // gets called without rows that have null/undefined as value
56
+ // due to the above two statements
52
57
  return col.sort(A, B, a, b) * dir
53
58
  }
54
59
  if (isNumber(A) === true && isNumber(B) === true) {
@@ -706,23 +706,36 @@ export default createComponent({
706
706
  }
707
707
  }
708
708
 
709
+ function goToViewWhenHasModel (newView) {
710
+ const model = props.modelValue
711
+ if (
712
+ view.value !== newView
713
+ && model !== void 0
714
+ && model !== null
715
+ && model !== ''
716
+ && typeof model !== 'string'
717
+ ) {
718
+ view.value = newView
719
+ }
720
+ }
721
+
709
722
  function verifyAndUpdate () {
710
723
  if (hourInSelection.value !== null && hourInSelection.value(innerModel.value.hour) !== true) {
711
724
  innerModel.value = __splitDate()
712
- view.value = 'hour'
725
+ goToViewWhenHasModel('hour')
713
726
  return
714
727
  }
715
728
 
716
729
  if (minuteInSelection.value !== null && minuteInSelection.value(innerModel.value.minute) !== true) {
717
730
  innerModel.value.minute = null
718
731
  innerModel.value.second = null
719
- view.value = 'minute'
732
+ goToViewWhenHasModel('minute')
720
733
  return
721
734
  }
722
735
 
723
736
  if (props.withSeconds === true && secondInSelection.value !== null && secondInSelection.value(innerModel.value.second) !== true) {
724
737
  innerModel.value.second = null
725
- view.value = 'second'
738
+ goToViewWhenHasModel('second')
726
739
  return
727
740
  }
728
741
 
@@ -16,9 +16,9 @@
16
16
  },
17
17
 
18
18
  "format24h": {
19
- "type": "Boolean",
20
- "desc": "Forces 24 hour time display instead of AM/PM system",
21
- "default": "(based on Quasar lang language being used)",
19
+ "type": [ "Boolean", "null" ],
20
+ "default": null,
21
+ "desc": "Forces 24 hour time display instead of AM/PM system; If prop is not set, then the default is based on Quasar lang language being used",
22
22
  "category": "behavior"
23
23
  },
24
24
 
@@ -33,6 +33,7 @@
33
33
  },
34
34
 
35
35
  "mask": {
36
+ "type": [ "String", "null" ],
36
37
  "default": "HH:mm",
37
38
  "examples": [ "HH:mm:ss", "YYYY-MM-DD HH:mm:ss", "HH:mm MMMM Do, YYYY" ]
38
39
  },
@@ -8,12 +8,16 @@
8
8
  "props": {
9
9
  "max-height": {
10
10
  "extends": "size",
11
+ "type": [ "String", "null" ],
12
+ "default": null,
11
13
  "desc": "The maximum height of the Tooltip; Size in CSS units, including unit name",
12
14
  "category": "content"
13
15
  },
14
16
 
15
17
  "max-width": {
16
18
  "extends": "size",
19
+ "type": [ "String", "null" ],
20
+ "default": null,
17
21
  "desc": "The maximum width of the Tooltip; Size in CSS units, including unit name",
18
22
  "category": "content"
19
23
  },
@@ -523,6 +523,8 @@ export default createComponent({
523
523
  + (m.selected === true ? ' q-tree__node--selected' : '')
524
524
  + (m.disabled === true ? ' q-tree__node--disabled' : ''),
525
525
  tabindex: m.link === true ? 0 : -1,
526
+ ariaExpanded: children.length > 0 ? m.expanded : null,
527
+ role: 'treeitem',
526
528
  onClick: (e) => {
527
529
  onClick(node, m, e)
528
530
  },
@@ -596,7 +598,8 @@ export default createComponent({
596
598
  body,
597
599
  h('div', {
598
600
  class: 'q-tree__children'
599
- + (m.disabled === true ? ' q-tree__node--disabled' : '')
601
+ + (m.disabled === true ? ' q-tree__node--disabled' : ''),
602
+ role: 'group'
600
603
  }, children)
601
604
  ])
602
605
  : null
@@ -614,7 +617,8 @@ export default createComponent({
614
617
  body,
615
618
  h('div', {
616
619
  class: 'q-tree__children'
617
- + (m.disabled === true ? ' q-tree__node--disabled' : '')
620
+ + (m.disabled === true ? ' q-tree__node--disabled' : ''),
621
+ role: 'group'
618
622
  }, children)
619
623
  ]),
620
624
  [ [ vShow, m.expanded ] ]
@@ -708,7 +712,8 @@ export default createComponent({
708
712
 
709
713
  return h(
710
714
  'div', {
711
- class: classes.value
715
+ class: classes.value,
716
+ role: 'tree'
712
717
  },
713
718
  children.length === 0
714
719
  ? (