# Test bottom focus (-1)assert resolve_focus_slot(-1, 5) ==4# Last slotassert resolve_focus_slot(-1, 3) ==2assert resolve_focus_slot(-1, 1) ==0# Test second from bottom (-2)assert resolve_focus_slot(-2, 5) ==3assert resolve_focus_slot(-2, 3) ==1print("Negative index focus tests passed!")
Negative index focus tests passed!
# Test positive focus positionsassert resolve_focus_slot(0, 5) ==0# Top slotassert resolve_focus_slot(1, 5) ==1# Second from topassert resolve_focus_slot(4, 5) ==4# Last slotprint("Positive index focus tests passed!")
Positive index focus tests passed!
# Test clamping for out-of-range valuesassert resolve_focus_slot(10, 5) ==4# Clamped to last slotassert resolve_focus_slot(-10, 5) ==0# Clamped to first slotprint("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).
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.
# Test center focus with 5 visible cards, 20 items, focused on item 10window = calculate_viewport_window(10, 20, 5)assert window == [8, 9, 10, 11, 12]print("Center viewport window test passed!")
Center viewport window test passed!
# 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!
# 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!
# Test bottom focus (-1): focused card at last slotwindow = 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!
# Test top focus (0): focused card at first slotwindow = 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!
# Test single card viewportwindow = 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.
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.
# Test with custom form input nameresult = 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!")