Update bundled reagent to v0.8.0-alpha2 and React 16

This commit is contained in:
Daniel Compton 2018-01-26 21:40:34 +13:00
parent e34047c54d
commit 5e68f4b7cf
29 changed files with 341 additions and 259 deletions

View File

@ -4,7 +4,7 @@
:license {:name "MIT"}
:dependencies [[org.clojure/clojure "1.9.0"]
[org.clojure/clojurescript "1.9.671"]
[reagent "0.6.0" :scope "provided"]
[reagent "0.8.0-alpha2" :scope "provided"]
[re-frame "0.10.3" :scope "provided"]
[binaryage/devtools "0.9.4"]
[garden "1.3.3"]
@ -31,7 +31,7 @@
:target-path "resources/day8/re_frame/trace"}
:profiles {:dev {:dependencies [[binaryage/dirac "RELEASE"]]}
:mranderson {:dependencies ^:replace [^:source-dep [re-frame "0.10.3"
:mranderson {:dependencies ^:replace [^:source-dep [re-frame "0.10.2"
:exclusions [org.clojure/clojurescript
cljsjs/react
cljsjs/react-dom
@ -39,7 +39,7 @@
cljsjs/create-react-class
org.clojure/tools.logging
net.cgrand/macrovich]]
^:source-dep [reagent "0.7.0"
^:source-dep [reagent "0.8.0-alpha2"
:exclusions [org.clojure/clojurescript
cljsjs/react
cljsjs/react-dom

View File

@ -3,6 +3,6 @@
lein do clean
lein with-profile mranderson source-deps
# Then delete the META-INF directories
rm -r target/srcdeps/mranderson047/reagent/v0v7v0/META-INF
rm -r target/srcdeps/mranderson047/reagent/v0v8v0-alpha2/META-INF
rm -r target/srcdeps/mranderson047/re-frame
cp -r target/srcdeps/mranderson047 src

View File

@ -22,7 +22,7 @@
[re-frame.interop :as interop]
[devtools.formatters.core :as devtools]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[mranderson047.reagent.v0v7v0.reagent.core :as r]))
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]))
(goog-define debug? false)

View File

@ -1,6 +1,6 @@
(ns day8.re-frame.trace.events
(:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[mranderson047.reagent.v0v7v0.reagent.core :as r]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]
[cljs.tools.reader.edn]
[day8.re-frame.trace.utils.utils :as utils]
[day8.re-frame.trace.utils.localstorage :as localstorage]

View File

@ -18,7 +18,7 @@
see additional properties that can be specified in options
https://github.com/joshwcomeau/react-flip-move#options"
(:require
[mranderson047.reagent.v0v7v0.reagent.core :as reagent]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as reagent]
[cljsjs.react-flip-move]))
(def component

View File

@ -1,7 +1,7 @@
(ns day8.re-frame.trace.utils.re-com
"Shameless pilfered from re-com."
(:require-macros [day8.re-frame.trace.utils.re-com :refer [handler-fn]])
(:require [mranderson047.reagent.v0v7v0.reagent.ratom :as reagent :refer [RAtom Reaction RCursor Track Wrapper]]
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as reagent :refer [RAtom Reaction RCursor Track Wrapper]]
[clojure.string :as string]))
(defn px

View File

@ -5,7 +5,7 @@
[day8.re-frame.trace.utils.animated :as animated]
[day8.re-frame.trace.view.components :as components]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[mranderson047.reagent.v0v7v0.reagent.core :as r]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]
[day8.re-frame.trace.utils.re-com :as rc :refer [css-join]]
[day8.re-frame.trace.common-styles :as common]
[clojure.data])

View File

@ -5,7 +5,7 @@
[day8.re-frame.trace.utils.localstorage :as localstorage]
[clojure.string :as str]
[day8.re-frame.trace.utils.re-com :as rc]
[mranderson047.reagent.v0v7v0.reagent.core :as r])
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r])
(:require-macros [day8.re-frame.trace.utils.macros :refer [with-cljs-devtools-prefs]]))
(defn search-input [{:keys [title placeholder on-save on-change on-stop]}]

View File

@ -1,6 +1,6 @@
(ns day8.re-frame.trace.view.settings
(:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[mranderson047.reagent.v0v7v0.reagent.core :as r]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]
[day8.re-frame.trace.utils.re-com :as rc :refer [css-join]]
[day8.re-frame.trace.common-styles :as common]
[garden.units :as units]

View File

@ -3,7 +3,7 @@
[day8.re-frame.trace.utils.utils :as utils]
[day8.re-frame.trace.utils.animated :as animated]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[mranderson047.reagent.v0v7v0.reagent.core :as r]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]
[day8.re-frame.trace.utils.re-com :as rc :refer [css-join]]
[day8.re-frame.trace.common-styles :as common]
[day8.re-frame.trace.view.components :as components])

