///|
pub(all) enum OverlayCloseReason {
CloseButton
Backdrop
Action
PageHidden
Programmatic
} derive(Eq, Debug)
///|
struct OverlayScope {
id : String
open : Bool
visible : Bool
disabled : Bool
modal : Bool
force_mount : Bool
close_on_overlay : Bool
kind : OverlayKind
bounds : @headless.Bounds?
change : @minimoon.Emit[(Bool, OverlayCloseReason)]
toggle : @minimoon.Cmd
act : @minimoon.Emit[(@minimoon.Cmd, Bool, OverlayCloseReason)]
}
///|
pub fn overlay_is_open(scope : OverlayScope) -> Bool {
scope.open
}
///|
pub fn overlay_open(scope : OverlayScope) -> @minimoon.Cmd {
(scope.change)((true, Programmatic))
}
///|
pub fn overlay_close(
scope : OverlayScope,
reason? : OverlayCloseReason = Programmatic,
) -> @minimoon.Cmd {
(scope.change)((false, reason))
}
///|
pub fn overlay_toggle(scope : OverlayScope) -> @minimoon.Cmd {
scope.toggle
}
///|
pub fn[C : @minimoon.IsChildren] overlay_trigger(
scope : OverlayScope,
children : C,
on_tap? : @minimoon.Cmd,
class? : String = "",
) -> @minimoon.Node {
let command = if scope.disabled {
@minimoon.none
} else {
@minimoon.batch([overlay_toggle(scope), on_tap.unwrap_or(@minimoon.none)])
}
let semantics = @minimoon.semantics(
expanded=scope.open,
controls=scope.id + "-surface",
has_popup="dialog",
)
if scope.kind is ContextSurface {
@minimoon.touch_view(
id=scope.id + "-trigger",
class="mmui-overlay-trigger " + class,
event_key=scope.id + "/trigger",
semantics~,
on_tap=command,
on_long_press=@minimoon.Emit(_ => command),
children,
)
} else {
@minimoon.button_children(
id=scope.id + "-trigger",
class="mmui-overlay-trigger " + class,
event_key=scope.id + "/trigger",
semantics~,
disabled=scope.disabled,
on_tap=command,
children,
)
}
}
///|
pub fn[C : @minimoon.IsChildren] overlay_content(
scope : OverlayScope,
children : C,
show_close? : Bool = true,
close_label? : String = "Close",
class? : String = "",
style? : String = "",
) -> @minimoon.Node {
let displayed = scope.open && scope.visible
if !displayed && !scope.force_mount {
return @minimoon.nothing()
}
let surface = ui_container(
"surface",
id=scope.id + "-surface",
class~,
style=surface_style(scope.kind, scope.bounds) +
(if displayed { "" } else { "display:none;" }) +
style,
semantics=@minimoon.semantics(
role=if scope.kind is TooltipSurface {
@minimoon.TooltipRole
} else if scope.kind is AlertSurface {
@minimoon.AlertDialogRole
} else {
@minimoon.DialogRole
},
modal=scope.modal,
labelled_by=scope.id + "-title",
described_by=scope.id + "-description",
hidden=!displayed,
),
[
@minimoon.fragment(children.to_nodes()),
if show_close {
overlay_close_button(scope, close_label)
} else {
@minimoon.nothing()
},
],
)
@minimoon.layer(id=scope.id + "-layer", [
if displayed {
@minimoon.tap_view(
class="mmui-overlay",
style="position:fixed;inset:0;",
event_key=scope.id + "/dismiss",
on_tap=if scope.close_on_overlay && !(scope.kind is AlertSurface) {
overlay_close(scope, reason=Backdrop)
} else {
@minimoon.none
},
@minimoon.nothing(),
)
} else {
@minimoon.nothing()
},
surface,
])
}
///|
pub fn[C : @minimoon.IsChildren] overlay_title(
scope : OverlayScope,
children : C,
) -> @minimoon.Node {
@minimoon.h1(id=scope.id + "-title", class="mmui-surface-title", children)
}
///|
pub fn[C : @minimoon.IsChildren] overlay_description(
scope : OverlayScope,
children : C,
) -> @minimoon.Node {
ui_container(
"surface-description",
id=scope.id + "-description",
children.to_nodes(),
)
}
///|
pub fn[C : @minimoon.IsChildren] overlay_header(children : C) -> @minimoon.Node {
ui_container("surface-header", children.to_nodes())
}
///|
pub fn[C : @minimoon.IsChildren] overlay_footer(children : C) -> @minimoon.Node {
ui_container("surface-footer", children.to_nodes())
}
///|
pub fn[C : @minimoon.IsChildren] overlay_close_button(
scope : OverlayScope,
children : C,
on_tap? : @minimoon.Cmd,
key? : String = "close",
) -> @minimoon.Node {
@minimoon.button_children(
event_key=scope.id + "/" + key,
disabled=!scope.open || !scope.visible,
on_tap=(scope.act)((on_tap.unwrap_or(@minimoon.none), true, CloseButton)),
children,
)
}
///|
pub fn[C : @minimoon.IsChildren] overlay_action(
scope : OverlayScope,
children : C,
on_tap~ : @minimoon.Cmd,
close? : Bool = true,
key? : String = "action",
) -> @minimoon.Node {
@minimoon.button_children(
event_key=scope.id + "/" + key,
disabled=!scope.open || !scope.visible,
on_tap=(scope.act)((on_tap, close, Action)),
children,
)
}
///|
pub fn overlay_arrow(side? : Side = Top) -> @minimoon.Node {
let margin = match side {
Top => "margin-top:-20px;"
Bottom => "margin-bottom:-20px;"
Left => "margin-left:-20px;"
Right => "margin-right:-20px;"
}
ui_container(
"surface-arrow",
style="width:8px;height:8px;background:var(--mmui-background);transform:rotate(45deg);" +
margin,
semantics=@minimoon.semantics(hidden=true),
[],
)
}