From 91d32658b66c236ae6ba467c4cbdfafd6a2590c8 Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Wed, 11 Feb 2026 01:43:36 +0200 Subject: Allow nesting of `defhtml` (#1) --- src/dompa/nodes.cljc | 27 +++----------------- test/dompa/nodes_test.cljc | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/src/dompa/nodes.cljc b/src/dompa/nodes.cljc index e717690..58ff045 100644 --- a/src/dompa/nodes.cljc +++ b/src/dompa/nodes.cljc @@ -110,28 +110,6 @@ `(defn ~name ~args (->html (vector ~@elements))))) -(defn $$ - "Creates a new node - - Usage: - - ```clojure - ($ :div - ($ \"hello world\" )) - ```" - [name & opts] - (if (string? name) - {:node/name :dompa/text - :node/value (apply str name opts)} - (let [first-opt (first opts) - attrs? (and (map? first-opt) - (not (contains? first-opt :node/name))) - attrs (if attrs? first-opt {}) - children (if attrs? (rest opts) opts)] - (cond-> {:node/name name} - attrs? (assoc :node/attrs attrs) - (seq children) (assoc :node/children (flatten children)))))) - (defn- list-of-one? [coll] (and (sequential? coll) @@ -160,10 +138,11 @@ (list-of-many? opt) {:node/name :<> - :node/children (remove nil? opt)} + :node/children (->> (map nodes-from-opt opt) + (remove nil?))} (list-of-one? opt) - (first opt) + (nodes-from-opt (first opt)) :else {:node/name :dompa/text diff --git a/test/dompa/nodes_test.cljc b/test/dompa/nodes_test.cljc index da9b7db..0340abb 100644 --- a/test/dompa/nodes_test.cljc +++ b/test/dompa/nodes_test.cljc @@ -45,6 +45,68 @@ (is (= "" (empty-list-items ["one" "two"]))))) +(defhtml greeting [who] + ($ :span who)) + +(defhtml page [who] + ($ :div + (greeting who))) + +(defhtml badge [text] + ($ :span {:class "badge"} text)) + +(defhtml card [title] + ($ :div {:class "card"} + (badge title))) + +(defhtml list-item [text] + ($ :li text)) + +(defhtml my-list [items] + ($ :ul + (->> items + (map list-item) + (into [])))) + +(defhtml header [title] + ($ :h1 title)) + +(defhtml nav [items] + ($ :nav + ($ :ul + (->> items + (map list-item) + (into []))))) + +(defhtml layout [title nav-items body] + ($ :div + (header title) + (nav nav-items) + ($ :main body))) + +(deftest nested-defhtml-test + (testing "simple nesting of defhtml" + (is (= "
world
" + (page "world")))) + + (testing "nested defhtml with attributes" + (is (= "
Hello
" + (card "Hello")))) + + (testing "nested defhtml via map/collection" + (is (= "" + (my-list ["a" "b" "c"])))) + + (testing "deeply nested defhtml (three levels)" + (is (= "

Title

content
" + (layout "Title" ["a" "b"] "content")))) + + (testing "mixing defhtml and $ in the same parent" + (is (= "
hi

bye

" + (nodes/->html [($ :div + (greeting "hi") + ($ :p "bye"))]))))) + (deftest $-test (testing "a simple node" (is (= {:node/name :div -- cgit v1.2.3