import AbstractPlutoDingetjes.Bonds
using HypertextLiteral
using Random: randstring
Radio
begin
struct Radio
options::Vector{Pair{<:AbstractString,<:Any}}
default::Union{Nothing, AbstractString}
orientation::Symbol
end
Radio(options::AbstractVector{<:AbstractString}; default=nothing, orientation=:vertical) = Radio([o => o for o in options], default, orientation)
Radio(options::AbstractVector{<:Pair{<:AbstractString,<:Any}}; default=nothing, orientation=:vertical) = Radio(options, default, orientation)
end
function Base.show(io::IO, m::MIME"text/html", radio::Radio)
groupname = randstring('a':'z')
h = @htl(
"""<form style="$(radio.orientation == :horizontal ? "display: flex" : nothing)">$(
map(radio.options) do o
@htl(
"""<div><input $((
type="radio",
id=(groupname * o.first),
name=groupname,
value=o.first,
checked=(radio.default === o.first),
))><label for=$(groupname * o.first)>$(
o.second
)</label></div>"""
)
end
)<script>
const form = currentScript.parentElement
const groupname = $(groupname)
const selected_radio = form.querySelector('input[checked]')
let val = selected_radio?.value
Object.defineProperty(form, "value", {
get: () => val,
set: (newval) => {
val = newval
const i = document.getElementById(groupname + newval)
if(i != null){
i.checked = true
}
},
})
form.oninput = (e) => {
val = e.target.value
// and bubble upwards
}
</script></form>""")
show(io, m, h)
end
Base.get(radio::Radio) = radio.default
Bonds.initial_value(select::Radio) = select.default
Bonds.possible_values(select::Radio) =
first.(select.options)
function Bonds.validate_value(select::Radio, val)
val ∈ (first(p) for p in select.options)
end
Radio(["a", "b", "c"], default="b")
Radio(["a", "b", "c"], orientation=:vertical, default="b")
Radio(["a", "b", "c"], orientation=:horizontal, default="b")