quasar 2.8.4 → 2.9.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.
- package/dist/api/QBreadcrumbsEl.json +52 -0
- package/dist/api/QBtn.json +41 -6
- package/dist/api/QBtnDropdown.json +1 -1
- package/dist/api/QChip.json +1 -1
- package/dist/api/QEditor.json +7 -0
- package/dist/api/QExpansionItem.json +1 -1
- package/dist/api/QItem.json +52 -0
- package/dist/api/QRating.json +13 -0
- package/dist/api/QRouteTab.json +42 -6
- package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
- package/dist/icon-set/eva-icons.umd.prod.js +1 -1
- package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
- package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
- package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
- package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
- package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
- package/dist/icon-set/line-awesome.umd.prod.js +1 -1
- package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
- package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
- package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
- package/dist/icon-set/material-icons.umd.prod.js +1 -1
- package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
- package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
- package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
- package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
- package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
- package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
- package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
- package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
- package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
- package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
- package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
- package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
- package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
- package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
- package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
- package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
- package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
- package/dist/icon-set/svg-themify.umd.prod.js +1 -1
- package/dist/icon-set/themify.umd.prod.js +1 -1
- package/dist/lang/ar-TN.umd.prod.js +1 -1
- package/dist/lang/ar.umd.prod.js +1 -1
- package/dist/lang/az-Latn.umd.prod.js +1 -1
- package/dist/lang/bg.umd.prod.js +1 -1
- package/dist/lang/bn.umd.prod.js +1 -1
- package/dist/lang/ca.umd.prod.js +1 -1
- package/dist/lang/cs.umd.prod.js +1 -1
- package/dist/lang/da.umd.prod.js +1 -1
- package/dist/lang/de.umd.prod.js +1 -1
- package/dist/lang/el.umd.prod.js +1 -1
- package/dist/lang/en-GB.umd.prod.js +1 -1
- package/dist/lang/en-US.umd.prod.js +1 -1
- package/dist/lang/eo.umd.prod.js +1 -1
- package/dist/lang/es.umd.prod.js +1 -1
- package/dist/lang/et.umd.prod.js +1 -1
- package/dist/lang/eu.umd.prod.js +1 -1
- package/dist/lang/fa-IR.umd.prod.js +1 -1
- package/dist/lang/fa.umd.prod.js +1 -1
- package/dist/lang/fi.umd.prod.js +1 -1
- package/dist/lang/fr.umd.prod.js +1 -1
- package/dist/lang/gn.umd.prod.js +1 -1
- package/dist/lang/he.umd.prod.js +1 -1
- package/dist/lang/hr.umd.prod.js +1 -1
- package/dist/lang/hu.umd.prod.js +1 -1
- package/dist/lang/id.umd.prod.js +1 -1
- package/dist/lang/is.umd.prod.js +1 -1
- package/dist/lang/it.umd.prod.js +1 -1
- package/dist/lang/ja.umd.prod.js +1 -1
- package/dist/lang/km.umd.prod.js +1 -1
- package/dist/lang/ko-KR.umd.prod.js +1 -1
- package/dist/lang/kur-CKB.umd.prod.js +1 -1
- package/dist/lang/kz.umd.prod.js +1 -1
- package/dist/lang/lt.umd.prod.js +1 -1
- package/dist/lang/lu.umd.prod.js +1 -1
- package/dist/lang/lv.umd.prod.js +1 -1
- package/dist/lang/ml.umd.prod.js +1 -1
- package/dist/lang/mm.umd.prod.js +1 -1
- package/dist/lang/ms.umd.prod.js +1 -1
- package/dist/lang/my.umd.prod.js +1 -1
- package/dist/lang/nb-NO.umd.prod.js +1 -1
- package/dist/lang/nl.umd.prod.js +2 -2
- package/dist/lang/pl.umd.prod.js +1 -1
- package/dist/lang/pt-BR.umd.prod.js +1 -1
- package/dist/lang/pt.umd.prod.js +1 -1
- package/dist/lang/ro.umd.prod.js +1 -1
- package/dist/lang/ru.umd.prod.js +1 -1
- package/dist/lang/sk.umd.prod.js +1 -1
- package/dist/lang/sl.umd.prod.js +1 -1
- package/dist/lang/sm.umd.prod.js +1 -1
- package/dist/lang/sr-CYR.umd.prod.js +1 -1
- package/dist/lang/sr.umd.prod.js +1 -1
- package/dist/lang/sv.umd.prod.js +1 -1
- package/dist/lang/ta.umd.prod.js +1 -1
- package/dist/lang/th.umd.prod.js +1 -1
- package/dist/lang/tr.umd.prod.js +1 -1
- package/dist/lang/ug.umd.prod.js +1 -1
- package/dist/lang/uk.umd.prod.js +1 -1
- package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
- package/dist/lang/uz-Latn.umd.prod.js +1 -1
- package/dist/lang/vi.umd.prod.js +1 -1
- package/dist/lang/zh-CN.umd.prod.js +1 -1
- package/dist/lang/zh-TW.umd.prod.js +1 -1
- package/dist/quasar.cjs.prod.js +2 -2
- package/dist/quasar.esm.js +533 -337
- package/dist/quasar.esm.prod.js +2 -2
- package/dist/quasar.sass +1 -1
- package/dist/quasar.umd.js +532 -336
- package/dist/quasar.umd.prod.js +2 -2
- package/dist/types/api/qeditor.d.ts +17 -0
- package/dist/types/api.d.ts +1 -0
- package/dist/types/index.d.ts +93 -8
- package/dist/types/utils/run-sequential-promises.d.ts +1 -1
- package/dist/vetur/quasar-attributes.json +4 -0
- package/dist/vetur/quasar-tags.json +1 -0
- package/dist/web-types/web-types.json +60 -9
- package/lang/nl.js +2 -2
- package/lang/nl.mjs +2 -2
- package/package.json +5 -3
- package/src/components/breadcrumbs/QBreadcrumbsEl.js +6 -7
- package/src/components/breadcrumbs/QBreadcrumbsEl.json +53 -0
- package/src/components/btn/QBtn.js +19 -19
- package/src/components/btn/QBtn.json +41 -6
- package/src/components/btn/use-btn.js +6 -4
- package/src/components/btn-dropdown/QBtnDropdown.json +1 -1
- package/src/components/checkbox/QCheckbox.js +1 -2
- package/src/components/checkbox/use-checkbox.js +2 -1
- package/src/components/chip/QChip.json +1 -1
- package/src/components/dialog/QDialog.js +6 -4
- package/src/components/drawer/QDrawer.js +7 -4
- package/src/components/editor/QEditor.json +9 -0
- package/src/components/expansion-item/QExpansionItem.json +1 -1
- package/src/components/item/QItem.js +4 -5
- package/src/components/item/QItem.json +53 -0
- package/src/components/menu/QMenu.js +4 -5
- package/src/components/menu/__tests__/QMenu.spec.js +7 -0
- package/src/components/popup-edit/QPopupEdit.js +2 -5
- package/src/components/radio/QRadio.js +3 -3
- package/src/components/rating/QRating.js +48 -10
- package/src/components/rating/QRating.json +11 -0
- package/src/components/stepper/QStep.js +5 -3
- package/src/components/table/QTable.js +3 -5
- package/src/components/tabs/QRouteTab.js +6 -4
- package/src/components/tabs/QRouteTab.json +42 -6
- package/src/components/tabs/QTabs.js +188 -108
- package/src/components/tabs/use-tab.js +62 -38
- package/src/components/tooltip/QTooltip.js +7 -13
- package/src/components/tree/QTree.js +1 -1
- package/src/composables/private/__tests__/use-model-toggle.spec.js +2 -0
- package/src/composables/private/__tests__/use-transition.spec.js +4 -0
- package/src/composables/private/use-router-link.js +80 -43
- package/src/composables/private/use-tick.js +15 -9
- package/src/composables/private/use-timeout.js +20 -7
- package/src/directives/TouchPan.js +1 -1
- package/src/directives/TouchRepeat.js +1 -1
- package/src/directives/TouchSwipe.js +1 -1
- package/src/utils/extend.js +19 -19
- package/src/utils/private/inject-obj-prop.js +2 -0
- package/src/utils/private/rtl.js +10 -7
- package/src/utils/run-sequential-promises.js +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, ref, computed, watch,
|
|
1
|
+
import { h, ref, computed, watch, onBeforeUnmount, onActivated, onDeactivated, getCurrentInstance, provide } from 'vue'
|
|
2
2
|
|
|
3
3
|
import QIcon from '../icon/QIcon.js'
|
|
4
4
|
import QResizeObserver from '../resize-observer/QResizeObserver.js'
|
|
@@ -11,7 +11,6 @@ import { noop } from '../../utils/event.js'
|
|
|
11
11
|
import { hSlot } from '../../utils/private/render.js'
|
|
12
12
|
import { tabsKey } from '../../utils/private/symbols.js'
|
|
13
13
|
import { rtlHasScrollBug } from '../../utils/private/rtl.js'
|
|
14
|
-
import { vmIsDestroyed } from '../../utils/private/vm.js'
|
|
15
14
|
|
|
16
15
|
function getIndicatorClass (color, top, vertical) {
|
|
17
16
|
const pos = vertical === true
|
|
@@ -22,7 +21,6 @@ function getIndicatorClass (color, top, vertical) {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
const alignValues = [ 'left', 'center', 'right', 'justify' ]
|
|
25
|
-
const emptyFn = () => {}
|
|
26
24
|
|
|
27
25
|
export default createComponent({
|
|
28
26
|
name: 'QTabs',
|
|
@@ -68,12 +66,15 @@ export default createComponent({
|
|
|
68
66
|
},
|
|
69
67
|
|
|
70
68
|
setup (props, { slots, emit }) {
|
|
71
|
-
const
|
|
72
|
-
const {
|
|
69
|
+
const { proxy } = getCurrentInstance()
|
|
70
|
+
const { $q } = proxy
|
|
73
71
|
|
|
74
72
|
const { registerTick: registerScrollTick } = useTick()
|
|
73
|
+
const { registerTick: registerUpdateArrowsTick } = useTick()
|
|
74
|
+
const { registerTick: registerAnimateTick } = useTick()
|
|
75
|
+
|
|
75
76
|
const { registerTimeout: registerFocusTimeout, removeTimeout: removeFocusTimeout } = useTimeout()
|
|
76
|
-
const { registerTimeout } = useTimeout()
|
|
77
|
+
const { registerTimeout: registerScrollToTabTimeout, removeTimeout: removeScrollToTabTimeout } = useTimeout()
|
|
77
78
|
|
|
78
79
|
const rootRef = ref(null)
|
|
79
80
|
const contentRef = ref(null)
|
|
@@ -88,10 +89,11 @@ export default createComponent({
|
|
|
88
89
|
$q.platform.is.desktop === true || props.mobileArrows === true
|
|
89
90
|
)
|
|
90
91
|
|
|
91
|
-
const
|
|
92
|
+
const tabDataList = []
|
|
93
|
+
const tabDataListLen = ref(0)
|
|
92
94
|
const hasFocus = ref(false)
|
|
93
95
|
|
|
94
|
-
let
|
|
96
|
+
let animateTimer, scrollTimer, unwatchRoute
|
|
95
97
|
let localUpdateArrows = arrowsEnabled.value === true
|
|
96
98
|
? updateArrowsFn
|
|
97
99
|
: noop
|
|
@@ -110,6 +112,19 @@ export default createComponent({
|
|
|
110
112
|
noCaps: props.noCaps
|
|
111
113
|
}))
|
|
112
114
|
|
|
115
|
+
const hasActiveTab = computed(() => {
|
|
116
|
+
const len = tabDataListLen.value
|
|
117
|
+
const val = currentModel.value
|
|
118
|
+
|
|
119
|
+
for (let i = 0; i < len; i++) {
|
|
120
|
+
if (tabDataList[ i ].name.value === val) {
|
|
121
|
+
return true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return false
|
|
126
|
+
})
|
|
127
|
+
|
|
113
128
|
const alignClass = computed(() => {
|
|
114
129
|
const align = scrollable.value === true
|
|
115
130
|
? 'left'
|
|
@@ -151,7 +166,7 @@ export default createComponent({
|
|
|
151
166
|
})
|
|
152
167
|
|
|
153
168
|
watch(() => props.outsideArrows, () => {
|
|
154
|
-
|
|
169
|
+
recalculateScroll()
|
|
155
170
|
})
|
|
156
171
|
|
|
157
172
|
watch(arrowsEnabled, v => {
|
|
@@ -159,12 +174,15 @@ export default createComponent({
|
|
|
159
174
|
? updateArrowsFn
|
|
160
175
|
: noop
|
|
161
176
|
|
|
162
|
-
|
|
177
|
+
recalculateScroll()
|
|
163
178
|
})
|
|
164
179
|
|
|
165
180
|
function updateModel ({ name, setCurrent, skipEmit, fromRoute }) {
|
|
166
181
|
if (currentModel.value !== name) {
|
|
167
|
-
skipEmit !== true &&
|
|
182
|
+
if (skipEmit !== true && props[ 'onUpdate:modelValue' ] !== void 0) {
|
|
183
|
+
emit('update:modelValue', name)
|
|
184
|
+
}
|
|
185
|
+
|
|
168
186
|
if (
|
|
169
187
|
setCurrent === true
|
|
170
188
|
|| props[ 'onUpdate:modelValue' ] === void 0
|
|
@@ -173,20 +191,14 @@ export default createComponent({
|
|
|
173
191
|
currentModel.value = name
|
|
174
192
|
}
|
|
175
193
|
}
|
|
176
|
-
|
|
177
|
-
if (fromRoute !== void 0) {
|
|
178
|
-
localFromRoute = fromRoute
|
|
179
|
-
}
|
|
180
194
|
}
|
|
181
195
|
|
|
182
196
|
function recalculateScroll () {
|
|
183
197
|
registerScrollTick(() => {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
})
|
|
189
|
-
}
|
|
198
|
+
updateContainer({
|
|
199
|
+
width: rootRef.value.offsetWidth,
|
|
200
|
+
height: rootRef.value.offsetHeight
|
|
201
|
+
})
|
|
190
202
|
})
|
|
191
203
|
}
|
|
192
204
|
|
|
@@ -208,27 +220,21 @@ export default createComponent({
|
|
|
208
220
|
),
|
|
209
221
|
scroll = size > 0 && scrollSize > size // when there is no tab, in Chrome, size === 0 and scrollSize === 1
|
|
210
222
|
|
|
211
|
-
|
|
212
|
-
scrollable.value = scroll
|
|
213
|
-
}
|
|
223
|
+
scrollable.value = scroll
|
|
214
224
|
|
|
215
225
|
// Arrows need to be updated even if the scroll status was already true
|
|
216
|
-
scroll === true &&
|
|
226
|
+
scroll === true && registerUpdateArrowsTick(localUpdateArrows)
|
|
217
227
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (justify.value !== localJustify) {
|
|
221
|
-
justify.value = localJustify
|
|
222
|
-
}
|
|
228
|
+
justify.value = size < parseInt(props.breakpoint, 10)
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
function animate (oldName, newName) {
|
|
226
232
|
const
|
|
227
233
|
oldTab = oldName !== void 0 && oldName !== null && oldName !== ''
|
|
228
|
-
?
|
|
234
|
+
? tabDataList.find(tab => tab.name.value === oldName)
|
|
229
235
|
: null,
|
|
230
236
|
newTab = newName !== void 0 && newName !== null && newName !== ''
|
|
231
|
-
?
|
|
237
|
+
? tabDataList.find(tab => tab.name.value === newName)
|
|
232
238
|
: null
|
|
233
239
|
|
|
234
240
|
if (oldTab && newTab) {
|
|
@@ -252,7 +258,7 @@ export default createComponent({
|
|
|
252
258
|
: `translate3d(${ oldPos.left - newPos.left }px,0,0) scale3d(${ newPos.width ? oldPos.width / newPos.width : 1 },1,1)`
|
|
253
259
|
|
|
254
260
|
// allow scope updates to kick in (QRouteTab needs more time)
|
|
255
|
-
|
|
261
|
+
registerAnimateTick(() => {
|
|
256
262
|
animateTimer = setTimeout(() => {
|
|
257
263
|
newEl.style.transition = 'transform .25s cubic-bezier(.4, 0, .2, 1)'
|
|
258
264
|
newEl.style.transform = 'none'
|
|
@@ -307,8 +313,6 @@ export default createComponent({
|
|
|
307
313
|
|
|
308
314
|
function animScrollTo (value) {
|
|
309
315
|
stopAnimScroll()
|
|
310
|
-
scrollTowards(value)
|
|
311
|
-
|
|
312
316
|
scrollTimer = setInterval(() => {
|
|
313
317
|
if (scrollTowards(value) === true) {
|
|
314
318
|
stopAnimScroll()
|
|
@@ -339,10 +343,12 @@ export default createComponent({
|
|
|
339
343
|
|
|
340
344
|
if (keyCode === 36) { // Home
|
|
341
345
|
scrollToTabEl(tabs[ 0 ])
|
|
346
|
+
tabs[ 0 ].focus()
|
|
342
347
|
return true
|
|
343
348
|
}
|
|
344
349
|
if (keyCode === 35) { // End
|
|
345
350
|
scrollToTabEl(tabs[ len - 1 ])
|
|
351
|
+
tabs[ len - 1 ].focus()
|
|
346
352
|
return true
|
|
347
353
|
}
|
|
348
354
|
|
|
@@ -408,77 +414,113 @@ export default createComponent({
|
|
|
408
414
|
return done
|
|
409
415
|
}
|
|
410
416
|
|
|
411
|
-
function
|
|
412
|
-
|
|
417
|
+
function hasQueryIncluded (targetQuery, matchingQuery) {
|
|
418
|
+
for (const key in targetQuery) {
|
|
419
|
+
if (targetQuery[ key ] !== matchingQuery[ key ]) {
|
|
420
|
+
return false
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return true
|
|
413
425
|
}
|
|
414
426
|
|
|
415
427
|
// do not use directly; use verifyRouteModel() instead
|
|
416
428
|
function updateActiveRoute () {
|
|
417
|
-
let name = null,
|
|
429
|
+
let name = null, bestScore = { matchedLen: 0, queryDiff: 9999, hrefLen: 0 }
|
|
418
430
|
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
model = currentModel.value
|
|
423
|
-
|
|
424
|
-
let wasItActive = wasActive === true
|
|
425
|
-
? emptyFn
|
|
426
|
-
: tab => {
|
|
427
|
-
if (model === tab.name.value) {
|
|
428
|
-
wasActive = true
|
|
429
|
-
wasItActive = emptyFn
|
|
430
|
-
}
|
|
431
|
-
}
|
|
431
|
+
const list = tabDataList.filter(tab => tab.routeData !== void 0 && tab.routeData.hasRouterLink.value === true)
|
|
432
|
+
const { hash: currentHash, query: currentQuery } = proxy.$route
|
|
433
|
+
const currentQueryLen = Object.keys(currentQuery).length
|
|
432
434
|
|
|
433
|
-
|
|
435
|
+
// Vue Router does not keep account of hash & query when matching
|
|
436
|
+
// so we're doing this as well
|
|
434
437
|
|
|
435
|
-
for (const tab of
|
|
436
|
-
const exact = tab.
|
|
438
|
+
for (const tab of list) {
|
|
439
|
+
const exact = tab.routeData.exact.value === true
|
|
437
440
|
|
|
438
|
-
if (
|
|
439
|
-
|
|
440
|
-
|| (best.exact === true && exact !== true)
|
|
441
|
-
) {
|
|
442
|
-
wasItActive(tab)
|
|
441
|
+
if (tab.routeData[ exact === true ? 'linkIsExactActive' : 'linkIsActive' ].value !== true) {
|
|
442
|
+
// it cannot match anything as it's not active nor exact-active
|
|
443
443
|
continue
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
tabHash = linkRoute.hash
|
|
446
|
+
const { hash, query, matched, href } = tab.routeData.resolvedLink.value
|
|
447
|
+
const queryLen = Object.keys(query).length
|
|
449
448
|
|
|
450
|
-
// Vue Router does not match the hash too, even if link is set to "exact"
|
|
451
449
|
if (exact === true) {
|
|
452
|
-
if (hash
|
|
453
|
-
|
|
454
|
-
|
|
450
|
+
if (hash !== currentHash) {
|
|
451
|
+
// it's set to exact but it doesn't matches the hash
|
|
452
|
+
continue
|
|
455
453
|
}
|
|
456
|
-
|
|
457
|
-
|
|
454
|
+
|
|
455
|
+
if (
|
|
456
|
+
queryLen !== currentQueryLen
|
|
457
|
+
|| hasQueryIncluded(currentQuery, query) === false
|
|
458
|
+
) {
|
|
459
|
+
// it's set to exact but it doesn't matches the query
|
|
458
460
|
continue
|
|
459
461
|
}
|
|
462
|
+
|
|
463
|
+
// yey, we found the perfect match (route + hash + query)
|
|
464
|
+
name = tab.name.value
|
|
465
|
+
break
|
|
460
466
|
}
|
|
461
467
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
468
|
+
if (hash !== '' && hash !== currentHash) {
|
|
469
|
+
// it has hash and it doesn't matches
|
|
470
|
+
continue
|
|
471
|
+
}
|
|
465
472
|
|
|
466
473
|
if (
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
: matchedLen > best.matchedLen
|
|
474
|
+
queryLen !== 0
|
|
475
|
+
&& hasQueryIncluded(query, currentQuery) === false
|
|
470
476
|
) {
|
|
477
|
+
// it has query and it doesn't includes the current one
|
|
478
|
+
continue
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const newScore = {
|
|
482
|
+
matchedLen: matched.length,
|
|
483
|
+
queryDiff: currentQueryLen - queryLen,
|
|
484
|
+
hrefLen: href.length - hash.length
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (newScore.matchedLen > bestScore.matchedLen) {
|
|
488
|
+
// it matches more routes so it's more specific so we set it as current champion
|
|
471
489
|
name = tab.name.value
|
|
472
|
-
|
|
490
|
+
bestScore = newScore
|
|
491
|
+
continue
|
|
492
|
+
}
|
|
493
|
+
else if (newScore.matchedLen !== bestScore.matchedLen) {
|
|
494
|
+
// it matches less routes than the current champion so we discard it
|
|
473
495
|
continue
|
|
474
496
|
}
|
|
475
497
|
|
|
476
|
-
|
|
498
|
+
if (newScore.queryDiff < bestScore.queryDiff) {
|
|
499
|
+
// query is closer to the current one so we set it as current champion
|
|
500
|
+
name = tab.name.value
|
|
501
|
+
bestScore = newScore
|
|
502
|
+
}
|
|
503
|
+
else if (newScore.queryDiff !== bestScore.queryDiff) {
|
|
504
|
+
// it matches less routes than the current champion so we discard it
|
|
505
|
+
continue
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (newScore.hrefLen > bestScore.hrefLen) {
|
|
509
|
+
// href is lengthier so it's more specific so we set it as current champion
|
|
510
|
+
name = tab.name.value
|
|
511
|
+
bestScore = newScore
|
|
512
|
+
}
|
|
477
513
|
}
|
|
478
514
|
|
|
479
|
-
if (
|
|
480
|
-
|
|
515
|
+
if (
|
|
516
|
+
name === null
|
|
517
|
+
&& tabDataList.some(tab => tab.routeData === void 0 && tab.name.value === currentModel.value) === true
|
|
518
|
+
) {
|
|
519
|
+
// we shouldn't interfere if non-route tab is active
|
|
520
|
+
return
|
|
481
521
|
}
|
|
522
|
+
|
|
523
|
+
updateModel({ name, setCurrent: true })
|
|
482
524
|
}
|
|
483
525
|
|
|
484
526
|
function onFocusin (e) {
|
|
@@ -496,6 +538,7 @@ export default createComponent({
|
|
|
496
538
|
// (it might be other elements focused, like additional QBtn)
|
|
497
539
|
if (tab && rootRef.value.contains(tab) === true) {
|
|
498
540
|
hasFocus.value = true
|
|
541
|
+
scrollable.value === true && scrollToTabEl(tab)
|
|
499
542
|
}
|
|
500
543
|
}
|
|
501
544
|
}
|
|
@@ -505,22 +548,52 @@ export default createComponent({
|
|
|
505
548
|
}
|
|
506
549
|
|
|
507
550
|
function verifyRouteModel () {
|
|
508
|
-
if ($tabs.avoidRouteWatcher
|
|
509
|
-
|
|
551
|
+
if ($tabs.avoidRouteWatcher === false) {
|
|
552
|
+
registerScrollToTabTimeout(updateActiveRoute)
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
removeScrollToTabTimeout()
|
|
510
556
|
}
|
|
511
557
|
}
|
|
512
558
|
|
|
513
|
-
function
|
|
514
|
-
|
|
559
|
+
function watchRoute () {
|
|
560
|
+
if (unwatchRoute === void 0) {
|
|
561
|
+
const unwatch = watch(() => proxy.$route.fullPath, verifyRouteModel)
|
|
562
|
+
unwatchRoute = () => {
|
|
563
|
+
unwatch()
|
|
564
|
+
unwatchRoute = void 0
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
515
568
|
|
|
516
|
-
|
|
569
|
+
function registerTab (tabData) {
|
|
570
|
+
tabDataList.push(tabData)
|
|
571
|
+
tabDataListLen.value++
|
|
517
572
|
|
|
518
|
-
|
|
519
|
-
if (unwatchRoute === void 0) {
|
|
520
|
-
unwatchRoute = watch(() => vm.proxy.$route, verifyRouteModel)
|
|
521
|
-
}
|
|
573
|
+
recalculateScroll()
|
|
522
574
|
|
|
523
|
-
|
|
575
|
+
// if it's a QTab
|
|
576
|
+
if (tabData.routeData === void 0) {
|
|
577
|
+
// we should position to the currently active tab (if any)
|
|
578
|
+
registerScrollToTabTimeout(() => {
|
|
579
|
+
if (scrollable.value === true) {
|
|
580
|
+
const value = currentModel.value
|
|
581
|
+
const newTab = value !== void 0 && value !== null && value !== ''
|
|
582
|
+
? tabDataList.find(tab => tab.name.value === value)
|
|
583
|
+
: null
|
|
584
|
+
|
|
585
|
+
newTab && scrollToTabEl(newTab.rootRef.value)
|
|
586
|
+
}
|
|
587
|
+
})
|
|
588
|
+
}
|
|
589
|
+
// else if it's a QRouteTab with a valid link
|
|
590
|
+
else {
|
|
591
|
+
// start watching route
|
|
592
|
+
watchRoute()
|
|
593
|
+
|
|
594
|
+
if (tabData.routeData.hasRouterLink.value === true) {
|
|
595
|
+
verifyRouteModel()
|
|
596
|
+
}
|
|
524
597
|
}
|
|
525
598
|
}
|
|
526
599
|
|
|
@@ -532,16 +605,18 @@ export default createComponent({
|
|
|
532
605
|
* always check the existing list again and infer the changes.
|
|
533
606
|
*/
|
|
534
607
|
function unregisterTab (tabData) {
|
|
535
|
-
|
|
608
|
+
tabDataList.splice(tabDataList.indexOf(tabData), 1)
|
|
609
|
+
tabDataListLen.value--
|
|
536
610
|
|
|
537
|
-
|
|
538
|
-
const routeList = getRouteList()
|
|
611
|
+
recalculateScroll()
|
|
539
612
|
|
|
540
|
-
|
|
613
|
+
if (unwatchRoute !== void 0 && tabData.routeData !== void 0) {
|
|
614
|
+
// unwatch route if we don't have any QRouteTabs left
|
|
615
|
+
if (tabDataList.every(tab => tab.routeData === void 0) === true) {
|
|
541
616
|
unwatchRoute()
|
|
542
|
-
unwatchRoute = void 0
|
|
543
617
|
}
|
|
544
618
|
|
|
619
|
+
// then update model
|
|
545
620
|
verifyRouteModel()
|
|
546
621
|
}
|
|
547
622
|
}
|
|
@@ -550,33 +625,38 @@ export default createComponent({
|
|
|
550
625
|
currentModel,
|
|
551
626
|
tabProps,
|
|
552
627
|
hasFocus,
|
|
628
|
+
hasActiveTab,
|
|
553
629
|
|
|
554
630
|
registerTab,
|
|
555
631
|
unregisterTab,
|
|
556
632
|
|
|
557
633
|
verifyRouteModel,
|
|
558
634
|
updateModel,
|
|
559
|
-
recalculateScroll,
|
|
560
635
|
onKbdNavigate,
|
|
561
636
|
|
|
562
|
-
avoidRouteWatcher: false
|
|
637
|
+
avoidRouteWatcher: false // false | string (uid)
|
|
563
638
|
}
|
|
564
639
|
|
|
565
640
|
provide(tabsKey, $tabs)
|
|
566
641
|
|
|
567
|
-
|
|
642
|
+
function cleanup () {
|
|
568
643
|
clearTimeout(animateTimer)
|
|
644
|
+
stopAnimScroll()
|
|
569
645
|
unwatchRoute !== void 0 && unwatchRoute()
|
|
570
|
-
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
let hadRouteWatcher
|
|
571
649
|
|
|
572
|
-
|
|
650
|
+
onBeforeUnmount(cleanup)
|
|
573
651
|
|
|
574
652
|
onDeactivated(() => {
|
|
575
|
-
|
|
653
|
+
hadRouteWatcher = unwatchRoute !== void 0
|
|
654
|
+
cleanup()
|
|
576
655
|
})
|
|
577
656
|
|
|
578
657
|
onActivated(() => {
|
|
579
|
-
|
|
658
|
+
hadRouteWatcher === true && watchRoute()
|
|
659
|
+
recalculateScroll()
|
|
580
660
|
})
|
|
581
661
|
|
|
582
662
|
return () => {
|
|
@@ -595,22 +675,22 @@ export default createComponent({
|
|
|
595
675
|
class: 'q-tabs__arrow q-tabs__arrow--left absolute q-tab__icon'
|
|
596
676
|
+ (leftArrow.value === true ? '' : ' q-tabs__arrow--faded'),
|
|
597
677
|
name: props.leftIcon || $q.iconSet.tabs[ props.vertical === true ? 'up' : 'left' ],
|
|
598
|
-
|
|
678
|
+
onMousedownPassive: scrollToStart,
|
|
599
679
|
onTouchstartPassive: scrollToStart,
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
680
|
+
onMouseupPassive: stopAnimScroll,
|
|
681
|
+
onMouseleavePassive: stopAnimScroll,
|
|
682
|
+
onTouchendPassive: stopAnimScroll
|
|
603
683
|
}),
|
|
604
684
|
|
|
605
685
|
h(QIcon, {
|
|
606
686
|
class: 'q-tabs__arrow q-tabs__arrow--right absolute q-tab__icon'
|
|
607
687
|
+ (rightArrow.value === true ? '' : ' q-tabs__arrow--faded'),
|
|
608
688
|
name: props.rightIcon || $q.iconSet.tabs[ props.vertical === true ? 'down' : 'right' ],
|
|
609
|
-
|
|
689
|
+
onMousedownPassive: scrollToEnd,
|
|
610
690
|
onTouchstartPassive: scrollToEnd,
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
691
|
+
onMouseupPassive: stopAnimScroll,
|
|
692
|
+
onMouseleavePassive: stopAnimScroll,
|
|
693
|
+
onTouchendPassive: stopAnimScroll
|
|
614
694
|
})
|
|
615
695
|
)
|
|
616
696
|
|
|
@@ -8,8 +8,10 @@ import { hMergeSlot } from '../../utils/private/render.js'
|
|
|
8
8
|
import { isKeyCode, shouldIgnoreKey } from '../../utils/private/key-composition.js'
|
|
9
9
|
import { tabsKey } from '../../utils/private/symbols.js'
|
|
10
10
|
import { stopAndPrevent } from '../../utils/event.js'
|
|
11
|
+
import uid from '../../utils/uid.js'
|
|
12
|
+
import { isDeepEqual } from '../../utils/is.js'
|
|
11
13
|
|
|
12
|
-
let
|
|
14
|
+
let id = 0
|
|
13
15
|
|
|
14
16
|
export const useTabEmits = [ 'click', 'keydown' ]
|
|
15
17
|
|
|
@@ -22,7 +24,7 @@ export const useTabProps = {
|
|
|
22
24
|
|
|
23
25
|
name: {
|
|
24
26
|
type: [ Number, String ],
|
|
25
|
-
default: () => `t_${
|
|
27
|
+
default: () => `t_${ id++ }`
|
|
26
28
|
},
|
|
27
29
|
|
|
28
30
|
noCaps: Boolean,
|
|
@@ -38,7 +40,7 @@ export const useTabProps = {
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export default function (props, slots, emit,
|
|
43
|
+
export default function (props, slots, emit, routeData) {
|
|
42
44
|
const $tabs = inject(tabsKey, () => {
|
|
43
45
|
console.error('QTab/QRouteTab component needs to be child of QTabs')
|
|
44
46
|
})
|
|
@@ -75,7 +77,7 @@ export default function (props, slots, emit, routerProps) {
|
|
|
75
77
|
+ (props.icon && props.label && $tabs.tabProps.value.inlineLabel === false ? ' q-tab--full' : '')
|
|
76
78
|
+ (props.noCaps === true || $tabs.tabProps.value.noCaps === true ? ' q-tab--no-caps' : '')
|
|
77
79
|
+ (props.disable === true ? ' disabled' : ' q-focusable q-hoverable cursor-pointer')
|
|
78
|
-
+ (
|
|
80
|
+
+ (routeData !== void 0 ? routeData.linkClass.value : '')
|
|
79
81
|
)
|
|
80
82
|
|
|
81
83
|
const innerClass = computed(() =>
|
|
@@ -85,53 +87,77 @@ export default function (props, slots, emit, routerProps) {
|
|
|
85
87
|
)
|
|
86
88
|
|
|
87
89
|
const tabIndex = computed(() => (
|
|
88
|
-
|
|
90
|
+
(
|
|
91
|
+
props.disable === true
|
|
92
|
+
|| $tabs.hasFocus.value === true
|
|
93
|
+
|| (isActive.value === false && $tabs.hasActiveTab.value === true)
|
|
94
|
+
)
|
|
89
95
|
? -1
|
|
90
96
|
: props.tabindex || 0
|
|
91
97
|
))
|
|
92
98
|
|
|
93
99
|
function onClick (e, keyboard) {
|
|
94
|
-
keyboard !== true && blurTargetRef.value !== null
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
let go
|
|
100
|
+
if (keyboard !== true && blurTargetRef.value !== null) {
|
|
101
|
+
blurTargetRef.value.focus()
|
|
102
|
+
}
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
if (props.disable === true) {
|
|
105
|
+
// we should hinder native navigation though
|
|
106
|
+
if (routeData !== void 0 && routeData.hasRouterLink.value === true) {
|
|
107
|
+
stopAndPrevent(e)
|
|
108
|
+
}
|
|
109
|
+
return
|
|
110
|
+
}
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
// do we have a QTab?
|
|
113
|
+
if (routeData === void 0) {
|
|
114
|
+
$tabs.updateModel({ name: props.name })
|
|
115
|
+
emit('click', e)
|
|
116
|
+
return
|
|
117
|
+
}
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
if (routeData.hasRouterLink.value === true) {
|
|
120
|
+
const go = (opts = {}) => {
|
|
121
|
+
// if requiring to go to another route, then we
|
|
122
|
+
// let the QTabs route watcher do its job,
|
|
123
|
+
// otherwise directly select this
|
|
124
|
+
let hardError
|
|
125
|
+
const reqId = opts.to === void 0 || isDeepEqual(opts.to, props.to) === true
|
|
126
|
+
? ($tabs.avoidRouteWatcher = uid())
|
|
127
|
+
: null
|
|
128
|
+
|
|
129
|
+
return routeData.navigateToRouterLink(e, { ...opts, returnRouterError: true })
|
|
130
|
+
.catch(err => { hardError = err })
|
|
131
|
+
.then(softError => {
|
|
132
|
+
if (reqId === $tabs.avoidRouteWatcher) {
|
|
108
133
|
$tabs.avoidRouteWatcher = false
|
|
134
|
+
|
|
135
|
+
// if we don't have any hard errors or any soft errors, except for
|
|
136
|
+
// when navigating to the same route (on all other soft errors,
|
|
137
|
+
// like when navigation was aborted in a nav guard, we don't activate this tab)
|
|
138
|
+
if (
|
|
139
|
+
hardError === void 0 && (
|
|
140
|
+
softError === void 0
|
|
141
|
+
|| softError.message.startsWith('Avoided redundant navigation') === true
|
|
142
|
+
)
|
|
143
|
+
) {
|
|
144
|
+
$tabs.updateModel({ name: props.name })
|
|
145
|
+
}
|
|
109
146
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (err === void 0) {
|
|
115
|
-
$tabs.updateModel({ name: props.name, fromRoute: true })
|
|
116
|
-
}
|
|
117
|
-
})
|
|
147
|
+
|
|
148
|
+
if (opts.returnRouterError === true) {
|
|
149
|
+
return hardError !== void 0 ? Promise.reject(hardError) : softError
|
|
118
150
|
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
emit('click', e)
|
|
123
|
-
return
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
go = () => {
|
|
128
|
-
$tabs.updateModel({ name: props.name, fromRoute: false })
|
|
129
|
-
}
|
|
151
|
+
})
|
|
130
152
|
}
|
|
131
153
|
|
|
132
154
|
emit('click', e, go)
|
|
133
155
|
e.defaultPrevented !== true && go()
|
|
156
|
+
|
|
157
|
+
return
|
|
134
158
|
}
|
|
159
|
+
|
|
160
|
+
emit('click', e)
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
function onKeydown (e) {
|
|
@@ -205,17 +231,15 @@ export default function (props, slots, emit, routerProps) {
|
|
|
205
231
|
name: computed(() => props.name),
|
|
206
232
|
rootRef,
|
|
207
233
|
tabIndicatorRef,
|
|
208
|
-
|
|
234
|
+
routeData
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
onBeforeUnmount(() => {
|
|
212
238
|
$tabs.unregisterTab(tabData)
|
|
213
|
-
$tabs.recalculateScroll()
|
|
214
239
|
})
|
|
215
240
|
|
|
216
241
|
onMounted(() => {
|
|
217
242
|
$tabs.registerTab(tabData)
|
|
218
|
-
$tabs.recalculateScroll()
|
|
219
243
|
})
|
|
220
244
|
|
|
221
245
|
function renderTab (tag, customData) {
|