-
Notifications
You must be signed in to change notification settings - Fork 16
/
react.cljc
106 lines (89 loc) · 3.61 KB
/
react.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
(ns hx.react
(:require #?(:cljs [goog.object :as gobj])
#?(:cljs ["react" :as react])
[hx.hiccup :as hiccup]
[hx.utils :as utils]))
#?(:cljs (defn parse-body [body]
(if (vector? body)
(hiccup/parse body)
body)))
(defmacro defcomponent
{:style/indent [1 :form [1]]}
[display-name constructor & body]
(let [;; with-compile (compile* body)
methods (filter #(not (or (= (first %) 'render)
(:static (meta %)))) body)
render (first (filter #(= (first %) 'render) body))
render' `(~(first render) ~(second render)
(hx.react/parse-body
(do ~@(nthrest render 2))))
statics (->> (filter #(:static (meta %)) body)
(map #(apply vector (str (munge (first %))) (rest %)))
(into {"displayName" (name display-name)}))
method-names (into [] (map #(list 'quote (first %)) methods))]
`(def ~display-name
(let [ctor# (fn ~(second constructor)
;; constructor must return `this`
~@(drop 2 constructor))
class# (hx.react/create-pure-component
ctor#
~statics
~method-names)]
(cljs.core/specify! (.-prototype class#)
~'Object
~render'
~@methods)
class#))))
(defmacro defnc [name props-bindings & body]
`(defn ~name [props#]
(let [~@props-bindings (hx.react/props->clj props#)]
(hx.react/parse-body
(do ~@body)))))
(defmacro shallow-render [& body]
`(with-redefs [hx.react/parse-body identity]
~@body))
#?(:cljs (def fragment react/Fragment))
#?(:cljs (defmethod hiccup/parse-element
:<>
[el & args]
(hiccup/-parse-element
hx.react/fragment
args)))
#?(:cljs (defn props->clj [props]
(utils/shallow-js->clj props :keywordize-keys true)))
#?(:clj (defn $ [el p & c]
nil)
:cljs (defn $ [el p & c]
(if (or (string? p) (number? p) (react/isValidElement p))
(apply react/createElement el nil p c)
;; if el is a keyword, or is not marked as an hx component,
;; we recursively convert styles
(let [js-interop? (string? el)
props (utils/clj->props p)]
(apply react/createElement el props c)))))
#?(:cljs (defn assign-methods [class method-map]
(doseq [[method-name method-fn] method-map]
(gobj/set (.-prototype class)
(munge (name method-name))
method-fn))
class))
#?(:cljs (defn create-class [super-class init-fn static-properties method-names]
(let [ctor (fn [props]
(this-as this
;; auto-bind methods
(doseq [method method-names]
(gobj/set this (munge method)
(.bind (gobj/get this (munge method)) this)))
(init-fn this props)))]
;; set static properties on prototype
(doseq [[k v] static-properties]
(gobj/set ctor k v))
(goog/inherits ctor super-class)
ctor)))
#?(:cljs (defn create-pure-component [init-fn static-properties method-names]
(create-class react/PureComponent init-fn static-properties method-names)))
(defn factory
"Takes a React component, and creates a function that returns
a new React element"
[component]
(partial $ component))