Primitives / State

Start with one: a page

ts
import { Schema } from 'effect'
import type { HtmlBuilder } from 'foldkit/html'
import { Bundle } from 'foldkit-bundle'
import { Pagination, PaginationMessage, pageCount, range } from 'foldkit-primitives/state'

const Page = Bundle.compose({}).pipe(
  Bundle.withChild('paging', Pagination, { args: { perPage: 20 } }),
)
type Model = typeof Page.Model.Type
type Message = typeof Page.Message.Type
const { placements } = Page

const config = placements.complete({
  init: () => placements.initial({}),
  update: placements.update(model => ({ model })),
  view: (model: Model, h: HtmlBuilder<Message>) =>
    h.nav(
      [],
      range(1, (pageCount(model.paging) ?? 0) + 1).map(page =>
        h.button(
          [h.OnClick(Page.Message.GotPagingMessage({ message: PaginationMessage.GoToPage({ page }) }))],
          [String(page)],
        ),
      ),
    ),
  subscriptions: placements.subscriptions(),
})

total is null until the application learns it and sends SetTotal; pageCount is null until then, and offset(model) is the first item's index for a slice or a query. Every transition clamps: past the last page lands on it, below one lands on one, and a smaller total pulls the page back. SetPerPage ignores a non-positive size and SetTotal a negative total.