quasar 2.16.11 → 2.17.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 (184) hide show
  1. package/dist/api/Platform.json +1 -1
  2. package/dist/api/QOptionGroup.json +1 -1
  3. package/dist/api/QScrollArea.json +1 -1
  4. package/dist/api/QSelect.json +1 -1
  5. package/dist/api/QUploader.json +1 -1
  6. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  7. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  10. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  11. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  12. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  13. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  14. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  16. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  17. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  18. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  19. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  20. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  21. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  24. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  25. package/dist/icon-set/mdi-v7.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-mdi-v7.umd.prod.js +1 -1
  43. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  44. package/dist/icon-set/themify.umd.prod.js +1 -1
  45. package/dist/lang/ar-TN.umd.prod.js +1 -1
  46. package/dist/lang/ar.umd.prod.js +1 -1
  47. package/dist/lang/az-Latn.umd.prod.js +1 -1
  48. package/dist/lang/bg.umd.prod.js +1 -1
  49. package/dist/lang/bn.umd.prod.js +1 -1
  50. package/dist/lang/bs-BA.umd.prod.js +1 -1
  51. package/dist/lang/ca.umd.prod.js +1 -1
  52. package/dist/lang/cs.umd.prod.js +1 -1
  53. package/dist/lang/da.umd.prod.js +1 -1
  54. package/dist/lang/de-CH.umd.prod.js +1 -1
  55. package/dist/lang/de-DE.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/eu.umd.prod.js +1 -1
  64. package/dist/lang/fa-IR.umd.prod.js +1 -1
  65. package/dist/lang/fa.umd.prod.js +1 -1
  66. package/dist/lang/fi.umd.prod.js +1 -1
  67. package/dist/lang/fr.umd.prod.js +1 -1
  68. package/dist/lang/gn.umd.prod.js +1 -1
  69. package/dist/lang/he.umd.prod.js +1 -1
  70. package/dist/lang/hi.umd.prod.js +1 -1
  71. package/dist/lang/hr.umd.prod.js +1 -1
  72. package/dist/lang/hu.umd.prod.js +1 -1
  73. package/dist/lang/id.umd.prod.js +1 -1
  74. package/dist/lang/is.umd.prod.js +1 -1
  75. package/dist/lang/it.umd.prod.js +1 -1
  76. package/dist/lang/ja.umd.prod.js +1 -1
  77. package/dist/lang/kk.umd.prod.js +1 -1
  78. package/dist/lang/km.umd.prod.js +1 -1
  79. package/dist/lang/ko-KR.umd.prod.js +1 -1
  80. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  81. package/dist/lang/lt.umd.prod.js +1 -1
  82. package/dist/lang/lu.umd.prod.js +1 -1
  83. package/dist/lang/lv.umd.prod.js +1 -1
  84. package/dist/lang/mk.umd.prod.js +1 -1
  85. package/dist/lang/ml.umd.prod.js +1 -1
  86. package/dist/lang/mm.umd.prod.js +1 -1
  87. package/dist/lang/ms-MY.umd.prod.js +1 -1
  88. package/dist/lang/ms.umd.prod.js +1 -1
  89. package/dist/lang/my.umd.prod.js +1 -1
  90. package/dist/lang/nb-NO.umd.prod.js +1 -1
  91. package/dist/lang/nl.umd.prod.js +1 -1
  92. package/dist/lang/pl.umd.prod.js +1 -1
  93. package/dist/lang/pt-BR.umd.prod.js +1 -1
  94. package/dist/lang/pt.umd.prod.js +1 -1
  95. package/dist/lang/ro.umd.prod.js +1 -1
  96. package/dist/lang/ru.umd.prod.js +1 -1
  97. package/dist/lang/sk.umd.prod.js +1 -1
  98. package/dist/lang/sl.umd.prod.js +1 -1
  99. package/dist/lang/sm.umd.prod.js +1 -1
  100. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  101. package/dist/lang/sr.umd.prod.js +1 -1
  102. package/dist/lang/sv.umd.prod.js +1 -1
  103. package/dist/lang/ta.umd.prod.js +1 -1
  104. package/dist/lang/th.umd.prod.js +1 -1
  105. package/dist/lang/tl.umd.prod.js +1 -1
  106. package/dist/lang/tr.umd.prod.js +1 -1
  107. package/dist/lang/ug.umd.prod.js +1 -1
  108. package/dist/lang/uk.umd.prod.js +1 -1
  109. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  110. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  111. package/dist/lang/vi.umd.prod.js +1 -1
  112. package/dist/lang/zh-CN.umd.prod.js +1 -1
  113. package/dist/lang/zh-TW.umd.prod.js +1 -1
  114. package/dist/quasar.client.js +758 -2145
  115. package/dist/quasar.css +6 -5
  116. package/dist/quasar.prod.css +1 -1
  117. package/dist/quasar.rtl.css +6 -5
  118. package/dist/quasar.rtl.prod.css +1 -1
  119. package/dist/quasar.sass +67 -63
  120. package/dist/quasar.server.prod.cjs +49 -49
  121. package/dist/quasar.server.prod.js +47 -47
  122. package/dist/quasar.umd.js +348 -1738
  123. package/dist/quasar.umd.prod.js +48 -48
  124. package/dist/types/api/slider.d.ts +2 -1
  125. package/dist/types/extras/icon-set.d.ts +11 -6
  126. package/dist/types/index.d.ts +272 -203
  127. package/dist/types/plugin.d.ts +7 -7
  128. package/dist/vetur/quasar-attributes.json +1 -1
  129. package/dist/vetur/quasar-tags.json +1 -1
  130. package/dist/web-types/web-types.json +1 -1
  131. package/package.json +9 -9
  132. package/src/components/menu/QMenu.sass +2 -2
  133. package/src/components/option-group/QOptionGroup.js +38 -15
  134. package/src/components/option-group/QOptionGroup.json +88 -1
  135. package/src/components/scroll-area/QScrollArea.js +115 -107
  136. package/src/components/scroll-area/QScrollArea.json +40 -0
  137. package/src/components/scroll-area/ScrollAreaControls.js +54 -0
  138. package/src/components/select/QSelect.js +16 -18
  139. package/src/components/select/QSelect.json +7 -0
  140. package/src/components/spinner/QSpinnerAudio.js +4 -70
  141. package/src/components/spinner/QSpinnerBall.js +4 -86
  142. package/src/components/spinner/QSpinnerBars.js +4 -125
  143. package/src/components/spinner/QSpinnerBox.js +4 -43
  144. package/src/components/spinner/QSpinnerClock.js +4 -54
  145. package/src/components/spinner/QSpinnerComment.js +4 -66
  146. package/src/components/spinner/QSpinnerCube.js +4 -114
  147. package/src/components/spinner/QSpinnerDots.js +4 -86
  148. package/src/components/spinner/QSpinnerFacebook.js +4 -85
  149. package/src/components/spinner/QSpinnerGears.js +4 -41
  150. package/src/components/spinner/QSpinnerGrid.js +4 -134
  151. package/src/components/spinner/QSpinnerHearts.js +4 -36
  152. package/src/components/spinner/QSpinnerHourglass.js +4 -94
  153. package/src/components/spinner/QSpinnerInfinity.js +4 -25
  154. package/src/components/spinner/QSpinnerIos.js +4 -156
  155. package/src/components/spinner/QSpinnerOrbit.js +4 -33
  156. package/src/components/spinner/QSpinnerOval.js +4 -32
  157. package/src/components/spinner/QSpinnerPie.js +4 -63
  158. package/src/components/spinner/QSpinnerPuff.js +4 -65
  159. package/src/components/spinner/QSpinnerRadio.js +4 -58
  160. package/src/components/spinner/QSpinnerRings.js +4 -88
  161. package/src/components/spinner/QSpinnerTail.js +4 -66
  162. package/src/components/tabs/QRouteTab.js +4 -3
  163. package/src/components/tabs/QTabs.js +28 -15
  164. package/src/components/time/QTime.sass +5 -5
  165. package/src/components/tooltip/QTooltip.sass +2 -0
  166. package/src/components/uploader/QUploader.json +9 -0
  167. package/src/components/uploader/QUploader.sass +0 -1
  168. package/src/components/uploader/uploader-core.js +6 -2
  169. package/src/composables/private.use-key-composition/use-key-composition.js +19 -2
  170. package/src/composables/private.use-panel/use-panel.js +5 -3
  171. package/src/css/core/elevation.sass +6 -4
  172. package/src/css/core/flex.sass +5 -6
  173. package/src/css/core/size.sass +20 -18
  174. package/src/css/core/typography.sass +11 -9
  175. package/src/css/core/visibility.sass +2 -2
  176. package/src/css/flex-addon.sass +22 -20
  177. package/src/css/helpers/math.sass +1 -1
  178. package/src/css/helpers/string.sass +7 -4
  179. package/src/css/variables.sass +14 -9
  180. package/src/plugins/platform/Platform.js +40 -5
  181. package/src/plugins/platform/Platform.json +52 -69
  182. package/src/plugins/platform/Platform.test.js +22 -14
  183. package/src/utils/private.config/nodes.js +1 -3
  184. package/src/utils/private.position-engine/position-engine.js +11 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar",