View File

@ -6,7 +6,7 @@
[day8.re-frame.trace.utils.localstorage :as localstorage]
[cljs.pprint :as pprint]
[clojure.set :as set]
[mranderson047.reagent.v0v7v0.reagent.core :as r]
[mranderson047.reagent.v0v8v0-alpha2.reagent.core :as r]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[day8.re-frame.trace.utils.re-com :as rc]))

View File

@ -48,7 +48,7 @@
(defn make-reaction
"On JVM Clojure, return a `deref`-able thing which invokes the given function
on every `deref`. That is, `make-reaction` here provides precisely none of the
benefits of `mranderson047.reagent.v0v7v0.reagent.ratom/make-reaction` (which only invokes its function if
benefits of `mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/make-reaction` (which only invokes its function if
the reactions that the function derefs have changed value). But so long as `f`
only depends on other reactions (which also behave themselves), the only
difference is one of efficiency. That is, your tests should see no difference

View File

@ -1,13 +1,13 @@
(ns mranderson047.re-frame.v0v10v2.re-frame.interop
(:require [goog.async.nextTick]
[mranderson047.reagent.v0v7v0.reagent.core]
[mranderson047.reagent.v0v7v0.reagent.ratom]))
[mranderson047.reagent.v0v8v0-alpha2.reagent.core]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom]))
(def next-tick goog.async.nextTick)
(def empty-queue #queue [])
(def after-render mranderson047.reagent.v0v7v0.reagent.core/after-render)
(def after-render mranderson047.reagent.v0v8v0-alpha2.reagent.core/after-render)
;; Make sure the Google Closure compiler sees this as a boolean constant,
;; otherwise Dead Code Elimination won't happen in `:advanced` builds.
@ -16,23 +16,23 @@
(def ^boolean debug-enabled? "@define {boolean}" ^boolean js/goog.DEBUG)
(defn ratom [x]
(mranderson047.reagent.v0v7v0.reagent.core/atom x))
(mranderson047.reagent.v0v8v0-alpha2.reagent.core/atom x))
(defn ratom? [x]
(satisfies? mranderson047.reagent.v0v7v0.reagent.ratom/IReactiveAtom x))
(satisfies? mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/IReactiveAtom x))
(defn deref? [x]
(satisfies? IDeref x))
(defn make-reaction [f]
(mranderson047.reagent.v0v7v0.reagent.ratom/make-reaction f))
(mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/make-reaction f))
(defn add-on-dispose! [a-ratom f]
(mranderson047.reagent.v0v7v0.reagent.ratom/add-on-dispose! a-ratom f))
(mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/add-on-dispose! a-ratom f))
(defn dispose! [a-ratom]
(mranderson047.reagent.v0v7v0.reagent.ratom/dispose! a-ratom))
(mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/dispose! a-ratom))
(defn set-timeout! [f ms]
(js/setTimeout f ms))
@ -46,11 +46,11 @@
"Produces an id for reactive Reagent values
e.g. reactions, ratoms, cursors."
[reactive-val]
(when (implements? mranderson047.reagent.v0v7v0.reagent.ratom/IReactiveAtom reactive-val)
(when (implements? mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/IReactiveAtom reactive-val)
(str (condp instance? reactive-val
mranderson047.reagent.v0v7v0.reagent.ratom/RAtom "ra"
mranderson047.reagent.v0v7v0.reagent.ratom/RCursor "rc"
mranderson047.reagent.v0v7v0.reagent.ratom/Reaction "rx"
mranderson047.reagent.v0v7v0.reagent.ratom/Track "tr"
mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/RAtom "ra"
mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/RCursor "rc"
mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/Reaction "rx"
mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/Track "tr"
"other")
(hash reactive-val))))

View File

