-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9707356
commit 3d2b733
Showing
25 changed files
with
999 additions
and
2,561 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,46 @@ | ||
(ns re-frame.cofx | ||
(:require | ||
[re-frame.db :refer [app-db]] | ||
[re-frame.interceptor :refer [->interceptor]] | ||
[re-frame.registrar :refer [get-handler register-handler]] | ||
[re-frame.registrar :refer [get-handler register-handler *current-frame*]] | ||
[re-frame.loggers :refer [console]])) | ||
|
||
;; -- Registration ------------------------------------------------------------ | ||
|
||
(def kind :cofx) | ||
(assert (re-frame.registrar/kinds kind)) | ||
|
||
(defn reg-cofx | ||
[id handler] | ||
(register-handler kind id handler)) | ||
|
||
;; -- Interceptor ------------------------------------------------------------- | ||
|
||
(defn inject-cofx | ||
([id] | ||
([registry id] | ||
(->interceptor | ||
:id :coeffects | ||
:before (fn coeffects-before | ||
[context] | ||
(if-let [handler (get-handler kind id)] | ||
(update context :coeffects handler) | ||
(if-let [handler (get-handler registry kind id)] | ||
(binding [*current-frame* (:frame context)] | ||
(update context :coeffects handler)) | ||
(console :error "No cofx handler registered for" id))))) | ||
([id value] | ||
([registry id value] | ||
(->interceptor | ||
:id :coeffects | ||
:before (fn coeffects-before | ||
[context] | ||
(if-let [handler (get-handler kind id)] | ||
(update context :coeffects handler value) | ||
(if-let [handler (get-handler registry kind id)] | ||
(binding [*current-frame* (:frame context)] | ||
(update context :coeffects handler value)) | ||
(console :error "No cofx handler registered for" id)))))) | ||
|
||
;; -- Builtin CoEffects Handlers --------------------------------------------- | ||
|
||
;; :db | ||
;; | ||
;; Adds to coeffects the value in `app-db`, under the key `:db` | ||
(reg-cofx | ||
:db | ||
(fn db-coeffects-handler | ||
[coeffects] | ||
(assoc coeffects :db @app-db))) | ||
|
||
;; Because this interceptor is used so much, we reify it | ||
(def inject-db (inject-cofx :db)) | ||
|
||
|
||
(defn register-built-in! | ||
[{:keys [registry]}] | ||
(let [reg-cofx (partial register-handler registry kind)] | ||
;; :db | ||
;; | ||
;; Adds to coeffects the value in `app-db`, under the key `:db` | ||
(reg-cofx | ||
:db | ||
(fn db-coeffects-handler | ||
[coeffects frame] | ||
(assoc coeffects :db @(:app-db frame)))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
(ns re-frame.context | ||
(:refer-clojure :exclude [bound-fn]) | ||
(:require [cljs.env] | ||
[cljs.analyzer])) | ||
|
||
(defmacro defc | ||
"For definining Reagent components that honor the contextual frame. Like defn | ||
but sets a :context-type metadata on the function, which Reagent will pick up | ||
on, so that the correct React context is set for this component." | ||
[name & fntail] | ||
(let [[doc fntail] (if (string? (first fntail)) | ||
[(first fntail) (rest fntail)] | ||
[nil fntail])] | ||
`(def ~(with-meta name (merge {:doc doc} (:meta &form))) | ||
^{:context-type frame-context} | ||
(fn ~@fntail)))) | ||
|
||
(defmacro bind-frame [frame & body] | ||
`(binding [~'re-frame.registrar/*current-frame* ~frame] | ||
(assert (satisfies? ~'re-frame.frame/IFrame ~frame) "given frame is not of type `re-frame.frame/IFrame`") | ||
~@body)) | ||
|
||
(defmacro import-with-frame | ||
([var-sym] | ||
`(import-with-frame ~(symbol (name var-sym)) ~var-sym)) | ||
([name var-sym] | ||
`(defn ~name | ||
;; Attempt at propagating the doc string / arglists, for some reason CIDER | ||
;; is not picking this up though. | ||
~(select-keys (:meta (cljs.analyzer/resolve-var cljs.env/*compiler* var-sym)) | ||
[:doc :arglists]) | ||
[& args#] | ||
(apply ~var-sym (current-frame) args#)))) | ||
|
||
(defmacro bound-fn [& args] | ||
(let [[name argv & body] (if (symbol? (first args)) | ||
args | ||
(into [nil] args))] | ||
`(let [frame# (~'re-frame.context/current-frame)] | ||
(fn ~@(when name name) ~argv | ||
(binding [~'re-frame.registrar/*current-frame* frame#] | ||
~@body))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
(ns re-frame.context | ||
(:require ["react" :as react] | ||
[goog.object :as gobj] | ||
[re-frame.core :as r] | ||
[re-frame.frame :as frame] | ||
[re-frame.registrar :as registrar] | ||
[re-frame.subs :as subs] | ||
[reagent.core]) | ||
(:require-macros [re-frame.context :refer [defc import-with-frame]])) | ||
|
||
(def frame-context (.createContext react r/default-frame)) | ||
|
||
(defn set-default-frame [frame] | ||
(gobj/set frame-context "_currentValue" frame) | ||
(gobj/set frame-context "_currentValue2" frame)) | ||
|
||
(defn current-context | ||
"Gets the react Context for the current component, to be used in lifecycle | ||
hooks (e.g. render). Assumes that Component.contextType has been set." | ||
[] | ||
(when-let [cmp (reagent.core/current-component)] | ||
;; When used without setting the right contextType we will get #js {} back | ||
(when (not (object? (.-context cmp))) | ||
(.-context cmp)))) | ||
|
||
(defn current-frame | ||
"Get the current frame provided by the context, falling back to the default | ||
frame. Assumes that Component.contextType = frame-context." | ||
[] | ||
(or registrar/*current-frame* | ||
(current-context) | ||
(gobj/get frame-context "_currentValue"))) | ||
|
||
(defn bound-frame [] | ||
(or registrar/*current-frame* | ||
(current-context) | ||
(throw (js/Error. "No frame bound")))) | ||
|
||
(defn provide-frame | ||
"Component that acts as a provider for the frame, so to run an isolated version | ||
of your app, use. | ||
[provide-frame (frame/make-frame) | ||
[app]]" | ||
[frame & children] | ||
(reagent.core/create-element | ||
(.-Provider frame-context) | ||
#js {:value frame | ||
:children (reagent.core/as-element (into [:<>] children))})) | ||
|
||
(defc provide-app-db | ||
"Component that acts as a provider for the app-db, it takes the registry from | ||
the current frame, but uses the given atom for the app-db" | ||
[app-db & children] | ||
`[~provide-frame ~(frame/make-frame {:registry (:registry (current-frame)) | ||
:app-db app-db}) | ||
~@children]) | ||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
;; Complete copy of the top-level re-frame API. If you are using the context | ||
;; approach then import re-frame.context instead of re-frame.core and things | ||
;; should generally Just Work™ | ||
|
||
(import-with-frame subscribe re-frame.frame/subscribe) | ||
(import-with-frame dispatch re-frame.frame/dispatch) | ||
(import-with-frame dispatch-sync re-frame.frame/dispatch-sync) | ||
(import-with-frame clear-sub re-frame.frame/clear-sub) | ||
(import-with-frame reg-fx re-frame.frame/reg-fx) | ||
(import-with-frame reg-cofx re-frame.frame/reg-cofx) | ||
(import-with-frame inject-cofx re-frame.frame/inject-cofx) | ||
(import-with-frame clear-cofx re-frame.frame/clear-cofx) | ||
(import-with-frame reg-event-db re-frame.frame/reg-event-db) | ||
(import-with-frame reg-event-fx re-frame.frame/reg-event-fx) | ||
(import-with-frame reg-event-ctx re-frame.frame/reg-event-ctx) | ||
(import-with-frame clear-event re-frame.frame/clear-event) | ||
|
||
;; A few special cases which we can't import directly | ||
|
||
(defn reg-sub-raw [query-id handler-fn] | ||
(frame/reg-sub-raw | ||
(current-frame) | ||
query-id | ||
(fn [frame query-v] | ||
(handler-fn (:app-db frame) query-v)))) | ||
|
||
(defn reg-sub [query-id & args] | ||
(apply frame/reg-sub (current-frame) query-id args)) | ||
|
||
(defn clear-subscriptions-cache! [& args] | ||
(apply subs/-clear (:subs-cache (current-frame)) args)) | ||
|
||
|
||
(defn context-fns | ||
"Returns subscribe/dispatch/dispatch-sync functions that are bound to the current frame. Use like this | ||
(defc my-component [] | ||
(reagent/with-let [{:keys [subscribe dispatch]} (re-frame/context-fns)] | ||
,,, | ||
)) " | ||
([] (context-fns (current-frame))) | ||
([frame] | ||
{:subscribe (partial re-frame.frame/subscribe frame) | ||
:dispatch (partial re-frame.frame/dispatch frame) | ||
:dispatch-sync (partial re-frame.frame/dispatch-sync frame)})) | ||
|
||
(defn bind-fn [f] | ||
(let [frame (current-frame)] | ||
(fn [& args] | ||
(binding [registrar/*current-frame* frame] | ||
(apply f args))))) |
Oops, something went wrong.