CRUD / foldkit-crud

A screen's Messages

A page with an editor and a remover answers the same four Messages every time: open a row, start a new one, close, and ask to delete. Crud.screen states them once, named after the screen, and answers them through the placements' helpers:

ts
const PostScreen = Crud.screen('Post', { id: Schema.String })
// In the page: Bundle.withMessages({ ...PostScreen.messages }), beside its own:
// OpenedPost({ id }), CreatedPost(), ClosedPost(), AskedToRemovePost({ id }).

const update = PostScreen.update(
  { editor: PostEditor, editing: Placed, removing: RemoveForm },
  placements.update((model, message) =>
    Remote.reduces(message) ? { model: Data.reduce(model, message) } : { model },
  ),
)

update answers OpenedPost with Placed.helpers.open(id), CreatedPost with blank(), ClosedPost with close() and AskedToRemovePost with RemoveForm.helpers.ask(id); every other Message goes to your update, and PostEditor.after runs after each. Leave removing out for a screen that cannot delete. Given pickers (from Crud.options), it also answers a picker's AskedForMore with pickers.ask, read out of the page's Message through the editor placement's link, and the form still hears it (a page that also answers AskedForMore itself would show two pages more: do one or the other). The screen places nothing and holds no state: the children, their onOut, the query's input and the wiring stay the page's, and a page that writes these cases itself works the same.

Detail

One record through a Selection, for a page that shows it. Like a list it holds no state.

ts
const PostDetail = Crud.detail('PostDetail', { selection: PostPage }).at({
  data: Data,
  id: model => Option.fromNullOr(model.shownPostId), // none while none is shown
})

PostDetail.value(model) // RemoteData of the Selection's value

Crud.detail(...).fields lists the selected members with their labels, as a list's columns does. PostDetail.active makes the value a requirement while an id is shown, and PostDetail.refresh(model) asks for it again.