@ -1,33 +0,0 @@
(ns mranderson047.reagent.v0v7v0.reagent.dom.server
(:require [cljsjs.react.dom.server]
[mranderson047.reagent.v0v7v0.reagent.impl.util :as util]
[mranderson047.reagent.v0v7v0.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v7v0.reagent.ratom :as ratom]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]))
(defonce ^:private imported nil)
(defn module []
(cond
(some? imported) imported
(exists? js/ReactDOMServer) (set! imported js/ReactDOMServer)
(exists? js/require) (or (set! imported (js/require "react-dom/server"))
(throw (js/Error.
"require('react-dom/server') failed")))
:else
(throw (js/Error. "js/ReactDOMServer is missing"))))
(defn render-to-string
"Turns a component into an HTML string."
[component]
(ratom/flush!)
(binding [util/*non-reactive* true]
($ (module) renderToString (tmpl/as-element component))))
(defn render-to-static-markup
"Turns a component into an HTML string, without data-react-id attributes, etc."
[component]
(ratom/flush!)
(binding [util/*non-reactive* true]
($ (module) renderToStaticMarkup (tmpl/as-element component))))

View File

@ -1,2 +0,0 @@
(ns mranderson047.reagent.v0v7v0.reagent.interop
(:require-macros [mranderson047.reagent.v0v7v0.reagent.interop]))

View File

@ -1,5 +1,5 @@
(ns mranderson047.reagent.v0v7v0.reagent.core
(:require [mranderson047.reagent.v0v7v0.reagent.ratom :as ra]))
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.core
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ra]))
(defmacro with-let [bindings & body]
"Bind variables as with let, except that when used in a component

View File

@ -1,22 +1,21 @@
(ns mranderson047.reagent.v0v7v0.reagent.core
(:require-macros [mranderson047.reagent.v0v7v0.reagent.core])
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.core
(:require-macros [mranderson047.reagent.v0v8v0-alpha2.reagent.core])
(:refer-clojure :exclude [partial atom flush])
(:require [mranderson047.reagent.v0v7v0.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v7v0.reagent.impl.component :as comp]
[mranderson047.reagent.v0v7v0.reagent.impl.util :as util]
[mranderson047.reagent.v0v7v0.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v7v0.reagent.ratom :as ratom]
[mranderson047.reagent.v0v7v0.reagent.debug :as deb :refer-macros [dbg prn
(:require [react :as react]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.component :as comp]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ratom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.debug :as deb :refer-macros [dbg prn
assert-some assert-component
assert-js-object assert-new-state
assert-callable]]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v7v0.reagent.dom :as dom]))
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.dom :as dom]))
(def is-client util/is-client)
(def react util/react)
(defn create-element
"Create a native React element, by calling React.createElement directly.
@ -34,13 +33,13 @@
(create-element type nil))
([type props]
(assert-js-object props)
($ react createElement type props))
(react/createElement type props))
([type props child]
(assert-js-object props)
($ react createElement type props child))
(react/createElement type props child))
([type props child & children]
(assert-js-object props)
(apply ($ react :createElement) type props child children)))
(apply react/createElement type props child children)))
(defn as-element
"Turns a vector of Hiccup syntax into a React element. Returns form
@ -51,9 +50,11 @@
(defn adapt-react-class
"Returns an adapter for a native React class, that may be used
just like a Reagent component function or class in Hiccup forms."
[c]
(assert-some c "Component")
(tmpl/adapt-react-class c))
([c opts]
(assert-some c "Component")
(tmpl/adapt-react-class c opts))
([c]
(adapt-react-class c {})))
(defn reactify-component
"Returns an adapter for a Reagent component, that may be used from

View File

@ -1,19 +1,19 @@
(ns mranderson047.reagent.v0v7v0.reagent.debug
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.debug
(:refer-clojure :exclude [prn println time]))
(defmacro log
"Print with console.log, if it exists."
[& forms]
`(when mranderson047.reagent.v0v7v0.reagent.debug.has-console
`(when mranderson047.reagent.v0v8v0-alpha2.reagent.debug.has-console
(.log js/console ~@forms)))
(defmacro warn
"Print with console.warn."
[& forms]
(when *assert*
`(when mranderson047.reagent.v0v7v0.reagent.debug.has-console
(.warn (if mranderson047.reagent.v0v7v0.reagent.debug.tracking
mranderson047.reagent.v0v7v0.reagent.debug.track-console js/console)
`(when mranderson047.reagent.v0v8v0-alpha2.reagent.debug.has-console
(.warn (if mranderson047.reagent.v0v8v0-alpha2.reagent.debug.tracking
mranderson047.reagent.v0v8v0-alpha2.reagent.debug.track-console js/console)
(str "Warning: " ~@forms)))))
(defmacro warn-unless
@ -26,9 +26,9 @@
"Print with console.error."
[& forms]
(when *assert*
`(when mranderson047.reagent.v0v7v0.reagent.debug.has-console
(.error (if mranderson047.reagent.v0v7v0.reagent.debug.tracking
mranderson047.reagent.v0v7v0.reagent.debug.track-console js/console)
`(when mranderson047.reagent.v0v8v0-alpha2.reagent.debug.has-console
(.error (if mranderson047.reagent.v0v8v0-alpha2.reagent.debug.tracking
mranderson047.reagent.v0v8v0-alpha2.reagent.debug.track-console js/console)
(str ~@forms)))))
(defmacro println
@ -77,7 +77,7 @@ as well as package name and line number. Returns x."
(defmacro assert-component [value]
`(assert (comp/reagent-component? ~value)
(str "Expected a mranderson047.reagent.v0v7v0.reagent component, not "
(str "Expected a mranderson047.reagent.v0v8v0-alpha2.reagent component, not "
(pr-str ~value))))
(defmacro assert-js-object [value]

View File

@ -1,5 +1,5 @@
(ns mranderson047.reagent.v0v7v0.reagent.debug
(:require-macros [mranderson047.reagent.v0v7v0.reagent.debug]))
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.debug
(:require-macros [mranderson047.reagent.v0v8v0-alpha2.reagent.debug]))
(def ^:const has-console (exists? js/console))

View File

@ -1,39 +1,29 @@
(ns mranderson047.reagent.v0v7v0.reagent.dom
(:require [cljsjs.react.dom]
[mranderson047.reagent.v0v7v0.reagent.impl.util :as util]
[mranderson047.reagent.v0v7v0.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v7v0.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v7v0.reagent.ratom :as ratom]
[mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg]]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]))
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.dom
(:require [react-dom :as react-dom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ratom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]))
(defonce ^:private imported nil)
(defn module []
(cond
(some? imported) imported
(exists? js/ReactDOM) (set! imported js/ReactDOM)
(exists? js/require) (or (set! imported (js/require "react-dom"))
(throw (js/Error. "require('react-dom') failed")))
:else
(throw (js/Error. "js/ReactDOM is missing"))))
(defonce ^:private roots (atom {}))
(defn- unmount-comp [container]
(swap! roots dissoc container)
($ (module) unmountComponentAtNode container))
(react-dom/unmountComponentAtNode container))
(defn- render-comp [comp container callback]
(binding [util/*always-update* true]
(->> ($ (module) render (comp) container
(fn []
(binding [util/*always-update* false]
(swap! roots assoc container [comp container])
(batch/flush-after-render)
(if (some? callback)
(callback))))))))
(react-dom/render (comp) container
(fn []
(binding [util/*always-update* false]
(swap! roots assoc container [comp container])
(batch/flush-after-render)
(if (some? callback)
(callback)))))))
(defn- re-render-component [comp container]
(render-comp comp container nil))
@ -59,7 +49,7 @@
(defn dom-node
"Returns the root DOM node of a mounted component."
[this]
($ (module) findDOMNode this))
(react-dom/findDOMNode this))
(set! tmpl/find-dom-node dom-node)

View File

@ -0,0 +1,22 @@
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.dom.server
(:require ["react-dom/server" :as dom-server]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.template :as tmpl]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ratom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]))
(defonce ^:private imported nil)
(defn render-to-string
"Turns a component into an HTML string."
[component]
(ratom/flush!)
(binding [util/*non-reactive* true]
(dom-server/renderToString (tmpl/as-element component))))
(defn render-to-static-markup
"Turns a component into an HTML string, without data-react-id attributes, etc."
[component]
(ratom/flush!)
(binding [util/*non-reactive* true]
(dom-server/renderToStaticMarkup (tmpl/as-element component))))

View File

@ -1,8 +1,8 @@
(ns mranderson047.reagent.v0v7v0.reagent.impl.batching
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching
(:refer-clojure :exclude [flush])
(:require [mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg assert-some]]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v7v0.reagent.impl.util :refer [is-client]]
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg assert-some]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :refer [is-client]]
[clojure.string :as string]))
;;; Update batching

View File

@ -1,9 +1,11 @@
(ns mranderson047.reagent.v0v7v0.reagent.impl.component
(:require [mranderson047.reagent.v0v7v0.reagent.impl.util :as util]
[mranderson047.reagent.v0v7v0.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v7v0.reagent.ratom :as ratom]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg prn dev? warn error warn-unless
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.impl.component
(:require [create-react-class :as create-react-class]
[react :as react]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ratom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg prn dev? warn error warn-unless
assert-callable]]))
(declare ^:dynamic *current-component*)
@ -49,7 +51,7 @@
(if-some [v ($ p :argv)]
(extract-children v)
(->> ($ p :children)
($ util/react Children.toArray)
(react/Children.toArray)
(into [])))))
(defn ^boolean reagent-class? [c]
@ -197,6 +199,10 @@
(when-not (nil? f)
(.call f c c))))
:componentDidCatch
(fn componentDidCatch [error info]
(this-as c (.call f c c error info)))
nil))
(defn get-wrapper [key f name]
@ -263,22 +269,37 @@
{:pre [(map? body)]}
(->> body
cljsify
util/create-class))
create-react-class))
(defn component-path [c]
(let [elem (some-> (or (some-> c ($ :_reactInternalInstance))
c)
($ :_currentElement))
name (some-> elem
(defn fiber-component-path [fiber]
(let [name (some-> fiber
($ :type)
($ :displayName))
path (some-> elem
($ :_owner)
component-path
parent (some-> fiber
($ :return))
path (some-> parent
fiber-component-path
(str " > "))
res (str path name)]
(when-not (empty? res) res)))
(defn component-path [c]
;; Alternative branch for React 16
(if-let [fiber (some-> c ($ :_reactInternalFiber))]
(fiber-component-path fiber)
(let [elem (or (some-> (or (some-> c ($ :_reactInternalInstance))
c)
($ :_currentElement)))
name (some-> elem
($ :type)
($ :displayName))
path (some-> elem
($ :_owner)
component-path
(str " > "))
res (str path name)]
(when-not (empty? res) res))))
(defn comp-name []
(if (dev?)
(let [c *current-component*

View File

@ -1,12 +1,13 @@
(ns mranderson047.reagent.v0v7v0.reagent.impl.template
(:require [clojure.string :as string]
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.impl.template
(:require [react :as react]
[clojure.string :as string]
[clojure.walk :refer [prewalk]]
[mranderson047.reagent.v0v7v0.reagent.impl.util :as util :refer [is-client]]
[mranderson047.reagent.v0v7v0.reagent.impl.component :as comp]
[mranderson047.reagent.v0v7v0.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v7v0.reagent.ratom :as ratom]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg prn println log dev?
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util :refer [is-client]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.component :as comp]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching :as batch]
[mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :as ratom]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg prn println log dev?
warn warn-unless]]))
;; From Weavejester's Hiccup, via pump:
@ -90,15 +91,23 @@
(str class " " old))))
p)))
(defn stringify-class [{:keys [class] :as props}]
(if (coll? class)
(->> class
(filter identity)
(string/join " ")
(assoc props :class))
props))
(defn convert-props [props id-class]
(-> props
stringify-class
convert-prop-value
(set-id-class id-class)))
;;; Specialization for input components
;; This gets set from mranderson047.reagent.v0v7v0.reagent.dom
;; This gets set from mranderson047.reagent.v0v8v0-alpha2.reagent.dom
(defonce find-dom-node nil)
;; <input type="??" >
@ -111,55 +120,68 @@
[input-type]
(contains? these-inputs-have-selection-api input-type))
(defn input-set-value [this]
(declare input-component-set-value)
(defn input-node-set-value
[node rendered-value dom-value component {:keys [on-write]}]
(if-not (and (identical? node ($ js/document :activeElement))
(has-selection-api? ($ node :type))
(string? rendered-value)
(string? dom-value))
;; just set the value, no need to worry about a cursor
(do
($! component :cljsDOMValue rendered-value)
($! node :value rendered-value)
(when (fn? on-write)
(on-write rendered-value)))
;; Setting "value" (below) moves the cursor position to the
;; end which gives the user a jarring experience.
;;
;; But repositioning the cursor within the text, turns out to
;; be quite a challenge because changes in the text can be
;; triggered by various events like:
;; - a validation function rejecting a user inputted char
;; - the user enters a lower case char, but is transformed to
;; upper.
;; - the user selects multiple chars and deletes text
;; - the user pastes in multiple chars, and some of them are
;; rejected by a validator.
;; - the user selects multiple chars and then types in a
;; single new char to repalce them all.
;; Coming up with a sane cursor repositioning strategy hasn't
;; been easy ALTHOUGH in the end, it kinda fell out nicely,
;; and it appears to sanely handle all the cases we could
;; think of.
;; So this is just a warning. The code below is simple
;; enough, but if you are tempted to change it, be aware of
;; all the scenarios you have handle.
(let [node-value ($ node :value)]
(if (not= node-value dom-value)
;; IE has not notified us of the change yet, so check again later
(batch/do-after-render #(input-component-set-value component))
(let [existing-offset-from-end (- (count node-value)
($ node :selectionStart))
new-cursor-offset (- (count rendered-value)
existing-offset-from-end)]
($! component :cljsDOMValue rendered-value)
($! node :value rendered-value)
(when (fn? on-write)
(on-write rendered-value))
($! node :selectionStart new-cursor-offset)
($! node :selectionEnd new-cursor-offset))))))
(defn input-component-set-value [this]
(when ($ this :cljsInputLive)
($! this :cljsInputDirty false)
(let [rendered-value ($ this :cljsRenderedValue)
dom-value ($ this :cljsDOMValue)
node (find-dom-node this)]
node (find-dom-node this) ;; Default to the root node within this component
synthetic-on-update ($ this :cljsSyntheticOnUpdate)]
(when (not= rendered-value dom-value)
(if-not (and (identical? node ($ js/document :activeElement))
(has-selection-api? ($ node :type))
(string? rendered-value)
(string? dom-value))
;; just set the value, no need to worry about a cursor
(do
($! this :cljsDOMValue rendered-value)
($! node :value rendered-value))
;; Setting "value" (below) moves the cursor position to the
;; end which gives the user a jarring experience.
;;
;; But repositioning the cursor within the text, turns out to
;; be quite a challenge because changes in the text can be
;; triggered by various events like:
;; - a validation function rejecting a user inputted char
;; - the user enters a lower case char, but is transformed to
;; upper.
;; - the user selects multiple chars and deletes text
;; - the user pastes in multiple chars, and some of them are
;; rejected by a validator.
;; - the user selects multiple chars and then types in a
;; single new char to repalce them all.
;; Coming up with a sane cursor repositioning strategy hasn't
;; been easy ALTHOUGH in the end, it kinda fell out nicely,
;; and it appears to sanely handle all the cases we could
;; think of.
;; So this is just a warning. The code below is simple
;; enough, but if you are tempted to change it, be aware of
;; all the scenarios you have handle.
(let [node-value ($ node :value)]
(if (not= node-value dom-value)
;; IE has not notified us of the change yet, so check again later
(batch/do-after-render #(input-set-value this))
(let [existing-offset-from-end (- (count node-value)
($ node :selectionStart))
new-cursor-offset (- (count rendered-value)
existing-offset-from-end)]
($! this :cljsDOMValue rendered-value)
($! node :value rendered-value)
($! node :selectionStart new-cursor-offset)
($! node :selectionEnd new-cursor-offset)))))))))
(if (fn? synthetic-on-update)
(synthetic-on-update input-node-set-value node rendered-value dom-value this)
(input-node-set-value node rendered-value dom-value this {}))))))
(defn input-handle-change [this on-change e]
($! this :cljsDOMValue (-> e .-target .-value))
@ -167,29 +189,38 @@
;; wants to keep the value unchanged
(when-not ($ this :cljsInputDirty)
($! this :cljsInputDirty true)
(batch/do-after-render #(input-set-value this)))
(batch/do-after-render #(input-component-set-value this)))
(on-change e))
(defn input-render-setup [this jsprops]
;; Don't rely on React for updating "controlled inputs", since it
;; doesn't play well with async rendering (misses keystrokes).
(when (and (some? jsprops)
(.hasOwnProperty jsprops "onChange")
(.hasOwnProperty jsprops "value"))
(assert find-dom-node
"reagent.dom needs to be loaded for controlled input to work")
(let [v ($ jsprops :value)
value (if (nil? v) "" v)
on-change ($ jsprops :onChange)]
(when-not ($ this :cljsInputLive)
;; set initial value
($! this :cljsInputLive true)
($! this :cljsDOMValue value))
($! this :cljsRenderedValue value)
(js-delete jsprops "value")
(doto jsprops
($! :defaultValue value)
($! :onChange #(input-handle-change this on-change %))))))
(defn input-render-setup
([this jsprops {:keys [synthetic-on-update synthetic-on-change]}]
;; Don't rely on React for updating "controlled inputs", since it
;; doesn't play well with async rendering (misses keystrokes).
(when (and (some? jsprops)
(.hasOwnProperty jsprops "onChange")
(.hasOwnProperty jsprops "value"))
(assert find-dom-node
"reagent.dom needs to be loaded for controlled input to work")
(when synthetic-on-update
;; Pass along any synthetic input setter given
($! this :cljsSyntheticOnUpdate synthetic-on-update))
(let [v ($ jsprops :value)
value (if (nil? v) "" v)
on-change ($ jsprops :onChange)
on-change (if synthetic-on-change
(partial synthetic-on-change on-change)
on-change)]
(when-not ($ this :cljsInputLive)
;; set initial value
($! this :cljsInputLive true)
($! this :cljsDOMValue value))
($! this :cljsRenderedValue value)
(js-delete jsprops "value")
(doto jsprops
($! :defaultValue value)
($! :onChange #(input-handle-change this on-change %))))))
([this jsprops]
(input-render-setup this jsprops {})))
(defn input-unmount [this]
($! this :cljsInputLive nil))
@ -201,11 +232,13 @@
(def reagent-input-class nil)
(def reagent-synthetic-input-class nil)
(declare make-element)
(def input-spec
{:display-name "ReagentInput"
:component-did-update input-set-value
:component-did-update input-component-set-value
:component-will-unmount input-unmount
:reagent-render
(fn [argv comp jsprops first-child]
@ -213,11 +246,31 @@
(input-render-setup this jsprops)
(make-element argv comp jsprops first-child)))})
(defn reagent-input []
(def synthetic-input-spec
;; Same as `input-spec` except it takes another argument for `input-setter`
{:display-name "ReagentSyntheticInput"
:component-did-update input-component-set-value
:component-will-unmount input-unmount
:reagent-render
(fn [on-update on-change argv comp jsprops first-child]
(let [this comp/*current-component*]
(input-render-setup this jsprops {:synthetic-on-update on-update
:synthetic-on-change on-change})
(make-element argv comp jsprops first-child)))})
(defn reagent-input
[]
(when (nil? reagent-input-class)
(set! reagent-input-class (comp/create-class input-spec)))
reagent-input-class)
(defn reagent-synthetic-input
[]
(when (nil? reagent-synthetic-input-class)
(set! reagent-synthetic-input-class (comp/create-class synthetic-input-spec)))
reagent-synthetic-input-class)
;;; Conversion from Hiccup forms
@ -251,13 +304,41 @@
jsprops #js{:argv v}]
(when-some [key (key-from-vec v)]
($! jsprops :key key))
($ util/react createElement c jsprops)))
(react/createElement c jsprops)))
(defn adapt-react-class [c]
(doto (->NativeWrapper)
($! :name c)
($! :id nil)
($! :class nil)))
(defn adapt-react-class
([c {:keys [synthetic-input]}]
(let [on-update (:on-update synthetic-input)
on-change (:on-change synthetic-input)]
(when synthetic-input
(assert (fn? on-update))
(assert (fn? on-change)))
(let [wrapped (doto (->NativeWrapper)
($! :name c)
($! :id nil)
($! :class nil))
wrapped (if synthetic-input
(doto wrapped
($! :syntheticInput true))
wrapped)
wrapped (if synthetic-input
(doto wrapped
($! :syntheticOnChange on-change))
wrapped)
wrapped (if synthetic-input
;; This is a synthetic input component, i.e. it has a complex
;; nesting of elements such that the root node is not necessarily
;; the <input> tag we need to control, and/or it needs to execute
;; custom code when updated values are written so we provide an affordance
;; to configure a setter fn that can choose a different DOM node
;; than the root node if it wants, and can supply a function hooked
;; to value updates so it can maintain its own component state as needed.
(doto wrapped
($! :syntheticOnUpdate on-update))
wrapped)]
wrapped)))
([c]
(adapt-react-class c {})))
(def tag-name-cache #js{})
@ -269,13 +350,24 @@
(declare as-element)
(defn native-element [parsed argv first]
(let [comp ($ parsed :name)]
(let [comp ($ parsed :name)
synthetic-input ($ parsed :syntheticInput)]
(let [props (nth argv first nil)
hasprops (or (nil? props) (map? props))
jsprops (convert-props (if hasprops props) parsed)
first-child (+ first (if hasprops 1 0))]
(if (input-component? comp)
(-> [(reagent-input) argv comp jsprops first-child]
(if (or synthetic-input (input-component? comp))
(-> (if synthetic-input
;; If we are dealing with a synthetic input, use the synthetic-input-spec form:
[(reagent-synthetic-input)
($ parsed :syntheticOnUpdate)
($ parsed :syntheticOnChange)
argv
comp
jsprops
first-child]
;; Else use the regular input-spec form:
[(reagent-input) argv comp jsprops first-child])
(with-meta (meta argv))
as-element)
(let [key (-> (meta argv) get-key)
@ -392,12 +484,12 @@
(defn make-element [argv comp jsprops first-child]
(case (- (count argv) first-child)
;; Optimize cases of zero or one child
0 ($ util/react createElement comp jsprops)
0 (react/createElement comp jsprops)
1 ($ util/react createElement comp jsprops
1 (react/createElement comp jsprops
(as-element (nth argv first-child nil)))
(.apply ($ util/react :createElement) nil
(.apply react/createElement nil
(reduce-kv (fn [a k v]
(when (>= k first-child)
(.push a (as-element v)))

View File

@ -1,22 +1,8 @@
(ns mranderson047.reagent.v0v7v0.reagent.impl.util
(:require [cljsjs.react]
[cljsjs.create-react-class]
[mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg log warn]]
[mranderson047.reagent.v0v7v0.reagent.interop :refer-macros [$ $!]]
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg log warn]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.interop :refer-macros [$ $!]]
[clojure.string :as string]))
(defonce react
(cond (exists? js/React) js/React
(exists? js/require) (or (js/require "react")
(throw (js/Error. "require('react') failed")))
:else (throw (js/Error. "js/React is missing"))))
(defonce create-class
(cond (exists? js/createReactClass) js/createReactClass
(exists? js/require) (or (js/require "create-react-class")
(throw (js/Error. "require('create-react-class') failed")))
:else (throw (js/Error. "js/createReactClass is missing"))))
(def is-client (and (exists? js/window)
(-> js/window ($ :document) nil? not)))

View File

@ -1,4 +1,4 @@
(ns mranderson047.reagent.v0v7v0.reagent.interop
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.interop
(:require [clojure.string :as string :refer [join]]))
(defn- js-call [f args]

View File

@ -0,0 +1,2 @@
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.interop
(:require-macros [mranderson047.reagent.v0v8v0-alpha2.reagent.interop]))

View File

@ -1,15 +1,15 @@
(ns mranderson047.reagent.v0v7v0.reagent.ratom
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.ratom
(:refer-clojure :exclude [run!])
(:require [mranderson047.reagent.v0v7v0.reagent.debug :as d]))
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.debug :as d]))
(defmacro reaction [& body]
`(mranderson047.reagent.v0v7v0.reagent.ratom/make-reaction
`(mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/make-reaction
(fn [] ~@body)))
(defmacro run!
"Runs body immediately, and runs again whenever atoms deferenced in the body change. Body should side effect."
[& body]
`(let [co# (mranderson047.reagent.v0v7v0.reagent.ratom/make-reaction (fn [] ~@body)
`(let [co# (mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/make-reaction (fn [] ~@body)
:auto-run true)]
(deref co#)
co#))
@ -37,14 +37,14 @@
[body nil]))
add-destroy (when destroy
`(let [destroy# ~destroy]
(if (mranderson047.reagent.v0v7v0.reagent.ratom/reactive?)
(if (mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/reactive?)
(when (nil? (.-destroy ~v))
(set! (.-destroy ~v) destroy#))
(destroy#))))
asserting (if *assert* true false)]
`(let [~v (mranderson047.reagent.v0v7v0.reagent.ratom/with-let-values ~k)]
`(let [~v (mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/with-let-values ~k)]
(when ~asserting
(when-some [c# mranderson047.reagent.v0v7v0.reagent.ratom/*ratom-context*]
(when-some [c# mranderson047.reagent.v0v8v0-alpha2.reagent.ratom/*ratom-context*]
(when (== (.-generation ~v) (.-ratomGeneration c#))
(d/error "Warning: The same with-let is being used more "
"than once in the same reactive context."))

View File

@ -1,9 +1,9 @@
(ns mranderson047.reagent.v0v7v0.reagent.ratom
(ns mranderson047.reagent.v0v8v0-alpha2.reagent.ratom
(:refer-clojure :exclude [atom])
(:require-macros [mranderson047.reagent.v0v7v0.reagent.ratom :refer [with-let]])
(:require [mranderson047.reagent.v0v7v0.reagent.impl.util :as util]
[mranderson047.reagent.v0v7v0.reagent.debug :refer-macros [dbg log warn error dev? time]]
[mranderson047.reagent.v0v7v0.reagent.impl.batching :as batch]
(:require-macros [mranderson047.reagent.v0v8v0-alpha2.reagent.ratom :refer [with-let]])
(:require [mranderson047.reagent.v0v8v0-alpha2.reagent.impl.util :as util]
[mranderson047.reagent.v0v8v0-alpha2.reagent.debug :refer-macros [dbg log warn error dev? time]]
[mranderson047.reagent.v0v8v0-alpha2.reagent.impl.batching :as batch]
[clojure.set :as s]))
(declare ^:dynamic *ratom-context*)
@ -146,6 +146,9 @@
(-swap! [a f x y] (-reset! a (f state x y)))
(-swap! [a f x y more] (-reset! a (apply f state x y more)))
IWithMeta
(-with-meta [_ new-meta] (RAtom. state new-meta validator watches))
IMeta
(-meta [_] meta)