aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Thompson <andrew.thompson@qmul.ac.uk>2022-02-11 01:01:48 +0000
committerAndy Thompson <andrew.thompson@qmul.ac.uk>2022-02-11 01:01:48 +0000
commit06e3827589771da31bf033d304da4ba3a40c9cde (patch)
tree9e0d705693a3bc78099c49b37f7ba824eb52b45c
parent72f64a5192da97307156c1529838556f15e94ffa (diff)
downloadlustre-06e3827589771da31bf033d304da4ba3a40c9cde.tar.gz
lustre-06e3827589771da31bf033d304da4ba3a40c9cde.zip
:construction: Begin experimenting with html/dom api.
-rw-r--r--src/index.html17
-rw-r--r--src/js/test.js5
-rw-r--r--src/lustre/dom/html.ffi.mjs14
-rw-r--r--src/lustre/dom/html.gleam54
-rw-r--r--src/lustre/dom/html/attr.ffi.mjs6
-rw-r--r--src/lustre/dom/html/attr.gleam61
-rw-r--r--src/lustre/dom/svg.gleam32
-rw-r--r--src/lustre/dom/svg/attr.gleam92
-rw-r--r--src/lustre/test.gleam11
9 files changed, 292 insertions, 0 deletions
diff --git a/src/index.html b/src/index.html
new file mode 100644
index 0000000..e807f2a
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Document</title>
+
+ <script type="module" src="./js/test.js"></script>
+</head>
+
+<body>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/src/js/test.js b/src/js/test.js
new file mode 100644
index 0000000..ef7923a
--- /dev/null
+++ b/src/js/test.js
@@ -0,0 +1,5 @@
+import * as Lustre from 'lustre/test.mjs'
+
+document.documentElement.append(
+ Lustre.html_test()
+) \ No newline at end of file
diff --git a/src/lustre/dom/html.ffi.mjs b/src/lustre/dom/html.ffi.mjs
new file mode 100644
index 0000000..2cbe58d
--- /dev/null
+++ b/src/lustre/dom/html.ffi.mjs
@@ -0,0 +1,14 @@
+export const createNode = (tag, namespace, attrs, children) => {
+ const el = namespace == ''
+ ? document.createElement(tag)
+ : document.createElementNS(namespace, tag)
+
+ for (const attr of attrs) el.setAttributeNode(attr)
+ for (const node of children) el.append(node)
+
+ return el
+}
+
+export const createText = (content) => {
+ return document.createTextNode(content)
+} \ No newline at end of file
diff --git a/src/lustre/dom/html.gleam b/src/lustre/dom/html.gleam
new file mode 100644
index 0000000..12ac25a
--- /dev/null
+++ b/src/lustre/dom/html.gleam
@@ -0,0 +1,54 @@
+import lustre/dom/html/attr.{Attr}
+
+// TYPES -----------------------------------------------------------------------
+
+pub external type Html
+
+// GENERIC CONSTRUCTORS --------------------------------------------------------
+
+external fn create_node (String, String, List(Attr), List(Html)) -> Html = "./html.ffi.mjs" "createNode"
+
+external fn create_text (String) -> Html =
+ "./html.ffi.mjs" "createText"
+
+pub fn node (tag: String, attrs: List(Attr), children: List(Html)) -> Html {
+ create_node(tag, "", attrs, children)
+}
+
+pub fn node_ns (tag: String, namespace: String, attrs: List(Attr), children: List(Html)) -> Html {
+ create_node(tag, namespace, attrs, children)
+}
+
+pub fn text (content: String) -> Html {
+ create_text(content)
+}
+
+// COMMON CONSTRUCTORS ---------------------------------------------------------
+
+pub fn div (attrs: List(Attr), children: List(Html)) -> Html {
+ node("div", attrs, children)
+}
+
+pub fn p (attrs: List(Attr), children: List(Html)) -> Html {
+ node("p", attrs, children)
+}
+
+pub fn span (attrs: List(Attr), children: List(Html)) -> Html {
+ node("span", attrs, children)
+}
+
+pub fn button (attrs: List(Attr), children: List(Html)) -> Html {
+ node("button", attrs, children)
+}
+
+// INPUT CONSTRUCTORS ----------------------------------------------------------
+
+pub fn input (attrs: List(Attr)) -> Html {
+ node("input", attrs, [])
+}
+
+// GRAPHICS CONSTRUCTORS -------------------------------------------------------
+
+pub fn img (attrs: List(Attr)) -> Html {
+ node("img", attrs, [])
+} \ No newline at end of file
diff --git a/src/lustre/dom/html/attr.ffi.mjs b/src/lustre/dom/html/attr.ffi.mjs
new file mode 100644
index 0000000..b75c37a
--- /dev/null
+++ b/src/lustre/dom/html/attr.ffi.mjs
@@ -0,0 +1,6 @@
+export const createAttr = (name, value) => {
+ const attr = document.createAttribute(name)
+ attr.value = value
+
+ return attr
+} \ No newline at end of file
diff --git a/src/lustre/dom/html/attr.gleam b/src/lustre/dom/html/attr.gleam
new file mode 100644
index 0000000..ac86cdf
--- /dev/null
+++ b/src/lustre/dom/html/attr.gleam
@@ -0,0 +1,61 @@
+import gleam/float
+import gleam/int
+
+// TYPES -----------------------------------------------------------------------
+
+pub external type Attr
+
+// GENERIC CONSTRUCTORS --------------------------------------------------------
+
+external fn create_attr (String, String) -> Attr =
+ "./attr.ffi.mjs" "createAttr"
+
+pub fn from_string (name: String, val: String) -> Attr {
+ create_attr(name, val)
+}
+
+pub fn from_float (name: String, val: Float) -> Attr {
+ create_attr(name, float.to_string(val))
+}
+
+pub fn from_int (name: String, val: Int) -> Attr {
+ create_attr(name, int.to_string(val))
+}
+
+pub fn from_bool (name: String, val: Bool) -> Attr {
+ create_attr(name, case val {
+ True ->
+ "true"
+
+ False ->
+ "false"
+ })
+}
+
+// COMMON ATTRIBUTES -----------------------------------------------------------
+
+pub fn style (styles: String) -> Attr {
+ from_string("style", styles)
+}
+
+pub fn class (class: String) -> Attr {
+ from_string("class", class)
+}
+
+pub fn id (id: String) -> Attr {
+ from_string("id", id)
+}
+
+// INPUT ATTRIBUTES ------------------------------------------------------------
+
+pub fn type_ (type_: String) -> Attr {
+ from_string("type", type_)
+}
+
+pub fn value (value: String) -> Attr {
+ from_string("value", value)
+}
+
+pub fn checked (checked: Bool) -> Attr {
+ from_bool("checked", checked)
+}
diff --git a/src/lustre/dom/svg.gleam b/src/lustre/dom/svg.gleam
new file mode 100644
index 0000000..e356e42
--- /dev/null
+++ b/src/lustre/dom/svg.gleam
@@ -0,0 +1,32 @@
+import lustre/dom/html.{Html}
+import lustre/dom/html/attr.{Attr}
+
+// CONSTANTS -------------------------------------------------------------------
+
+const svg_namespace = "http://www.w3.org/2000/svg"
+
+// COMMON CONSTRUCTORS ---------------------------------------------------------
+
+pub fn svg (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("svg", svg_namespace, attrs, children)
+}
+
+pub fn rect (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("rect", svg_namespace, attrs, children)
+}
+
+pub fn circle (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("circle", svg_namespace, attrs, children)
+}
+
+pub fn ellipse (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("ellipse", svg_namespace, attrs, children)
+}
+
+pub fn line (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("line", svg_namespace, attrs, children)
+}
+
+pub fn text (attrs: List(Attr), children: List(Html)) -> Html {
+ html.node_ns("text", svg_namespace, attrs, children)
+}
diff --git a/src/lustre/dom/svg/attr.gleam b/src/lustre/dom/svg/attr.gleam
new file mode 100644
index 0000000..c2ce5cc
--- /dev/null
+++ b/src/lustre/dom/svg/attr.gleam
@@ -0,0 +1,92 @@
+import gleam/float
+import gleam/list
+import gleam/string
+import lustre/dom/html/attr
+
+// TYPES -----------------------------------------------------------------------
+
+pub type Attr = attr.Attr
+
+// COMMON CONSTRUCTORS ---------------------------------------------------------
+
+pub fn x (x: Float) -> Attr {
+ attr.from_float("x", x)
+}
+
+pub fn x1 (x1: Float) -> Attr {
+ attr.from_float("x1", x1)
+}
+
+pub fn x2 (x2: Float) -> Attr {
+ attr.from_float("x2", x2)
+}
+
+pub fn y (y: Float) -> Attr {
+ attr.from_float("y", y)
+}
+
+pub fn y1 (y1: Float) -> Attr {
+ attr.from_float("y1", y1)
+}
+
+pub fn y2 (y2: Float) -> Attr {
+ attr.from_float("y2", y2)
+}
+
+pub fn width (width: Float) -> Attr {
+ attr.from_float("width", width)
+}
+
+pub fn height (height: Float) -> Attr {
+ attr.from_float("height", height)
+}
+
+pub fn viewbox (min_x: Float, min_y: Float, width: Float, height: Float) -> Attr {
+ attr.from_string("viewbox", [ min_x, min_y, width, height ] |> list.map(float.to_string) |> string.join(" "))
+}
+
+// STYLING CONSTRUCTORS --------------------------------------------------------
+
+pub fn rgb (r: Float, g: Float, b: Float) -> String {
+ rgba(r, g, b, 1.0)
+}
+
+pub fn rgba (r: Float, g: Float, b: Float, a: Float) -> String {
+ let r = clamp(r, between: 0.0, and: 255.0) |> float.to_string
+ let g = clamp(g, between: 0.0, and: 255.0) |> float.to_string
+ let b = clamp(b, between: 0.0, and: 255.0) |> float.to_string
+ let a = clamp(a, between: 0.0, and: 1.0) |> float.to_string
+
+ string.concat([ "rgba(", r, ",", g, ",", b, ",", a, ")" ])
+}
+
+pub fn fill (color: String) -> Attr {
+ attr.from_string("fill", color)
+}
+
+pub fn stroke (color: String) -> Attr {
+ attr.from_string("stroke", color)
+}
+
+pub fn stroke_width (width: Float) -> Attr {
+ attr.from_float("stroke-width", width)
+}
+
+pub fn opacity (opacity: Float) -> Attr {
+ attr.from_float("opacity", clamp(opacity, between: 0.0, and: 1.0))
+}
+
+// UTILS -----------------------------------------------------------------------
+
+fn clamp (val: Float, between min: Float, and max: Float) -> Float {
+ case val {
+ _ if val <. min ->
+ min
+
+ _else if val >. max ->
+ max
+
+ _else ->
+ val
+ }
+} \ No newline at end of file
diff --git a/src/lustre/test.gleam b/src/lustre/test.gleam
new file mode 100644
index 0000000..f8f913b
--- /dev/null
+++ b/src/lustre/test.gleam
@@ -0,0 +1,11 @@
+import lustre/dom/html
+import lustre/dom/html/attr
+
+pub fn html_test () {
+ html.div([ attr.class("foo") ], [
+ html.p([], [
+ html.text("testing")
+ ]),
+ html.input([ attr.value("hello") ])
+ ])
+}