Router

Convenience router factory that wires up standard card stack routes (Tier 2 API).

init_card_stack_router

Factory function that creates an APIRouter with all standard card stack routes wired up. Returns a tuple of (APIRouter, CardStackUrls) so the consumer has access to the route URLs for keyboard navigation and component rendering.

For consumers who need custom before/after logic in their handlers (e.g., resetting a caret position before entering split mode), use the Tier 1 response builder functions from routes.handlers directly instead.


source

init_card_stack_router


def init_card_stack_router(
    config:CardStackConfig, # Card stack configuration
    state_getter:Callable, # Function to get current state
    state_setter:Callable, # Function to save state
    get_items:Callable, # Function to get current items list
    render_card:Callable, # Card renderer callback: (item, CardRenderContext) -> FT
    route_prefix:str='/card-stack', # Route prefix for all card stack routes
    progress_label:str='Item', # Label for progress indicator
)->Tuple: # (router, urls) tuple

Initialize an APIRouter with all standard card stack routes.

Tests

from cjm_fasthtml_card_stack.core.config import _reset_prefix_counter
from cjm_fasthtml_card_stack.core.models import CardRenderContext
from fasthtml.common import Div, Span

# Simple render_card for testing
def _test_render(item, ctx: CardRenderContext):
    return Div(Span(f"{item}"), cls=f"card-{ctx.card_role}")

# Simple state storage
_reset_prefix_counter()
_state = CardStackState()
_items = [f"Test item {i}" for i in range(10)]

def _get_state(): return _state
def _set_state(s): global _state; _state = s
def _get_items(): return _items

print("Test setup ready.")
Test setup ready.
# Test router creation and URL generation
_reset_prefix_counter()
config = CardStackConfig(prefix="demo")

router, urls = init_card_stack_router(
    config=config,
    state_getter=_get_state,
    state_setter=_set_state,
    get_items=_get_items,
    render_card=_test_render,
    route_prefix="/cs",
)

assert router is not None
assert router.prefix == "/cs"
print(f"Router prefix: {router.prefix}")
Router prefix: /cs
# Test URL generation
assert urls.nav_up == "/cs/nav_up"
assert urls.nav_down == "/cs/nav_down"
assert urls.nav_first == "/cs/nav_first"
assert urls.nav_last == "/cs/nav_last"
assert urls.nav_page_up == "/cs/nav_page_up"
assert urls.nav_page_down == "/cs/nav_page_down"
assert urls.nav_to_index == "/cs/nav_to_index"
assert urls.update_viewport == "/cs/update_viewport"
assert urls.save_width == "/cs/save_width"
assert urls.save_scale == "/cs/save_scale"
print("All URL generation tests passed!")
print(f"Sample URL: {urls.nav_up}")
All URL generation tests passed!
Sample URL: /cs/nav_up
# Test multi-instance routers produce unique URL prefixes
config_a = CardStackConfig(prefix="text")
config_b = CardStackConfig(prefix="vad")

router_a, urls_a = init_card_stack_router(
    config_a, _get_state, _set_state, _get_items, _test_render,
    route_prefix="/text-stack",
)
router_b, urls_b = init_card_stack_router(
    config_b, _get_state, _set_state, _get_items, _test_render,
    route_prefix="/vad-stack",
)

assert urls_a.nav_up == "/text-stack/nav_up"
assert urls_b.nav_up == "/vad-stack/nav_up"
assert urls_a.nav_up != urls_b.nav_up
print("Multi-instance URL uniqueness tests passed!")
Multi-instance URL uniqueness tests passed!