///|
/// Event batches decode handlers before dispatching any command. Keep only the
/// semantic request in the handler and read reactive input at reducer time.
fn[Input : Eq, Message] form_dispatch(
input : @minimoon.Val[Input],
dispatch : (Input, Message) -> @minimoon.Cmd,
) -> @minimoon.Emit[Message] {
let (_, emit) = @minimoon.create_state_with_input(
input~,
init=(_, _) => @minimoon.no_cmd(()),
update=(_, input, message, _) => ((), dispatch(input, message)),
)
emit
}
///|
fn normalize_toggle_keys(
options : Array[ChoiceOption],
keys : Array[String],
multiple : Bool,
) -> Array[String] {
let normalized : Array[String] = []
for key in keys {
if !normalized.contains(key) &&
options.any(option => option.key == key) &&
(multiple || normalized.is_empty()) {
normalized.push(key)
}
}
normalized
}