Toast
A notice in the corner that goes by itself, or when dismissed.
forSlots(ToastSlots)(Recipes.Toast({}))
Usage
The function that drew the preview, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.
export const ToastStyle = forSlots(ToastSlots)(Recipes.Toast({}))
const NoticeStyle = forSlots(ItemSlots)(Recipes.Item({}))
const DismissStyle = forSlots(ButtonSlots)(
Recipes.Button({ tone: 'neutral', variant: 'ghost', size: 'sm' }),
)
export const Notice = Schema.Struct({ title: Schema.String, text: Schema.String })
// Annotated: the inferred type names a foldkit internal module.
export const Notices: ReturnType<typeof ToastView.make<typeof Notice.Type, typeof Notice.Encoded>> =
ToastView.make(Notice)
/** The stack and each entry's timer are the component's; what was said is the Message's. */
export interface ToastMessages<Message> {
readonly onNotify: Message
readonly toMessage: (message: typeof Notices.Message.Type) => Message
}
export const toast = <Message>(
style: NamedStyle<typeof ToastSlots>,
model: typeof Notices.Model.Type,
messages: ToastMessages<Message>,
h: HtmlBuilder<Message>,
): Html =>
h.div(
[],
[
Button.view({ label: 'Save draft', onClick: messages.onNotify, style: ButtonStyle }, h),
h.submodel({
slotId: model.id,
model,
view: Notices.view,
viewInputs: {
position: 'BottomRight',
entryToView: (entry, handlers) =>
Item.view(
{
title: entry.payload.title,
description: entry.payload.text,
actions: h.button(
SlotView.buildersFor(ButtonSlots, [DismissStyle.mixin], {
input: undefined,
h,
}).button.attrs([...handlers.dismiss, h.Type('button'), h.AriaLabel('Dismiss')]),
['✕'],
),
style: NoticeStyle,
},
h,
),
toView: Toast.toView([style.mixin], { h }, ({ container, entries }) =>
h.div(
container,
entries.map(entry => h.keyed('div')(entry.id, entry.attributes, [entry.content])),
),
),
},
toParentMessage: messages.toMessage,
}),
],
)