///|
/// One tab in a `tabs` control.
pub(all) struct TabEntry {
value : String
label : String
icon : @html.Html?
}
///|
pub fn TabEntry::new(
value : String,
label : String,
icon? : @html.Html,
) -> TabEntry {
{ value, label, icon, }
}
///|
const TabsListStyle : String = "display:inline-flex;align-items:center;gap:4px;padding:2px;border-radius:var(--sumi-radius-lg,12px);background:var(--sumi-block,rgba(255,255,255,0.08))"
///|
const TabsTriggerBaseStyle : String = "display:inline-flex;flex:none;align-items:center;justify-content:center;gap:4px;height:28px;padding:0 10px;margin:0;border:none;border-radius:calc(var(--sumi-radius,8px) - 2px);background:transparent;font-size:12px;line-height:20px;font-weight:500;white-space:nowrap;cursor:pointer;user-select:none;appearance:none;-webkit-appearance:none;outline:none"
///|
const TabsTriggerOnStyle : String = "background:var(--sumi-spotlight,#292929);color:var(--sumi-text,#ffffff)"
///|
const TabsTriggerOffStyle : String = "color:var(--sumi-text-secondary,rgba(255,255,255,0.7))"
///|
/// A tab strip. Controlled: the caller owns the selected value; render the
/// matching panel content next to the returned strip.
///
/// ```moonbit nocheck
/// tabs(
/// items=[TabEntry::new("all", "All"), TabEntry::new("mine", "Mine")],
/// selected=tab,
/// on_select=set_tab.map(v => _ => v),
/// )
/// ```
pub fn tabs(
items~ : Array[TabEntry],
selected~ : String,
on_select? : @internal.Emit[String],
id? : String,
class? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
) -> @html.Html {
let element_attrs = @internal.sumi_attrs(attrs).data_set("slot", "tabs")
@html.div(
style=@internal.sumi_styles(
[
@internal.SumiBoxSizing,
@internal.SumiFontSans,
@internal.SumiTextRendering,
TabsListStyle,
],
style,
),
id?,
class?,
attrs=element_attrs,
items.map(item => {
let is_selected = item.value == selected
let trigger_attrs = @html.Attrs::build()
.data_set("slot", "tabs-trigger")
.data_set("state", if is_selected { "on" } else { "off" })
.role("tab")
.aria_selected(@internal.sumi_bool(is_selected))
let children : Array[@html.Html] = match item.icon {
Some(icon) => [icon, @html.text(item.label)]
None => [@html.text(item.label)]
}
@html.button(
style=[
@internal.SumiBoxSizing,
@internal.SumiFontSans,
@internal.SumiTextRendering,
@internal.SumiTransition,
TabsTriggerBaseStyle,
if is_selected {
TabsTriggerOnStyle
} else {
TabsTriggerOffStyle
},
],
type_="button",
on_click?=on_select.map(emit => emit(item.value)),
attrs=trigger_attrs,
children,
)
}),
)
}