quasar 2.16.10 → 2.17.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 (174) 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 +753 -2121
  115. package/dist/quasar.css +3 -2
  116. package/dist/quasar.prod.css +1 -1
  117. package/dist/quasar.rtl.css +3 -2
  118. package/dist/quasar.rtl.prod.css +1 -1
  119. package/dist/quasar.sass +8 -4
  120. package/dist/quasar.server.prod.cjs +53 -53
  121. package/dist/quasar.server.prod.js +51 -51
  122. package/dist/quasar.umd.js +344 -1715
  123. package/dist/quasar.umd.prod.js +44 -44
  124. package/dist/types/index.d.ts +120 -51
  125. package/dist/vetur/quasar-attributes.json +1 -1
  126. package/dist/vetur/quasar-tags.json +1 -1
  127. package/dist/web-types/web-types.json +1 -1
  128. package/package.json +9 -9
  129. package/src/components/checkbox/QCheckbox.js +3 -1
  130. package/src/components/icon/QIcon.js +1 -1
  131. package/src/components/menu/QMenu.sass +2 -2
  132. package/src/components/option-group/QOptionGroup.js +38 -15
  133. package/src/components/option-group/QOptionGroup.json +88 -1
  134. package/src/components/radio/QRadio.js +3 -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/space/QSpace.js +1 -2
  141. package/src/components/spinner/QSpinnerAudio.js +4 -69
  142. package/src/components/spinner/QSpinnerBall.js +4 -85
  143. package/src/components/spinner/QSpinnerBars.js +4 -124
  144. package/src/components/spinner/QSpinnerBox.js +4 -42
  145. package/src/components/spinner/QSpinnerClock.js +4 -53
  146. package/src/components/spinner/QSpinnerComment.js +4 -65
  147. package/src/components/spinner/QSpinnerCube.js +4 -113
  148. package/src/components/spinner/QSpinnerDots.js +4 -85
  149. package/src/components/spinner/QSpinnerFacebook.js +4 -84
  150. package/src/components/spinner/QSpinnerGears.js +4 -40
  151. package/src/components/spinner/QSpinnerGrid.js +4 -133
  152. package/src/components/spinner/QSpinnerHearts.js +4 -35
  153. package/src/components/spinner/QSpinnerHourglass.js +4 -93
  154. package/src/components/spinner/QSpinnerInfinity.js +4 -24
  155. package/src/components/spinner/QSpinnerIos.js +4 -155
  156. package/src/components/spinner/QSpinnerOrbit.js +4 -32
  157. package/src/components/spinner/QSpinnerOval.js +4 -31
  158. package/src/components/spinner/QSpinnerPie.js +4 -62
  159. package/src/components/spinner/QSpinnerPuff.js +4 -64
  160. package/src/components/spinner/QSpinnerRadio.js +4 -57
  161. package/src/components/spinner/QSpinnerRings.js +4 -87
  162. package/src/components/spinner/QSpinnerTail.js +4 -65
  163. package/src/components/tabs/QRouteTab.js +4 -3
  164. package/src/components/tabs/QTabs.js +28 -15
  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-panel/use-panel.js +5 -3
  170. package/src/css/variables.sass +3 -0
  171. package/src/plugins/platform/Platform.js +40 -5
  172. package/src/plugins/platform/Platform.json +52 -69
  173. package/src/plugins/platform/Platform.test.js +22 -14
  174. 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.10",
3
+ "version": "2.17.0",
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.23.1",
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.78.0",
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
  },
@@ -5,7 +5,7 @@ import QIcon from '../icon/QIcon.js'
5
5
  import { createComponent } from '../../utils/private.create/create.js'
6
6
  import useCheckbox, { useCheckboxProps, useCheckboxEmits } from './use-checkbox.js'
7
7
 
8
- const bgNode = h('div', {
8
+ const createBgNode = () => h('div', {
9
9
  key: 'svg',
10
10
  class: 'q-checkbox__bg absolute'
11
11
  }, [
@@ -33,6 +33,8 @@ export default createComponent({
33
33
  emits: useCheckboxEmits,
34
34
 
35
35
  setup (props) {
36
+ const bgNode = createBgNode()
37
+
36
38
  function getInner (isTrue, isIndeterminate) {
37
39
  const icon = computed(() =>
38
40
  (isTrue.value === true
@@ -42,7 +42,7 @@ const mRE = /^[Mm]\s?[-+]?\.?\d/
42
42
  const imgRE = /^img:/
43
43
  const svgUseRE = /^svguse:/
44
44
  const ionRE = /^ion-/
45
- const faRE = /^(fa-(sharp|solid|regular|light|brands|duotone|thin)|[lf]a[srlbdk]?) /
45
+ const faRE = /^(fa-(classic|sharp|solid|regular|light|brands|duotone|thin)|[lf]a[srlbdk]?) /
46
46
 
47
47
  export default createComponent({
48
48
  name: 'QIcon',
@@ -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": {
@@ -12,7 +12,7 @@ import optionSizes from '../../utils/private.option-sizes/option-sizes.js'
12
12
  import { stopAndPrevent } from '../../utils/event/event.js'
13
13
  import { hSlot, hMergeSlot } from '../../utils/private.render/render.js'
14
14
 
15
- const svg = h('svg', {
15
+ const createSvg = () => h('svg', {
16
16
  key: 'svg',
17
17
  class: 'q-radio__bg absolute non-selectable',
18
18
  viewBox: '0 0 24 24'
@@ -138,6 +138,8 @@ export default createComponent({
138
138
  // expose public methods
139
139
  Object.assign(proxy, { set: onClick })
140
140
 
141
+ const svg = createSvg()
142
+
141
143
  return () => {
142
144
  const content = icon.value !== null
143
145
  ? [
@@ -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
  }