lambdaisland / ornament

Clojure Styled Components
Mozilla Public License 2.0
118 stars 13 forks source link

Keyframes / `.animate-*` classes from tailwind not supported #26

Open oxalorg opened 4 months ago

oxalorg commented 4 months ago

Currently the .animate-* classes from tailwind don't render correctly.

(o/defstyled test-line :div
  :bg-blue-400 :animate-pulse
  ([]
   [:<>]))

(o/as-garden test-line)
[".com_thehumbleai_chrome-ext_util_macros__test_line"
 {:--gi-bg-opacity 1,
  :background-color "rgba(96,165,250,var(--gi-bg-opacity))"}
 [{:animation "pulse 2s cubic-bezier(0.4,0,0.6,1) infinite"}
  {:identifier :keyframes,
   :value
   {:identifier "pulse",
    :frames (["0%" "100%" {:opacity 1}] ["50%" {:opacity 0.5}])}}]]

Then running (print (gc/compile-css {:pretty-print? true} (o/as-garden test-line)))

.com_thehumbleai_chrome-ext_util_macros__test_line {
  --gi-bg-opacity: 1;
  background-color: rgba(96,165,250,var(--gi-bg-opacity));
}

@keyframes pulse {
  .com_thehumbleai_chrome-ext_util_macros__test_line 0%, .com_thehumbleai_chrome-ext_util_macros__test_line 100% {
    opacity: 1;
  }
  .com_thehumbleai_chrome-ext_util_macros__test_line 50% {
    opacity: 0.5;
  }
}

Notice the addition of classnames in front of the offset percentages .com_thehumbleai_chrome-ext_util_macros__test_line 0% which is invalid css syntax: https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes

Not only this, but if you had a sharp eye you must have caught that the animation: pules 2s ... is missing from this garden.

Now I have spent some time debugging and I can understand why all of this happening underneath. Need to try and figure out a clean solution to solve this, but it most definitely involves manually adding keyframes as a part of the global registry instead of tying it to specific components.

Debugging notes

For a minute here, let's keep aside ornament and girouette and let's start with garden.

Garden's css compiler expects a hiccup like structure to cascade css.

(gc/compile-css [".parent"
                 [".nested1" {:height "8px"} {:width "10px"}]
                 [".nested2" {:height "8px"}]])

For top level css, it expects var args, so something like:

(gc/compile-css ["comp1" {:height "8px" :width "10px"}]
                ["comp2" {:height "8px"}])

Now if we try

(garden.stylesheet/at-keyframes "myanim" [:100% {:height "10px"}])
;; => #garden.types.CSSAtRule{:identifier :keyframes, :value {:identifier "myanim", :frames ([:100% {:height "10px"}])}}

We get back a CSSAtRule which garden understands to convert to css as follows:

(print
 (gc/compile-css
  {:pretty-print? true}
  (garden.stylesheet/at-keyframes "myanim" [:100% {:height "10px"}])
  [:div {:animation "myanim 2s"}]))
@keyframes myanim {

100% {
    height: 10px;
  }

}

div {
  animation: myanim 2s;
}

BUT, garden does not understand an animation rule as a part of a tag:

(print
 (gc/compile-css
  {:pretty-print? true}
  [:div
   (garden.stylesheet/at-keyframes "myanim" [:100% {:height "10px"}])
   [:p {:animation "myanim 2s"}]]))
@keyframes myanim {

  div 100% {
    height: 10px;
  }

}

div p {
  animation: myanim 2s;
}

I have also tested this with girouette's processor @green-coder and the processor is also not handling this case correctly 🤔

Am I missing something here? 🤔 If not, then we somehow need to raise this rule into a global space and render the keyframe CSSAtRule at the top level. Now I am not sure if this should be done in garden or ornament

An alternative is to not support tailwind animations, and instead use the set-tokens to define custom animations using garden's defkeyframes.

Any thoughts / ideas?