Site / foldkit-site

Nested rendering

Site.view(site, route, model, h) draws the route: the deepest node's view, wrapped by every ancestor's layout root-first. Declare them on nodes:

ts
const Section = Site.route(sectionRouter, AppRoute.Section, {
  layout: {
    render: (child, model, h) => h.div([], [sidebar(model, h), child]),
  },
  view: {
    render: (model, h) => h.ul([], [...]),
  },
})

Ancestors contribute layouts only — never their views. A layout receives its composed child explicitly: no Outlet, no context provider, no hidden route state, no child router. Unknown tags and viewless leaves fail loudly instead of guessing.

Attached Surfaces. A node may name the Surface its route activates:

ts
const People = Site.route(peopleRouter, AppRoute.People, {
  surface: {
    surface: PeoplePage,
    params: route => ({ searchText: route.searchText }),
  },
})

Site.sources(site, App.owner, App.model.route) is each surfaced node as its Surface.when, keyed by tag, for Data.wiring, Data.subscriptions, Data.satisfy, or an SSR plan's surfaces. A surface from another application is refused here. Each entry answers its own tag only: on a person page the person surface is active and the people surface is not. Site.sourcesFor(site, owner, place, target.route) is the same entries for the target's chain only — the route-level Sources prefetch and SSR read. A layout surface active for several tags is not yet expressible — that is a Surface.whenAny-shaped extension, deliberately deferred until a real layout needs it.