123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103open!Coreopen!Bonsai_web(** This control is similar to the typeahead control, differing in the fact that it
doesn't aim to complete your input. Think of this control as a multi-select that
you're free to add random values to. *)let[@warning"-16"]input?(placeholder="")?(value="")~extra_attrs~id~on_input=Vdom.Node.input~attr:(Vdom.Attr.many_without_merge(extra_attrs@[Vdom.Attr.type_"text";Vdom.Attr.create"list"id;Vdom.Attr.placeholderplaceholder(* Both Attr.value and Attr.string_property value must be set. The former only affects
initial control state while the latter affects the control state whilst the form is
being used. *);Vdom.Attr.valuevalue;Vdom.Attr.string_property"value"value;Vdom.Attr.on_change(fun_input->on_inputinput)]))[];;letpills~selected_options~on_set_change~inject_selected_options=letpilloption=letremove_option_=letselected_options=Set.removeselected_optionsoptioninUi_effect.Many[on_set_changeselected_options;inject_selected_optionsselected_options]inVdom.Node.span~attr:(Vdom.Attr.many_without_merge[Vdom.Attr.tabindex0;Vdom.Attr.create"data-value"option;Vdom.Attr.on_clickremove_option;Vdom.Attr.on_keyup(funev->matchJs_of_ocaml.Dom_html.Keyboard_code.of_eventevwith|Space|Enter|NumpadEnter|Backspace|Delete->remove_optionev|_->Ui_effect.Ignore)])[Vdom.Node.text(option^" ×")]inifSet.is_emptyselected_optionsthenVdom.Node.noneelseVdom.Node.div~attr:(Vdom.Attr.class_"bonsai-web-ui-freeform-multiselect-pills")(Set.to_listselected_options|>List.map~f:pill);;letinput~placeholder~extra_attrs~split~id~selected_options~on_set_change=letopen!Bonsai.Let_syntaxin(* This state is held internally to force the typeahead to clear the text contents
of the input field when an option is selected. *)let%subselect=Bonsai.state[%here](moduleString)~default_model:""inreturn@@let%mapselect,inject_select=selectandselected_options,inject_selected_options=selected_optionsandextra_attrs=extra_attrsandid=idandon_set_change=on_set_changeinleton_inputuser_input=letmaybe_changed_options=splituser_input|>String.Set.of_list|>Set.filter~f:(funitem->not(String.stripitem|>String.is_empty))|>Set.unionselected_optionsinletui_events=ifSet.equalmaybe_changed_optionsselected_optionsthen[inject_selectuser_input]else[inject_select"";on_set_changemaybe_changed_options]inUi_effect.Many(inject_selected_optionsmaybe_changed_options::ui_events)ininput~extra_attrs~value:select~placeholder~id~on_input;;letcreate?(extra_attrs=Value.return[])?(placeholder="")?(on_set_change=Value.return(constUi_effect.Ignore))?(split=List.return)()=letopenBonsai.Let_syntaxinlet%subselected_options=Bonsai.state[%here](moduleString.Set)~default_model:String.Set.emptyinlet%subid=Bonsai.path_idinlet%subinput=input~placeholder~extra_attrs~id~on_set_change~split~selected_optionsinreturn@@let%mapselected_options,inject_selected_options=selected_optionsandinput=inputandon_set_change=on_set_changeinletpills=pills~selected_options~on_set_change~inject_selected_optionsinselected_options,Vdom.Node.div[input;pills],inject_selected_options;;