|
1 | 1 | import { shallowRef, ref, unref, watch, computed, readonly, type CSSProperties as CSS } from 'vue' |
2 | 2 |
|
3 | | -import { isSSR, useReducedMotion } from './utils' |
| 3 | +import { useReducedMotion, isBrowser } from './utils' |
4 | 4 | import { TRANSITION_STYLES } from './constants' |
5 | 5 |
|
6 | 6 | import type { UseFixedHeaderOptions, MaybeTemplateRef } from './types' |
@@ -29,10 +29,9 @@ export function useFixedHeader( |
29 | 29 |
|
30 | 30 | const internal = { |
31 | 31 | resizeObserver: undefined as ResizeObserver | undefined, |
32 | | - skipInitialObserverCb: true, |
| 32 | + initResizeObserver: false, |
33 | 33 | isListeningScroll: false, |
34 | 34 | isHovering: false, |
35 | | - isMount: true, |
36 | 35 | } |
37 | 36 |
|
38 | 37 | const styles = shallowRef<CSS>({}) |
@@ -80,47 +79,15 @@ export function useFixedHeader( |
80 | 79 |
|
81 | 80 | // Callbacks |
82 | 81 |
|
83 | | - /** |
84 | | - * Hides the header on page load before it has a chance to paint |
85 | | - * if scroll restoration is instant. If not, applies the enter |
86 | | - * styles immediately (without transitions). |
87 | | - */ |
88 | | - function onScrollRestoration() { |
89 | | - window.requestAnimationFrame(() => { |
90 | | - if (!internal.isMount) return |
91 | | - |
92 | | - if (!isFixed()) { |
93 | | - internal.isMount = false |
94 | | - return |
95 | | - } |
96 | | - |
97 | | - const isInstant = getScrollTop() > getHeaderHeight() * 1.2 // Resolves to false if scroll is smooth |
98 | | - |
99 | | - if (isInstant) { |
100 | | - setStyles({ |
101 | | - transform: leaveStyles.transform, |
102 | | - ...(transitionOpacity() ? { opacity: 0 } : {}), |
103 | | - visibility: 'hidden', |
104 | | - }) |
105 | | - } else { |
106 | | - setStyles({ |
107 | | - transform: enterStyles.transform, |
108 | | - ...(transitionOpacity() ? { opacity: 1 } : {}), |
109 | | - }) |
110 | | - } |
111 | | - |
112 | | - internal.isMount = false |
113 | | - }) |
114 | | - } |
115 | | - |
116 | 82 | /** |
117 | 83 | * Resize observer is added wheter or not the header is fixed/sticky |
118 | 84 | * as it is in charge of toggling scroll/pointer listeners if it |
119 | 85 | * turns from fixed/sticky to something else and vice-versa. |
120 | 86 | */ |
121 | 87 | function addResizeObserver() { |
122 | 88 | internal.resizeObserver = new ResizeObserver(() => { |
123 | | - if (internal.skipInitialObserverCb) return (internal.skipInitialObserverCb = false) |
| 89 | + // Skip the initial call |
| 90 | + if (!internal.initResizeObserver) return (internal.initResizeObserver = true) |
124 | 91 | toggleListeners() |
125 | 92 | }) |
126 | 93 |
|
@@ -189,7 +156,7 @@ export function useFixedHeader( |
189 | 156 | // Scroll Events |
190 | 157 |
|
191 | 158 | function createScrollHandler() { |
192 | | - let prevTop = 0 |
| 159 | + let prevTop = isBrowser ? getScrollTop() : 0 |
193 | 160 |
|
194 | 161 | return () => { |
195 | 162 | const scrollTop = getScrollTop() |
@@ -276,22 +243,22 @@ export function useFixedHeader( |
276 | 243 | removePointerListener() |
277 | 244 | } |
278 | 245 |
|
279 | | - !isSSR && |
| 246 | + isBrowser && |
280 | 247 | watch( |
281 | 248 | () => [unref(target), getRoot(), isReduced.value, unref(options.watch)], |
282 | 249 | ([headerEl, rootEl, isReduced], _, onCleanup) => { |
283 | 250 | const shouldInit = !isReduced && headerEl && (rootEl || rootEl === null) |
284 | 251 |
|
285 | 252 | if (shouldInit) { |
286 | 253 | addResizeObserver() |
287 | | - onScrollRestoration() |
288 | 254 | toggleListeners() |
289 | 255 | } |
290 | 256 |
|
291 | 257 | onCleanup(() => { |
292 | 258 | removeListeners() |
293 | | - internal.resizeObserver?.disconnect() |
294 | 259 | removeStyles() |
| 260 | + internal.resizeObserver?.disconnect() |
| 261 | + internal.initResizeObserver = false |
295 | 262 | }) |
296 | 263 | }, |
297 | 264 | { immediate: true, flush: 'post' }, |
|
0 commit comments