Add class-names utility function

This commit is contained in:
Juho Teperi 2018-12-31 12:49:37 +02:00
parent 18143e6e97
commit f7ca1ff8ff
5 changed files with 85 additions and 36 deletions

View File

@ -8,6 +8,8 @@
- Create React Component without `create-react-class` ([#416](https://github.com/reagent-project/reagent/issues/416))
- Allow any number of arguments for `reagent.core/merge-props` and
ensure `:class` is merged correctly when it is defined as collection. ([#412](https://github.com/reagent-project/reagent/issues/412))
- Add `reagent.core/class-names` utility functions which can be used
to normalize and combine `:class` values (similar to `classnames` JS library)
## 0.8.1 (2018-05-15)

View File

@ -194,8 +194,23 @@
[this]
(dom/dom-node this))
(defn class-names
"Function which normalizes and combines class values to a string
Reagent allows classes to be defined as:
- Strings
- Named objects (Symbols or Keywords)
- Collections of previous types"
([])
([class] (util/class-names class))
([class1 class2] (util/class-names class1 class2))
([class1 class2 & others] (apply util/class-names class1 class2 others)))
(defn merge-props
"Utility function that merges some maps, handling :class and :style"
"Utility function that merges some maps, handling `:class` and `:style`.
The :class value is always normalized (using `class-names`) even if no
merging is done."
([] (util/merge-props))
([defaults] (util/merge-props defaults))
([defaults props] (util/merge-props defaults props))

View File

@ -117,19 +117,12 @@
;; Merge classes
class
(assoc :class (let [old-class (:class props)]
(if (nil? old-class) class (str class " " (if (named? old-class)
(name old-class)
old-class))))))))
(defn stringify-class [{:keys [class] :as props}]
(if (coll? class)
(assoc props :class (util/stringify-class class))
props))
(assoc :class (util/class-names class (:class props))))))
(defn convert-props [props id-class]
(let [props (-> props
util/stringify-class
(let [class (:class props)
props (-> props
(cond-> class (assoc :class (util/class-names class)))
(set-id-class id-class))]
(if ($ id-class :custom)
(convert-custom-prop-value props)

View File

@ -111,28 +111,34 @@
(or (keyword? x)
(symbol? x)))
(defn stringify-class [props]
(let [class (:class props)]
(if (coll? class)
(->> class
(keep (fn [c]
(if c
(if (named? c)
(name c)
c))))
(string/join " ")
(assoc props :class))
props)))
(defn class-names
([])
([class]
(if (coll? class)
(let [classes (keep (fn [c]
(if c
(if (named? c)
(name c)
c)))
class)]
(if (seq classes)
(string/join " " classes)))
(if (named? class)
(name class)
class)))
([a b]
(if a
(if b
(str (class-names a) " " (class-names b))
(class-names a))
(class-names b)))
([a b & rst]
(reduce class-names
(class-names a b)
rst)))
(defn- merge-class [p1 p2]
(let [p1 (stringify-class p1)
p2 (stringify-class p2)
class (when-let [c1 (:class p1)]
(when-let [c2 (:class p2)]
(str c1 " " c2)))]
(if (nil? class)
p2
(assoc p2 :class class))))
(assoc p2 :class (class-names (:class p1) (:class p2))))
(defn- merge-style [p1 p2]
(let [style (when-let [s1 (:style p1)]
@ -144,10 +150,16 @@
(defn merge-props
([] nil)
([p] (stringify-class p))
;; Normalize :class even if there are no merging
([p]
(if-let [c (:class p)]
(assoc p :class (class-names c))
p))
([p1 p2]
(if (nil? p1)
(stringify-class p2)
(if-let [c (:class p2)]
(assoc p2 :class (class-names c))
p2)
(do
(assert (map? p1)
(str "Property must be a map, not " (pr-str p1)))

View File

@ -2,6 +2,33 @@
(:require [clojure.test :refer [deftest is testing]]
[reagent.impl.util :as util]))
(deftest class-names-test
(is (= nil
(util/class-names)
(util/class-names nil)
(util/class-names [])
(util/class-names nil [])))
(is (= "a b"
(util/class-names ["a" "b"])
(util/class-names "a" "b")))
(is (= "a"
(util/class-names :a)
(util/class-names [:a])
(util/class-names nil "a")
(util/class-names [] nil "a")))
(is (= "a b c d"
(util/class-names "a" "b" nil ["c" "d"]))))
; (simple-benchmark []
; (do (util/class-names "a" "b")
; (util/class-names nil "a")
; (util/class-names "a" nil))
; 10000)
; (simple-benchmark []
; (util/class-names "a" "b" nil "c" "d")
; 10000)
(deftest merge-props-test
(testing "no arguments"
(is (nil? (util/merge-props))))
@ -36,9 +63,9 @@
:class "quux"}
nil))))
(testing ":class collection"
(testing ":class"
(is (= {:class "foo bar baz quux"}
(util/merge-props {:class "foo bar"}
{:class ["baz" "quux"]})
(util/merge-props {} {:class ["foo" "bar" "baz" "quux"]})
(util/merge-props nil {:class ["foo" "bar" "baz" "quux"]})
(util/merge-props {:class ["foo" "bar" "baz" "quux"]})))))