# Focus


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

## resolve_focus_slot

Converts the `focus_position` setting (which uses Python negative
indexing convention) into an actual 0-indexed slot position within the
viewport.

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

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

### resolve_focus_slot

``` python

def resolve_focus_slot(
    focus_position:Optional, # Slot offset (None=center, -1=bottom, 0=top)
    visible_count:int, # Number of visible card slots
)->int: # Resolved 0-indexed slot position

```

*Resolve focus_position to an actual slot index within the viewport.*

``` python
# Test center focus (None)
assert resolve_focus_slot(None, 5) == 2  # 5 cards -> slot 2 (middle)
assert resolve_focus_slot(None, 3) == 1  # 3 cards -> slot 1
assert resolve_focus_slot(None, 1) == 0  # 1 card -> slot 0
assert resolve_focus_slot(None, 7) == 3  # 7 cards -> slot 3
print("Center focus tests passed!")
```

    Center focus tests passed!

``` python
# Test bottom focus (-1)
assert resolve_focus_slot(-1, 5) == 4  # Last slot
assert resolve_focus_slot(-1, 3) == 2
assert resolve_focus_slot(-1, 1) == 0

# Test second from bottom (-2)
assert resolve_focus_slot(-2, 5) == 3
assert resolve_focus_slot(-2, 3) == 1
print("Negative index focus tests passed!")
```

    Negative index focus tests passed!

``` python
# Test positive focus positions
assert resolve_focus_slot(0, 5) == 0  # Top slot
assert resolve_focus_slot(1, 5) == 1  # Second from top
assert resolve_focus_slot(4, 5) == 4  # Last slot
print("Positive index focus tests passed!")
```

    Positive index focus tests passed!

``` python
# Test clamping for out-of-range values
assert resolve_focus_slot(10, 5) == 4   # Clamped to last slot
assert resolve_focus_slot(-10, 5) == 0  # Clamped to first slot
print("Clamping tests passed!")
```

    Clamping tests passed!

## calculate_viewport_window

Determines which item indices are visible in each viewport slot. Returns
`None` for slots that fall outside the items list (rendered as
placeholders).

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

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

### calculate_viewport_window

``` python

def calculate_viewport_window(
    focused_index:int, # Index of the focused item
    total_items:int, # Total number of items
    visible_count:int, # Number of visible card slots
    focus_position:Optional=None, # Focus slot (None=center)
)->List: # Item indices for each slot (negative or >= total_items for placeholders)

```

*Calculate which item indices should be visible in each viewport slot.*

``` python
# Test center focus with 5 visible cards, 20 items, focused on item 10
window = calculate_viewport_window(10, 20, 5)
assert window == [8, 9, 10, 11, 12]
print("Center viewport window test passed!")
```

    Center viewport window test passed!

``` python
# Test center focus at beginning (negative indices for placeholders)
window = calculate_viewport_window(0, 20, 5)
assert window == [-2, -1, 0, 1, 2]

window = calculate_viewport_window(1, 20, 5)
assert window == [-1, 0, 1, 2, 3]
print("Beginning placeholder tests passed!")
```

    Beginning placeholder tests passed!

``` python
# Test center focus at end (indices >= total_items for placeholders)
window = calculate_viewport_window(19, 20, 5)
assert window == [17, 18, 19, 20, 21]

window = calculate_viewport_window(18, 20, 5)
assert window == [16, 17, 18, 19, 20]
print("End placeholder tests passed!")
```

    End placeholder tests passed!

``` python
# Test bottom focus (-1): focused card at last slot
window = calculate_viewport_window(5, 20, 5, focus_position=-1)
assert window == [1, 2, 3, 4, 5]  # 4 context before, focused at end

# At beginning with bottom focus (all before slots are placeholders)
window = calculate_viewport_window(0, 20, 5, focus_position=-1)
assert window == [-4, -3, -2, -1, 0]
print("Bottom focus tests passed!")
```

    Bottom focus tests passed!

``` python
# Test top focus (0): focused card at first slot
window = calculate_viewport_window(5, 20, 5, focus_position=0)
assert window == [5, 6, 7, 8, 9]  # Focused first, 4 context after

# At end with top focus (all after slots are placeholders)
window = calculate_viewport_window(19, 20, 5, focus_position=0)
assert window == [19, 20, 21, 22, 23]
print("Top focus tests passed!")
```

    Top focus tests passed!

``` python
# Test single card viewport
window = calculate_viewport_window(5, 20, 1)
assert window == [5]
print("Single card viewport test passed!")
```

    Single card viewport test passed!

## render_focus_oob

Renders OOB hidden inputs to synchronize the focused index after HTMX
swaps. One input is for keyboard navigation focus recovery, the other
for HTMX form submissions.

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

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

### render_focus_oob

``` python

def render_focus_oob(
    focused_index:int, # The item index to focus
    ids:CardStackHtmlIds, # HTML IDs for this card stack instance
    form_input_name:str='focused_index', # Field name for the form input
)->Tuple: # Hidden inputs with OOB swap

```

*Render OOB hidden inputs to synchronize focus after HTMX swap.*

``` python
# Test render_focus_oob
ids = CardStackHtmlIds(prefix="cs0")
result = render_focus_oob(5, ids)
assert len(result) == 1
assert result[0].id == "cs0-focused-index"
assert result[0].name == "focused_index"
assert result[0].value == "5"
print("render_focus_oob tests passed!")
```

    render_focus_oob tests passed!

``` python
# Test with custom form input name
result = render_focus_oob(10, ids, form_input_name="segment_index")
assert result[0].name == "segment_index"
assert result[0].value == "10"
print("Custom form input name test passed!")
```

    Custom form input name test passed!
