JavaScript generator for dynamic viewport height calculation.
generate_viewport_height_js
Delegates to cjm-fasthtml-viewport-fit for the core measurement algorithm.
The card stack uses the library’s individual generator functions (not the top-level IIFE compositor) because the card stack has its own IIFE in core.py that coordinates resize across multiple subsystems (viewport height, width, scale, scroll, touch, auto-adjust).
What the card stack coordinator handles (not delegated to viewport-fit): - IIFE wrapper — the card stack has its own in core.py - HTMX settle — coordinator’s _afterSettleHandler with card-stack-specific filtering
What viewport-fit provides: - Debug helpers (conditional logging via window.viewportFitDebug_{prefix}) - Space-below DOM walker - Collapse-measure-apply height calculation (with box-sizing awareness) - Debounced resize handler with auto-adjust callback - Sibling observation via ResizeObserver (auto-recalculates when siblings resize) - Initialization with scroll-to-top for consistent HTMX SPA measurements
def generate_viewport_height_js( ids:CardStackHtmlIds, # HTML IDs for this card stack instance container_id:str='', # Unused — kept for API compatibility)->str: # JavaScript code fragment for viewport height calculation
Generate JS for dynamic viewport height calculation via cjm-fasthtml-viewport-fit.
Delegates to the viewport-fit library’s individual generator functions. The card stack coordinator handles HTMX settle events separately.
# Test that the generator produces valid JS referencing correct IDsids = CardStackHtmlIds(prefix="cs0")js = generate_viewport_height_js(ids, container_id="my-container")assert ids.card_stack in jsassert ids.card_stack_inner in jsassert"ns.recalculateHeight"in jsassert"_calculateAndSetHeight"in js# Verify position-based measurement approachassert"spaceAbove"in jsassert"spaceBelow"in jsassert"_calculateSpaceBelow"in js# Verify temporary collapse approach for accurate measurementassert"'0px'"in jsassert"offsetHeight"in js # Force reflow# Verify position-based sibling detection (beside vs below)assert"siblingRect.top < currentRect.bottom"in js# Verify debug mode uses viewport-fit conventionassertf"viewportFitDebug_{ids.prefix}"in jsassertf"[vf:{ids.prefix}]"in js# Verify auto-adjust trigger in resize handlerassert"ns.triggerAutoAdjust"in js# Verify resize listener uses remove-and-replacehandler_key =f"_vfResizeHandler_{ids.prefix.replace('-', '_')}"assertf"window.{handler_key}"in jsassert"removeEventListener"in js# Verify sibling observerassert"_setupSiblingObserver"in jsassert"ResizeObserver"in jsassert"ns._setupSiblingObserver"in js# Verify init with scroll-to-topassert"window.scrollTo(0, 0)"in js# Verify section comment for core.py compositionassert"Viewport Height"in jsprint("Viewport height JS generator tests passed!")
Viewport height JS generator tests passed!
# container_id is unused — both paths produce identical outputjs_no_container = generate_viewport_height_js(ids)assert js == js_no_container# Verify position-based measurement is presentassert"spaceAbove"in js_no_containerassert"_calculateSpaceBelow"in js_no_containerprint("Viewport height JS container_id compatibility test passed!")
Viewport height JS container_id compatibility test passed!