Skip to content

Commit

Permalink
Implemented emotion with compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
cj-price committed Jun 21, 2023
1 parent a14faba commit e09a8e6
Show file tree
Hide file tree
Showing 10 changed files with 807 additions and 6 deletions.
18 changes: 17 additions & 1 deletion demo/reagentdemo/intro.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
[reagentdemo.syntax :as s]
[reagentdemo.common :as common :refer [demo-component]]
[simpleexample.core :as simple]
[todomvc.core :as todo]))
[todomvc.core :as todo]
[emotion.core :as emotion]))

(defn simple-component []
[:div
Expand Down Expand Up @@ -325,13 +326,28 @@
:complete true
:src (s/src-of nil "todomvc/core.cljs")}]])

(defn emotion-component []
[:div {:css {:background-color "pink"}}
"worked"])

(defn emotion-demo []
[:div.demo-text
[:h2 "Emotion"]

[:p "This demo uses a compiler to implement the " [:code ":css"] " from emotion."]

[demo-component {:comp emotion/simple-example
:complete true
:src (s/src-of nil "emotion/core.cljs")}]])

(defn main []
(let [show-all (r/atom false)
head "Reagent: Minimalistic React for ClojureScript"]
(js/setTimeout #(reset! show-all true) 500)
(fn []
[:div.reagent-demo
[:h1 head]
[emotion-demo]
[intro]
[managing-state]
[essential-api]
Expand Down
15 changes: 15 additions & 0 deletions examples/emotion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Reagent example app

Run "`lein figwheel`" in a terminal to compile the app, and then open http://localhost:3449

Any changes to ClojureScript source files (in `src`) will be reflected in the running page immediately (while "`lein figwheel`" is running).

Run "`lein clean; lein with-profile prod cljsbuild once client`" to compile an optimized version.

To check built version on browser, copy resources to target folder and open the
index file on browser:

```
cp resources/public/* target/public
google-chrome target/public/index.html
```
32 changes: 32 additions & 0 deletions examples/emotion/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(defproject emotion-reagent "0.6.0"
:dependencies [[org.clojure/clojure "1.10.1"]
[org.clojure/clojurescript "1.10.597"]
[reagent "0.10.0"]
[figwheel "0.5.19"]]

:plugins [[lein-cljsbuild "1.1.7"]
[lein-figwheel "0.5.19"]]

:resource-paths ["resources" "target"]
:clean-targets ^{:protect false} [:target-path]

:profiles {:dev {:cljsbuild
{:builds {:client
{:figwheel {:on-jsload "emotion.core/run"}
:compiler {:main "emotion.core"
:optimizations :none}}}}}

:prod {:cljsbuild
{:builds {:client
{:compiler {:optimizations :advanced
:elide-asserts true
:pretty-print false}}}}}}

:figwheel {:repl false
:http-server-root "public"}

:cljsbuild {:builds {:client
{:source-paths ["src"]
:compiler {:output-dir "target/public/client"
:asset-path "client"
:output-to "target/public/client.js"}}}})
22 changes: 22 additions & 0 deletions examples/emotion/resources/public/example.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

div, h1, input {
font-family: HelveticaNeue, Helvetica;
color: #777;
}

.example-clock {
font-size: 128px;
line-height: 1.2em;
font-family: HelveticaNeue-UltraLight, Helvetica;
}

@media (max-width: 768px) {
.example-clock {
font-size: 64px;
}
}

.color-input, .color-input input {
font-size: 24px;
line-height: 1.5em;
}
17 changes: 17 additions & 0 deletions examples/emotion/resources/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Example</title>
<link rel="stylesheet" href="example.css">
</head>
<body>
<div id="app">
<h1>Reagent example app – see README.md</h1>
</div>
<script src="client.js"></script>
<script>
simpleexample.core.run();
</script>
</body>
</html>
95 changes: 95 additions & 0 deletions examples/emotion/src/emotion/core.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
(ns emotion.core
(:require ["@emotion/react" :as emotion]
[reagent.impl.protocols :as p]
[reagent.impl.template :as t]
[reagent.core :as r]
[reagent.dom :as rdom]))

(defn simple-test-0 []
[:div {:css {"&:after" {:content "\"Hi\""}}}])

(defn simple-test-1 []
[:div {:css {:background-color "purple"
:color "pink !important"}}
"Simple test"])

(defn simple-test-n []
[:div {:css {:background-color "pink"
:color "purple !important"}}
"A simple component that uses emotions "
[:code ":css"]
" prop to change colors"])

(defn shorthand-test []
[:div>p {:css {:transform "rotate(180deg)"}}
"Rotate your text 180deg"])

(defn functional-test []
[:div {:css {:animation "wiggle 3s infinite"
:text-align "center"
:transform-origin "center"
"@keyframes wiggle" {"0%" {:transform "rotate(0deg)"}
"25%" {:transform "rotate(0deg)"}
"50%" {:transform "rotate(5deg)"}
"75%" {:transform "rotate(-5deg)"}
"100%" {:transform "rotate(0deg)"}}}}
"This is a functional component that has some styling"])

(defn emotion-components []
[:div
[simple-test-0]
[simple-test-1]
[simple-test-n]
[shorthand-test]
[:f> functional-test]])

;;; Emotion compiler

(defn make-element
[this argv component jsprops first-child]
(case (- (count argv) first-child)
;; Optimize cases of zero or one child
0 (emotion/jsx component jsprops)

1 (emotion/jsx component jsprops
(p/as-element this (nth argv first-child nil)))

(.apply emotion/jsx nil
(reduce-kv (fn [a k v]
(when (>= k first-child)
(.push a (p/as-element this v)))
a)
#js [component jsprops] argv))))

(defn emotion-compiler [opts]
(let [id (gensym "reagent-compiler")
fn-to-element (if (:function-components opts)
t/maybe-function-element
t/reag-element)
parse-fn (get opts :parse-tag t/cached-parse)]
(reify p/Compiler
;; This is used to as cache key to cache component fns per compiler
(get-id [this] id)
(parse-tag [this tag-name tag-value]
(parse-fn this tag-name tag-value))
(as-element [this x]
(t/as-element this x fn-to-element))
(make-element [this argv component jsprops first-child]
(make-element this argv component jsprops first-child)))))

(def compiler (emotion-compiler {}))

(defn simple-example []
(r/create-class
{:component-did-mount #(rdom/render
[emotion-components]
(js/document.getElementById "emotion-container")
compiler)
:reagent-render
(fn []
[:div#emotion-container])}))



(defn ^:export run []
(rdom/render [simple-example] (js/document.getElementById "app")))
Loading

0 comments on commit e09a8e6

Please sign in to comment.