diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2022-03-21 20:03:23 +0000 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2022-03-21 20:03:23 +0000 |
commit | 101bf051131105a8fd8e714d7d6dc910a6eb5ef9 (patch) | |
tree | ca302e933ba89d090045542814c9b84259b15f74 | |
parent | 170a249f1bc5caae55ae5a3469f0fc6beef63568 (diff) | |
download | lustre-101bf051131105a8fd8e714d7d6dc910a6eb5ef9.tar.gz lustre-101bf051131105a8fd8e714d7d6dc910a6eb5ef9.zip |
:sparkles: Add support for components with encapsulated state.
-rw-r--r-- | src/lustre.gleam | 19 | ||||
-rw-r--r-- | src/lustre/element.gleam | 411 | ||||
-rw-r--r-- | src/lustre/ffi.mjs | 28 |
3 files changed, 310 insertions, 148 deletions
diff --git a/src/lustre.gleam b/src/lustre.gleam index 2058da6..0f119b1 100644 --- a/src/lustre.gleam +++ b/src/lustre.gleam @@ -2,17 +2,19 @@ // IMPORTS --------------------------------------------------------------------- + import lustre/element import lustre/attribute // TYPES ----------------------------------------------------------------------- + /// pub opaque type Program(state, action) { Program( init: state, update: Update(state, action), - view: View(state, action) + render: View(state, action) ) } @@ -25,22 +27,19 @@ pub type Attribute(action) = attribute.Attribute(action) /// type Update(state, action) = fn (state, action) -> state -type View(state, action) = fn (state) -> Element(action) +type Render(state, action) = fn (state) -> Element(action) // CONSTRUCTORS ---------------------------------------------------------------- + /// -pub fn create (init: state, update: Update(state, action), view: View(state, action)) -> Program(state, action) { - Program(init, update, view) +pub fn program (init: state, update: Update(state, action), render: Render(state, action)) -> Program(state, action) { + Program(init, update, render) } +// EFFECTS --------------------------------------------------------------------- + /// pub external fn start (program: Program(state, action), selector: String) -> Nil = "./lustre/ffi.mjs" "mount" - - -// CONVERSIONS ----------------------------------------------------------------- -/// -pub external fn to_element (program: Program(state, action)) -> Element(a) - = "./lustre/ffi.mjs" "Program" diff --git a/src/lustre/element.gleam b/src/lustre/element.gleam index aa0d605..a1d3286 100644 --- a/src/lustre/element.gleam +++ b/src/lustre/element.gleam @@ -1,6 +1,7 @@ //// // IMPORTS --------------------------------------------------------------------- + import lustre/attribute.{ Attribute, attribute } // TYPES ----------------------------------------------------------------------- @@ -10,484 +11,636 @@ pub external type Element(action) // CONSTRUCTORS ---------------------------------------------------------------- +/// Construct a plain HTML element or registered Web Component by providing the +/// tag name, a list of attributes (including event handlers), and a list of +/// child elements. /// -pub external fn element (tag: String, attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) - = "./ffi.mjs" "element" +pub external fn html (tag: String, attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) + = "./ffi.mjs" "html" +/// A stateful element is exactly what it sounds like: some element with local +/// encapsulated state! The `render` function we must provide is called with the +/// element's current state as well as a function to set a new state. Whenever +/// that function is called, the element is re-rendered. +/// +/// You might be wondering where the `stateless` version of this function is. +/// Those are just regular Gleam functions that return `Element`s! +/// +pub external fn stateful (init: state, render: fn (state, fn (state) -> Nil) -> Element(action)) -> Element(action) + = "./ffi.mjs" "stateful" + +/// A fragment doesn't appear in the DOM, but allows us to treat a list of elements +/// as if it were a single one. +/// pub external fn fragment (children: List(Element(action))) -> Element(action) = "./ffi.mjs" "fragment" +/// Render a Gleam string as an HTML text node. +/// pub external fn text (content: String) -> Element(action) = "./ffi.mjs" "text" +// MANIPULATIONS --------------------------------------------------------------- + +/// Transforms the actions produced by some element. +/// +pub external fn map (element: Element(a), f: fn (a) -> b) -> Element(b) + = "./ffi.mjs" "map" + + // CONSTRUCTING NODES ---------------------------------------------------------- // This list and grouping of nodes has been taken from the MDN reference at: // https://developer.mozilla.org/en-US/docs/Web/HTML/Element -// MAIN ROOT: -pub fn html (attributes: List(Attribute(action)), head: Element(action), body: Element(action)) -> Element(action) { - element("html", attributes, [ head, body ]) +// MAIN ROOT ------------------------------------------------------------------- + +/// +pub fn html_ (attributes: List(Attribute(action)), head: Element(action), body: Element(action)) -> Element(action) { + html("html", attributes, [ head, body ]) } -// DOCUMENT METADATA: +// DOCUMENT METADATA ----------------------------------------------------------- + +/// pub fn base (attributes: List(Attribute(action))) -> Element(action) { - element("base", attributes, []) + html("base", attributes, []) } +/// pub fn head (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("head", attributes, children) + html("head", attributes, children) } +/// pub fn meta (attributes: List(Attribute(action))) -> Element(action) { - element("meta", attributes, []) + html("meta", attributes, []) } +/// pub fn style (attributes: List(Attribute(action)), css: String) -> Element(action) { - element("style", attributes, [ text(css) ]) + html("style", attributes, [ text(css) ]) } +/// pub fn title (attributes: List(Attribute(action)), name: String) -> Element(action) { - element("title", attributes, [ text(name) ]) + html("title", attributes, [ text(name) ]) } -// SECTIONING ROOT: +// SECTIONING ROOT ------------------------------------------------------------- + +/// pub fn body (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("body", attributes, children) + html("body", attributes, children) } -// CONTENT SECTIONING: +// CONTENT SECTIONING ---------------------------------------------------------- + +/// pub fn address (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("address", attributes, children) + html("address", attributes, children) } +/// pub fn article (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("article", attributes, children) + html("article", attributes, children) } +/// pub fn aside (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("aside", attributes, children) + html("aside", attributes, children) } +/// pub fn footer (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("footer", attributes, children) + html("footer", attributes, children) } +/// pub fn header (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("header", attributes, children) + html("header", attributes, children) } +/// pub fn h1 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h1", attributes, children) + html("h1", attributes, children) } +/// pub fn h2 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h2", attributes, children) + html("h2", attributes, children) } +/// pub fn h3 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h3", attributes, children) + html("h3", attributes, children) } +/// pub fn h4 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h4", attributes, children) + html("h4", attributes, children) } +/// pub fn h5 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h5", attributes, children) + html("h5", attributes, children) } +/// pub fn h6 (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("h6", attributes, children) + html("h6", attributes, children) } +/// pub fn main (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("main", attributes, children) + html("main", attributes, children) } +/// pub fn nav (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("nav", attributes, children) + html("nav", attributes, children) } +/// pub fn section (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("section", attributes, children) + html("section", attributes, children) } -// TEXT CONTENT: +// TEXT CONTENT ---------------------------------------------------------------- + +/// pub fn blockquote (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("blockquote", attributes, children) + html("blockquote", attributes, children) } +/// pub fn dd (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("dd", attributes, children) + html("dd", attributes, children) } +/// pub fn div (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("div", attributes, children) + html("div", attributes, children) } +/// pub fn dl (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("dl", attributes, children) + html("dl", attributes, children) } +/// pub fn dt (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("dt", attributes, children) + html("dt", attributes, children) } +/// pub fn figcaption (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("figcaption", attributes, children) + html("figcaption", attributes, children) } +/// pub fn figure (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("figure", attributes, children) + html("figure", attributes, children) } +/// pub fn hr (attributes: List(Attribute(action))) -> Element(action) { - element("hr", attributes, []) + html("hr", attributes, []) } +/// pub fn li (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("li", attributes, children) + html("li", attributes, children) } +/// pub fn menu (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("menu", attributes, children) + html("menu", attributes, children) } +/// pub fn ol (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("ol", attributes, children) + html("ol", attributes, children) } +/// pub fn p (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("p", attributes, children) + html("p", attributes, children) } +/// pub fn pre (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("pre", attributes, children) + html("pre", attributes, children) } +/// pub fn ul (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("ul", attributes, children) + html("ul", attributes, children) } -// INLINE TEXT SEMANTICS: +// INLINE TEXT SEMANTICS ------------------------------------------------------- + +/// pub fn a (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("a", attributes, children) + html("a", attributes, children) } +/// pub fn abbr (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("abbr", attributes, children) + html("abbr", attributes, children) } +/// pub fn b (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("b", attributes, children) + html("b", attributes, children) } +/// pub fn bdi (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("bdi", attributes, children) + html("bdi", attributes, children) } +/// pub fn bdo (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("bdo", attributes, children) + html("bdo", attributes, children) } +/// pub fn br (attributes: List(Attribute(action))) -> Element(action) { - element("br", attributes, []) + html("br", attributes, []) } +/// pub fn cite (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("cite", attributes, children) + html("cite", attributes, children) } +/// pub fn code (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("code", attributes, children) + html("code", attributes, children) } +/// pub fn dfn (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("dfn", attributes, children) + html("dfn", attributes, children) } +/// pub fn em (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("em", attributes, children) + html("em", attributes, children) } +/// pub fn i (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("i", attributes, children) + html("i", attributes, children) } +/// pub fn kbd (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("kbd", attributes, children) + html("kbd", attributes, children) } +/// pub fn mark (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("mark", attributes, children) + html("mark", attributes, children) } +/// pub fn rp (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("rp", attributes, children) + html("rp", attributes, children) } +/// pub fn rt (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("rt", attributes, children) + html("rt", attributes, children) } +/// pub fn ruby (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("ruby", attributes, children) + html("ruby", attributes, children) } +/// pub fn s (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("s", attributes, children) + html("s", attributes, children) } +/// pub fn samp (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("samp", attributes, children) + html("samp", attributes, children) } +/// pub fn small (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("small", attributes, children) + html("small", attributes, children) } +/// pub fn span (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("span", attributes, children) + html("span", attributes, children) } +/// pub fn strong (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("strong", attributes, children) + html("strong", attributes, children) } +/// pub fn sub (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("sub", attributes, children) + html("sub", attributes, children) } +/// pub fn sup (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("sup", attributes, children) + html("sup", attributes, children) } +/// pub fn time (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("time", attributes, children) + html("time", attributes, children) } +/// pub fn u (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("u", attributes, children) + html("u", attributes, children) } +/// pub fn var_ (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("var", attributes, children) + html("var", attributes, children) } +/// pub fn wbr (attributes: List(Attribute(action))) -> Element(action) { - element("wbr", attributes, []) + html("wbr", attributes, []) } -// IMAGE AND MULTIMEDIA: +// IMAGE AND MULTIMEDIA -------------------------------------------------------- + +/// pub fn area (attributes: List(Attribute(action))) -> Element(action) { - element("area", attributes, []) + html("area", attributes, []) } +/// pub fn audio (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("audio", attributes, children) + html("audio", attributes, children) } +/// pub fn img (attributes: List(Attribute(action))) -> Element(action) { - element("img", attributes, []) + html("img", attributes, []) } -pub fn map (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("map", attributes, children) +/// +pub fn map_ (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { + html("map", attributes, children) } +/// pub fn track (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("track", attributes, children) + html("track", attributes, children) } +/// pub fn video (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("video", attributes, children) + html("video", attributes, children) } -// EMBEDDED CONTENT: +// EMBEDDED CONTENT ------------------------------------------------------------ + +/// pub fn embed (attributes: List(Attribute(action))) -> Element(action) { - element("embed", attributes, []) + html("embed", attributes, []) } +/// pub fn iframe (attributes: List(Attribute(action))) -> Element(action) { - element("iframe", attributes, []) + html("iframe", attributes, []) } +/// pub fn object (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("object", attributes, children) + html("object", attributes, children) } +/// pub fn param (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("param", attributes, children) + html("param", attributes, children) } +/// pub fn picture (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("picture", attributes, children) + html("picture", attributes, children) } +/// pub fn portal (attributes: List(Attribute(action))) -> Element(action) { - element("portal", attributes, []) + html("portal", attributes, []) } +/// pub fn source (attributes: List(Attribute(action))) -> Element(action) { - element("source", attributes, []) + html("source", attributes, []) } -// SVG AND MATHML: +// SVG AND MATHML -------------------------------------------------------------- + +/// pub fn svg (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("svg", [attribute("xmlns", "http://www.w3.org/2000/svg"), ..attributes], children) + html("svg", [attribute("xmlns", "http://www.w3.org/2000/svg"), ..attributes], children) } +/// pub fn mathml (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("mathml", [attribute("xmlns", "http://www.w3.org/1998/Math/MathML"), ..attributes], children) + html("mathml", [attribute("xmlns", "http://www.w3.org/1998/Math/MathML"), ..attributes], children) } -// SCRIPTING: +// SCRIPTING ------------------------------------------------------------------- + +/// pub fn canvas (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("canvas", attributes, children) + html("canvas", attributes, children) } +/// pub fn noscript (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("noscript", attributes, children) + html("noscript", attributes, children) } -// DEMARCATING EDITS: +// DEMARCATING EDITS ----------------------------------------------------------- + +/// pub fn del (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("del", attributes, children) + html("del", attributes, children) } +/// pub fn ins (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("ins", attributes, children) + html("ins", attributes, children) } -// TABLE CONTENT: +// TABLE CONTENT --------------------------------------------------------------- + +/// pub fn caption (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("caption", attributes, children) + html("caption", attributes, children) } +/// pub fn col (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("col", attributes, children) + html("col", attributes, children) } +/// pub fn colgroup (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("colgroup", attributes, children) + html("colgroup", attributes, children) } +/// pub fn table (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("table", attributes, children) + html("table", attributes, children) } +/// pub fn tbody (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("tbody", attributes, children) + html("tbody", attributes, children) } +/// pub fn td (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("td", attributes, children) + html("td", attributes, children) } +/// pub fn tfoot (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("tfoot", attributes, children) + html("tfoot", attributes, children) } +/// pub fn th (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("th", attributes, children) + html("th", attributes, children) } +/// pub fn thead (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("thead", attributes, children) + html("thead", attributes, children) } +/// pub fn tr (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("tr", attributes, children) + html("tr", attributes, children) } -// FORMS: +// FORMS ----------------------------------------------------------------------- + +/// pub fn button (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("button", attributes, children) + html("button", attributes, children) } +/// pub fn datalist (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("datalist", attributes, children) + html("datalist", attributes, children) } +/// pub fn fieldset (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("fieldset", attributes, children) + html("fieldset", attributes, children) } +/// pub fn form (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("form", attributes, children) + html("form", attributes, children) } +/// pub fn input (attributes: List(Attribute(action))) -> Element(action) { - element("input", attributes, []) + html("input", attributes, []) } +/// pub fn label (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("label", attributes, children) + html("label", attributes, children) } +/// pub fn legend (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("legend", attributes, children) + html("legend", attributes, children) } +/// pub fn meter (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("meter", attributes, children) + html("meter", attributes, children) } +/// pub fn optgroup (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("optgroup", attributes, children) + html("optgroup", attributes, children) } +/// pub fn option (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("option", attributes, children) + html("option", attributes, children) } +/// pub fn output (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("output", attributes, children) + html("output", attributes, children) } +/// pub fn progress (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("progress", attributes, children) + html("progress", attributes, children) } +/// pub fn select (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("select", attributes, children) + html("select", attributes, children) } +/// pub fn textarea (attributes: List(Attribute(action))) -> Element(action) { - element("textarea", attributes, []) + html("textarea", attributes, []) } -// INTERACTIVE ELEMENTS: +// INTERACTIVE ELEMENTS -------------------------------------------------------- + +/// pub fn details (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("details", attributes, children) + html("details", attributes, children) } +/// pub fn dialog (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("dialog", attributes, children) + html("dialog", attributes, children) } +/// pub fn summary (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("summary", attributes, children) + html("summary", attributes, children) } -// WEB COMPONENTS: +// WEB COMPONENTS -------------------------------------------------------------- + +/// pub fn slot (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("slot", attributes, children) + html("slot", attributes, children) } +/// pub fn template (attributes: List(Attribute(action)), children: List(Element(action))) -> Element(action) { - element("template", attributes, children) + html("template", attributes, children) } diff --git a/src/lustre/ffi.mjs b/src/lustre/ffi.mjs index 9d27c5e..0869e0e 100644 --- a/src/lustre/ffi.mjs +++ b/src/lustre/ffi.mjs @@ -1,24 +1,22 @@ import * as React from 'react' import * as ReactDOM from 'react-dom' -export const Program = ({ init, update, view }) => () => { - return React.createElement(() => { +// ----------------------------------------------------------------------------- + +export const mount = ({ init, update, view }, selector) => { + const root = document.querySelector(selector) + const App = React.createElement(() => { const [state, dispatch] = React.useReducer(update, init) return view(state)(dispatch) }) -} -export const mount = (program, selector) => { - const root = document.querySelector(selector) - const App = Program(program) - - ReactDOM.render(App(), root) + ReactDOM.render(App, root) } // ----------------------------------------------------------------------------- -export const element = (tag, attributes, children) => (dispatch) => { +export const html = (tag, attributes, children) => (dispatch) => { const props = attributes.toArray().map(attr => { switch (attr.constructor.name) { case "Attribute": @@ -51,6 +49,12 @@ export const element = (tag, attributes, children) => (dispatch) => { ) } +export const stateful = (init, render) => (dispatch) => { + const [state, setState] = React.useState(init) + + return render(state, setState)(dispatch) +} + export const fragment = (children) => (dispatch) => { return React.createElement(React.Fragment, null, ...children.toArray().map(child => typeof child === 'function' @@ -63,3 +67,9 @@ export const fragment = (children) => (dispatch) => { // This is just an identity function! We need it because we want to trick Gleam // into converting a `String` into an `Element(action)` . export const text = (content) => content + +// ----------------------------------------------------------------------------- + +export const map = (element, f) => (dispatch) => { + return element(action => dispatch(f(action))) +} |