3
- "version": "2.16.11",
3
+ "version": "2.17.1",
4
4
  "description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time",
5
5
  "type": "module",
6
6
  "module": "dist/quasar.client.js",
@@ -59,23 +59,23 @@
59
59
  },
60
60
  "homepage": "https://quasar.dev",
61
61
  "devDependencies": {
62
- "autoprefixer": "^10.4.19",
62
+ "autoprefixer": "^10.4.20",
63
63
  "cli-highlight": "^2.1.11",
64
64
  "cross-env": "^7.0.3",
65
- "cssnano": "^7.0.4",
65
+ "cssnano": "^7.0.6",
66
66
  "diff": "^5.2.0",
67
- "esbuild": "^0.23.0",
67
+ "esbuild": "^0.24.0",
68
68
  "eslint": "^8.57.0",
69
69
  "fast-glob": "^3.3.2",
70
70
  "fs-extra": "^11.2.0",
71
71
  "kolorist": "^1.8.0",
72
72
  "open": "^10.1.0",
73
- "postcss-rtlcss": "^5.3.0",
74
- "prettier": "^3.3.2",
75
- "sass-embedded": "^1.77.5",
73
+ "postcss-rtlcss": "^5.4.0",
74
+ "prettier": "^3.3.3",
75
+ "sass-embedded": "^1.80.2",
76
76
  "table": "^6.8.2",
77
- "typescript": "^5.4.5",
78
- "vue": "^3.4.31",
77
+ "typescript": "^5.6.2",
78
+ "vue": "^3.5.5",
79
79
  "@quasar/extras": "1.16.12",
80
80
  "eslint-config-quasar": "0.0.1"
81
81
  },
