Dialog
A modal that holds focus until it is answered or Escape dismisses it.
forSlots(DialogSlots)(Recipes.Dialog({}))
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 DialogStyle = forSlots(DialogSlots)(Recipes.Dialog({}))
const DangerStyle = forSlots(ButtonSlots)(Recipes.Button({ tone: 'danger' }))
const QuietStyle = forSlots(ButtonSlots)(Recipes.Button({ tone: 'neutral', variant: 'ghost' }))
/** The Messages that open and close the dialog, and the one that wraps its own. */
export interface DialogMessages<Message> {
readonly onOpen: Message
readonly onClose: Message
readonly toMessage: (message: UiDialog.Message) => Message
}
export const dialog = <Message>(
style: NamedStyle<typeof DialogSlots>,
model: UiDialog.Model,
messages: DialogMessages<Message>,
h: HtmlBuilder<Message>,
): Html =>
h.div(
[],
[
Button.view({ label: 'Delete project', onClick: messages.onOpen, style: DangerStyle }, h),
h.submodel({
slotId: model.id,
model,
view: UiDialog.view,
viewInputs: {
hasDescription: true,
toView: Dialog.toView([style.mixin], { h }, dialog =>
h.dialog(
dialog.dialog,
dialog.isVisible
? [
h.div(dialog.backdrop),
h.div(dialog.panel, [
h.button(dialog.closeButton, ['✕']),
h.h2(dialog.title, ['Delete this project?']),
h.p(dialog.description, [
'Its pages and their history go for good. Escape keeps it.',
]),
h.div(
[h.Style({ display: 'flex', gap: '0.5rem', justifyContent: 'end' })],
[
Button.view(
{ label: 'Cancel', onClick: messages.onClose, style: QuietStyle },
h,
),
Button.view(
{ label: 'Delete', onClick: messages.onClose, style: DangerStyle },
h,
),
],
),
]),
]
: [],
),
),
},
toParentMessage: messages.toMessage,
}),
],
)