-
Notifications
You must be signed in to change notification settings - Fork 16
/
react.cljc
111 lines (92 loc) · 3.89 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
105
106
107
108
109
110
111
(ns hx.react
(:require #?(:cljs [goog.object :as gobj])
#?(:cljs ["react" :as react])
#?(:clj [hx.compiler.core])
#?(:clj [hx.compiler.parser :as parser])
#?(:clj [hx.react.interceptors :as interceptors])
[hx.utils :as utils])
(:refer-clojure :exclude [compile]))
(defn is-hx? [el]
;; TODO: detect hx component
true)
(defmacro c [form]
(hx.compiler.core/compile-hiccup form 'hx.react/create-element))
(defmacro defcomponent
{:style/indent [1 :form [1]]}
[display-name constructor & body]
(let [;; with-compile (compile* body)
methods (filter #(not (:static (meta %))) body)
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
~@methods)
class#))))
(defmacro defnc [name props-bindings & body]
`(defn ~name [props#]
(let [~@props-bindings (hx.react/props->clj props#)]
~@body)))
#?(:clj (defmethod parser/parse-element
:<>
[el & args]
(parser/-parse-element
'hx.react/fragment
args)))
#?(:cljs (defn props->clj [props]
(utils/shallow-js->clj props :keywordize-keys true)))
#?(:cljs (defn styles->js [props]
(cond
(and (map? props) (:style props))
(assoc props :style (clj->js (:style props)))
(gobj/containsKey props "style")
(do (->> (gobj/get props "style")
(clj->js)
(gobj/set props "style"))
props)
:default props)))
#?(:cljs (defn clj->props [props & {:keys [styles?]}]
(-> (if styles? (styles->js props) props)
(utils/reactify-props)
(utils/shallow-clj->js props))))
#?(:clj (defn create-element [el p & c]
nil)
:cljs (defn create-element [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? (or (string? el) (not (is-hx? el)))
props (clj->props p :styles? js-interop?)]
(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)))
#?(:cljs (def fragment react/Fragment))