diff --git a/src/sablono/compiler.clj b/src/sablono/compiler.clj index 5070f96..1129cea 100644 --- a/src/sablono/compiler.clj +++ b/src/sablono/compiler.clj @@ -54,7 +54,7 @@ :else `(sablono.util/join-classes ~value))) (defmethod compile-attr :style [_ value] - (let [value (camel-case-keys value)] + (let [value (style-attribute-camel-case-keys value)] (if (map? value) (to-js value) `(sablono.interpreter/attributes ~value)))) diff --git a/src/sablono/html.cljc b/src/sablono/html.cljc index 1d0d1e4..bf3d18c 100644 --- a/src/sablono/html.cljc +++ b/src/sablono/html.cljc @@ -1,7 +1,8 @@ (ns sablono.html (:refer-clojure :exclude [map meta time]) (:require [clojure.string :as str] - [sablono.protocol :as p]) + [sablono.protocol :as p] + [sablono.util :as util]) #?(:cljs (:import goog.string.StringBuffer))) (def MOD 65521) @@ -468,8 +469,9 @@ (pos? v)) (str "px")))] (run! (fn [[k v]] - (let [k (name k)] - (append! sb (camel->kebab-case k) ":" (coerce-value k v) ";"))) + (let [k (name k) + k-ident (if (util/css-custom-property? k) k (camel->kebab-case k))] + (append! sb k-ident ":" (coerce-value k v) ";"))) styles))) (defn render-styles! [sb styles] diff --git a/src/sablono/util.cljc b/src/sablono/util.cljc index 4b65239..ff05ed4 100644 --- a/src/sablono/util.cljc +++ b/src/sablono/util.cljc @@ -16,6 +16,11 @@ [& xs] (str/join (map to-str xs))) +(defn css-custom-property? [k] + "Tests whether the string `k` represents a CSS custom property; + according to the standard, such properties starts with the prefix '--'." + (str/starts-with? (name k) "--")) + (defn camel-case "Returns camel case version of the key, e.g. :http-equiv becomes :httpEquiv." [k] @@ -33,16 +38,27 @@ keyword))) k)) +(defn map-keys [k-fn m] + (into {} + (map (fn [[k v]] [(k-fn k) v])) + m)) + +(defn style-attribute-camel-case-keys + "Transform all the map keys into camel case while not transforming CSS custom properties." + [style-m] + (if (map? style-m) + (map-keys #(if (css-custom-property? %) % (camel-case %)) style-m) + style-m)) + (defn camel-case-keys - "Recursively transforms all map keys into camel case." + "Recursively transforms all map keys into camel case; the `:style` key is handled as + a special case to support CSS custom properties." [m] (if (map? m) - (let [m (into {} - (map (fn [[k v]] [(camel-case k) v])) - m)] + (let [m (map-keys camel-case m)] (cond-> m (map? (:style m)) - (update :style camel-case-keys))) + (update :style style-attribute-camel-case-keys))) m)) (defn element? diff --git a/test/sablono/compiler_test.clj b/test/sablono/compiler_test.clj index fd5b2d8..4dfc17f 100644 --- a/test/sablono/compiler_test.clj +++ b/test/sablono/compiler_test.clj @@ -55,6 +55,8 @@ :style {:background-color '(identity "black")}} #j {:className (sablono.util/join-classes (identity "my-class")) :style #j {:backgroundColor (identity "black")}} + {:style {:--var 1}} + #j {:style #j {:--var 1}} {:id :XY} #j {:id "XY"})) @@ -74,7 +76,9 @@ {:class '(identity "my-class") :style {:background-color '(identity "black")}} #j {:className (sablono.util/join-classes '(identity "my-class")) - :style #j {:backgroundColor '(identity "black")}})) + :style #j {:backgroundColor '(identity "black")}} + {:style {:--var 1}} + #j {:style #j {:--var 1}})) (deftest test-to-js (let [v (to-js [])] diff --git a/test/sablono/util_test.cljc b/test/sablono/util_test.cljc index 492698b..9ad4a2c 100644 --- a/test/sablono/util_test.cljc +++ b/test/sablono/util_test.cljc @@ -28,6 +28,8 @@ {:httpEquiv "Expires"} {:style {:z-index 1000}} {:style {:zIndex 1000}} + {:style {:--var 1}} + {:style {:--var 1}} {:on-click '(fn [e] (let [m {:a-b "c"}]))} {:onClick '(fn [e] (let [m {:a-b "c"}]))} {'(identity :class) "my-class" @@ -46,6 +48,8 @@ {:httpEquiv "Expires"} {:style {:z-index 1000}} {:style {:zIndex 1000}} + {:style {:--var 1}} + {:style {:--var 1}} {:on-click '(fn [e] (let [m {:a-b "c"}]))} {:onClick '(fn [e] (let [m {:a-b "c"}]))} {'(identity :class) "my-class"