-
Notifications
You must be signed in to change notification settings - Fork 21
/
fulcro_portal.cljs
108 lines (88 loc) · 3.6 KB
/
fulcro_portal.cljs
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
(ns nubank.workspaces.lib.fulcro-portal
(:require [cljs.spec.alpha :as s]
[fulcro-css.css :as css]
[fulcro.client :as fulcro]
[fulcro.client.dom :as dom]
[fulcro.client.primitives :as fp]
[fulcro.inspect.client :as fi.client]
[goog.object :as gobj]))
(s/def ::root any?)
(s/def ::wrap-root? boolean?)
(s/def ::app map?)
(s/def ::persistence-key any?)
(s/def ::initial-state (s/or :fn? fn? :factory-param any?))
(defonce css-components* (atom #{}))
(defonce persistent-apps* (atom #{}))
(defn gen-css-component []
(fp/sc [_ _] {:css-include (fn [] (vec @css-components*))}))
(defn make-root [Root]
(let [factory (fp/factory Root)]
(fp/ui
static fp/InitialAppState
(initial-state [_ params]
{:ui/root (or (fp/get-initial-state Root params) {})})
static fp/IQuery
(query [_] [:fulcro.inspect.core/app-id {:ui/root (fp/get-query Root)}])
Object
(render [this]
(let [{:ui/keys [root]} (fp/props this)]
(factory root))))))
(defn fulcro-initial-state [{::keys [initial-state wrap-root? root]
:or {wrap-root? true}}]
(let [state (if (fn? initial-state)
(initial-state (fp/get-initial-state root nil))
(fp/get-initial-state root initial-state))]
(if wrap-root?
{:ui/root state}
state)))
(defn upsert-app [{::keys [app persistence-key]
:fulcro.inspect.core/keys [app-id]
:as config}]
(if-let [instance (and persistence-key (get-in @persistent-apps* persistence-key))]
instance
(let [app (cond-> app
(not (contains? app :initial-state))
(assoc :initial-state (fulcro-initial-state config))
app-id
(assoc-in [:initial-state :fulcro.inspect.core/app-id] app-id))
instance (apply fulcro/new-fulcro-client (apply concat app))]
(if persistence-key (swap! persistent-apps* assoc persistence-key instance))
instance)))
(defn dispose-app [{::keys [persistence-key] :as app}]
(if persistence-key (swap! persistent-apps* dissoc persistence-key))
(when-let [app-uuid (some-> app :reconciler fp/app-state deref (get fi.client/app-uuid-key))]
(fi.client/dispose-app app-uuid)))
(defn refresh-css! []
(css/upsert-css "fulcro-portal-css" (gen-css-component)))
(defn add-component-css! [comp]
(swap! css-components* conj comp)
(refresh-css!))
(defn mount-at [app* {::keys [root wrap-root? persistence-key] :or {wrap-root? true}} node]
(add-component-css! root)
(let [instance (if wrap-root? (make-root root) root)]
(if persistence-key
(swap! persistent-apps* assoc persistence-key instance))
(swap! app* fulcro/mount instance node)))
(fp/defsc FulcroPortal
[this _]
{:componentDidMount
(fn []
(let [props (fp/props this)
app* (atom (upsert-app props))]
(gobj/set this "app" app*)
(mount-at app* props (dom/node this))))
:componentDidUpdate
(fn [_ _] (some-> (gobj/get this "app") deref :reconciler fp/force-root-render!))
:componentWillUnmount
(fn []
(let [{::keys [persistence-key]} (fp/props this)
app* (gobj/get this "app")]
(if-not persistence-key (dispose-app @app*))
(reset! app* nil)
(js/ReactDOM.unmountComponentAtNode (dom/node this))))
:shouldComponentUpdate
(fn [_ _] false)}
(dom/div))
(def fulcro-portal* (fp/factory FulcroPortal))
(defn fulcro-portal [component options]
(fulcro-portal* (assoc options ::root component)))