diff --git a/src/dompa/nodes.cljc b/src/dompa/nodes.cljc
index e99b364..d2f8e4b 100644
--- a/src/dompa/nodes.cljc
+++ b/src/dompa/nodes.cljc
@@ -1,5 +1,6 @@
(ns dompa.nodes
- (:require [clojure.zip :as zip]))
+ (:require
+ [clojure.zip :as zip]))
(def ^:private default-void-nodes
#{:!doctype :!DOCTYPE :area :base :br :col :embed :hr :img :input
@@ -35,7 +36,9 @@
:else
(let [value (nodes->html-fn (-> node :node/children))]
- (str html "<" node-name node-attrs ">" value "" node-name ">")))))))
+ (str html "<" node-name node-attrs ">" value "" node-name ">"))))
+
+ :else "")))
(defn traverse
"Recursively traverses given tree of `nodes` with a `traverser-fn`
@@ -55,13 +58,13 @@
"Creates a zipper for given a given `node`."
[node]
(zip/zipper
- (fn branch? [node]
- (boolean (seq (:node/children node))))
- (fn children [node]
- (:node/children node))
- (fn make-node [node children]
- (assoc node :node/children children))
- node))
+ (fn branch? [node]
+ (boolean (seq (:node/children node))))
+ (fn children [node]
+ (:node/children node))
+ (fn make-node [node children]
+ (assoc node :node/children children))
+ node))
(defn ->html
"Transform a vector of `nodes` into an HTML string.
@@ -107,7 +110,7 @@
`(defn ~name ~args
(->html (vector ~@elements)))))
-(defn $
+(defn $$
"Creates a new node
Usage:
@@ -128,3 +131,67 @@
(cond-> {:node/name name}
attrs? (assoc :node/attrs attrs)
(seq children) (assoc :node/children (flatten children))))))
+
+(defn- list-of-one?
+ [coll]
+ (and (sequential? coll)
+ (= (count coll) 1)))
+
+(defn- list-of-many?
+ [coll]
+ (and (sequential? coll)
+ (> (count coll) 1)))
+
+(defn- nodes-from-opt
+ [opt]
+ (cond (map? opt)
+ opt
+
+ (list-of-many? opt)
+ {:node/name :<>
+ :node/children opt}
+
+ (list-of-one? opt)
+ (first opt)
+
+ :else
+ {:node/name :dompa/text
+ :node/value (str opt)}))
+
+(defn- node-from-opts
+ [opts]
+ (let [first-opt (first opts)
+ second-op (second opts)
+ attrs? (and (map? second-op)
+ (not (contains? second-op :node/name)))
+ attrs (if attrs? second-op {})
+ children-opts (if attrs? (drop 2 opts) (rest opts))
+ children-nodes (->> children-opts
+ (map nodes-from-opt)
+ flatten)]
+ (cond-> {:node/name first-opt}
+ attrs? (assoc :node/attrs attrs)
+ (seq children-nodes) (assoc :node/children children-nodes))))
+
+(defn- nodes-from-opts
+ [opts]
+ (let [nodes (->> (remove nil? opts)
+ (map nodes-from-opt))]
+ (if (> (count nodes) 1)
+ {:node/name :<>
+ :node/children nodes}
+ (first nodes))))
+
+(defn $
+ "Creates a new node
+
+ Usage:
+
+ ```clojure
+ ($ :div
+ ($ \"hello world\" ))
+ ```"
+ [& opts]
+ (if (keyword? (first opts))
+ (node-from-opts opts)
+ (nodes-from-opts opts)))
diff --git a/test/dompa/coordinates_test.cljc b/test/dompa/coordinates_test.cljc
index 9b05826..9d145b0 100644
--- a/test/dompa/coordinates_test.cljc
+++ b/test/dompa/coordinates_test.cljc
@@ -1,8 +1,12 @@
(ns dompa.coordinates-test
- #?(:clj (:require [clojure.test :refer [deftest testing is]]
- [dompa.coordinates :as coordinates]))
- #?(:cljs (:require [cljs.test :refer-macros [deftest testing is]]
- [dompa.coordinates :as coordinates])))
+ #?(:clj
+ (:require
+ [clojure.test :refer [deftest testing is]]
+ [dompa.coordinates :as coordinates]))
+ #?(:cljs
+ (:require
+ [cljs.test :refer-macros [deftest testing is]]
+ [dompa.coordinates :as coordinates])))
(deftest compose-test
(testing "Create coordinates"
@@ -107,7 +111,7 @@
coordinates/compose
coordinates/unify
coordinates/->nodes))))
-
+
(testing "Create nodes from self-closing tags"
(is (= [{:node/name :hr
:node/attrs {}}]
@@ -115,16 +119,16 @@
coordinates/compose
coordinates/unify
coordinates/->nodes))))
-
+
(testing "Parse attributes with forward slashes in them"
- (is (= [{:node/name :meta,
- :node/attrs {:name "route-pattern",
- :content "/:user_id/:repository",
+ (is (= [{:node/name :meta,
+ :node/attrs {:name "route-pattern",
+ :content "/:user_id/:repository",
:data-turbo-transient true}}]
- (-> ""
- coordinates/compose
- coordinates/unify
- coordinates/->nodes))))
+ (-> ""
+ coordinates/compose
+ coordinates/unify
+ coordinates/->nodes))))
(testing "Create nodes with attributes"
(is (= [{:node/name :div
diff --git a/test/dompa/html_test.cljc b/test/dompa/html_test.cljc
index 77107d1..5b620ba 100644
--- a/test/dompa/html_test.cljc
+++ b/test/dompa/html_test.cljc
@@ -1,8 +1,12 @@
(ns dompa.html-test
- #?(:clj (:require [clojure.test :refer [deftest is testing]]
- [dompa.html :as html]))
- #?(:cljs (:require [cljs.test :refer-macros [deftest testing is]]
- [dompa.html :as html])))
+ #?(:clj
+ (:require
+ [clojure.test :refer [deftest is testing]]
+ [dompa.html :as html]))
+ #?(:cljs
+ (:require
+ [cljs.test :refer-macros [deftest testing is]]
+ [dompa.html :as html])))
(deftest coordinates-test
(testing "HTML to coordinates"
diff --git a/test/dompa/nodes_test.cljc b/test/dompa/nodes_test.cljc
index ca8d483..53e502a 100644
--- a/test/dompa/nodes_test.cljc
+++ b/test/dompa/nodes_test.cljc
@@ -1,13 +1,16 @@
(ns dompa.nodes-test
- #?(:clj (:require
- [clojure.test :refer [deftest is testing]]
- [clojure.zip :as zip]
- [dompa.html :as html]
- [dompa.nodes :as nodes :refer [$ defhtml]]))
- #?(:cljs (:require [cljs.test :refer-macros [deftest testing is]]
- [clojure.zip :as zip]
- [dompa.nodes :as nodes :refer [$] :refer-macros [defhtml]]
- [dompa.html :as html])))
+ #?(:clj
+ (:require
+ [clojure.test :refer [deftest is testing]]
+ [clojure.zip :as zip]
+ [dompa.html :as html]
+ [dompa.nodes :as nodes :refer [$ defhtml]]))
+ #?(:cljs
+ (:require
+ [cljs.test :refer-macros [deftest testing is]]
+ [clojure.zip :as zip]
+ [dompa.nodes :as nodes :refer [$] :refer-macros [defhtml]]
+ [dompa.html :as html])))
(defhtml hello [who]
($ :div
@@ -21,7 +24,7 @@
($ :ul
(->> items
(map (fn [item]
- ($ :li ($ item))))
+ ($ :li item)))
(into []))))
(deftest list-items-test
@@ -33,7 +36,7 @@
(is (= {:node/name :div
:node/children [{:node/name :dompa/text
:node/value "hello world"}]}
- ($ :div ($ "hello world")))))
+ ($ :div "hello world"))))
(testing "a fragment node"
(is (= {:node/name :<>
@@ -47,7 +50,71 @@
($ :span
($ "hello"))
($ :span
- ($ "world")))))))
+ ($ "world"))))))
+
+ (testing "a nil node"
+ (is (= nil
+ ($ nil))))
+
+ (testing "a string node"
+ (is (= {:node/name :dompa/text
+ :node/value "hello world"}
+ ($ "hello world"))))
+
+ (testing "a node of multiple sub-nodes"
+ (is (= {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "hello"}
+ {:node/name :dompa/text
+ :node/value "12345"}
+ {:node/name :dompa/text
+ :node/value "123.3"}
+ {:node/name :dompa/text
+ :node/value "world"}]}
+ ($ "hello" 12345 nil 123.3 "world")))
+
+ (is (= {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "hello"}
+ {:node/name :dompa/text
+ :node/value "12345"}
+ {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "w"}
+ {:node/name :dompa/text
+ :node/value "o"}
+ {:node/name :dompa/text
+ :node/value "r"}
+ {:node/name :dompa/text
+ :node/value "l"}
+ {:node/name :dompa/text
+ :node/value "d"}]}]}
+ ($ "hello" 12345 (map #($ %) ["w" "o" "r" "l" "d"]))))
+
+ (is (= {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "hello"}
+ {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "w"}
+ {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "o"}
+ {:node/name :dompa/text
+ :node/value "r"}
+ {:node/name :<>
+ :node/children [{:node/name :dompa/text
+ :node/value "l"}
+ {:node/name :dompa/text
+ :node/value "d"}]}]}]}]}
+ ($ "hello"
+ (map (fn [x]
+ ($ x))
+ ["w" (map (fn [x]
+ ($ x))
+ ["o" "r" (map (fn [x]
+ ($ x))
+ ["l" "d"])])]))))))
(deftest traverse-test
(let [traverser-fn (fn [node]