fix: replace legacy timeouts with v-bind in navtab component (#5343)
* fix: dont use timeouts for navtabs * fix: remove nexttick
This commit is contained in:
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Component } from 'vue'
|
import type { Component } from 'vue'
|
||||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
|
|
||||||
const route = useNativeRoute()
|
const route = useNativeRoute()
|
||||||
|
|
||||||
@@ -104,6 +104,9 @@ const subpageSelected = ref(false)
|
|||||||
const sliderReady = ref(false) // Slider is positioned and should be visible
|
const sliderReady = ref(false) // Slider is positioned and should be visible
|
||||||
const transitionsEnabled = ref(false) // CSS transitions should apply (after first paint)
|
const transitionsEnabled = ref(false) // CSS transitions should apply (after first paint)
|
||||||
|
|
||||||
|
// Stagger delays for the trailing edges of the slider animation
|
||||||
|
const sliderDelays = ref({ left: '0ms', top: '0ms', right: '0ms', bottom: '0ms' })
|
||||||
|
|
||||||
const filteredLinks = computed(() => props.links.filter((link) => link.shown ?? true))
|
const filteredLinks = computed(() => props.links.filter((link) => link.shown ?? true))
|
||||||
|
|
||||||
const sliderStyle = computed(() => ({
|
const sliderStyle = computed(() => ({
|
||||||
@@ -114,6 +117,11 @@ const sliderStyle = computed(() => ({
|
|||||||
opacity: sliderReady.value && currentActiveIndex.value !== -1 ? 1 : 0,
|
opacity: sliderReady.value && currentActiveIndex.value !== -1 ? 1 : 0,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const leftDelay = computed(() => sliderDelays.value.left)
|
||||||
|
const rightDelay = computed(() => sliderDelays.value.right)
|
||||||
|
const topDelay = computed(() => sliderDelays.value.top)
|
||||||
|
const bottomDelay = computed(() => sliderDelays.value.bottom)
|
||||||
|
|
||||||
const isActiveAndNotSubpage = computed(
|
const isActiveAndNotSubpage = computed(
|
||||||
() => (index: number) => currentActiveIndex.value === index && !subpageSelected.value,
|
() => (index: number) => currentActiveIndex.value === index && !subpageSelected.value,
|
||||||
)
|
)
|
||||||
@@ -229,25 +237,20 @@ function animateSliderTo(newPosition: {
|
|||||||
right: number
|
right: number
|
||||||
bottom: number
|
bottom: number
|
||||||
}) {
|
}) {
|
||||||
const STAGGER_DELAY = 200
|
const STAGGER_DELAY = '200ms'
|
||||||
|
|
||||||
// Horizontal animation - lead with the direction of movement
|
// Set stagger delays: leading edge moves immediately, trailing edge is delayed
|
||||||
if (newPosition.left < sliderLeft.value) {
|
sliderDelays.value = {
|
||||||
sliderLeft.value = newPosition.left
|
left: newPosition.left < sliderLeft.value ? '0ms' : STAGGER_DELAY,
|
||||||
setTimeout(() => (sliderRight.value = newPosition.right), STAGGER_DELAY)
|
right: newPosition.left < sliderLeft.value ? STAGGER_DELAY : '0ms',
|
||||||
} else {
|
top: newPosition.top < sliderTop.value ? '0ms' : STAGGER_DELAY,
|
||||||
sliderRight.value = newPosition.right
|
bottom: newPosition.top < sliderTop.value ? STAGGER_DELAY : '0ms',
|
||||||
setTimeout(() => (sliderLeft.value = newPosition.left), STAGGER_DELAY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical animation - lead with the direction of movement
|
sliderLeft.value = newPosition.left
|
||||||
if (newPosition.top < sliderTop.value) {
|
sliderRight.value = newPosition.right
|
||||||
sliderTop.value = newPosition.top
|
sliderTop.value = newPosition.top
|
||||||
setTimeout(() => (sliderBottom.value = newPosition.bottom), STAGGER_DELAY)
|
sliderBottom.value = newPosition.bottom
|
||||||
} else {
|
|
||||||
sliderBottom.value = newPosition.bottom
|
|
||||||
setTimeout(() => (sliderTop.value = newPosition.top), STAGGER_DELAY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveTab() {
|
function updateActiveTab() {
|
||||||
@@ -256,7 +259,7 @@ function updateActiveTab() {
|
|||||||
subpageSelected.value = isSubpage
|
subpageSelected.value = isSubpage
|
||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
nextTick(positionSlider)
|
positionSlider()
|
||||||
} else {
|
} else {
|
||||||
sliderLeft.value = 0
|
sliderLeft.value = 0
|
||||||
sliderRight.value = 0
|
sliderRight.value = 0
|
||||||
@@ -293,7 +296,10 @@ watch(() => props.links, updateActiveTab, { deep: true })
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.navtabs-transition {
|
.navtabs-transition {
|
||||||
transition:
|
transition:
|
||||||
all 150ms cubic-bezier(0.4, 0, 0.2, 1),
|
left 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(leftDelay),
|
||||||
|
right 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(rightDelay),
|
||||||
|
top 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(topDelay),
|
||||||
|
bottom 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(bottomDelay),
|
||||||
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
|
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user