# JS: Touch Navigation


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## generate_touch_nav_js

Converts touch gestures on the card stack container into navigation
button clicks and scale adjustments. Uses the Pointer Events API with
`setPointerCapture` so that events survive HTMX OOB DOM swaps mid-drag.

**Single-finger gestures:**

- *Simple swipe* — a quick flick that doesn’t cover a full card height
  triggers one navigation step.
- *Touch-and-drag* — holding the finger down and dragging triggers one
  step each time the finger travels one focused-slot-height of distance.
  After direction lock, `setPointerCapture` pins events to the card
  stack element so DOM mutations underneath don’t break tracking.
- *Momentum* — a fast swipe continues navigating after the finger lifts,
  decelerating via an exponential friction model.

**Two-finger gestures:**

- *Pinch-to-zoom* — maps to the card stack’s `increaseScale` /
  `decreaseScale` functions.

Supports mode-based disabling via `disable_in_modes`.

------------------------------------------------------------------------

<a
href="https://github.com/cj-mills/cjm-fasthtml-card-stack/blob/main/cjm_fasthtml_card_stack/js/touch.py#L20"
target="_blank" style="float:right; font-size:smaller">source</a>

### generate_touch_nav_js

``` python

def generate_touch_nav_js(
    ids:CardStackHtmlIds, # HTML IDs for this card stack instance
    button_ids:CardStackButtonIds, # Button IDs for navigation triggers
    disable_in_modes:Tuple=(), # Mode names where touch nav is suppressed
    zone_id:str='', # Keyboard zone ID to activate on touch interaction
)->str: # JavaScript code fragment for touch navigation

```

*Generate JS for touch gesture to navigation conversion.*

``` python
# Test touch nav JS generation
from cjm_fasthtml_card_stack.core.html_ids import CardStackHtmlIds
from cjm_fasthtml_card_stack.core.button_ids import CardStackButtonIds

ids = CardStackHtmlIds(prefix="cs0")
btn = CardStackButtonIds(prefix="cs0")
js = generate_touch_nav_js(ids, btn)

# Element IDs and button IDs present
assert ids.card_stack in js
assert btn.nav_up in js
assert btn.nav_down in js

# No mode check when no modes specified
assert "isTouchDisabled" not in js

# Setup function exposed on namespace
assert "ns._setupTouchNav" in js

# Pointer Events API (not Touch Events)
assert "pointerdown" in js
assert "pointermove" in js
assert "pointerup" in js
assert "pointercancel" in js
assert "pointerType" in js
assert "setPointerCapture" in js

# Pointer tracking map for multi-touch
assert "pointers" in js
assert "primaryId" in js

# Pinch-to-zoom maps to scale controls
assert "ns.increaseScale" in js
assert "ns.decreaseScale" in js

# Momentum with requestAnimationFrame and friction
assert "_TOUCH_MOMENTUM_FRICTION" in js
assert "requestAnimationFrame" in js
assert "momentumTick" in js

# Direction locking (horizontal vs vertical)
assert "deltaX" in js

# Step distance from focused slot
assert "_getTouchStepDistance" in js
assert "viewport-slot" in js

# Constants inlined
assert "_TOUCH_SWIPE_THRESHOLD" in js
assert "_TOUCH_PINCH_THRESHOLD" in js
assert "_TOUCH_VEL_SAMPLES" in js

# Velocity history buffer
assert "history" in js

# Uses AbortController for clean listener teardown/re-setup
assert "AbortController" in js
assert "_touchNavAbort" in js
assert "signal" in js

# No zone activation when zone_id not provided
assert "setActiveZone" not in js

# Zone activation when zone_id provided
js_zone = generate_touch_nav_js(ids, btn, zone_id="my-card-stack")
assert "setActiveZone('my-card-stack')" in js_zone

print("Touch nav JS basic tests passed!")
```

    Touch nav JS basic tests passed!

``` python
# Test with disabled modes
js_modes = generate_touch_nav_js(ids, btn, disable_in_modes=("split", "edit"))
assert "isTouchDisabled" in js_modes
assert "'split'" in js_modes
assert "'edit'" in js_modes
# Momentum loop also checks mode
assert "isTouchDisabled" in js_modes
print("Touch nav JS mode disabling tests passed!")
```

    Touch nav JS mode disabling tests passed!
