22 * Header Squish Animation
33 *
44 * Two-step WAAPI animation for the header collapse/expand effect triggered
5- * on scroll. Uses the FLIP pattern (First → Last → Invert → Play) to
5+ * on scroll. Uses the FLIP pattern (First / Last / Invert / Play) to
66 * measure before/after states, then animates between them.
77 *
88 * Collapse (forward):
9- * Step 1 – scale/size reduction (brand, icons, nav text shrink in place)
10- * Step 2 – position shift (items move + header height change)
9+ * Step 1 -- scale/size reduction (brand, icons, nav text shrink in place)
10+ * Step 2 -- position shift (items move + header height change)
1111 *
1212 * Expand (reverse):
13- * Step 1 – position shift (header height grows + items move)
14- * Step 2 – scale/size growth (brand, icons, nav text grow)
13+ * Step 1 -- position shift (header height grows + items move)
14+ * Step 2 -- scale/size growth (brand, icons, nav text grow)
1515 */
1616import { handleScriptError } from '@components/scripts/errors/handler'
17+ import { getAnimationElements , type AnimationElements } from './selectors'
1718
1819// ============================================================================
1920// CONSTANTS
@@ -29,19 +30,6 @@ export const HEADER_TRANSITION_DURATION = 320
2930const EASING = 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'
3031const COLLAPSED_CLASS = 'is-collapsed'
3132
32- // ============================================================================
33- // TYPES
34- // ============================================================================
35-
36- interface AnimationElements {
37- headerShell : HTMLElement
38- siteHeader : HTMLElement
39- brand : HTMLElement
40- footprint : HTMLElement
41- icons : HTMLElement [ ]
42- navLinks : HTMLElement [ ]
43- }
44-
4533interface MeasuredSnapshot {
4634 brandTransform : string
4735 headerPaddingTop : string
@@ -78,7 +66,7 @@ export const animateCollapse = async (headerShell: HTMLElement): Promise<void> =
7866 if ( headerShell . classList . contains ( COLLAPSED_CLASS ) ) return
7967
8068 try {
81- const elements = queryElements ( headerShell )
69+ const elements = getAnimationElements ( headerShell )
8270 if ( ! elements ) {
8371 headerShell . classList . add ( COLLAPSED_CLASS )
8472 return
@@ -125,7 +113,7 @@ export const animateExpand = async (headerShell: HTMLElement): Promise<void> =>
125113 if ( ! headerShell . classList . contains ( COLLAPSED_CLASS ) ) return
126114
127115 try {
128- const elements = queryElements ( headerShell )
116+ const elements = getAnimationElements ( headerShell )
129117 if ( ! elements ) {
130118 headerShell . classList . remove ( COLLAPSED_CLASS )
131119 return
@@ -162,29 +150,6 @@ export const animateExpand = async (headerShell: HTMLElement): Promise<void> =>
162150 }
163151}
164152
165- // ============================================================================
166- // DOM QUERIES
167- // ============================================================================
168-
169- /**
170- * Query all animated elements from the header shell.
171- * Returns null if required elements are missing (e.g. during SSR or testing).
172- */
173- function queryElements ( headerShell : HTMLElement ) : AnimationElements | null {
174- const siteHeader = headerShell . querySelector < HTMLElement > ( '.site-header' )
175- const brand = headerShell . querySelector < HTMLElement > ( '.header-brand' )
176- const footprint = headerShell . querySelector < HTMLElement > ( '.header-footprint' )
177-
178- if ( ! siteHeader || ! brand || ! footprint ) return null
179-
180- const icons = Array . from ( headerShell . querySelectorAll < HTMLElement > ( '.header-icon' ) )
181- const navLinks = Array . from (
182- headerShell . querySelectorAll < HTMLElement > ( '.header-nav a' ) ,
183- )
184-
185- return { headerShell, siteHeader, brand, footprint, icons, navLinks }
186- }
187-
188153// ============================================================================
189154// MEASUREMENT
190155// ============================================================================
@@ -218,15 +183,15 @@ function measureState(elements: AnimationElements): MeasuredSnapshot {
218183/**
219184 * Build WAAPI animations for each element with 3-keyframe sequences.
220185 *
221- * Collapse (forward) — sizes first, then positions:
222- * 0% → expanded values for everything
223- * 50% → collapsed sizes, expanded positions
224- * 100% → collapsed sizes, collapsed positions
186+ * Collapse (forward) - sizes first, then positions:
187+ * 0% = expanded values for everything
188+ * 50% = collapsed sizes, expanded positions
189+ * 100% = collapsed sizes, collapsed positions
225190 *
226- * Expand (reverse) — positions first, then sizes:
227- * 0% → collapsed values for everything
228- * 50% → collapsed sizes, expanded positions
229- * 100% → expanded sizes, expanded positions
191+ * Expand (reverse) - positions first, then sizes:
192+ * 0% = collapsed values for everything
193+ * 50% = collapsed sizes, expanded positions
194+ * 100% = expanded sizes, expanded positions
230195 */
231196function buildAnimations (
232197 elements : AnimationElements ,
@@ -324,8 +289,8 @@ function buildAnimations(
324289
325290/**
326291 * Keyframes for a "size" property:
327- * Collapse → changes in first half, holds in second
328- * Expand → holds in first half, changes in second
292+ * Collapse - changes in first half, holds in second.
293+ * Expand - holds in first half, changes in second.
329294 */
330295function sizeFirstKeyframes (
331296 from : Record < string , string > ,
@@ -349,8 +314,8 @@ function sizeFirstKeyframes(
349314
350315/**
351316 * Keyframes for a "position" property:
352- * Collapse → holds in first half, changes in second
353- * Expand → changes in first half, holds in second
317+ * Collapse - holds in first half, changes in second.
318+ * Expand - changes in first half, holds in second.
354319 */
355320function positionFirstKeyframes (
356321 from : Record < string , string > ,
0 commit comments