virtual_list/page_transition

Types

A (list_re, detail_re) route pair. Each page module owns its Pair — declare it as a module-level constant next to the rest of the page’s routing config, then pass it to register at app init.

list matches the list page path(s), e.g. "^(/contacts|/)$". detail matches the detail path AND captures the item id in group 1. Use (\\d+) for integer ids or ([^/]+) for arbitrary string ids (e.g. UUIDs).

pub const transition = page_transition.Pair(
  list: "^(/contacts|/)$",
  detail: "^/contacts/([^/]+)$",
)
pub type Pair {
  Pair(list: String, detail: String)
}

Constructors

  • Pair(list: String, detail: String)

Values

pub fn install() -> Nil

Install the global page-transition event handlers. Idempotent — calling twice is a no-op. Call once at app init, BEFORE modem.init, so the capture-phase popstate handler runs ahead of modem’s bubble-phase one.

Per-page route pairs are added separately via register.

pub const item_id_attr: String

Page transition support for virtual lists.

Virtual lists pool and reuse DOM nodes, so a view-transition-name set via inline style on one slot can linger when that slot is repurposed for a different item. Two elements with the same name in a snapshot causes an InvalidStateError. The pattern to avoid it:

  1. Before starting a transition, clear all [data-vt-field] elements.
  2. Tag only the specific item’s fields right before the snapshot.
  3. Repeat on cleanup.

Place item_id_attr on each row element and vt_field_attr on each child element that should morph during the transition. The JS helpers query by these attributes and set style.viewTransitionName from the value. Attribute placed on each row element to identify the item. Set it to the item’s id as a string (numeric ids should be passed through int.to_string).

attribute.attribute(page_transition.item_id_attr, item.id)
pub fn navigate_back(item_id: String) -> Nil

Navigate back (detail → list) with a view transition. Call this instead of history.back() when inside the app (e.g. a back button click). item_id must match the item_id_attr on the list row to morph back to. Numeric ids should be passed through int.to_string.

pub fn navigate_forward(
  item_id: String,
  path: String,
  then_fn: fn() -> Nil,
) -> Nil

Navigate forward (list → detail) with a view transition. item_id must match the item_id_attr on the list row to morph from. Numeric ids should be passed through int.to_string. then_fn is called after the history push (use it to mark history state).

pub fn register(pairs: List(Pair)) -> Nil

Register a batch of route pairs. The popstate handler iterates registered pairs to find a list ↔ detail transition match. Idempotent by regex source — registering the same Pair twice yields one registry entry.

Pass every page’s pair in one call from app init:

vt_pt.register([contacts.route_transition, users.route_transition])
pub fn uninstall() -> Nil

Remove every listener install registered and clear the pair registry. Useful for hot-reload and tests; ordinary SPAs never need this.

pub const vt_field_attr: String

Attribute placed on child elements that should morph during a view transition. The attribute value becomes the view-transition-name, so each value must be unique within the page at snapshot time.

attribute.attribute(page_transition.vt_field_attr, "contact-name")
Search Document