quasar 2.9.1 → 2.10.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 (171) hide show
  1. package/dist/api/QBreadcrumbsEl.json +0 -14
  2. package/dist/api/QBtnDropdown.json +36 -0
  3. package/dist/api/QPagination.json +134 -102
  4. package/dist/api/QTabs.json +1 -1
  5. package/dist/api/QTree.json +6 -0
  6. package/dist/api/TouchPan.json +0 -4
  7. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  8. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  10. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  11. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  12. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  13. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  14. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  16. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  17. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  18. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  19. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  20. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  21. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  24. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  25. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  26. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  43. package/dist/icon-set/themify.umd.prod.js +1 -1
  44. package/dist/lang/ar-TN.umd.prod.js +1 -1
  45. package/dist/lang/ar.umd.prod.js +1 -1
  46. package/dist/lang/az-Latn.umd.prod.js +1 -1
  47. package/dist/lang/bg.umd.prod.js +1 -1
  48. package/dist/lang/bn.umd.prod.js +1 -1
  49. package/dist/lang/ca.umd.prod.js +1 -1
  50. package/dist/lang/cs.umd.prod.js +1 -1
  51. package/dist/lang/da.umd.prod.js +1 -1
  52. package/dist/lang/de.umd.prod.js +1 -1
  53. package/dist/lang/el.umd.prod.js +1 -1
  54. package/dist/lang/en-GB.umd.prod.js +1 -1
  55. package/dist/lang/en-US.umd.prod.js +1 -1
  56. package/dist/lang/eo.umd.prod.js +1 -1
  57. package/dist/lang/es.umd.prod.js +1 -1
  58. package/dist/lang/et.umd.prod.js +1 -1
  59. package/dist/lang/eu.umd.prod.js +1 -1
  60. package/dist/lang/fa-IR.umd.prod.js +1 -1
  61. package/dist/lang/fa.umd.prod.js +1 -1
  62. package/dist/lang/fi.umd.prod.js +1 -1
  63. package/dist/lang/fr.umd.prod.js +1 -1
  64. package/dist/lang/gn.umd.prod.js +1 -1
  65. package/dist/lang/he.umd.prod.js +1 -1
  66. package/dist/lang/hr.umd.prod.js +1 -1
  67. package/dist/lang/hu.umd.prod.js +1 -1
  68. package/dist/lang/id.umd.prod.js +1 -1
  69. package/dist/lang/is.umd.prod.js +1 -1
  70. package/dist/lang/it.umd.prod.js +1 -1
  71. package/dist/lang/ja.umd.prod.js +1 -1
  72. package/dist/lang/km.umd.prod.js +1 -1
  73. package/dist/lang/ko-KR.umd.prod.js +1 -1
  74. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  75. package/dist/lang/kz.umd.prod.js +1 -1
  76. package/dist/lang/lt.umd.prod.js +1 -1
  77. package/dist/lang/lu.umd.prod.js +1 -1
  78. package/dist/lang/lv.umd.prod.js +1 -1
  79. package/dist/lang/ml.umd.prod.js +1 -1
  80. package/dist/lang/mm.umd.prod.js +1 -1
  81. package/dist/lang/ms.umd.prod.js +1 -1
  82. package/dist/lang/my.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/sm.umd.prod.js +1 -1
  93. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  94. package/dist/lang/sr.umd.prod.js +1 -1
  95. package/dist/lang/sv.umd.prod.js +1 -1
  96. package/dist/lang/ta.umd.prod.js +1 -1
  97. package/dist/lang/th.umd.prod.js +1 -1
  98. package/dist/lang/tr.umd.prod.js +1 -1
  99. package/dist/lang/ug.umd.prod.js +1 -1
  100. package/dist/lang/uk.umd.prod.js +1 -1
  101. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  102. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  103. package/dist/lang/vi.umd.prod.js +1 -1
  104. package/dist/lang/zh-CN.umd.prod.js +1 -1
  105. package/dist/lang/zh-TW.umd.prod.js +1 -1
  106. package/dist/quasar.cjs.prod.js +2 -2
  107. package/dist/quasar.css +10 -0
  108. package/dist/quasar.esm.js +554 -349
  109. package/dist/quasar.esm.prod.js +2 -2
  110. package/dist/quasar.prod.css +1 -1
  111. package/dist/quasar.rtl.css +26 -0
  112. package/dist/quasar.rtl.prod.css +1 -1
  113. package/dist/quasar.sass +11 -1
  114. package/dist/quasar.umd.js +554 -349
  115. package/dist/quasar.umd.prod.js +2 -2
  116. package/dist/transforms/auto-import.json +7 -3
  117. package/dist/transforms/import-map.json +2 -0
  118. package/dist/types/index.d.ts +70 -51
  119. package/dist/vetur/quasar-attributes.json +65 -49
  120. package/dist/vetur/quasar-tags.json +17 -13
  121. package/dist/web-types/web-types.json +131 -97
  122. package/package.json +1 -1
  123. package/src/components/badge/QBadge.js +1 -1
  124. package/src/components/badge/__tests__/QBadge.spec.js +98 -23
  125. package/src/components/breadcrumbs/QBreadcrumbsEl.json +0 -4
  126. package/src/components/breadcrumbs/__tests__/BasicBreadcrumbs.vue +7 -0
  127. package/src/components/breadcrumbs/__tests__/BreadcrumbWithSeparatorSlot.vue +11 -0
  128. package/src/components/breadcrumbs/__tests__/QBreadcrumbs.spec.js +112 -0
  129. package/src/components/breadcrumbs/__tests__/QBreadcrumbsEl.spec.js +87 -0
  130. package/src/components/btn/use-btn.js +24 -14
  131. package/src/components/btn-dropdown/QBtnDropdown.js +39 -16
  132. package/src/components/btn-dropdown/QBtnDropdown.json +1 -1
  133. package/src/components/btn-toggle/QBtnToggle.js +14 -14
  134. package/src/components/checkbox/use-checkbox.js +1 -1
  135. package/src/components/chip/QChip.js +14 -11
  136. package/src/components/dialog/QDialog.js +2 -1
  137. package/src/components/dialog-bottom-sheet/BottomSheet.js +6 -2
  138. package/src/components/drawer/QDrawer.js +5 -3
  139. package/src/components/footer/QFooter.js +5 -3
  140. package/src/components/header/QHeader.js +5 -3
  141. package/src/components/input/use-mask.js +1 -1
  142. package/src/components/item/QItem.js +1 -0
  143. package/src/components/item/QList.js +1 -1
  144. package/src/components/option-group/QOptionGroup.js +1 -1
  145. package/src/components/page/QPage.js +11 -4
  146. package/src/components/page/QPageContainer.js +5 -3
  147. package/src/components/page-sticky/use-page-sticky.js +5 -3
  148. package/src/components/pagination/QPagination.js +265 -188
  149. package/src/components/pagination/QPagination.json +82 -65
  150. package/src/components/pagination/QPagination.sass +14 -0
  151. package/src/components/pull-to-refresh/QPullToRefresh.js +1 -4
  152. package/src/components/resize-observer/QResizeObserver.js +14 -10
  153. package/src/components/stepper/QStep.js +7 -5
  154. package/src/components/tab-panels/QTabPanel.js +1 -1
  155. package/src/components/tabs/QTabs.js +2 -9
  156. package/src/components/tabs/QTabs.json +1 -1
  157. package/src/components/tabs/use-tab.js +5 -3
  158. package/src/components/timeline/QTimelineEntry.js +5 -3
  159. package/src/components/toolbar/QToolbar.js +1 -1
  160. package/src/components/tooltip/QTooltip.js +1 -1
  161. package/src/components/tree/QTree.js +33 -20
  162. package/src/components/tree/QTree.json +7 -0
  163. package/src/components/uploader/QUploaderAddTrigger.js +7 -3
  164. package/src/composables/private/use-file.js +10 -1
  165. package/src/directives/TouchHold.js +10 -3
  166. package/src/directives/TouchPan.js +21 -8
  167. package/src/directives/TouchPan.json +0 -5
  168. package/src/directives/TouchRepeat.js +20 -6
  169. package/src/directives/TouchSwipe.js +10 -3
  170. package/src/utils/morph.js +7 -3
  171. package/src/utils/private/symbols.js +2 -0
