Files
hedena_gold/apps/user-app/src/composables/useReveal.ts
T

44 lines
1.6 KiB
TypeScript

import { nextTick, ref } from 'vue'
/**
* First-paint entrance shared by the tab screens (Home, Dashboard, Cart):
* once a screen's first data load lands, its sections rise and fade in one
* after another. The styles are the global `.reveal` / `.is-revealed` pair in
* assets/styles/style.less.
*
* MasterLayout keeps the main tabs alive, but a screen still remounts after a
* full-page route or if it is not in the keep-alive list. Which screens have
* already played is kept here in module scope, so the entrance is a first-run
* flourish that resets only on a full reload — replaying it on each return
* would fight the page transition rather than add to it. (A `let` at the top of <script setup>
* would not do this: that code runs once per mount.)
*/
const played = new Set<string>()
export function useReveal(key: string, stepMs = 70) {
const revealed = ref(played.has(key))
// Each item starts a beat after the one before it. Kept small, so the whole
// sequence finishes well under a second and reads as the page arriving.
function revealDelay(i: number) {
return { '--reveal-delay': `${i * stepMs}ms` }
}
// Call once the first load has populated the DOM. Waits for the new nodes
// to be mounted, then for one painted frame in their "before" state — with
// a single frame the browser can resolve both states in the same style pass
// and there is nothing to animate.
async function reveal() {
if (revealed.value) return
await nextTick()
requestAnimationFrame(() =>
requestAnimationFrame(() => {
revealed.value = true
played.add(key)
}),
)
}
return { revealed, revealDelay, reveal }
}