Skip to content

Commit

Permalink
Apply changes from freerange
Browse files Browse the repository at this point in the history
  • Loading branch information
olimsaidov committed Dec 10, 2024
1 parent 9707356 commit 3d2b733
Show file tree
Hide file tree
Showing 25 changed files with 999 additions and 2,561 deletions.
1,398 changes: 0 additions & 1,398 deletions src/re_frame/alpha.cljc

This file was deleted.

45 changes: 20 additions & 25 deletions src/re_frame/cofx.cljc
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))))))
42 changes: 42 additions & 0 deletions src/re_frame/context.clj
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)))))
110 changes: 110 additions & 0 deletions src/re_frame/context.cljs
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)))))
Loading

0 comments on commit 3d2b733

Please sign in to comment.