@@ -0,0 +1,112 @@
1
+ import { mount } from '@cypress/vue'
2
+ import { alignMap, alignValues } from '../../../composables/private/use-align.js'
3
+ import BasicBreadcrumbs from './BasicBreadcrumbs.vue'
4
+ import BreadcrumbWithSeparatorSlot from './BreadcrumbWithSeparatorSlot.vue'
5
+
6
+ const gutterValues = [ 'xs', 'sm', 'md', 'lg', 'xl' ]
7
+
8
+ describe('Breadcrumbs API', () => {
9
+ describe('Props', () => {
10
+ describe('Category: content', () => {
11
+ describe('(prop): separator', () => {
12
+ it('should render a custom separator based on the defined value', () => {
13
+ const customSeparator = '>'
14
+
15
+ mount(BasicBreadcrumbs, {
16
+ props: {
17
+ separator: customSeparator
18
+ }
19
+ })
20
+ cy.get('.q-breadcrumbs__separator')
21
+ .each(($el) => cy.wrap($el).should('contain', customSeparator))
22
+ })
23
+ })
24
+
25
+ describe('(prop): gutter', () => {
26
+ it(`should render a breadcrumb with a gutter based on defined values: ${ gutterValues.join(', ') }`, () => {
27
+ mount(BasicBreadcrumbs)
28
+
29
+ // loop through each gutter value
30
+ for (const gutter of gutterValues) {
31
+ cy.get('.q-breadcrumbs > div')
32
+ .then(() => Cypress.vueWrapper.setProps({ gutter }))
33
+ .should('have.class', `q-gutter-${ gutter }`)
34
+ }
35
+ })
36
+
37
+ it('should render a breadcrumb with no gutter when the value is set to "none"', () => {
38
+ mount(BasicBreadcrumbs, {
39
+ props: {
40
+ gutter: 'none'
41
+ }
42
+ })
43
+ cy.get('.q-breadcrumbs > div')
44
+ .should('not.have.class', 'q-gutter')
45
+ })
46
+ })
47
+
48
+ describe('(prop): align', () => {
49
+ it(`should render a breadcrumb aligned based on defined values: ${ alignValues.join(', ') }`, () => {
50
+ mount(BasicBreadcrumbs)
51
+
52
+ // loop over alignValues
53
+ for (const align of alignValues) {
54
+ cy.get('.q-breadcrumbs > div')
55
+ .then(() => Cypress.vueWrapper.setProps({ align }))
56
+ .should('have.class', `justify-${ alignMap[ align ] }`)
57
+ }
58
+ })
59
+ })
60
+ })
61
+
62
+ describe('Category: style', () => {
63
+ describe('(prop): active-color', () => {
64
+ it('should change breadcrumb item color based on Quasar Color Palette', () => {
65
+ const activeColor = 'red'
66
+
67
+ mount(BasicBreadcrumbs, {
68
+ props: {
69
+ activeColor
70
+ }
71
+ })
72
+ cy.get('.q-breadcrumbs > div > .flex.items-center:not(.q-breadcrumbs--last)')
73
+ .each(($el) => cy.wrap($el).should('have.class', `text-${ activeColor }`))
74
+ })
75
+ })
76
+
77
+ describe('(prop): separator-color', () => {
78
+ it('should change breadcrumb separator color based on Quasar Color Palette', () => {
79
+ const separatorColor = 'red'
80
+
81
+ mount(BasicBreadcrumbs, {
82
+ props: {
83
+ separatorColor
84
+ }
85
+ })
86
+ cy.get('.q-breadcrumbs__separator')
87
+ .each(($el) => cy.wrap($el).should('have.class', `text-${ separatorColor }`))
88
+ })
89
+ })
90
+ })
91
+ })
92
+
93
+ describe('Slots', () => {
94
+ describe('(slot): default', () => {
95
+ it('should display the default slot content', () => {
96
+ mount(BasicBreadcrumbs)
97
+
98
+ cy.get('.q-breadcrumbs > div')
99
+ .should('contain', 'Home')
100
+ })
101
+ })
102
+
103
+ describe('(slot): separator', () => {
104
+ it('should display the separator slot content', () => {
105
+ mount(BreadcrumbWithSeparatorSlot)
106
+
107
+ cy.get('.q-breadcrumbs__separator')
108
+ .should('contain', 'arrow_forward')
109
+ })
110
+ })
111
+ })
112
+ })
@@ -0,0 +1,87 @@
1
+ import { mount } from '@cypress/vue'
2
+ import QBreadcrumbsEl from '../QBreadcrumbsEl.js'
3
+
4
+ describe('BreadcrumbsEl API', () => {
5
+ describe('Props', () => {
6
+ describe('Category: content', () => {
7
+ describe('(prop): label', () => {
8
+ it('should render a label inside the breadcrumb element', () => {
9
+ const label = 'Breadcrumb label'
10
+
11
+ mount(QBreadcrumbsEl, {
12
+ props: { label }
13
+ })
14
+
15
+ cy.get('.q-breadcrumbs__el')
16
+ .should('contain', label)
17
+ })
18
+ })
19
+
20
+ describe('(prop): icon', () => {
21
+ it('should render on the left of the breadcrumb element', () => {
22
+ const icon = 'home'
23
+
24
+ mount(QBreadcrumbsEl, {
25
+ props: { icon }
26
+ })
27
+
28
+ cy.get('.q-breadcrumbs__el')
29
+ .should('contain', icon)
30
+ })
31
+ })
32
+
33
+ describe('(prop): tag', () => {
34
+ it('should render a custom tag', () => {
35
+ const tag = 'a'
36
+
37
+ mount(QBreadcrumbsEl, {
38
+ props: { tag }
39
+ })
40
+
41
+ cy.get('.q-breadcrumbs__el')
42
+ .should('have.prop', 'tagName', tag.toUpperCase())
43
+ })
44
+ })
45
+ })
46
+
47
+ describe('Category: style', () => {
48
+ it.skip(' ', () => {
49
+ //
50
+ })
51
+ })
52
+ })
53
+
54
+ describe('Slots', () => {
55
+ describe('(slot): default', () => {
56
+ it('should render the default slot', () => {
57
+ const label = 'Breadcrumb label'
58
+
59
+ mount(QBreadcrumbsEl, {
60
+ slots: { default: label }
61
+ })
62
+
63
+ cy.get('.q-breadcrumbs__el')
64
+ .should('contain', label)
65
+ })
66
+ })
67
+ })
68
+
69
+ describe('Events', () => {
70
+ describe('(event): click', () => {
71
+ it('should emit "click" event when clicked', () => {
72
+ const fn = cy.stub()
73
+
74
+ mount(QBreadcrumbsEl, {
75
+ props: {
76
+ label: 'clicked breadcrumb',
77
+ onClick: fn
78
+ }
79
+ })
80
+
81
+ cy.get('.q-breadcrumbs__el')
82
+ .click()
83
+ .then(() => expect(fn).to.be.calledOnce)
84
+ })
85
+ })
86
+ })
87
+ })
@@ -4,7 +4,7 @@ import useAlign, { useAlignProps } from '../../composables/private/use-align.js'
4
4
  import useSize, { useSizeProps } from '../../composables/private/use-size.js'
