Skip to content

Commit

Permalink
Add parameters to defkeyframes (#5)
Browse files Browse the repository at this point in the history
* Make defkeyframes accept a params vector

This is a breaking change! But it makes the API much more logically
consistent—why shouldn't you be able to parameterize keyframes?

This change also includes some heavy refactoring to simplify code
generation for the other cases, as well as an optimization that skips
the call to build-style-name if the function does not accept parameters.

* Update README to reflect params support on defkeyframes
  • Loading branch information
dhleong authored Aug 28, 2019
1 parent 5e3b432 commit c55e8c5
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Spade supports `@media` queries in the exact same way you see them in the [garde
Spade even supports generating `@keyframes` just like you'd expect:

```clojure
(defkeyframes anim-frames
(defkeyframes anim-frames []
["0%" {:opacity 0}]
["100%" {:opacity 1}])
```
Expand Down
8 changes: 6 additions & 2 deletions dev/spade/demo.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
[reagent.core :as r]
[spade.core :refer [defclass defattrs defglobal defkeyframes]]))

(defkeyframes anim-frames
(defkeyframes anim-frames []
["0%" {:opacity 0}]
["100%" {:opacity 1}])

(defkeyframes parameterized-anim-frames [start end]
["0%" {:opacity start}]
["100%" {:opacity end}])

(defglobal background
[:body {:background "#333"}])

Expand All @@ -19,7 +23,7 @@
{:padding "8px"}

[:.title {:font-size "22pt"
:animation [[(anim-frames) "560ms" 'ease-in-out]]}])
:animation [[(parameterized-anim-frames 0 0.5) "560ms" 'ease-in-out]]}])

(defclass colorized-with-key [color]
^{:key (str/upper-case color)}
Expand Down
96 changes: 62 additions & 34 deletions src/spade/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -51,54 +51,82 @@
(assoc base :composes composition)
base)))

(defn- transform-named-style [style style-name-var params-var]
(defn- build-style-naming-let
[style params original-style-name-var params-var]
(let [has-key-meta? (find-key-meta style)
static-key (extract-key style)
[composition style] (extract-composes style)
name-var (gensym "name")
style-var (gensym "style")]
(if (or static-key
(not has-key-meta?))
name-var (gensym "name")]
(cond
; easiest case: no params? no need to call build-style-name
(nil? (seq params))
[nil original-style-name-var nil]

(or static-key
(not has-key-meta?))
; if we can extract the key statically, that's better
(let [name-creator `(#'build-style-name
~style-name-var
~static-key
~params-var)]
`(let [~name-var ~name-creator
~style-var ~(into [`(str "." ~name-var)] style)]
~(with-composition composition name-var style-var)))

`(let [base-style# ~(vec style)
key# (:key (meta (first base-style#)))
~name-var (#'build-style-name
~style-name-var
key#
~params-var)
~style-var (into [(str "." ~name-var)] base-style#)]
~(with-composition composition name-var style-var)))))

(defn- transform-style [mode style style-name-var params-var]
[nil name-var `[~name-var (#'build-style-name
~original-style-name-var
~static-key
~params-var)]]

:else
(let [base-style-var (gensym "base-style")]
[base-style-var name-var `[~base-style-var ~(vec style)
key# (:key (meta (first ~base-style-var)))
~name-var (#'build-style-name
~original-style-name-var
key#
~params-var)]]))))

(defn- transform-named-style [style params style-name-var params-var]
(let [[composition style] (extract-composes style)
style-var (gensym "style")
[base-style-var name-var name-let] (build-style-naming-let
style params style-name-var
params-var)
style-decl (if base-style-var
`(into [(str "." ~name-var)] ~base-style-var)
(into [`(str "." ~name-var)] style))]
`(let ~(vec (concat name-let
[style-var style-decl]))
~(with-composition composition name-var style-var))))

(defn- transform-keyframes-style [style params style-name-var params-var]
(let [[style-var name-var style-naming-let] (build-style-naming-let
style params style-name-var
params-var)
info-map `{:css (spade.runtime/compile-css
(garden.stylesheet/at-keyframes
~name-var
~(or style-var
(vec style))))
:name ~name-var}]

; this (let) might get compiled out in advanced mode anyway, but
; let's just generate simpler code instead of having a redundant
; (let) if the keyframes take no params
(if style-naming-let
`(let ~style-naming-let ~info-map)
info-map)))

(defn- transform-style [mode style params style-name-var params-var]
(let [style (replace-at-forms style)]
(cond
(#{:global} mode)
`{:css (spade.runtime/compile-css ~(vec style))
:name ~style-name-var}

; keyframes are a bit of a special case
(#{:keyframes} mode)
`{:css (spade.runtime/compile-css
(garden.stylesheet/at-keyframes
~style-name-var
~(vec style)))
:name ~style-name-var}
(transform-keyframes-style style params style-name-var params-var)

:else
(transform-named-style style style-name-var params-var))))
(transform-named-style style params style-name-var params-var))))

(defmulti ^:private declare-style
(fn [mode _class-name params _factory-name-var _factory-fn-name]
(case mode
:global :static
:keyframes :no-args
(cond
(some #{'&} params) :variadic
(every? symbol? params) :default
Expand Down Expand Up @@ -166,7 +194,7 @@
factory-name-var (gensym "factory-name")]
`(do
(defn ~factory-fn-name ~factory-params
~(transform-style mode style style-name-var params-var))
~(transform-style mode style params style-name-var params-var))

(let [~factory-name-var (factory->name ~factory-fn-name)]
~(declare-style mode class-name params factory-name-var factory-fn-name)))))
Expand All @@ -180,5 +208,5 @@
(defmacro defglobal [group-name & style]
(declare-style-fns :global group-name nil style))

(defmacro defkeyframes [keyframes-name & style]
(declare-style-fns :keyframes keyframes-name nil style))
(defmacro defkeyframes [keyframes-name params & style]
(declare-style-fns :keyframes keyframes-name params style))
12 changes: 10 additions & 2 deletions test/spade/core_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,22 @@
"@media (min-width: 42px) {"))))


(defkeyframes key-frames
(defkeyframes key-frames []
[:from {:opacity 0}])

(defkeyframes parameterized-key-frames [from]
[:from {:opacity from}])

(deftest defkeyframes-test
(testing "Return keyframes name from defkeyframes"
(is (fn? key-frames))
(is (= "spade-core-test-key-frames"
(key-frames)))))
(key-frames))))

(testing "Return dynamic keyframes name from parameterized defkeyframes"
(is (fn? key-frames))
(is (= (str "spade-core-test-parameterized-key-frames_" (hash [0]))
(parameterized-key-frames 0)))))

(defclass composed [color]
^{:key color}
Expand Down

0 comments on commit c55e8c5

Please sign in to comment.