this repo has no description
at main 90 lines 3.7 kB view raw
1(** Interactive widget support for the OCaml toplevel. 2 3 Widgets are rendered in the client as HTML elements built from 4 {!View.node} trees. Event handlers in the view are symbolic string 5 identifiers — when the user interacts with a widget, the client sends 6 the handler ID and input value back to the worker, where the registered 7 callback is invoked. 8 9 Typical usage with Note FRP: 10 {[ 11 let e, send = Note.E.create () 12 let s = Note.S.hold 50 e 13 14 let () = 15 let open Widget.View in 16 Widget.display ~id:"my-slider" 17 ~handlers:["x", (fun v -> 18 send (int_of_string (Option.get v)))] 19 (Element { tag = "input"; 20 attrs = [Property ("type", "range")]; 21 children = [] }) 22 23 (* Wire up automatic updates via Note: *) 24 let _logr = Note.S.log 25 (Note.S.map (fun v -> ... build view ...) s) 26 (Widget.update ~id:"my-slider") 27 ]} *) 28 29(** Re-export of {!Js_top_worker_message.Widget_view} for convenient access 30 from toplevel code. Use [let open Widget.View in ...] to access 31 constructors like [Element], [Text], [Property], [Handler], etc. *) 32module View = Js_top_worker_message.Widget_view 33 34val display : 35 id:string -> 36 handlers:(string * (string option -> unit)) list -> 37 View.node -> 38 unit 39(** [display ~id ~handlers view] registers a widget with the given [id], 40 installs [handlers] for routing incoming events, and sends the 41 initial [view] to the client. If a widget with this [id] already 42 exists, it is replaced. *) 43 44val update : id:string -> View.node -> unit 45(** [update ~id view] sends an updated view for an existing widget. 46 The handler map is not changed. *) 47 48val clear : id:string -> unit 49(** [clear ~id] removes the widget and its handlers. Sends a 50 WidgetClear message to the client. *) 51 52val display_managed : 53 id:string -> 54 kind:string -> 55 config:string -> 56 handlers:(string * (string option -> unit)) list -> 57 unit 58(** [display_managed ~id ~kind ~config ~handlers] registers a managed widget. 59 The client delegates rendering to the adapter registered for [kind]. 60 [config] is a JSON string interpreted by the adapter. 61 [handlers] route incoming events, same as {!display}. *) 62 63val update_config : id:string -> string -> unit 64(** [update_config ~id config] sends an updated config to a managed widget. 65 The adapter decides how to reconcile the change (e.g. flyTo, setData). *) 66 67val command : id:string -> string -> string -> unit 68(** [command ~id cmd data] sends an imperative command to a managed widget. 69 [cmd] is the command name, [data] is a JSON string payload. 70 Use for one-shot actions like animations that don't represent state. *) 71 72val register_adapter : kind:string -> js:string -> unit 73(** [register_adapter ~kind ~js] sends a JavaScript adapter to the client. 74 The JS code must be an IIFE that returns an object with methods: 75 - [create(container, config, send)] — creates the widget, returns state 76 - [update(state, config)] — reconciles a config change 77 - [command(state, cmd, data)] — handles an imperative command 78 - [destroy(state)] — cleans up 79 where [send(handler_id, value)] sends an event back to the worker. *) 80 81val handle_event : 82 widget_id:string -> handler_id:string -> value:string option -> unit 83(** [handle_event ~widget_id ~handler_id ~value] routes an incoming 84 event to the registered handler. Called by the worker message loop 85 when a WidgetEvent is received. *) 86 87val set_sender : (string -> unit) -> unit 88(** [set_sender f] installs the function used to send JSON strings to 89 the client. Called once by the worker at startup. The function [f] 90 should call [Worker.post_message]. *)