`. The same path interpolated a symbol's _name_ when `:class` was bound to an expression, so `(let [x "big"] [:div.card {:class x}])` rendered `class="card x"`.
+- Omit an attribute whose value is `nil` or `false`. `[:input {:disabled false}]` rendered `disabled="false"`, which — HTML boolean attributes being presence-based — disabled the element. An attribute map that now renders to nothing no longer leaves a stray space (`
`), which also fixes `[:div {}]`.
+- Render `aria-*` booleans as the strings `"true"` and `"false"`. ARIA attributes are string-valued enumerations in which absence is a distinct state, so `[:button {:aria-expanded false}]` must render `aria-expanded="false"` rather than being omitted, and `true` must render `aria-expanded="true"` rather than a bare attribute (whose empty value is invalid, and falls back to the attribute's default). `nil` still omits.
## 0.2.6
diff --git a/src/borkdude/html.cljc b/src/borkdude/html.cljc
index ae41c26..e1e7741 100644
--- a/src/borkdude/html.cljc
+++ b/src/borkdude/html.cljc
@@ -37,19 +37,29 @@
([opts m]
(let [xml? (= :xml (:mode opts))]
(str/join " "
- (map (fn [[k v]]
- (if (and (true? v) (not xml?))
- (name k)
- (str (name k)
- "=" (cond (string? v) (pr-str (escape-html v))
- (keyword? v) (pr-str (name v))
- (and (map? v) (= "style" (name k))) (pr-str (escape-html (->css v)))
- :else (pr-str (escape-html (str v)))))))
- m))))
+ (keep (fn [[k v]]
+ (let [k (name k)
+ aria? (str/starts-with? k "aria-")]
+ (cond
+ (nil? v) nil
+ (and (false? v) (not aria?)) nil
+ (and (true? v) (not xml?) (not aria?)) k
+ :else
+ (str k
+ "=" (cond (string? v) (pr-str (escape-html v))
+ (keyword? v) (pr-str (name v))
+ (and (map? v) (= "style" k)) (pr-str (escape-html (->css v)))
+ :else (pr-str (escape-html (str v))))))))
+ m))))
([opts m base-map]
(let [m (merge base-map m)]
(->attrs opts m))))
+(defn attrs-prefix
+ "Implementation, do not use"
+ [s]
+ (if (= "" s) "" (str " " s)))
+
(defn constant? [v]
(not (or (seq? v) (symbol? v))))
@@ -128,8 +138,8 @@
attrs (if ?attrs
(let [a (compile-attrs opts ?attrs)]
(if (string? a)
- (str " " a)
- a))
+ (attrs-prefix a)
+ `(attrs-prefix ~a)))
"")]
(if unsafe?
`(->Html (str ~(first children)))
@@ -137,7 +147,7 @@
nil
(if (string? attrs)
[(str "<" tag attrs ">")]
- ["<" tag " " attrs ">"]))
+ ["<" tag attrs ">"]))
~@(map #(list (if xml?
`xml
`html) %) children)
diff --git a/test/borkdude/html_test.cljc b/test/borkdude/html_test.cljc
index b93bdca..d691014 100644
--- a/test/borkdude/html_test.cljc
+++ b/test/borkdude/html_test.cljc
@@ -81,6 +81,44 @@
"
"
(xml [:input {:checked true}])
+ "
"
+ (html [:input {:disabled false}])
+
+ "
"
+ (html [:input {:disabled nil}])
+
+ "
"
+ (xml [:input {:disabled nil}])
+
+ "
"
+ (html [:input {:type "text" :disabled false}])
+
+ "
"
+ (let [d false]
+ (html [:input {:type "text" :disabled d}]))
+
+ "
"
+ (html [:button {:aria-expanded true}])
+
+ "
"
+ (html [:button {:aria-expanded false}])
+
+ "
"
+ (let [b false]
+ (html [:button {:aria-expanded b}]))
+
+ "
"
+ (xml [:button {:aria-expanded true}])
+
+ "
"
+ (html [:span {:aria-label nil}])
+
+ "
"
+ (html [:div {:role "checkbox" :aria-checked "mixed"}])
+
+ "
"
+ (html [:div {:data-open false}])
+
"
"
(html [:a {:href (str "http://" "dude")}])
@@ -100,6 +138,9 @@
"
"
(html [:div.card {}])
+ "
"
+ (html [:div {}])
+
"
"
(let [x "big"]
(html [:div.card {:class x}]))