5
5
  import useRouterLink, { useRouterLinkProps } from '../../composables/private/use-router-link.js'
6
6
 
7
- const padding = {
7
+ export const btnPadding = {
8
8
  none: 0,
9
9
  xs: 4,
10
10
  sm: 8,
@@ -24,6 +24,21 @@ const defaultSizes = {
24
24
  const formTypes = [ 'button', 'submit', 'reset' ]
25
25
  const mediaTypeRE = /[^\s]\/[^\s]/
26
26
 
27
+ export const btnDesignOptions = [ 'flat', 'outline', 'push', 'unelevated' ]
28
+ export const getBtnDesign = (props, defaultValue) => {
29
+ if (props.flat === true) return 'flat'
30
+ if (props.outline === true) return 'outline'
31
+ if (props.push === true) return 'push'
32
+ if (props.unelevated === true) return 'unelevated'
33
+ return defaultValue
34
+ }
35
+ export const getBtnDesignAttr = props => {
36
+ const design = getBtnDesign(props)
37
+ return design !== void 0
38
+ ? { [ design ]: true }
39
+ : {}
40
+ }
41
+
27
42
  export const useBtnProps = {
28
43
  ...useSizeProps,
29
44
  ...useRouterLinkProps,
@@ -37,13 +52,14 @@ export const useBtnProps = {
37
52
  icon: String,
38
53
  iconRight: String,
39
54
 
40
- round: Boolean,
55
+ ...btnDesignOptions.reduce(
56
+ (acc, val) => (acc[ val ] = Boolean) && acc,
57
+ {}
58
+ ),
59
+
41
60
  square: Boolean,
42
- outline: Boolean,
43
- flat: Boolean,
44
- unelevated: Boolean,
61
+ round: Boolean,
45
62
  rounded: Boolean,
46
- push: Boolean,
47
63
  glossy: Boolean,
48
64
 
49
65
  size: String,
@@ -93,7 +109,7 @@ export default function (props) {
93
109
  ? Object.assign({}, obj, {
94
110
  padding: props.padding
95
111
  .split(/\s+/)
96
- .map(v => (v in padding ? padding[ v ] + 'px' : v))
112
+ .map(v => (v in btnPadding ? btnPadding[ v ] + 'px' : v))
97
113
  .join(' '),
98
114
  minWidth: '0',
99
115
  minHeight: '0'
@@ -113,13 +129,7 @@ export default function (props) {
113
129
  isActionable.value === true ? props.tabindex || 0 : -1
114
130
  ))
115
131
 
116
- const design = computed(() => {
117
- if (props.flat === true) return 'flat'
118
- if (props.outline === true) return 'outline'
119
- if (props.push === true) return 'push'
120
- if (props.unelevated === true) return 'unelevated'
121
- return 'standard'
122
- })
132
+ const design = computed(() => getBtnDesign(props, 'standard'))
123
133
 
124
134
  const attributes = computed(() => {
125
135
  const acc = { tabindex: tabIndex.value }
@@ -5,18 +5,40 @@ import QBtn from '../btn/QBtn.js'
5
5
  import QBtnGroup from '../btn-group/QBtnGroup.js'
6
6
  import QMenu from '../menu/QMenu.js'
7
7
 
8
- import { useBtnProps } from '../btn/use-btn.js'
8
+ import { getBtnDesignAttr, useBtnProps } from '../btn/use-btn.js'
9
+ import { useTransitionProps } from '../../composables/private/use-transition.js'
9
10
 
10
11
  import { createComponent } from '../../utils/private/create.js'
11
12
  import { stop } from '../../utils/event.js'
12
13
  import uid from '../../utils/uid.js'
13
14
  import { hSlot } from '../../utils/private/render.js'
14
15
 
16
+ const btnPropsList = Object.keys(useBtnProps)
17
+
18
+ // let's not duplicate type checking and prop validations
19
+ // so just specify the props here with no type description
20
+ const btnProps = btnPropsList.reduce(
21
+ (acc, key) => (acc[ key ] = {}) && acc,
22
+ {}
23
+ )
24
+
25
+ export const passBtnProps = props => btnPropsList.reduce(
26
+ (acc, key) => {
27
+ const val = props[ key ]
28
+ if (val !== void 0) {
29
+ acc[ key ] = val
30
+ }
31
+ return acc
32
+ },
33
+ {}
34
+ )
35
+
15
36
  export default createComponent({
16
37
  name: 'QBtnDropdown',
17
38
 
18
39
  props: {
19
- ...useBtnProps,
40
+ ...btnProps,
41
+ ...useTransitionProps,
20
42
 
21
43
  modelValue: Boolean,
22
44
  split: Boolean,
@@ -57,7 +79,7 @@ export default createComponent({
57
79
  const menuRef = ref(null)
58
80
  const targetUid = uid()
59
81
 
60
- const attributes = computed(() => {
82
+ const ariaAttrs = computed(() => {
61
83
  const acc = {
62
84
  'aria-expanded': showing.value === true ? 'true' : 'false',
63
85
  'aria-haspopup': 'true',
@@ -85,6 +107,9 @@ export default createComponent({
85
107
  + (props.split === false ? ' q-btn-dropdown__arrow-container' : '')
86
108
  )
87
109
 
110
+ const btnDesignAttr = computed(() => getBtnDesignAttr(props))
111
+ const btnProps = computed(() => passBtnProps(props))
112
+
88
113
  watch(() => props.modelValue, val => {
89
114
  menuRef.value !== null && menuRef.value[ val ? 'show' : 'hide' ]()
90
115
  })
@@ -165,6 +190,9 @@ export default createComponent({
165
190
  self: props.menuSelf,
166
191
  offset: props.menuOffset,
167
192
  separateClosePopup: true,
193
+ transitionShow: props.transitionShow,
194
+ transitionHide: props.transitionHide,
195
+ transitionDuration: props.transitionDuration,
168
196
  onBeforeShow,
169
197
  onShow,
170
198
  onBeforeHide,
@@ -175,11 +203,11 @@ export default createComponent({
175
203
  if (props.split === false) {
176
204
  return h(QBtn, {
177
205
  class: 'q-btn-dropdown q-btn-dropdown--simple',
178
- ...props,
206
+ ...btnProps.value,
207
+ ...ariaAttrs.value,
179
208
  disable: props.disable === true || props.disableMainBtn === true,
180
209
  noWrap: true,
181
210
  round: false,
182
- ...attributes.value,
183
211
  onClick
184
212
  }, {
185
213
  default: () => hSlot(slots.label, []).concat(Arrow),
@@ -189,21 +217,17 @@ export default createComponent({
189
217
 
190
218
  return h(QBtnGroup, {
191
219
  class: 'q-btn-dropdown q-btn-dropdown--split no-wrap q-btn-item',
192
- outline: props.outline,
193
- flat: props.flat,
194
220
  rounded: props.rounded,
195
221
  square: props.square,
196
- push: props.push,
197
- unelevated: props.unelevated,
222
+ ...btnDesignAttr.value,
198
223
  glossy: props.glossy,
199
224
  stretch: props.stretch
200
225
  }, () => [
201
226
  h(QBtn, {
202
227
  class: 'q-btn-dropdown--current',
203
- ...props,
228
+ ...btnProps.value,
204
229
  disable: props.disable === true || props.disableMainBtn === true,
205
230
  noWrap: true,
206
- iconRight: props.iconRight,
207
231
  round: false,
208
232
  onClick: onClickHide
209
233
  }, {
@@ -213,16 +237,15 @@ export default createComponent({
213
237
 
214
238
  h(QBtn, {
215
239
  class: 'q-btn-dropdown__arrow-container q-anchor--skip',
216
- ...attributes.value,
240
+ ...ariaAttrs.value,
241
+ ...btnDesignAttr.value,
217
242
  disable: props.disable === true || props.disableDropdown === true,
218
- outline: props.outline,
219
- flat: props.flat,
220
243
  rounded: props.rounded,
221
- push: props.push,
222
- size: props.size,
223
244
  color: props.color,
224
245
  textColor: props.textColor,
225
246
  dense: props.dense,
247
+ size: props.size,
248
+ padding: props.padding,
226
249
  ripple: props.ripple
227
250
  }, () => Arrow)
228
251
  ])
@@ -1,5 +1,5 @@
1
1
  {
2
- "mixins": [ "components/btn/use-btn", "composables/private/use-model-toggle" ],
2
+ "mixins": [ "components/btn/use-btn", "composables/private/use-model-toggle", "composables/private/use-transition" ],
3
3
 
4
4
  "meta": {
5
5
  "docsUrl": "https://v2.quasar.dev/vue-components/button-dropdown"
@@ -7,6 +7,7 @@ import { createComponent } from '../../utils/private/create.js'
7
7
  import { useFormInject, useFormProps } from '../../composables/private/use-form.js'
8
8
 
9
9
  import { hMergeSlot } from '../../utils/private/render.js'
10
+ import { getBtnDesignAttr } from '../btn/use-btn.js'
10
11
 
11
12
  export default createComponent({
12
13
  name: 'QBtnToggle',
@@ -80,6 +81,14 @@ export default createComponent({
80
81
 
81
82
  const injectFormInput = useFormInject(formAttrs)
82
83
 
84
+ const btnDesignAttr = computed(() => getBtnDesignAttr(props))
85
+
86
+ const btnOptionDesign = computed(() => ({
87
+ rounded: props.rounded,
88
+ dense: props.dense,
89
+ ...btnDesignAttr.value
90
+ }))
91
+
83
92
  const btnOptions = computed(() => props.options.map((item, i) => {
84
93
  const { attrs, value, slot, ...opt } = item
85
94
 
@@ -87,19 +96,11 @@ export default createComponent({
87
96
  slot,
88
97
  props: {
89
98
  key: i,
90
- onClick (e) { set(value, item, e) },
91
99
 
92
100
  'aria-pressed': value === props.modelValue ? 'true' : 'false',
93
-
94
101
  ...attrs,
95
102
  ...opt,
96
-
97
- outline: props.outline,
98
- flat: props.flat,
99
- rounded: props.rounded,
100
- push: props.push,
101
- unelevated: props.unelevated,
102
- dense: props.dense,
103
+ ...btnOptionDesign.value,
103
104
 
104
105
  disable: props.disable === true || opt.disable === true,
105
106
 
@@ -117,7 +118,9 @@ export default createComponent({
117
118
  padding: mergeOpt(opt, 'padding'),
118
119
  ripple: mergeOpt(opt, 'ripple'),
119
120
  stack: mergeOpt(opt, 'stack') === true,
120
- stretch: mergeOpt(opt, 'stretch') === true
121
+ stretch: mergeOpt(opt, 'stretch') === true,
122
+
123
+ onClick (e) { set(value, item, e) }
121
124
  }
122
125
  }
123
126
  }))
@@ -156,12 +159,9 @@ export default createComponent({
156
159
 
157
160
  return () => h(QBtnGroup, {
158
161
  class: 'q-btn-toggle',
159
- outline: props.outline,
160
- flat: props.flat,
162
+ ...btnDesignAttr.value,
161
163
  rounded: props.rounded,
162
- push: props.push,
163
164
  stretch: props.stretch,
164
- unelevated: props.unelevated,
165
165
  glossy: props.glossy,
166
166
  spread: props.spread
167
167
  }, getContent)
@@ -127,7 +127,7 @@ export default function (type, getInner) {
127
127
  const attributes = computed(() => {
128
128
  const attrs = {
129
129
  tabindex: tabindex.value,
130
- role: 'checkbox',
130
+ role: type === 'toggle' ? 'switch' : 'checkbox',
131
131
  'aria-label': props.label,
132
132
  'aria-checked': isIndeterminate.value === true
133
133
  ? 'mixed'
@@ -102,16 +102,19 @@ export default createComponent({
102
102
  + (isDark.value === true ? ' q-chip--dark q-dark' : '')
103
103
  })
104
104
 
105
- const attributes = computed(() => (
106
- props.disable === true
105
+ const attributes = computed(() => {
106
+ const chip = props.disable === true
107
107
  ? { tabindex: -1, 'aria-disabled': 'true' }
108
- : {
109
- tabindex: props.tabindex || 0,
110
- role: 'button',
111
- 'aria-hidden': 'false',
112
- 'aria-label': props.removeAriaLabel || $q.lang.label.remove
113
- }
114
- ))
108
+ : { tabindex: props.tabindex || 0 }
109
+ const remove = {
110
+ ...chip,
111
+ role: 'button',
112
+ 'aria-hidden': 'false',
113
+ 'aria-label': props.removeAriaLabel || $q.lang.label.remove
114
+ }
115
+
116
+ return { chip, remove }
117
+ })
115
118
 
116
119
  function onKeyup (e) {
117
120
  e.keyCode === 13 /* ENTER */ && onClick(e)
@@ -169,7 +172,7 @@ export default createComponent({
169
172
  h(QIcon, {
170
173
  class: 'q-chip__icon q-chip__icon--remove cursor-pointer',
171
174
  name: removeIcon.value,
172
- ...attributes.value,
175
+ ...attributes.value.remove,
173
176
  onClick: onRemove,
174
177
  onKeyup: onRemove
175
178
  })
@@ -188,7 +191,7 @@ export default createComponent({
188
191
 
189
192
  isClickable.value === true && Object.assign(
190
193
  data,
191
- attributes.value,
194
+ attributes.value.chip,
192
195
  { onClick, onKeyup }
193
196
  )
194
197
 
@@ -376,7 +376,8 @@ export default createComponent({
376
376
 
377
377
  function renderPortalContent () {
378
378
  return h('div', {
379
- 'aria-modal': 'true',
379
+ role: 'dialog',
380
+ 'aria-modal': useBackdrop.value === true ? 'true' : 'false',
380
381
  ...attrs,
381
382
  class: rootClasses.value
382
383
  }, [
@@ -70,6 +70,7 @@ export default createComponent({
70
70
  action.class
71
71
  ],
72
72
  tabindex: 0,
73
+ role: 'listitem',
73
74
  onClick () { onOk(action) },
74
75
  onKeyup (e) { e.keyCode === 13 && onOk(action) }
75
76
  }, [
@@ -145,9 +146,12 @@ export default createComponent({
145
146
  child.push(
146
147
  props.grid === true
147
148
  ? h('div', {
148
- class: 'row items-stretch justify-start'
149
+ class: 'row items-stretch justify-start',
150
+ role: 'list'
149
151
  }, getGrid())
150
- : h('div', getList())
152
+ : h('div', {
153
+ role: 'list'
154
+ }, getList())
151
155
  )
152
156
 
153
157
  return child
@@ -11,7 +11,7 @@ import TouchPan from '../../directives/TouchPan.js'
11
11
  import { createComponent } from '../../utils/private/create.js'
12
12
  import { between } from '../../utils/format.js'
13
13
  import { hSlot, hDir } from '../../utils/private/render.js'
14
- import { layoutKey } from '../../utils/private/symbols.js'
14
+ import { layoutKey, emptyRenderFn } from '../../utils/private/symbols.js'
15
15
 
16
16
  const duration = 150
17
17
 
@@ -77,9 +77,11 @@ export default createComponent({
77
77
  const { preventBodyScroll } = usePreventScroll()
78
78
  const { registerTimeout, removeTimeout } = useTimeout()
79
79
 
80
- const $layout = inject(layoutKey, () => {
80
+ const $layout = inject(layoutKey, emptyRenderFn)
81
+ if ($layout === emptyRenderFn) {
81
82
  console.error('QDrawer needs to be child of QLayout')
82
- })
83
+ return emptyRenderFn
84
+ }
83
85
 
84
86
  let lastDesktopState, timerMini, layoutTotalWidthWatcher
85
87
 
@@ -6,7 +6,7 @@ import QResizeObserver from '../resize-observer/QResizeObserver.js'
6
6
 
7
7
  import { createComponent } from '../../utils/private/create.js'
8
8
  import { hMergeSlot } from '../../utils/private/render.js'
9
- import { layoutKey } from '../../utils/private/symbols.js'
9
+ import { layoutKey, emptyRenderFn } from '../../utils/private/symbols.js'
10
10
 
11
11
  export default createComponent({
12
12
  name: 'QFooter',
@@ -31,9 +31,11 @@ export default createComponent({
31
31
  setup (props, { slots, emit }) {
32
32
  const { proxy: { $q } } = getCurrentInstance()
33
33
 
34
- const $layout = inject(layoutKey, () => {
34
+ const $layout = inject(layoutKey, emptyRenderFn)
35
+ if ($layout === emptyRenderFn) {
35
36
  console.error('QFooter needs to be child of QLayout')
36
- })
37
+ return emptyRenderFn
38
+ }
37
39
 
38
40
  const size = ref(parseInt(props.heightHint, 10))
39
41
  const revealed = ref(true)
@@ -4,7 +4,7 @@ import QResizeObserver from '../resize-observer/QResizeObserver.js'
4
4
 
5
5
  import { createComponent } from '../../utils/private/create.js'
6
6
  import { hUniqueSlot } from '../../utils/private/render.js'
7
- import { layoutKey } from '../../utils/private/symbols.js'
7
+ import { layoutKey, emptyRenderFn } from '../../utils/private/symbols.js'
8
8
 
9
9
  export default createComponent({
10
10
  name: 'QHeader',
@@ -33,9 +33,11 @@ export default createComponent({
33
33
  setup (props, { slots, emit }) {
34
34
  const { proxy: { $q } } = getCurrentInstance()
35
35
 
36
- const $layout = inject(layoutKey, () => {
36
+ const $layout = inject(layoutKey, emptyRenderFn)
37
+ if ($layout === emptyRenderFn) {
37
38
  console.error('QHeader needs to be child of QLayout')
38
- })
39
+ return emptyRenderFn
40
+ }
39
41
 
40
42
  const size = ref(parseInt(props.heightHint, 10))
41
43
  const revealed = ref(true)
@@ -166,7 +166,7 @@ export default function (props, emit, emitValue, inputRef) {
166
166
  '^'
167
167
  + unmask.join('')
168
168
  + '(' + (unmaskChar === '' ? '.' : '[^' + unmaskChar + ']') + '+)?'
169
- + '$'
169
+ + (unmaskChar === '' ? '' : '[' + unmaskChar + ']*') + '$'
170
170
  ),
171
171
  extractLast = extract.length - 1,
172
172
  extractMatcher = extract.map((re, index) => {
@@ -136,6 +136,7 @@ export default createComponent({
136
136
  ref: rootRef,
137
137
  class: classes.value,
138
138
  style: style.value,
139
+ role: 'listitem',
139
140
  onClick,
140
141
  onKeyup
141
142
  }
@@ -29,6 +29,6 @@ export default createComponent({
29
29
  + (props.padding === true ? ' q-list--padding' : '')
30
30
  )
31
31
 
32
- return () => h('div', { class: classes.value }, hSlot(slots.default))
32
+ return () => h('div', { class: classes.value, role: 'list' }, hSlot(slots.default))
33
33
  }
34
34
  })
@@ -74,7 +74,7 @@ export default createComponent({
74
74
  )
75
75
 
76
76
  const attrs = computed(() => {
77
- const attrs = {}
77
+ const attrs = { role: 'group' }
78
78
 
79
79
  if (props.type === 'radio') {
80
80
  attrs.role = 'radiogroup'