(** Interactive widget support for the OCaml toplevel. Widgets are rendered in the client as HTML elements built from {!View.node} trees. Event handlers in the view are symbolic string identifiers — when the user interacts with a widget, the client sends the handler ID and input value back to the worker, where the registered callback is invoked. Typical usage with Note FRP: {[ let e, send = Note.E.create () let s = Note.S.hold 50 e let () = let open Widget.View in Widget.display ~id:"my-slider" ~handlers:["x", (fun v -> send (int_of_string (Option.get v)))] (Element { tag = "input"; attrs = [Property ("type", "range")]; children = [] }) (* Wire up automatic updates via Note: *) let _logr = Note.S.log (Note.S.map (fun v -> ... build view ...) s) (Widget.update ~id:"my-slider") ]} *) (** Re-export of {!Js_top_worker_message.Widget_view} for convenient access from toplevel code. Use [let open Widget.View in ...] to access constructors like [Element], [Text], [Property], [Handler], etc. *) module View = Js_top_worker_message.Widget_view val display : id:string -> handlers:(string * (string option -> unit)) list -> View.node -> unit (** [display ~id ~handlers view] registers a widget with the given [id], installs [handlers] for routing incoming events, and sends the initial [view] to the client. If a widget with this [id] already exists, it is replaced. *) val update : id:string -> View.node -> unit (** [update ~id view] sends an updated view for an existing widget. The handler map is not changed. *) val clear : id:string -> unit (** [clear ~id] removes the widget and its handlers. Sends a WidgetClear message to the client. *) val display_managed : id:string -> kind:string -> config:string -> handlers:(string * (string option -> unit)) list -> unit (** [display_managed ~id ~kind ~config ~handlers] registers a managed widget. The client delegates rendering to the adapter registered for [kind]. [config] is a JSON string interpreted by the adapter. [handlers] route incoming events, same as {!display}. *) val update_config : id:string -> string -> unit (** [update_config ~id config] sends an updated config to a managed widget. The adapter decides how to reconcile the change (e.g. flyTo, setData). *) val command : id:string -> string -> string -> unit (** [command ~id cmd data] sends an imperative command to a managed widget. [cmd] is the command name, [data] is a JSON string payload. Use for one-shot actions like animations that don't represent state. *) val register_adapter : kind:string -> js:string -> unit (** [register_adapter ~kind ~js] sends a JavaScript adapter to the client. The JS code must be an IIFE that returns an object with methods: - [create(container, config, send)] — creates the widget, returns state - [update(state, config)] — reconciles a config change - [command(state, cmd, data)] — handles an imperative command - [destroy(state)] — cleans up where [send(handler_id, value)] sends an event back to the worker. *) val handle_event : widget_id:string -> handler_id:string -> value:string option -> unit (** [handle_event ~widget_id ~handler_id ~value] routes an incoming event to the registered handler. Called by the worker message loop when a WidgetEvent is received. *) val set_sender : (string -> unit) -> unit (** [set_sender f] installs the function used to send JSON strings to the client. Called once by the worker at startup. The function [f] should call [Worker.post_message]. *)