@@ -1,7 +1,8 @@
1
1
  .q-menu
2
2
  position: fixed !important
3
3
  display: inline-block
4
- max-width: $menu-max-width
4
+ max-width: $menu-max-width // required by the position-engine
5
+ max-height: $menu-max-height // required by the position-engine
5
6
 
6
7
  box-shadow: $menu-box-shadow
7
8
  background: $menu-background
@@ -9,7 +10,6 @@
9
10
  overflow-y: auto
10
11
  overflow-x: hidden
11
12
  outline: 0
12
- max-height: 65vh
13
13
  z-index: $z-menu
14
14
 
15
15
  &--square
@@ -7,6 +7,7 @@ import QToggle from '../toggle/QToggle.js'
7
7
  import { createComponent } from '../../utils/private.create/create.js'
8
8
 
9
9
  import useDark, { useDarkProps } from '../../composables/private.use-dark/use-dark.js'
10
+ import { isObject } from '../../utils/is/is.js'
10
11
 
11
12
  const components = {
12
13
  radio: QRadio,
@@ -16,6 +17,16 @@ const components = {
16
17
 
17
18
  const typeValues = Object.keys(components)
18
19
 
20
+ function getPropValueFn (userPropName, defaultPropName) {
21
+ if (typeof userPropName === 'function') return userPropName
22
+
23
+ const propName = userPropName !== void 0
24
+ ? userPropName
25
+ : defaultPropName
26
+
27
+ return opt => opt[ propName ]
28
+ }
29
+
19
30
  export default createComponent({
20
31
  name: 'QOptionGroup',
21
32
 
@@ -27,9 +38,14 @@ export default createComponent({
27
38
  },
28
39
  options: {
29
40
  type: Array,
30
- validator: opts => opts.every(opt => 'value' in opt && 'label' in opt)
41
+ validator: opts => opts.every(isObject),
42
+ default: () => []
31
43
  },
32
44
 
45
+ optionValue: [ Function, String ],
46
+ optionLabel: [ Function, String ],
47
+ optionDisable: [ Function, String ],
48
+
33
49
  name: String,
34
50
 
35
51
  type: {
@@ -66,9 +82,26 @@ export default createComponent({
66
82
  }
67
83
 
68
84
  const isDark = useDark(props, $q)
69
-
70
85
  const component = computed(() => components[ props.type ])
71
86
 
87
+ const getOptionValue = computed(() => getPropValueFn(props.optionValue, 'value'))
88
+ const getOptionLabel = computed(() => getPropValueFn(props.optionLabel, 'label'))
89
+ const getOptionDisable = computed(() => getPropValueFn(props.optionDisable, 'disable'))
90
+
91
+ const innerOptions = computed(() => props.options.map(opt => ({
92
+ val: getOptionValue.value(opt),
93
+ name: opt.name === void 0 ? props.name : opt.name,
94
+ disable: props.disable || getOptionDisable.value(opt),
95
+ leftLabel: opt.leftLabel === void 0 ? props.leftLabel : opt.leftLabel,
96
+ color: opt.color === void 0 ? props.color : opt.color,
97
+ checkedIcon: opt.checkedIcon,
98
+ uncheckedIcon: opt.uncheckedIcon,
99
+ dark: opt.dark === void 0 ? isDark.value : opt.dark,
100
+ size: opt.size === void 0 ? props.size : opt.size,
101
+ dense: props.dense,
102
+ keepColor: opt.keepColor === void 0 ? props.keepColor : opt.keepColor
103
+ })))
104
+
72
105
  const classes = computed(() =>
73
106
  'q-option-group q-gutter-x-sm'
74
107
  + (props.inline === true ? ' q-option-group--inline' : '')
@@ -109,20 +142,10 @@ export default createComponent({
109
142
 
110
143
  return h('div', [
111
144
  h(component.value, {
145
+ label: child === void 0 ? getOptionLabel.value(opt) : null,
112
146
  modelValue: props.modelValue,
113
- val: opt.value,
114
- name: opt.name === void 0 ? props.name : opt.name,
115
- disable: props.disable || opt.disable,
116
- label: child === void 0 ? opt.label : null,
117
- leftLabel: opt.leftLabel === void 0 ? props.leftLabel : opt.leftLabel,
118
- color: opt.color === void 0 ? props.color : opt.color,
119
- checkedIcon: opt.checkedIcon,
120
- uncheckedIcon: opt.uncheckedIcon,
121
- dark: opt.dark || isDark.value,
122
- size: opt.size === void 0 ? props.size : opt.size,
123
- dense: props.dense,
124
- keepColor: opt.keepColor === void 0 ? props.keepColor : opt.keepColor,
125
- 'onUpdate:modelValue': onUpdateModelValue
147
+ 'onUpdate:modelValue': onUpdateModelValue,
148
+ ...innerOptions.value[ i ]
126
149
  }, child)
127
150
  ])
128
151
  }))
@@ -15,6 +15,7 @@
15
15
  "options": {
16
16
  "type": "Array",
17
17
  "desc": "Array of objects with value, label, and disable (optional) props. The binary components will be created according to this array; Props from QToggle, QCheckbox or QRadio can also be added as key/value pairs to control the components singularly",
18
+ "default": "[]",
18
19
  "definition": {
19
20
  "label": {
20
21
  "type": "String",
@@ -39,7 +40,93 @@
39
40
  }
40
41
  },
41
42
  "examples": [ "[ { label: 'Option 1', value: 'op1' }, { label: 'Option 2', value: 'op2' }, { label: 'Option 3', value: 'op3', disable: true } ]" ],
42
- "category": "model"
43
+ "category": "options"
44
+ },
45
+
46
+ "option-value": {
47
+ "type": [ "Function", "String" ],
48
+ "desc": "Property of option which holds the 'value'; If using a function then for best performance, reference it from your scope and do not define it inline",
49
+ "default": "'value'",
50
+ "__runtimeDefault": true,
51
+ "params": {
52
+ "option": {
53
+ "type": [ "String", "Object" ],
54
+ "desc": "The current option being processed",
55
+ "examples": [
56
+ "'Tesla'",
57
+ "'iPhone'",
58
+ "{ label: 'Tesla', value: 'car', cannotSelect: true }"
59
+ ]
60
+ }
61
+ },
62
+ "returns": {
63
+ "type": "Any",
64
+ "desc": "Value of the current option",
65
+ "examples": [ "'car'", "34" ]
66
+ },
67
+ "examples": [
68
+ "'modelNumber'",
69
+ "item => (item === null ? null : item.modelNumber)"
70
+ ],
71
+ "category": "options",
72
+ "addedIn": "v2.17"
73
+ },
74
+
75
+ "option-label": {
76
+ "type": [ "Function", "String" ],
77
+ "desc": "Property of option which holds the 'label'; If using a function then for best performance, reference it from your scope and do not define it inline",
78
+ "default": "'label'",
79
+ "__runtimeDefault": true,
80
+ "params": {
81
+ "option": {
82
+ "type": [ "String", "Object" ],
83
+ "desc": "The current option being processed",
84
+ "examples": [
85
+ "'Tesla'",
86
+ "'iPhone'",
87
+ "{ label: 'Tesla', value: 'car', cannotSelect: true }"
88
+ ]
89
+ }
90
+ },
91
+ "returns": {
92
+ "type": "String",
93
+ "desc": "Label of the current option",
94
+ "examples": [ "'Tesla'", "'iPhone'" ]
95
+ },
96
+ "examples": [
97
+ "'itemName'",
98
+ "item => (item === null ? 'Null value' : item.itemName)"
99
+ ],
100
+ "category": "options",
101
+ "addedIn": "v2.17"
102
+ },
103
+
104
+ "option-disable": {
105
+ "type": [ "Function", "String" ],
106
+ "desc": "Property of option which tells it's disabled; The value of the property must be a Boolean; If using a function then for best performance, reference it from your scope and do not define it inline",
107
+ "default": "'disable'",
108
+ "__runtimeDefault": true,
109
+ "params": {
110
+ "option": {
111
+ "type": [ "String", "Object" ],
112
+ "desc": "The current option being processed",
113
+ "examples": [
114
+ "'Tesla'",
115
+ "'iPhone'",
116
+ "{ label: 'Tesla', value: 'car', cannotSelect: true }"
117
+ ]
118
+ }
119
+ },
120
+ "returns": {
121
+ "type": "Boolean",
122
+ "desc": "If true, the current option will be disabled"
123
+ },
124
+ "examples": [
125
+ "item => (item === null ? true : item.cannotSelect)",
126
+ "# option-disable=\"cannotSelect\""
127
+ ],
128
+ "category": "options",
129
+ "addedIn": "v2.17"
43
130
  },
44
131
 
45
132
  "name": {
@@ -1,7 +1,8 @@
1
- import { h, ref, computed, watch, withDirectives, onActivated, onDeactivated, onBeforeUnmount, getCurrentInstance } from 'vue'
1
+ import { h, ref, computed, watch, onActivated, onDeactivated, onBeforeUnmount, getCurrentInstance } from 'vue'
2
2
 
3
3
  import useDark, { useDarkProps } from '../../composables/private.use-dark/use-dark.js'
4
4
 
5
+ import ScrollAreaControls from './ScrollAreaControls.js'
5
6
  import QResizeObserver from '../resize-observer/QResizeObserver.js'
6
7
  import QScrollObserver from '../scroll-observer/QScrollObserver.js'
7
8
 
@@ -40,6 +41,15 @@ export default createComponent({
40
41
  verticalBarStyle: [ Array, String, Object ],
41
42
  horizontalBarStyle: [ Array, String, Object ],
42
43
 
44
+ verticalOffset: {
45
+ type: Array,
46
+ default: [ 0, 0 ]
47
+ },
48
+ horizontalOffset: {
49
+ type: Array,
50
+ default: [ 0, 0 ]
51
+ },
52
+
43
53
  contentStyle: [ Array, String, Object ],
44
54
  contentActiveStyle: [ Array, String, Object ],
45
55
 
@@ -97,47 +107,57 @@ export default createComponent({
97
107
  + (isDark.value === true ? ' q-scrollarea--dark' : '')
98
108
  )
99
109
 
110
+ Object.assign(container, {
111
+ verticalInner: computed(() => (
112
+ container.vertical.value - props.verticalOffset[ 0 ] - props.verticalOffset[ 1 ]
113
+ )),
114
+
115
+ horizontalInner: computed(() => (
116
+ container.horizontal.value - props.horizontalOffset[ 0 ] - props.horizontalOffset[ 1 ]
117
+ ))
118
+ })
119
+
100
120
  scroll.vertical.percentage = computed(() => {
101
121
  const diff = scroll.vertical.size.value - container.vertical.value
102
122
  if (diff <= 0) { return 0 }
103
123
  const p = between(scroll.vertical.position.value / diff, 0, 1)
104
124
  return Math.round(p * 10000) / 10000
105
125
  })
106
- scroll.vertical.thumbHidden = computed(() =>
126
+ scroll.vertical.thumbHidden = computed(() => (
107
127
  (
108
128
  (props.visible === null ? hover.value : props.visible) !== true
109
129
  && tempShowing.value === false
110
130
  && panning.value === false
111
131
  ) || scroll.vertical.size.value <= container.vertical.value + 1
112
- )
113
- scroll.vertical.thumbStart = computed(() =>
114
- scroll.vertical.percentage.value * (container.vertical.value - scroll.vertical.thumbSize.value)
115
- )
132
+ ))
133
+ scroll.vertical.thumbStart = computed(() => (
134
+ props.verticalOffset[ 0 ]
135
+ + scroll.vertical.percentage.value * (container.verticalInner.value - scroll.vertical.thumbSize.value)
136
+ ))
116
137
  scroll.vertical.thumbSize = computed(() =>
117
138
  Math.round(
118
139
  between(
119
- container.vertical.value * container.vertical.value / scroll.vertical.size.value,
120
- getMinThumbSize(container.vertical.value),
121
- container.vertical.value
140
+ container.verticalInner.value * container.verticalInner.value / scroll.vertical.size.value,
141
+ getMinThumbSize(container.verticalInner.value),
142
+ container.verticalInner.value
122
143
  )
123
144
  )
124
145
  )
125
- scroll.vertical.style = computed(() => {
126
- return {
127
- ...props.thumbStyle,
128
- ...props.verticalThumbStyle,
129
- top: `${ scroll.vertical.thumbStart.value }px`,
130
- height: `${ scroll.vertical.thumbSize.value }px`
131
- }
132
- })
133
- scroll.vertical.thumbClass = computed(() =>
146
+ scroll.vertical.style = computed(() => ({
147
+ ...props.thumbStyle,
148
+ ...props.verticalThumbStyle,
149
+ top: `${ scroll.vertical.thumbStart.value }px`,
150
+ height: `${ scroll.vertical.thumbSize.value }px`,
151
+ right: `${ props.horizontalOffset[ 1 ] }px`
152
+ }))
153
+ scroll.vertical.thumbClass = computed(() => (
134
154
  'q-scrollarea__thumb q-scrollarea__thumb--v absolute-right'
135
155
  + (scroll.vertical.thumbHidden.value === true ? ' q-scrollarea__thumb--invisible' : '')
136
- )
137
- scroll.vertical.barClass = computed(() =>
156
+ ))
157
+ scroll.vertical.barClass = computed(() => (
138
158
  'q-scrollarea__bar q-scrollarea__bar--v absolute-right'
139
159
  + (scroll.vertical.thumbHidden.value === true ? ' q-scrollarea__bar--invisible' : '')
140
- )
160
+ ))
141
161
 
142
162
  scroll.horizontal.percentage = computed(() => {
143
163
  const diff = scroll.horizontal.size.value - container.horizontal.value
@@ -145,41 +165,41 @@ export default createComponent({
145
165
  const p = between(Math.abs(scroll.horizontal.position.value) / diff, 0, 1)
146
166
  return Math.round(p * 10000) / 10000
147
167
  })
148
- scroll.horizontal.thumbHidden = computed(() =>
168
+ scroll.horizontal.thumbHidden = computed(() => (
149
169
  (
150
170
  (props.visible === null ? hover.value : props.visible) !== true
151
171
  && tempShowing.value === false
152
172
  && panning.value === false
153
173
  ) || scroll.horizontal.size.value <= container.horizontal.value + 1
154
- )
155
- scroll.horizontal.thumbStart = computed(() =>
156
- scroll.horizontal.percentage.value * (container.horizontal.value - scroll.horizontal.thumbSize.value)
157
- )
174
+ ))
175
+ scroll.horizontal.thumbStart = computed(() => (
176
+ props.horizontalOffset[ 0 ]
177
+ + scroll.horizontal.percentage.value * (container.horizontalInner.value - scroll.horizontal.thumbSize.value)
178
+ ))
158
179
  scroll.horizontal.thumbSize = computed(() =>
159
180
  Math.round(
160
181
  between(
161
- container.horizontal.value * container.horizontal.value / scroll.horizontal.size.value,
162
- getMinThumbSize(container.horizontal.value),
163
- container.horizontal.value
182
+ container.horizontalInner.value * container.horizontalInner.value / scroll.horizontal.size.value,
183
+ getMinThumbSize(container.horizontalInner.value),
184
+ container.horizontalInner.value
164
185
  )
165
186
  )
166
187
  )
167
- scroll.horizontal.style = computed(() => {
168
- return {
169
- ...props.thumbStyle,
170
- ...props.horizontalThumbStyle,
171
- [ proxy.$q.lang.rtl === true ? 'right' : 'left' ]: `${ scroll.horizontal.thumbStart.value }px`,
172
- width: `${ scroll.horizontal.thumbSize.value }px`
173
- }
174
- })
175
- scroll.horizontal.thumbClass = computed(() =>
188
+ scroll.horizontal.style = computed(() => ({
189
+ ...props.thumbStyle,
190
+ ...props.horizontalThumbStyle,
191
+ [ proxy.$q.lang.rtl === true ? 'right' : 'left' ]: `${ scroll.horizontal.thumbStart.value }px`,
192
+ width: `${ scroll.horizontal.thumbSize.value }px`,
193
+ bottom: `${ props.verticalOffset[ 1 ] }px`
194
+ }))
195
+ scroll.horizontal.thumbClass = computed(() => (
176
196
  'q-scrollarea__thumb q-scrollarea__thumb--h absolute-bottom'
177
197
  + (scroll.horizontal.thumbHidden.value === true ? ' q-scrollarea__thumb--invisible' : '')
178
- )
179
- scroll.horizontal.barClass = computed(() =>
198
+ ))
199
+ scroll.horizontal.barClass = computed(() => (
180
200
  'q-scrollarea__bar q-scrollarea__bar--h absolute-bottom'
181
201
  + (scroll.horizontal.thumbHidden.value === true ? ' q-scrollarea__bar--invisible' : '')
182
- )
202
+ ))
183
203
 
184
204
  const mainStyle = computed(() => (
185
205
  scroll.vertical.thumbHidden.value === true && scroll.horizontal.thumbHidden.value === true
@@ -187,30 +207,18 @@ export default createComponent({
187
207
  : props.contentActiveStyle
188
208
  ))
189
209
 
190
- const thumbVertDir = [ [
191
- TouchPan,
192
- e => { onPanThumb(e, 'vertical') },
193
- void 0,
194
- { vertical: true, ...panOpts }
195
- ] ]
196
-
197
- const thumbHorizDir = [ [
198
- TouchPan,
199
- e => { onPanThumb(e, 'horizontal') },
200
- void 0,
201
- { horizontal: true, ...panOpts }
202
- ] ]
203
-
204
210
  function getScroll () {
205
211
  const info = {}
206
212
 
207
213
  axisList.forEach(axis => {
208
214
  const data = scroll[ axis ]
209
-
210
- info[ axis + 'Position' ] = data.position.value
211
- info[ axis + 'Percentage' ] = data.percentage.value
212
- info[ axis + 'Size' ] = data.size.value
213
- info[ axis + 'ContainerSize' ] = container[ axis ].value
215
+ Object.assign(info, {
216
+ [ axis + 'Position' ]: data.position.value,
217
+ [ axis + 'Percentage' ]: data.percentage.value,
218
+ [ axis + 'Size' ]: data.size.value,
219
+ [ axis + 'ContainerSize' ]: container[ axis ].value,
220
+ [ axis + 'ContainerInnerSize' ]: container[ axis + 'Inner' ].value
221
+ })
214
222
  })
215
223
 
216
224
  return info
@@ -302,9 +310,11 @@ export default createComponent({
302
310
  }
303
311
 
304
312
  const dProp = dirProps[ axis ]
305
- const containerSize = container[ axis ].value
306
313
 
307
- const multiplier = (data.size.value - containerSize) / (containerSize - data.thumbSize.value)
314
+ const multiplier = (
315
+ (data.size.value - container[ axis ].value)
316
+ / (container[ axis + 'Inner' ].value - data.thumbSize.value)
317
+ )
308
318
  const distance = e.distance[ dProp.dist ]
309
319
  const pos = panRefPos + (e.direction === dProp.dir ? 1 : -1) * distance * multiplier
310
320
 
@@ -315,10 +325,17 @@ export default createComponent({
315
325
  const data = scroll[ axis ]
316
326
 
317
327
  if (data.thumbHidden.value !== true) {
318
- const offset = evt[ dirProps[ axis ].offset ]
319
- if (offset < data.thumbStart.value || offset > data.thumbStart.value + data.thumbSize.value) {
320
- const pos = offset - data.thumbSize.value / 2
321
- setScroll(pos / container[ axis ].value * data.size.value, axis)
328
+ const startOffset = axis === 'vertical'
329
+ ? props.verticalOffset[ 0 ]
330
+ : props.horizontalOffset[ 0 ]
331
+
332
+ const offset = evt[ dirProps[ axis ].offset ] - startOffset
333
+ const thumbStart = data.thumbStart.value - startOffset
334
+
335
+ if (offset < thumbStart || offset > thumbStart + data.thumbSize.value) {
336
+ const targetThumbStart = offset - data.thumbSize.value / 2
337
+ const percentage = between(targetThumbStart / (container[ axis + 'Inner' ].value - data.thumbSize.value), 0, 1)
338
+ setScroll(percentage * Math.max(0, data.size.value - container[ axis ].value), axis)
322
339
  }
323
340
 
324
341
  // activate thumb pan
@@ -328,14 +345,6 @@ export default createComponent({
328
345
  }
329
346
  }
330
347
 
331
- function onVerticalMousedown (evt) {
332
- onMousedown(evt, 'vertical')
333
- }
334
-
335
- function onHorizontalMousedown (evt) {
336
- onMousedown(evt, 'horizontal')
337
- }
338
-
339
348
  function startTimer () {
340
349
  tempShowing.value = true
341
350
 
@@ -430,6 +439,32 @@ export default createComponent({
430
439
  }
431
440
  })
432
441
 
442
+ const store = {
443
+ scroll,
444
+
445
+ thumbVertDir: [ [
446
+ TouchPan,
447
+ e => { onPanThumb(e, 'vertical') },
448
+ void 0,
449
+ { vertical: true, ...panOpts }
450
+ ] ],
451
+
452
+ thumbHorizDir: [ [
453
+ TouchPan,
454
+ e => { onPanThumb(e, 'horizontal') },
455
+ void 0,
456
+ { horizontal: true, ...panOpts }
457
+ ] ],
458
+
459
+ onVerticalMousedown (evt) {
460
+ onMousedown(evt, 'vertical')
461
+ },
462
+
463
+ onHorizontalMousedown (evt) {
464
+ onMousedown(evt, 'horizontal')
465
+ }
466
+ }
467
+
433
468
  return () => {
434
469
  return h('div', {
435
470
  class: classes.value,
@@ -462,39 +497,12 @@ export default createComponent({
462
497
  onResize: updateContainer
463
498
  }),
464
499
 
465
- h('div', {
466
- class: scroll.vertical.barClass.value,
467
- style: [ props.barStyle, props.verticalBarStyle ],
468
- 'aria-hidden': 'true',
469
- onMousedown: onVerticalMousedown
470
- }),
471
-
472
- h('div', {
473
- class: scroll.horizontal.barClass.value,
474
- style: [ props.barStyle, props.horizontalBarStyle ],
475
- 'aria-hidden': 'true',
476
- onMousedown: onHorizontalMousedown
477
- }),
478
-
479
- withDirectives(
480
- h('div', {
481
- ref: scroll.vertical.ref,
482
- class: scroll.vertical.thumbClass.value,
483
- style: scroll.vertical.style.value,
484
- 'aria-hidden': 'true'
485
- }),
486
- thumbVertDir
487
- ),
488
-
489
- withDirectives(
490
- h('div', {
491
- ref: scroll.horizontal.ref,
492
- class: scroll.horizontal.thumbClass.value,
493
- style: scroll.horizontal.style.value,
494
- 'aria-hidden': 'true'
495
- }),
496
- thumbHorizDir
497
- )
500
+ h(ScrollAreaControls, {
501
+ store,
502
+ barStyle: props.barStyle,
503
+ verticalBarStyle: props.verticalBarStyle,
504
+ horizontalBarStyle: props.horizontalBarStyle
505
+ })
498
506
  ])
499
507
  }
500
508
  }
@@ -8,6 +8,22 @@
8
8
  "extends": "dark"
9
9
  },
10
10
 
11
+ "vertical-offset": {
12
+ "type": "Array",
13
+ "desc": "Adds [top, bottom] offset to vertical thumb",
14
+ "default": "# [ 0, 0 ]",
15
+ "category": "style",
16
+ "addedIn": "v2.17"
17
+ },
18
+
19
+ "horizontal-offset": {
20
+ "type": "Array",
21
+ "desc": "Adds [left, right] offset to horizontal thumb",
22
+ "default": "# [ 0, 0 ]",
23
+ "category": "style",
24
+ "addedIn": "v2.17"
25
+ },
26
+
11
27
  "bar-style": {
12
28
  "type": [ "String", "Array", "Object" ],
13
29
  "tsType": "VueStyleProp",
@@ -132,6 +148,12 @@
132
148
  "required": true,
133
149
  "desc": "Height of the container (in px)"
134
150
  },
151
+ "verticalContainerInnerSize": {
152
+ "type": "Number",
153
+ "required": true,
154
+ "desc": "Height of the container without the vertical offset (in px)",
155
+ "addedIn": "v2.17"
156
+ },
135
157
 
136
158
  "horizontalPosition": {
137
159
  "type": "Number",
@@ -152,6 +174,12 @@
152
174
  "type": "Number",
153
175
  "required": true,
154
176
  "desc": "Width of the container (in px)"
177
+ },
178
+ "horizontalContainerInnerSize": {
179
+ "type": "Number",
180
+ "required": true,
181
+ "desc": "Width of the container without the horizontal offset (in px)",
182
+ "addedIn": "v2.17"
155
183
  }
156
184
  }
157
185
  }
@@ -196,6 +224,12 @@
196
224
  "required": true,
197
225
  "desc": "Height of the container (in px)"
198
226
  },
227
+ "verticalContainerInnerSize": {
228
+ "type": "Number",
229
+ "required": true,
230
+ "desc": "Height of the container without the vertical offset (in px)",
231
+ "addedIn": "v2.17"
232
+ },
199
233
 
200
234
  "horizontalPosition": {
201
235
  "type": "Number",
@@ -216,6 +250,12 @@
216
250
  "type": "Number",
217
251
  "required": true,
218
252
  "desc": "Width of the container (in px)"
253
+ },
254
+ "horizontalContainerInnerSize": {
255
+ "type": "Number",
256
+ "required": true,
257
+ "desc": "Width of the container without the horizontal offset (in px)",
258
+ "addedIn": "v2.17"
219
259
  }
220
260
  }
221
261
  }