Files
kjol/go/webui/toggleswitch.go

66 lines
2.1 KiB
Go

package webui
import "kjol/vdom"
// Port of web/kit/ToggleSwitch.tsx. Reactive accessors collapse to plain values.
// ToggleSwitch renders an on/off <button role="switch"> with an optional label
// and description. onChange receives the next checked state.
func ToggleSwitch(checked bool, onChange func(bool), label, description string, disabled bool, class string) *vdom.VNode {
toggle := func() {
if disabled {
return
}
onChange(!checked)
}
trackState := "bg-neutral-300"
if checked {
trackState = "bg-primary"
}
trackCls := cx("relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50", trackState)
knobState := "translate-x-0.5"
if checked {
knobState = "translate-x-[18px]"
}
knobCls := cx("inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform", knobState)
ariaChecked := "false"
if checked {
ariaChecked = "true"
}
btnMods := []vdom.Mod{
vdom.Attr("type", "button"),
vdom.Attr("role", "switch"),
vdom.Attr("aria-checked", ariaChecked),
vdom.Attr("class", trackCls),
vdom.On(vdom.EVENT_CLICK, toggle),
vdom.El("span", vdom.Attr("class", knobCls)),
}
if disabled {
btnMods = append(btnMods, vdom.Attr("disabled", "disabled"))
}
mods := []vdom.Mod{vdom.Attr("class", cx("flex items-center gap-2", class)), vdom.El("button", btnMods...)}
if label != "" || description != "" {
text := []vdom.Mod{vdom.Attr("class", "flex flex-col leading-tight")}
if label != "" {
labelColor := "text-neutral-800"
if disabled {
labelColor = "text-neutral-400"
}
text = append(text, vdom.El("span",
vdom.Attr("class", cx("text-sm select-none", labelColor)),
vdom.On(vdom.EVENT_CLICK, toggle),
vdom.Text(label)))
}
if description != "" {
text = append(text, vdom.El("span", vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text(description)))
}
mods = append(mods, vdom.El("div", text...))
}
return vdom.El("div", mods...)
}