diff --git a/examples/cssclasstest-brr/index.html b/examples/cssclasstest-brr/index.html index 41b943c..4e64b15 100644 --- a/examples/cssclasstest-brr/index.html +++ b/examples/cssclasstest-brr/index.html @@ -3,14 +3,14 @@ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> - Minesweeper + Minesweeper embryo -
+
diff --git a/examples/cssclasstest-brr/main.ml b/examples/cssclasstest-brr/main.ml index 0175ef6..bf9ddfc 100644 --- a/examples/cssclasstest-brr/main.ml +++ b/examples/cssclasstest-brr/main.ml @@ -40,18 +40,21 @@ let ui = Lwd_seq.monoid squares in - Elwd.div ~at:[ `P (At.class' (Jstr.v "game-board")) ] [ + [ `S (Lwd_seq.lift board) ] -let () = - let ui = Lwd.observe ui in - let on_invalidate _ = - ignore @@ G.request_animation_frame @@ fun _ -> - ignore @@ Lwd.quick_sample ui - in - let on_load _ = - El.append_children (Document.body G.document) [ Lwd.quick_sample ui ]; - Lwd.set_on_invalidate ui on_invalidate +let defer_after_dom_loading f = + let on_load _ = f () in + let _listen_id = + Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window) in - ignore @@ Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window) + () + +let () = + defer_after_dom_loading @@ fun () -> + match El.find_first_by_selector (Jstr.v ".game-board") with + | None -> failwith ".game-board could not be found, check your html" + | Some main -> + let _remove_token = Elwd.set_children main ui in + () diff --git a/examples/focustest-brr/main.ml b/examples/focustest-brr/main.ml index 4b81ab8..eb1ee20 100644 --- a/examples/focustest-brr/main.ml +++ b/examples/focustest-brr/main.ml @@ -46,22 +46,17 @@ let ui = `S (Lwd_seq.map El.txt' values); ] -let () = - let ui = Lwd.observe ui in - let on_invalidate _ = - Console.(log [str "on invalidate"]); - let _ : int = - G.request_animation_frame @@ fun _ -> - let _ui = Lwd.quick_sample ui in - (*El.set_children (Document.body G.document) [ui]*) - () - in - () - in - let on_load _ = - Console.(log [str "onload"]); - El.append_children (Document.body G.document) [Lwd.quick_sample ui]; - Lwd.set_on_invalidate ui on_invalidate +let defer_after_dom_loading f = + let on_load _ = f () in + let _listen_id = + Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window) in - ignore (Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window)); () + +let () = + defer_after_dom_loading @@ fun () -> + match El.find_first_by_selector (Jstr.v "#main") with + | None -> failwith "#main could not be found, check your html" + | Some main -> + let _remove_token = Elwd.insert_sibling `Replace main ui in + () diff --git a/lib/brr-lwd/elwd.ml b/lib/brr-lwd/elwd.ml index 4b09c03..ba89973 100644 --- a/lib/brr-lwd/elwd.ml +++ b/lib/brr-lwd/elwd.ml @@ -409,3 +409,61 @@ let ul = cons Name.ul let var = cons Name.var let video = cons Name.video let wbr = void_cons Name.wbr + +type root = t Lwd.root + +let insert first_insert anchor reactive = + let root = Lwd.observe reactive in + let last_element = ref (Lwd.quick_sample root) in + first_insert anchor [!last_element]; + let on_invalidate _ = + let _ : int = + G.request_animation_frame @@ fun _ -> + let new_element = Lwd.quick_sample root in + if !last_element = new_element then () + else ( + El.insert_siblings `Replace !last_element [ new_element ]; + last_element := new_element + ) + in + () + in + Lwd.set_on_invalidate root on_invalidate; + root + +let insert_sibling where anchor reactive = + let first_insert = El.insert_siblings where in + insert first_insert anchor reactive + +let append_child anchor reactive = + insert El.append_children anchor reactive + +let prepend_child anchor reactive = + insert El.prepend_children anchor reactive + +let set_children el children = + let reactive = + let children, impure_children = consume_children children in + match impure_children with + | None -> El.set_children el children; Lwd.pure el + | Some children -> + let root = Lwd.observe children in + let c = Lwd.quick_sample root in + El.set_children el (Lwd_seq.to_list c); + Lwd.quick_release root; + update_children el children + in + let root = Lwd.observe reactive in + let _el = Lwd.quick_sample root in + let on_invalidate _ = + let _ : int = + G.request_animation_frame @@ fun _ -> + let _el = Lwd.quick_sample root in + () + in + () + in + Lwd.set_on_invalidate root on_invalidate; + root + +let release root = Lwd.quick_release root diff --git a/lib/brr-lwd/elwd.mli b/lib/brr-lwd/elwd.mli index 38fc4ea..2d89172 100644 --- a/lib/brr-lwd/elwd.mli +++ b/lib/brr-lwd/elwd.mli @@ -24,6 +24,33 @@ val v : ?d:document -> ?at:At.t col -> ?ev:handler col -> tag_name -> t col -> t the final value. [d] is the document on which the element is defined it defaults {!Brr.G.document}. *) + +(** {1 Inserting reactive elements in the DOM} *) + +type root + +val insert_sibling : [ `Before | `After | `Replace ] -> t -> t Lwd.t -> root +(** Inserts a reactive element in the DOM, right before/after/instead of the + given element. The element is updated until the return value is passed to + {!release}. *) + +val set_children : t -> t col -> root +(** Sets a set of reactive elements as the children of the given element. The + set is updated until the return value is passed to {!release}. *) + +val append_child : t -> t Lwd.t -> root +(** Inserts a reactive element in the DOM, as last child of the given + element. The element is updated until the return value is passed to + {!release}. *) + +val prepend_child : t -> t Lwd.t -> root +(** Inserts a reactive element in the DOM, as first child of the given + element. The element is updated until the return value is passed to + {!release}. *) + +val release : root -> unit +(** Stop updating the reactive elements, leaving what is currently there. *) + (** {1:els Element constructors} *) type cons = ?d:document -> ?at:At.t col -> ?ev:handler col -> t col -> t Lwd.t