diff --git a/examples/dom/WebReconciler.re b/examples/dom/WebReconciler.re
index 83b8c03..86f7ea3 100644
--- a/examples/dom/WebReconciler.re
+++ b/examples/dom/WebReconciler.re
@@ -5,16 +5,20 @@
* This is just an example but you could use this to create interesting
* CLI apps, with a react-like functional API!
*/
+
+exception InvalidNodePrimitiveMatchInUpdateInstance;
+
+let str = string_of_int;
+
module Reconciler = {
/*
Step 1: Define primitives
*/
- type imageProps = {src: string};
- type buttonProps = {src: string};
type primitives =
- | Div
- | Span(string)
- | Image(imageProps);
+ | View
+ | Text(string)
+ | Image(string) /* img src */
+ | Button(unit => unit, string); /* onPress, title */
/*
Step 2: Define node type
@@ -23,6 +27,7 @@ module Reconciler = {
| Div(Js.t(Dom_html.divElement))
| Span(Js.t(Dom_html.element))
| Image(Js.t(Dom_html.imageElement))
+ | Button(Js.t(Dom_html.buttonElement))
| Container(Js.t(Dom_html.element));
let document = Dom_html.window##.document;
@@ -32,15 +37,27 @@ module Reconciler = {
let createInstance: primitives => node =
primitive =>
switch (primitive) {
- | Div => Div(Dom_html.createDiv(document))
- | Span(s) =>
+ | View => Div(Dom_html.createDiv(document))
+ | Text(s) =>
let e = Dom_html.createSpan(document);
e##.innerHTML := Js.string(s);
Span(e);
| Image(p) =>
let img = Dom_html.createImg(document);
- img##.src := Js.string(p.src);
+ img##.src := Js.string(p);
Image(img);
+ | Button(onPress, title) =>
+ let button =
+ Dom_html.createButton(~_type=Js.string("button"), document);
+ let t = Js.string(title);
+ button##.title := t;
+ button##.innerHTML := t;
+ button##.onclick :=
+ Dom_html.handler(_e => {
+ onPress();
+ Js.bool(false);
+ });
+ Button(button);
};
/*
@@ -52,15 +69,26 @@ module Reconciler = {
| Div(e) => e |> Dom_html.element
| Span(e) => e |> Dom_html.element
| Image(e) => e |> Dom_html.element
+ | Button(e) => e |> Dom_html.element
| Container(e) => e |> Dom_html.element
};
let updateInstance =
(node: node, _oldPrimitive: primitives, newPrimitive: primitives) =>
switch (newPrimitive, node) {
- /* The only update operation we handle today is updating src for an image! */
- | (Image({src}), Image(e)) => e##.src := Js.string(src)
- | _ => ()
+ | (View, Div(_e)) => ()
+ | (Text(s), Span(e)) => e##.innerHTML := Js.string(s)
+ | (Image(src), Image(e)) => e##.src := Js.string(src)
+ | (Button(onPress, title), Button(e)) =>
+ let t = Js.string(title);
+ e##.title := t;
+ e##.innerHTML := t;
+ e##.onclick :=
+ Dom_html.handler(_e => {
+ onPress();
+ Js.bool(false);
+ });
+ | _ => raise(InvalidNodePrimitiveMatchInUpdateInstance)
};
let appendChild = (parentNode: node, childNode: node) => {
@@ -69,6 +97,7 @@ module Reconciler = {
| Div(e) => Dom.appendChild(e, innerNode)
| Span(e) => Dom.appendChild(e, innerNode)
| Image(e) => Dom.appendChild(e, innerNode)
+ | Button(e) => Dom.appendChild(e, innerNode)
| Container(e) => Dom.appendChild(e, innerNode)
};
};
@@ -79,6 +108,7 @@ module Reconciler = {
| Div(e) => Dom.removeChild(e, innerNode)
| Span(e) => Dom.removeChild(e, innerNode)
| Image(e) => Dom.removeChild(e, innerNode)
+ | Button(e) => Dom.removeChild(e, innerNode)
| Container(e) => Dom.removeChild(e, innerNode)
};
};
@@ -90,6 +120,7 @@ module Reconciler = {
| Div(e) => Dom.replaceChild(e, newInnerNode, oldInnerNode)
| Span(e) => Dom.replaceChild(e, newInnerNode, oldInnerNode)
| Image(e) => Dom.replaceChild(e, newInnerNode, oldInnerNode)
+ | Button(e) => Dom.replaceChild(e, newInnerNode, oldInnerNode)
| Container(e) => Dom.replaceChild(e, newInnerNode, oldInnerNode)
};
};
@@ -97,16 +128,44 @@ module Reconciler = {
/* Step 5: Hook it up! */
module JsooReact = Reactify.Make(Reconciler);
+open JsooReact;
/* Define our primitive components */
-let div = (~children, ()) => JsooReact.primitiveComponent(Div, ~children);
-
-let span = (~text, ~children, ()) =>
- JsooReact.primitiveComponent(Span(text), ~children);
+let view = (~children, ()) => JsooReact.primitiveComponent(View, ~children);
-let image = (~children, ~src, ()) =>
+let image = (~children, ~src="", ()) =>
JsooReact.primitiveComponent(Image(src), ~children);
+let text = (~children: list(string), ()) =>
+ JsooReact.primitiveComponent(Text(List.hd(children)), ~children=[]);
+
+let button = (~children, ~onPress, ~title, ()) =>
+ JsooReact.primitiveComponent(Button(onPress, title), ~children);
+
+type action =
+ | Increment
+ | Decrement;
+
+let reducer = (state, action) =>
+ switch (action) {
+ | Increment => state + 1
+ | Decrement => state - 1
+ };
+
+let renderCounter = () => {
+ let (count, dispatch) = useReducer(reducer, 0);
+
+