Bundle / foldkit-bundle
Reacting to a child's Messages
An OutMessage is what a child chooses to tell its parent. Sometimes the parent
must react to what the child received instead: a socket's Opened or
Failed, a media query's change. onMessage in the placement config sees each
of the child's Messages as a Step of the parent, after the child has handled it
and after its onOut:
const Observed = Page.assemble(
Page.at(Dark, { args: { query: '(prefers-color-scheme: dark)' } }),
Page.at(Narrow, {
args: { query: '(max-width: 40rem)' },
// Help closes when the window becomes narrow.
onMessage:
({ matches }) =>
model => ({ model: matches ? { ...model, helpOpen: false } : model }),
}),
)It observes; the child still owns its own transition, and a helper, which is
not a Message, does not reach it. A collection's onMessage also receives the
item's key.
The parent's own update, given to placements.update(own), never receives a
placement's wrapper: the placement takes it. Its Message is typed that way, as
Bundle.OwnMessage<Message, typeof placements.placements>, so an exhaustive
match over it needs no arm for GotDarkMessage. Match it with Effect's
Match.valueTags, which is exhaustive over the union it is given; a union's
own Message.match asks for every variant of the whole union.
type OwnMessage = Bundle.OwnMessage<Message, typeof Observed.placements>
const updateOwn = (model: Model, message: OwnMessage) =>
Match.valueTags(message, {
ClickedHelp: () => ({ model: { ...model, helpOpen: true } }),
})
Observed.update(updateOwn)A wiring's tags are strings at runtime, so a Message a wiring claims still
appears in OwnMessage.
Presets
bundle.with(args) binds the args, so a placement gives none:
const PrefersDark = MediaQuery.with({ query: '(prefers-color-scheme: dark)' })
Page.place(PrefersDark, 'dark')Page.place(bundle, field, config) is Page.at without a separate declaration,
for a Message union built another way.