From 638d820c84e23be79b8c52f8f136a611d942443f Mon Sep 17 00:00:00 2001 From: andrey Date: Mon, 19 Apr 2021 10:39:47 +0200 Subject: [PATCH] 1.5.0 --- README.md | 14 +- dev/re_frisk/demo.cljs | 3 +- img/feature-watch.png | Bin 0 -> 47248 bytes project.clj | 2 +- public/client/index.html | 4 +- re-frisk/project.clj | 9 +- re-frisk/src/re_frisk/core.cljs | 16 +- re-frisk/src/re_frisk/db.cljs | 2 +- .../reagent/v1v0v0/reagent/core.clj | 10 + .../reagent/v1v0v0/reagent/core.cljs | 374 +++++++++++ .../reagent/v1v0v0/reagent/debug.clj | 97 +++ .../reagent/v1v0v0/reagent/debug.cljs | 27 + .../reagent/v1v0v0/reagent/dom.cljs | 74 ++ .../reagent/v1v0v0/reagent/dom/server.cljs | 24 + .../reagent/v1v0v0/reagent/impl/batching.cljs | 126 ++++ .../v1v0v0/reagent/impl/component.cljs | 497 ++++++++++++++ .../reagent/v1v0v0/reagent/impl/input.cljs | 141 ++++ .../v1v0v0/reagent/impl/protocols.cljs | 7 + .../reagent/v1v0v0/reagent/impl/template.cljs | 313 +++++++++ .../reagent/v1v0v0/reagent/impl/util.cljs | 246 +++++++ .../reagent/v1v0v0/reagent/interop.clj | 20 + .../reagent/v1v0v0/reagent/interop.cljs | 2 + .../reagent/v1v0v0/reagent/ratom.clj | 56 ++ .../reagent/v1v0v0/reagent/ratom.cljs | 632 ++++++++++++++++++ re-frisk/src/re_frisk/subs_graph.cljs | 2 +- re-frisk/src/re_frisk/ui.cljs | 4 +- re-frisk/src/re_frisk/ui/components/drag.cljs | 2 +- .../src/re_frisk/ui/components/frisk.cljs | 81 ++- re-frisk/src/re_frisk/ui/components/recom.clj | 33 + .../src/re_frisk/ui/components/splits.cljs | 46 +- re-frisk/src/re_frisk/ui/events.cljs | 22 +- re-frisk/src/re_frisk/ui/external_hml.cljs | 2 +- re-frisk/src/re_frisk/ui/reagent_views.cljs | 62 +- re-frisk/src/re_frisk/ui/stat.cljs | 2 +- re-frisk/src/re_frisk/ui/subs.cljs | 2 +- re-frisk/src/re_frisk/ui/timeline.cljs | 2 +- re-frisk/src/re_frisk/ui/trace.cljs | 2 +- re-frisk/src/re_frisk/ui/views.cljs | 36 +- resources/public/js/main.js | 496 +++++++------- resources/public/re-frisk.html | 4 +- src/re_frisk_remote/server/client/main.cljs | 4 +- 41 files changed, 3148 insertions(+), 350 deletions(-) create mode 100644 img/feature-watch.png create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.clj create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.clj create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom/server.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/batching.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/component.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/input.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/protocols.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/template.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/util.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.clj create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.cljs create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.clj create mode 100644 re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.cljs create mode 100644 re-frisk/src/re_frisk/ui/components/recom.clj diff --git a/README.md b/README.md index 4147de3..ab54474 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ https://flexsurfer.github.io/conduit-re-frisk-demo/ +### Watching keys from app-db + + + ### Events with app-db difference for each event @@ -48,8 +52,8 @@ Render trace is supported only in the re-frisk-remote ## Usage -`[re-frisk "1.4.0"]` -`[re-frisk-remote "1.4.0"]` +`[re-frisk "1.5.0"]` +`[re-frisk-remote "1.5.0"]` **Important**: Please note the following compatibility table: @@ -66,7 +70,7 @@ re-frisk Version | React Version | Reagent Versions re-frisk will be embedded in the DOM of your application. So my suggestion is to use re-frisk-remote, it doesn't affect your application and has more features -1. Add re-frisk as a dev dependency `[re-frisk "1.4.0"]` +1. Add re-frisk as a dev dependency `[re-frisk "1.5.0"]` 2. Enable re-frisk @@ -83,7 +87,7 @@ re-frisk will be embedded in the DOM of your application. So my suggestion is to [![Clojars](https://img.shields.io/clojars/v/re-frisk-remote.svg)](https://clojars.org/re-frisk-remote) -1. Add re-frisk as a dev dependency `[re-frisk-remote "1.4.0"]` +1. Add re-frisk as a dev dependency `[re-frisk-remote "1.5.0"]` 2. Enable re-frisk on default port (4567): @@ -103,7 +107,7 @@ re-frisk will be embedded in the DOM of your application. So my suggestion is to add in `deps.edn` - `:aliases {:dev {:extra-deps {re-frisk-remote {:mvn/version "1.4.0"}}}}}` + `:aliases {:dev {:extra-deps {re-frisk-remote {:mvn/version "1.5.0"}}}}}` create `re_frisk.clj` diff --git a/dev/re_frisk/demo.cljs b/dev/re_frisk/demo.cljs index 9c82e33..c298412 100644 --- a/dev/re_frisk/demo.cljs +++ b/dev/re_frisk/demo.cljs @@ -27,7 +27,8 @@ :jsobj js/setInterval :time-color "#f88" :clock? true - :form2-text "FORM 2"}) + :form2-text "FORM 2" + :test {:test1 {:test2 {:test3 {:test4 {:test5 "DEMO"}}}}}}) ;; -- Event Handlers ---------------------------------------------------------- diff --git a/img/feature-watch.png b/img/feature-watch.png new file mode 100644 index 0000000000000000000000000000000000000000..be608b41ba6006b6b774eea51e162e150aceb9fa GIT binary patch literal 47248 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 cQ`~o div { display: inline; } - +input { + outline:none; +} diff --git a/re-frisk/project.clj b/re-frisk/project.clj index c38cec7..e296bb4 100644 --- a/re-frisk/project.clj +++ b/re-frisk/project.clj @@ -1,11 +1,16 @@ -(defproject re-frisk "1.4.0" +(defproject re-frisk "1.5.0" :description "Take full control of re-frame app" :url "https://github.com/flexsurfer/re-frisk" :license {:name "MIT" :url "https://opensource.org/licenses/MIT"} :source-paths ["src"] + :plugins [[thomasa/mranderson "0.5.3"]] + :profiles {:mranderson {:mranderson {:project-prefix "re-frisk.inlined-deps"} + :dependencies ^:replace [^:source-dep [reagent "1.0.0" + :exclusions [cljsjs/react + cljsjs/react-dom + cljsjs/react-dom-server]]]}} :dependencies [[org.clojure/clojure "1.10.1"] [org.clojure/clojurescript "1.10.597"] - [reagent "0.10.0"] [re-frame "0.12.0"] [re-com "2.8.0"]]) \ No newline at end of file diff --git a/re-frisk/src/re_frisk/core.cljs b/re-frisk/src/re_frisk/core.cljs index 8d1323c..13c62c8 100644 --- a/re-frisk/src/re_frisk/core.cljs +++ b/re-frisk/src/re_frisk/core.cljs @@ -4,14 +4,15 @@ [re-frisk.db :as data] [re-frisk.ui :as ui] [re-frisk.diff.diff :as diff] - [reagent.core :as reagent] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-frisk.utils :as utils] [re-frame.trace] [re-frisk.trace :as trace] [re-frisk.subs-graph :as subs-graph] [re-frame.interop :as interop] [re-frisk.stat :as stat] - [day8.reagent.impl.batching :refer [patch-next-tick]])) + [day8.reagent.impl.batching :refer [patch-next-tick]] + [day8.reagent.impl.component :refer [patch-wrap-funs]])) (defonce initialized (atom false)) (defonce prev-event (atom {})) @@ -28,9 +29,14 @@ (reset! (:subs re-frame-data) (utils/get-subs)) (reset! (:app-db re-frame-data) @db/app-db)) +(defn update-views [views] + (when (seq views) + (reset! (:views re-frame-data) views))) + (defn trace-cb [traces] (when-not (:paused? @data/tool-state) (let [ignore-events (get-in @data/tool-state [:opts :ignore-events]) + traces (trace/update-views-and-get-traces update-views traces) normalized (trace/normalize-traces traces ignore-events) first-event (or (first @(:events re-frame-data)) (first normalized))] (when (seq normalized) @@ -91,6 +97,10 @@ (gOldOnError error-msg url line-number) false))))) +(defn patch-reagent! [] + (patch-wrap-funs) + (patch-next-tick)) + (defn enable-re-frisk! [& [opts]] (when-not @initialized (reset! initialized true) @@ -98,7 +108,7 @@ #_(register-exception-handler) (if (re-frame.trace/is-trace-enabled?) (do - #_(patch-reagent!) + (patch-reagent!) (re-frame.trace/register-trace-cb :re-frisk-trace trace-cb)) (when-not (= (:events? opts) false) (reset! prev-event {:app-db @db/app-db}) diff --git a/re-frisk/src/re_frisk/db.cljs b/re-frisk/src/re_frisk/db.cljs index fddf30e..3c61df4 100644 --- a/re-frisk/src/re_frisk/db.cljs +++ b/re-frisk/src/re_frisk/db.cljs @@ -1,5 +1,5 @@ (ns re-frisk.db - (:require [reagent.core :as reagent] + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-frame.trace :as trace])) (defonce diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.clj b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.clj new file mode 100644 index 0000000..7c7cb99 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.clj @@ -0,0 +1,10 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.core + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ra])) + +(defmacro with-let + "Bind variables as with let, except that when used in a component + the bindings are only evaluated once. Also takes an optional finally + clause at the end, that is executed when the component is + destroyed." + [bindings & body] + `(ra/with-let ~bindings ~@body)) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.cljs new file mode 100644 index 0000000..96eb8cf --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/core.cljs @@ -0,0 +1,374 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.core + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core]) + (:refer-clojure :exclude [partial atom flush]) + (:require [react :as react] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template :as tmpl] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.component :as comp] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ratom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :as deb :refer-macros [assert-some assert-component + assert-js-object assert-new-state + assert-callable]])) + +(def is-client util/is-client) + +(defn create-element + "Create a native React element, by calling React.createElement directly. + + That means the second argument must be a javascript object (or nil), and + that any Reagent hiccup forms must be processed with as-element. For example + like this: + + ```cljs + (r/create-element \"div\" #js{:className \"foo\"} + \"Hi \" (r/as-element [:strong \"world!\"]) + ``` + + which is equivalent to + + ```cljs + [:div.foo \"Hi\" [:strong \"world!\"]] + ```" + ([type] + (create-element type nil)) + ([type props] + (assert-js-object props) + (react/createElement type props)) + ([type props child] + (assert-js-object props) + (react/createElement type props child)) + ([type props child & children] + (assert-js-object props) + (apply react/createElement type props child children))) + +(defn as-element + "Turns a vector of Hiccup syntax into a React element. Returns form + unchanged if it is not a vector." + ([form] (p/as-element tmpl/default-compiler form)) + ([form compiler] (p/as-element compiler form))) + +(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)) + +(defn reactify-component + "Returns an adapter for a Reagent component, that may be used from + React, for example in JSX. A single argument, props, is passed to + the component, converted to a map." + ([c] (reactify-component c tmpl/default-compiler)) + ([c compiler] + (assert-some c "Component") + (comp/reactify-component c compiler))) + +(defn create-class + "Creates JS class based on provided Clojure map, for example: + + ```cljs + {;; Constructor + :constructor (fn [this props]) + :get-initial-state (fn [this]) + ;; Static methods + :get-derived-state-from-props (fn [props state] partial-state) + :get-derived-state-from-error (fn [error] partial-state) + ;; Methods + :get-snapshot-before-update (fn [this old-argv new-argv] snapshot) + :should-component-update (fn [this old-argv new-argv]) + :component-did-mount (fn [this]) + :component-did-update (fn [this old-argv old-state snapshot]) + :component-will-unmount (fn [this]) + :component-did-catch (fn [this error info]) + :reagent-render (fn [args....]) + ;; Or alternatively: + :render (fn [this]) + ;; Deprecated methods: + :UNSAFE_component-will-receive-props (fn [this new-argv]) + :UNSAFE_component-will-update (fn [this new-argv new-state]) + :UNSAFE_component-will-mount (fn [this])} + ``` + + Everything is optional, except either :reagent-render or :render. + + Map keys should use `React.Component` method names (https://reactjs.org/docs/react-component.html), + and can be provided in snake-case or camelCase. + + State can be initialized using constructor, which matches React.Component class, + or using getInitialState which matches old React createClass function and is + now implemented by Reagent for compatibility. + + State can usually be anything, e.g. Cljs object. But if using getDerivedState + methods, the state has to be plain JS object as React implementation uses + Object.assign to merge partial state into the current state. + + React built-in static methods or properties are automatically defined as statics." + ([spec] + (comp/create-class spec tmpl/default-compiler)) + ([spec compiler] + (comp/create-class spec compiler))) + + +(defn current-component + "Returns the current React component (a.k.a `this`) in a component + function." + [] + comp/*current-component*) + +(defn state-atom + "Returns an atom containing a components state." + [this] + (assert-component this) + (comp/state-atom this)) + +(defn state + "Returns the state of a component, as set with replace-state or set-state. + Equivalent to `(deref (r/state-atom this))`" + [this] + (assert-component this) + (deref (state-atom this))) + +(defn replace-state + "Set state of a component. + Equivalent to `(reset! (state-atom this) new-state)`" + [this new-state] + (assert-component this) + (assert-new-state new-state) + (reset! (state-atom this) new-state)) + +(defn set-state + "Merge component state with new-state. + Equivalent to `(swap! (state-atom this) merge new-state)`" + [this new-state] + (assert-component this) + (assert-new-state new-state) + (swap! (state-atom this) merge new-state)) + +(defn force-update + "Force a component to re-render immediately. + + If the second argument is true, child components will also be + re-rendered, even is their arguments have not changed." + ([this] + (force-update this false)) + ([this deep] + (ratom/flush!) + (util/force-update this deep) + (batch/flush-after-render))) + +(defn props + "Returns the props passed to a component." + [this] + (assert-component this) + (comp/get-props this)) + +(defn children + "Returns the children passed to a component." + [this] + (assert-component this) + (comp/get-children this)) + +(defn argv + "Returns the entire Hiccup form passed to the component." + [this] + (assert-component this) + (comp/get-argv this)) + +(defn class-names + "Function which normalizes and combines class values to a string + + Reagent allows classes to be defined as: + - Strings + - Named objects (Symbols or Keywords) + - Collections of previous types" + ([]) + ([class] (util/class-names class)) + ([class1 class2] (util/class-names class1 class2)) + ([class1 class2 & others] (apply util/class-names class1 class2 others))) + +(defn merge-props + "Utility function that merges some maps, handling `:class` and `:style`. + + The :class value is always normalized (using `class-names`) even if no + merging is done." + ([] (util/merge-props)) + ([defaults] (util/merge-props defaults)) + ([defaults props] (util/merge-props defaults props)) + ([defaults props & others] (apply util/merge-props defaults props others))) + +(defn flush + "Render dirty components immediately. + + Note that this may not work in event handlers, since React.js does + batching of updates there." + [] + (batch/flush)) + +;; Ratom + +(defn atom + "Like clojure.core/atom, except that it keeps track of derefs. + Reagent components that derefs one of these are automatically + re-rendered." + ([x] (ratom/atom x)) + ([x & rest] (apply ratom/atom x rest))) + +(defn track + "Takes a function and optional arguments, and returns a derefable + containing the output of that function. If the function derefs + Reagent atoms (or track, etc), the value will be updated whenever + the atom changes. + + In other words, `@(track foo bar)` will produce the same result + as `(foo bar)`, but foo will only be called again when the atoms it + depends on changes, and will only trigger updates of components when + its result changes. + + track is lazy, i.e the function is only evaluated on deref." + [f & args] + {:pre [(ifn? f)]} + (ratom/make-track f args)) + +(defn track! + "An eager version of track. The function passed is called + immediately, and continues to be called when needed, until stopped + with dispose!." + [f & args] + {:pre [(ifn? f)]} + (ratom/make-track! f args)) + +(defn dispose! + "Stop the result of track! from updating." + [x] + (ratom/dispose! x)) + +(defn wrap + "Provide a combination of value and callback, that looks like an atom. + + The first argument can be any value, that will be returned when the + result is deref'ed. + + The second argument should be a function, that is called with the + optional extra arguments provided to wrap, and the new value of the + resulting 'atom'. + + Use for example like this: + + ```cljs + (wrap (:foo @state) + swap! state assoc :foo) + ``` + + Probably useful only for passing to child components." + [value reset-fn & args] + (assert-callable reset-fn) + (ratom/make-wrapper value reset-fn args)) + + +;; RCursor + +(defn cursor + "Provide a cursor into a Reagent atom. + + Behaves like a Reagent atom but focuses updates and derefs to + the specified path within the wrapped Reagent atom. e.g., + + ```cljs + (let [c (cursor ra [:nested :content])] + ... @c ;; equivalent to (get-in @ra [:nested :content]) + ... (reset! c 42) ;; equivalent to (swap! ra assoc-in [:nested :content] 42) + ... (swap! c inc) ;; equivalence to (swap! ra update-in [:nested :content] inc) + ) + ``` + + The first parameter can also be a function, that should look + something like this: + + ```cljs + (defn set-get + ([k] (get-in @state k)) + ([k v] (swap! state assoc-in k v))) + ``` + + The function will be called with one argument – the path passed to + cursor – when the cursor is deref'ed, and two arguments (path and + new value) when the cursor is modified. + + Given that set-get function, (and that state is a Reagent atom, or + another cursor) these cursors are equivalent: + `(cursor state [:foo])` and `(cursor set-get [:foo])`. + + Note that a cursor is lazy: its value will not change until it is + used. This may be noticed with add-watch." + ([src path] + (ratom/cursor src path))) + + +;; Utilities + +(defn rswap! + "Swaps the value of a to be `(apply f current-value-of-atom args)`. + + rswap! works like swap!, except that recursive calls to rswap! on + the same atom are allowed – and it always returns nil." + [^IAtom a f & args] + {:pre [(satisfies? IAtom a) + (ifn? f)]} + (if (.-rswapping a) + (-> (or (.-rswapfs a) + (set! (.-rswapfs a) (array))) + (.push #(apply f % args))) + (do (set! (.-rswapping a) true) + (try (swap! a (fn [state] + (loop [s (apply f state args)] + (if-some [sf (some-> a .-rswapfs .shift)] + (recur (sf s)) + s)))) + (finally + (set! (.-rswapping a) false))))) + nil) + +(defn next-tick + "Run f using requestAnimationFrame or equivalent. + + f will be called just before components are rendered." + [f] + (batch/do-before-flush f)) + +(defn after-render + "Run f using requestAnimationFrame or equivalent. + + f will be called just after any queued renders in the next animation + frame (and even if no renders actually occur)." + [f] + (batch/do-after-render f)) + +(defn partial + "Works just like clojure.core/partial, but the result can be compared with =" + [f & args] + (util/make-partial-fn f args)) + +(defn create-compiler + "Creates Compiler object with given `opts`, + this can be passed to `render`, `as-element` and other functions to control + how they turn the Reagent-style Hiccup into React components and elements." + [opts] + (tmpl/create-compiler opts)) + +(defn set-default-compiler! + "Globally sets the Compiler object used by `render`, `as-element` and other + calls by default, when no `compiler` parameter is provided. + + Use `nil` value to restore the original default compiler." + [compiler] + (tmpl/set-default-compiler! (if (nil? compiler) + tmpl/default-compiler* + compiler))) + +(defn render + {:deprecated "0.10.0"} + [& _] + (throw (js/Error. "Reagent.core/render function was moved to re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom namespace in Reagent v1.0.")) + nil) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.clj b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.clj new file mode 100644 index 0000000..2a1e1fc --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.clj @@ -0,0 +1,97 @@ +(ns re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug + (:refer-clojure :exclude [prn println time]) + (:require [cljs.analyzer :as analyzer])) + +(defmacro log + "Print with console.log, if it exists." + [& forms] + `(when re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.has-console + (.log js/console ~@forms))) + +(defmacro warn + "Print with console.warn." + [& forms] + (when *assert* + `(when re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.has-console + (.warn (if re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.tracking + re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.track-console js/console) + (str "Warning: " ~@forms))))) + +(defmacro warn-unless + [cond & forms] + (when *assert* + `(when (not ~cond) + (warn ~@forms)))) + +(defmacro error + "Print with console.error." + [& forms] + (when *assert* + `(when re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.has-console + (.error (if re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.tracking + re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug.track-console js/console) + (str ~@forms))))) + +(defmacro println + "Print string with console.log" + [& forms] + `(log (str ~@forms))) + +(defmacro prn + "Like standard prn, but prints using console.log (so that we get +nice clickable links to source in modern browsers)." + [& forms] + `(log (pr-str ~@forms))) + +(defmacro dbg + "Useful debugging macro that prints the source and value of x, +as well as package name and line number. Returns x." + [x] + (let [ns (str analyzer/*cljs-ns*)] + `(let [x# ~x] + (println (str "dbg " + ~ns ":" + ~(:line (meta &form)) + ": " + ~(pr-str x) + ": " + (pr-str x#))) + x#))) + +(defmacro dev? + "True if assertions are enabled." + [] + (if *assert* true false)) + +(defmacro time [& forms] + (let [ns (str analyzer/*cljs-ns*) + label (str ns ":" (:line (meta &form)))] + `(let [label# ~label + res# (do + (js/console.time label#) + ~@forms)] + (js/console.timeEnd label#) + res#))) + +(defmacro assert-some [value tag] + `(assert ~value (str ~tag " must not be nil"))) + +(defmacro assert-component [value] + `(assert (comp/reagent-component? ~value) + (str "Expected a reagent component, not " + (pr-str ~value)))) + +(defmacro assert-js-object [value] + `(assert (not (map? ~value)) + (str "Expected a JS object, not " + (pr-str ~value)))) + +(defmacro assert-new-state [value] + `(assert (or (nil? ~value) (map? ~value)) + (str "Expected a valid new state, not " + (pr-str ~value)))) + +(defmacro assert-callable [value] + `(assert (ifn? ~value) + (str "Expected something callable, not " + (pr-str ~value)))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.cljs new file mode 100644 index 0000000..14bf8a4 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/debug.cljs @@ -0,0 +1,27 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug])) + +(def ^:const has-console (exists? js/console)) + +(def ^boolean tracking false) + +(defonce warnings (atom nil)) + +(defonce track-console + (let [o #js{}] + (set! (.-warn o) + (fn [& args] + (swap! warnings update-in [:warn] conj (apply str args)))) + (set! (.-error o) + (fn [& args] + (swap! warnings update-in [:error] conj (apply str args)))) + o)) + +(defn track-warnings [f] + (set! tracking true) + (reset! warnings nil) + (f) + (let [warns @warnings] + (reset! warnings nil) + (set! tracking false) + warns)) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom.cljs new file mode 100644 index 0000000..74796d6 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom.cljs @@ -0,0 +1,74 @@ +(ns re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom + (:require [react-dom :as react-dom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template :as tmpl] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.input :as input] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ratom])) + +(defonce ^:private roots (atom {})) + +(defn- unmount-comp [container] + (swap! roots dissoc container) + (react-dom/unmountComponentAtNode container)) + +(defn- render-comp [comp container callback] + (binding [util/*always-update* true] + (react-dom/render (comp) container + (fn [] + (binding [util/*always-update* false] + (swap! roots assoc container comp) + (batch/flush-after-render) + (if (some? callback) + (callback))))))) + +(defn- re-render-component [comp container] + (render-comp comp container nil)) + +(defn render + "Render a Reagent component into the DOM. The first argument may be + either a vector (using Reagent's Hiccup syntax), or a React element. + The second argument should be a DOM node. + + Optionally takes a callback that is called when the component is in place. + + Returns the mounted component instance." + ([comp container] + (render comp container tmpl/default-compiler)) + ([comp container callback-or-compiler] + (ratom/flush!) + (let [[compiler callback] (if (fn? callback-or-compiler) + [tmpl/default-compiler callback-or-compiler] + ;; TODO: Callback option doesn't make sense now that + ;; val is compiler object, not map. + [callback-or-compiler (:callback callback-or-compiler)]) + f (fn [] + (p/as-element compiler (if (fn? comp) (comp) comp)))] + (render-comp f container callback)))) + +(defn unmount-component-at-node + "Remove a component from the given DOM node." + [container] + (unmount-comp container)) + +(defn dom-node + "Returns the root DOM node of a mounted component." + [this] + (react-dom/findDOMNode this)) + +(defn force-update-all + "Force re-rendering of all mounted Reagent components. This is + probably only useful in a development environment, when you want to + update components in response to some dynamic changes to code. + + Note that force-update-all may not update root components. This + happens if a component 'foo' is mounted with `(render [foo])` (since + functions are passed by value, and not by reference, in + ClojureScript). To get around this you'll have to introduce a layer + of indirection, for example by using `(render [#'foo])` instead." + [] + (ratom/flush!) + (doseq [[container comp] @roots] + (re-render-component comp container)) + (batch/flush-after-render)) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom/server.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom/server.cljs new file mode 100644 index 0000000..7b78b1a --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/dom/server.cljs @@ -0,0 +1,24 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom.server + (:require ["react-dom/server" :as dom-server] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template :as tmpl] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ratom])) + +(defn render-to-string + "Turns a component into an HTML string." + ([component] + (render-to-string component tmpl/default-compiler)) + ([component compiler] + (ratom/flush!) + (binding [util/*non-reactive* true] + (dom-server/renderToString (p/as-element compiler component))))) + +(defn render-to-static-markup + "Turns a component into an HTML string, without data-react-id attributes, etc." + ([component] + (render-to-static-markup component tmpl/default-compiler)) + ([component compiler] + (ratom/flush!) + (binding [util/*non-reactive* true] + (dom-server/renderToStaticMarkup (p/as-element compiler component))))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/batching.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/batching.cljs new file mode 100644 index 0000000..02a2de0 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/batching.cljs @@ -0,0 +1,126 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching + (:refer-clojure :exclude [flush]) + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :refer-macros [assert-some]] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :refer [is-client]])) + +;;; Update batching +(set! *warn-on-infer* false) + +(defonce mount-count 0) + +(defn next-mount-count [] + (set! mount-count (inc mount-count))) + +(defn fake-raf [f] + (js/setTimeout f 16)) + +(def next-tick + (if-not is-client + fake-raf + (let [w js/window] + (.bind (or (.-requestAnimationFrame w) + (.-webkitRequestAnimationFrame w) + (.-mozRequestAnimationFrame w) + (.-msRequestAnimationFrame w) + fake-raf) + w)))) + +(defn compare-mount-order + [^clj c1 ^clj c2] + (- (.-cljsMountOrder c1) + (.-cljsMountOrder c2))) + +(defn run-queue [a] + ;; sort components by mount order, to make sure parents + ;; are rendered before children + (.sort a compare-mount-order) + (dotimes [i (alength a)] + (let [^js/React.Component c (aget a i)] + (when (true? (.-cljsIsDirty c)) + (.forceUpdate c))))) + + +;; Set from ratom.cljs +(defonce ratom-flush (fn [])) + +(defn run-funs [fs] + (dotimes [i (alength fs)] + ((aget fs i)))) + +(defn enqueue [^clj queue fs f] + (assert-some f "Enqueued function") + (.push fs f) + (.schedule queue)) + +(deftype RenderQueue [^:mutable ^boolean scheduled?] + Object + (schedule [this] + (when-not scheduled? + (set! scheduled? true) + (next-tick #(.run-queues this)))) + + (queue-render [this c] + (when (nil? (.-componentQueue this)) + (set! (.-componentQueue this) (array))) + (enqueue this (.-componentQueue this) c)) + + (add-before-flush [this f] + (when (nil? (.-beforeFlush this)) + (set! (.-beforeFlush this) (array))) + (enqueue this (.-beforeFlush this) f)) + + (add-after-render [this f] + (when (nil? (.-afterRender this)) + (set! (.-afterRender this) (array))) + (enqueue this (.-afterRender this) f)) + + (run-queues [this] + (set! scheduled? false) + (.flush-queues this)) + + (flush-before-flush [this] + (when-some [fs (.-beforeFlush this)] + (set! (.-beforeFlush this) nil) + (run-funs fs))) + + (flush-render [this] + (when-some [fs (.-componentQueue this)] + (set! (.-componentQueue this) nil) + (run-queue fs))) + + (flush-after-render [this] + (when-some [fs (.-afterRender this)] + (set! (.-afterRender this) nil) + (run-funs fs))) + + (flush-queues [this] + (.flush-before-flush this) + (ratom-flush) + (.flush-render this) + (.flush-after-render this))) + +(defonce render-queue (->RenderQueue false)) + +(defn flush [] + (.flush-queues render-queue)) + +(defn flush-after-render [] + (.flush-after-render render-queue)) + +(defn queue-render [^clj c] + (when-not (.-cljsIsDirty c) + (set! (.-cljsIsDirty c) true) + (.queue-render render-queue c))) + +(defn mark-rendered [^clj c] + (set! (.-cljsIsDirty c) false)) + +(defn do-before-flush [f] + (.add-before-flush render-queue f)) + +(defn do-after-render [f] + (.add-after-render render-queue f)) + +(defn schedule [] + (when (false? (.-scheduled? render-queue)) + (.schedule render-queue))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/component.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/component.cljs new file mode 100644 index 0000000..f7b8559 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/component.cljs @@ -0,0 +1,497 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.component + (:require [goog.object :as gobj] + [react :as react] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ratom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :refer-macros [dev? warn error warn-unless assert-callable]])) + +(declare ^:dynamic *current-component*) + + +;;; Argv access + +(defn extract-props [v] + (let [p (nth v 1 nil)] + (if (map? p) p))) + +(defn extract-children [v] + (let [p (nth v 1 nil) + first-child (if (or (nil? p) (map? p)) 2 1)] + (if (> (count v) first-child) + (subvec v first-child)))) + +(defn props-argv [^js/React.Component c p] + (if-some [a (.-argv p)] + a + [(.-constructor c) (util/shallow-obj-to-map p)])) + +(defn get-argv [^js/React.Component c] + (props-argv c (.-props c))) + +(defn get-props [^js/React.Component c] + (let [p (.-props c)] + (if-some [v (.-argv p)] + (extract-props v) + (util/shallow-obj-to-map p)))) + +(defn get-children [^js/React.Component c] + (let [p (.-props c)] + (if-some [v (.-argv p)] + (extract-children v) + (->> (.-children p) + (react/Children.toArray) + (into []))))) + +(defn ^boolean reagent-class? [c] + (and (fn? c) + (some? (some-> c (.-prototype) (.-reagentRender))))) + +(defn ^boolean react-class? [c] + (and (fn? c) + (some? (some-> c (.-prototype) (.-render))))) + +(defn ^boolean reagent-component? [^clj c] + (some? (.-reagentRender c))) + +;;; State + +(defn state-atom [^clj this] + (let [sa (.-cljsState this)] + (if-not (nil? sa) + sa + (set! (.-cljsState this) (ratom/atom nil))))) + +;;; Rendering + +(defn wrap-render + "Calls the render function of the component `c`. If result `res` evaluates to a: + 1) Vector (form-1 component) - Treats the vector as hiccup and returns + a react element with a render function based on that hiccup + 2) Function (form-2 component) - updates the render function to `res` i.e. the internal function + and calls wrap-render again (`recur`), until the render result doesn't evaluate to a function. + 3) Anything else - Returns the result of evaluating `c`" + [^clj c compiler] + (let [f (.-reagentRender c) + _ (assert-callable f) + ;; cljsLegacyRender tells if this calls was defined + ;; using :render instead of :reagent-render + ;; in that case, the :render fn is called with just `this` as argument. + res (if (true? (.-cljsLegacyRender c)) + (.call f c c) + (let [v (get-argv c) + n (count v)] + (case n + 1 (.call f c) + 2 (.call f c (nth v 1)) + 3 (.call f c (nth v 1) (nth v 2)) + 4 (.call f c (nth v 1) (nth v 2) (nth v 3)) + 5 (.call f c (nth v 1) (nth v 2) (nth v 3) (nth v 4)) + (.apply f c (.slice (into-array v) 1)))))] + (cond + (vector? res) (p/as-element compiler res) + (ifn? res) (let [f (if (reagent-class? res) + (fn [& args] + (p/as-element compiler (apply vector res args))) + res)] + (set! (.-reagentRender c) f) + (recur c compiler)) + :else res))) + +(defn component-name [c] + (or (some-> c .-constructor .-displayName) + (some-> c .-constructor .-name))) + +(defn comp-name [] + (if (dev?) + (let [c *current-component* + n (component-name c)] + (if-not (empty? n) + (str " (in " n ")") + "")) + "")) + +(defn do-render [c compiler] + (binding [*current-component* c] + (if (dev?) + ;; Log errors, without using try/catch (and mess up call stack) + (let [ok (array false)] + (try + (let [res (wrap-render c compiler)] + (aset ok 0 true) + res) + (finally + (when-not (aget ok 0) + (error (str "Error rendering component" + (comp-name))))))) + (wrap-render c compiler)))) + + +;;; Method wrapping + +(def rat-opts {:no-cache true}) + +(defn custom-wrapper [key f] + (case key + :getDefaultProps + (throw (js/Error. "getDefaultProps not supported")) + + :getDerivedStateFromProps + (fn getDerivedStateFromProps [props state] + ;; Read props from Reagent argv + (.call f nil (if-some [a (.-argv props)] (extract-props a) props) state)) + + ;; In ES6 React, this is now part of the constructor + :getInitialState + (fn getInitialState [c] + (reset! (state-atom c) (.call f c c))) + + :getSnapshotBeforeUpdate + (fn getSnapshotBeforeUpdate [oldprops oldstate] + (this-as c (.call f c c (props-argv c oldprops) oldstate))) + + ;; Deprecated - warning in 16.9 will work through 17.x + :componentWillReceiveProps + (fn componentWillReceiveProps [nextprops] + (this-as c (.call f c c (props-argv c nextprops)))) + + ;; Deprecated - will work in 17.x + :UNSAFE_componentWillReceiveProps + (fn componentWillReceiveProps [nextprops] + (this-as c (.call f c c (props-argv c nextprops)))) + + :shouldComponentUpdate + (fn shouldComponentUpdate [nextprops nextstate] + (or util/*always-update* + (this-as c + ;; Don't care about nextstate here, we use forceUpdate + ;; when only when state has changed anyway. + (let [old-argv (.. c -props -argv) + new-argv (.-argv nextprops) + noargv (or (nil? old-argv) (nil? new-argv))] + (cond + (nil? f) (or noargv (try (not= old-argv new-argv) + (catch :default e + (warn "Exception thrown while comparing argv's in shouldComponentUpdate: " old-argv " " new-argv " " e) + false))) + noargv (.call f c c (get-argv c) (props-argv c nextprops)) + :else (.call f c c old-argv new-argv)))))) + + ;; Deprecated - warning in 16.9 will work through 17.x + :componentWillUpdate + (fn componentWillUpdate [nextprops nextstate] + (this-as c (.call f c c (props-argv c nextprops) nextstate))) + + ;; Deprecated - will work in 17.x + :UNSAFE_componentWillUpdate + (fn componentWillUpdate [nextprops nextstate] + (this-as c (.call f c c (props-argv c nextprops) nextstate))) + + :componentDidUpdate + (fn componentDidUpdate [oldprops oldstate snapshot] + (this-as c (.call f c c (props-argv c oldprops) oldstate snapshot))) + + ;; Deprecated - warning in 16.9 will work through 17.x + :componentWillMount + (fn componentWillMount [] + (this-as c (.call f c c))) + + ;; Deprecated - will work in 17.x + :UNSAFE_componentWillMount + (fn componentWillMount [] + (this-as c (.call f c c))) + + :componentDidMount + (fn componentDidMount [] + (this-as c (.call f c c))) + + :componentWillUnmount + (fn componentWillUnmount [] + (this-as c + (some-> (gobj/get c "cljsRatom") ratom/dispose!) + (batch/mark-rendered c) + (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] + (let [wrap (custom-wrapper key f)] + (when (and wrap f) + (assert-callable f)) + (or wrap f))) + +;; Though the value is nil here, the wrapper function will be +;; added to class to manage Reagent ratom lifecycle. +(def obligatory {:shouldComponentUpdate nil + :componentWillUnmount nil}) + +(def dash-to-method-name (util/memoize-1 util/dash-to-method-name)) + +(defn camelify-map-keys [fun-map] + (reduce-kv (fn [m k v] + (assoc m (-> k dash-to-method-name keyword) v)) + {} fun-map)) + +(defn add-obligatory [fun-map] + (merge obligatory fun-map)) + +(defn wrap-funs [fmap compiler] + (when (dev?) + (let [renders (select-keys fmap [:render :reagentRender]) + render-fun (-> renders vals first)] + (assert (not (:componentFunction fmap)) ":component-function is no longer supported, use :reagent-render instead.") + (assert (pos? (count renders)) "Missing reagent-render") + (assert (== 1 (count renders)) "Too many render functions supplied") + (assert-callable render-fun))) + (let [render-fun (or (:reagentRender fmap) + (:render fmap)) + legacy-render (nil? (:reagentRender fmap)) + name (or (:displayName fmap) + (util/fun-name render-fun) + (str (gensym "reagent"))) + fmap (reduce-kv (fn [m k v] + (assoc m k (get-wrapper k v))) + {} fmap)] + (assoc fmap + :displayName name + :cljsLegacyRender legacy-render + :reagentRender render-fun + :render (fn render [] + (this-as c (if util/*non-reactive* + (do-render c compiler) + (let [^clj rat (gobj/get c "cljsRatom")] + (batch/mark-rendered c) + (if (nil? rat) + (ratom/run-in-reaction #(do-render c compiler) c "cljsRatom" + batch/queue-render rat-opts) + (._run rat false))))))))) + +(defn map-to-js [m] + (reduce-kv (fn [o k v] + (doto o + (gobj/set (name k) v))) + #js{} m)) + +(defn cljsify [body compiler] + (-> body + camelify-map-keys + add-obligatory + (wrap-funs compiler))) + +;; Idea from: +;; https://gist.github.com/pesterhazy/2a25c82db0519a28e415b40481f84554 +;; https://gist.github.com/thheller/7f530b34de1c44589f4e0671e1ef7533#file-es6-class-cljs-L18 + +(def built-in-static-method-names + [:childContextTypes :contextTypes :contextType + :getDerivedStateFromProps :getDerivedStateFromError]) + +(defn create-class + "Creates JS class based on provided Clojure map. + + Map keys should use `React.Component` method names (https://reactjs.org/docs/react-component.html), + and can be provided in snake-case or camelCase. + Constructor function is defined using key `:getInitialState`. + + React built-in static methods or properties are automatically defined as statics." + [body compiler] + {:pre [(map? body)]} + (let [body (cljsify body compiler) + methods (map-to-js (apply dissoc body :displayName :getInitialState :constructor + :render :reagentRender + built-in-static-method-names)) + static-methods (map-to-js (select-keys body built-in-static-method-names)) + display-name (:displayName body) + get-initial-state (:getInitialState body) + construct (:constructor body) + cmp (fn [props context updater] + (this-as ^clj this + (.call react/Component this props context updater) + (when construct + (construct this props)) + (when get-initial-state + (set! (.-state this) (get-initial-state this))) + (set! (.-cljsMountOrder this) (batch/next-mount-count)) + this))] + + (gobj/extend (.-prototype cmp) (.-prototype react/Component) methods) + + ;; These names SHOULD be mangled by Closure so we can't use goog/extend + + (when (:render body) + (set! (.-render ^js (.-prototype cmp)) (:render body))) + + (when (:reagentRender body) + (set! (.-reagentRender ^clj (.-prototype cmp)) (:reagentRender body))) + + (when (:cljsLegacyRender body) + (set! (.-cljsLegacyRender ^clj (.-prototype cmp)) (:cljsLegacyRender body))) + + (gobj/extend cmp react/Component static-methods) + + (when display-name + (set! (.-displayName cmp) display-name) + (set! (.-cljs$lang$ctorStr cmp) display-name) + (set! (.-cljs$lang$ctorPrWriter cmp) + (fn [this writer opt] + (cljs.core/-write writer display-name)))) + + (set! (.-cljs$lang$type cmp) true) + (set! (.. cmp -prototype -constructor) cmp) + + cmp)) + +;; Cache result to the tag but per compiler ID +;; TODO: Generate cache & get methods to the Object using macro, +;; can generate code calling interop forms. +(defn cached-react-class [compiler ^clj c] + (gobj/get c (p/get-id compiler))) + +(defn cache-react-class [compiler ^clj c constructor] + (gobj/set c (p/get-id compiler) constructor) + constructor) + +(defn fn-to-class [compiler f] + (assert-callable f) + (warn-unless (not (and (react-class? f) + (not (reagent-class? f)))) + "Using native React classes directly in Hiccup forms " + "is not supported. Use create-element or " + "adapt-react-class instead: " (or (util/fun-name f) + f) + (comp-name)) + (if (reagent-class? f) + (cache-react-class compiler f f) + (let [spec (meta f) + withrender (assoc spec :reagent-render f) + res (create-class withrender compiler)] + (cache-react-class compiler f res)))) + +(defn as-class [tag compiler] + (if-some [cached-class (cached-react-class compiler tag)] + cached-class + (fn-to-class compiler tag))) + +(defn reactify-component [comp compiler] + (if (react-class? comp) + comp + (as-class comp compiler))) + +(defn functional-wrap-render + [compiler ^clj c] + (let [f (.-reagentRender c) + _ (assert-callable f) + argv (.-argv c) + res (apply f argv)] + (cond + (vector? res) (p/as-element compiler res) + (ifn? res) (let [f (if (reagent-class? res) + (fn [& args] + (p/as-element compiler (apply vector res args))) + res)] + (set! (.-reagentRender c) f) + (recur compiler c)) + :else res))) + +(defn functional-do-render [compiler c] + (binding [*current-component* c] + (if (dev?) + ;; Log errors, without using try/catch (and mess up call stack) + (let [ok (array false)] + (try + (let [res (functional-wrap-render compiler c)] + (aset ok 0 true) + res) + (finally + (when-not (aget ok 0) + (error (str "Error rendering component" (comp-name))))))) + (functional-wrap-render compiler c)))) + +(defn functional-render [compiler ^clj jsprops] + (if util/*non-reactive* + ;; Non-reactive component needs just the render fn and argv + (functional-do-render compiler jsprops) + (let [argv (.-argv jsprops) + tag (.-reagentRender jsprops) + + ;; Use counter to trigger render manually. + [_ update-count] (react/useState 0) + + ;; This object mimics React Class attributes and methods. + ;; To support form-2 components, even the render fn needs to + ;; be stored as it is created during the first render, + ;; and subsequent renders need to retrieve the created fn. + state-ref (react/useRef) + + _ (when-not (.-current state-ref) + (let [obj #js {}] + (set! (.-forceUpdate obj) (fn [] (update-count inc))) + (set! (.-cljsMountOrder obj) (batch/next-mount-count)) + ;; Use reagentRender name, as that is also used + ;; by class components, and some checks. + ;; reagentRender is replaced with form-2 inner fn, + ;; constructor refers to the original fn. + (set! (.-constructor obj) tag) + (set! (.-reagentRender obj) tag) + + (set! (.-current state-ref) obj))) + + reagent-state (.-current state-ref) + + ;; FIXME: Access cljsRatom using interop forms + rat ^ratom/Reaction (gobj/get reagent-state "cljsRatom")] + + (react/useEffect + (fn mount [] + (fn unmount [] + (some-> (gobj/get reagent-state "cljsRatom") ratom/dispose!))) + ;; Ignore props - only run effect once on mount and unmount + #js []) + + ;; Argv is also stored in the state, + ;; so reaction fn will always see the latest value. + (set! (.-argv reagent-state) argv) + + (batch/mark-rendered reagent-state) + + ;; static-fns :render + (if (nil? rat) + (ratom/run-in-reaction + ;; Mock Class component API + #(functional-do-render compiler reagent-state) + reagent-state + "cljsRatom" + batch/queue-render + rat-opts) + ;; TODO: Consider passing props here, instead of keeping them in state? + (._run rat false))))) + +(defn functional-render-memo-fn + [prev-props next-props] + (let [old-argv (.-argv prev-props) + new-argv (.-argv next-props)] + (and (false? util/*always-update*) + (try + (= old-argv new-argv) + (catch :default e + (warn "Exception thrown while comparing argv's in shouldComponentUpdate: " old-argv " " new-argv " " e) + false))))) + +(defn functional-render-fn + "Create copy of functional-render with displayName set to name of the + original Reagent component." + [compiler tag] + ;; TODO: Could be disabled for optimized builds? + ;; Or not currently - the memo wrap is required. + (or (cached-react-class compiler tag) + (let [f (fn [jsprops] (functional-render compiler jsprops)) + _ (set! (.-displayName f) (util/fun-name tag)) + f (react/memo f functional-render-memo-fn)] + (cache-react-class compiler tag f) + f))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/input.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/input.cljs new file mode 100644 index 0000000..d13a8fe --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/input.cljs @@ -0,0 +1,141 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.input + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.component :as comp] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p])) + +;; +;; The properites 'selectionStart' and 'selectionEnd' only exist on some inputs +;; See: https://html.spec.whatwg.org/multipage/forms.html#do-not-apply +(def these-inputs-have-selection-api #{"text" "textarea" "password" "search" + "tel" "url"}) + +(defn ^boolean has-selection-api? + [input-type] + (contains? these-inputs-have-selection-api input-type)) + +(declare input-component-set-value) + +(defn input-node-set-value + [node rendered-value dom-value ^clj component {:keys [on-write]}] + (if-not (and (identical? node (.-activeElement js/document)) + (has-selection-api? (.-type node)) + (string? rendered-value) + (string? dom-value)) + ;; just set the value, no need to worry about a cursor + (do + (set! (.-cljsDOMValue component) rendered-value) + (set! (.-value node) 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 (.-value node)] + (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) + (.-selectionStart node)) + new-cursor-offset (- (count rendered-value) + existing-offset-from-end)] + (set! (.-cljsDOMValue component) rendered-value) + (set! (.-value node) rendered-value) + (when (fn? on-write) + (on-write rendered-value)) + (set! (.-selectionStart node) new-cursor-offset) + (set! (.-selectionEnd node) new-cursor-offset)))))) + +(defn input-component-set-value [^clj this] + (when (.-cljsInputLive this) + (set! (.-cljsInputDirty this) false) + (let [rendered-value (.-cljsRenderedValue this) + dom-value (.-cljsDOMValue this) + ;; Default to the root node within this component + node (.-inputEl this)] + (when (not= rendered-value dom-value) + (input-node-set-value node rendered-value dom-value this {}))))) + +(defn input-handle-change [^clj this on-change e] + (set! (.-cljsDOMValue this) (-> e .-target .-value)) + ;; Make sure the input is re-rendered, in case on-change + ;; wants to keep the value unchanged + (when-not (.-cljsInputDirty this) + (set! (.-cljsInputDirty this) true) + (batch/do-after-render #(input-component-set-value this))) + (on-change e)) + +(defn input-render-setup + [^clj this ^js 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")) + (let [v (.-value jsprops) + value (if (nil? v) "" v) + on-change (.-onChange jsprops) + original-ref-fn (.-ref jsprops)] + (when-not (.-cljsInputLive this) + ;; set initial value + (set! (.-cljsInputLive this) true) + (set! (.-cljsDOMValue this) value)) + (when-not (.-reagentRefFn this) + (set! (.-reagentRefFn this) + (cond + ;; ref fn + (fn? original-ref-fn) + (fn [el] + (set! (.-inputEl this) el) + (original-ref-fn el)) + + ;; react/createRef object + (and original-ref-fn (.hasOwnProperty original-ref-fn "current")) + (fn [el] + (set! (.-inputEl this) el) + (set! (.-current original-ref-fn) el)) + + :else + (fn [el] + (set! (.-inputEl this) el))))) + (set! (.-cljsRenderedValue this) value) + (js-delete jsprops "value") + (set! (.-defaultValue jsprops) value) + (set! (.-onChange jsprops) #(input-handle-change this on-change %)) + (set! (.-ref jsprops) (.-reagentRefFn this))))) + +(defn input-unmount [^clj this] + (set! (.-cljsInputLive this) nil)) + +(defn ^boolean input-component? [x] + (case x + ("input" "textarea") true + false)) + +(def input-spec + {:display-name "ReagentInput" + :component-did-update input-component-set-value + :component-will-unmount input-unmount + :reagent-render + (fn [argv component jsprops first-child compiler] + (let [this comp/*current-component*] + (input-render-setup this jsprops) + (p/make-element compiler argv component jsprops first-child)))}) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/protocols.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/protocols.cljs new file mode 100644 index 0000000..361758d --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/protocols.cljs @@ -0,0 +1,7 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols) + +(defprotocol Compiler + (get-id [this]) + (as-element [this x]) + (make-element [this argv component jsprops first-child])) + diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/template.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/template.cljs new file mode 100644 index 0000000..ecb8509 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/template.cljs @@ -0,0 +1,313 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template + (:require [react :as react] + [clojure.string :as string] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util :refer [named?]] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.component :as comp] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.input :as input] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.protocols :as p] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :as ratom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :refer-macros [dev? warn]] + [goog.object :as gobj])) + +;; From Weavejester's Hiccup, via pump: +(def ^{:doc "Regular expression that parses a CSS-style id and class + from a tag name."} + re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?") + +(deftype NativeWrapper [tag id className]) + +(defn adapt-react-class + [c] + (->NativeWrapper c nil nil)) + +;;; Common utilities + +(defn ^boolean hiccup-tag? [x] + (or (named? x) + (string? x))) + +(defn ^boolean valid-tag? [x] + (or (hiccup-tag? x) + (ifn? x) + (instance? NativeWrapper x))) + +;;; Props conversion + +;; TODO: Move prop-name caches to the compiler object, if this +;; conversion can be configured. + +(def prop-name-cache #js{:class "className" + :for "htmlFor" + :charset "charSet"}) + +(defn cache-get [o k] + (when ^boolean (.hasOwnProperty o k) + (gobj/get o k))) + +(defn cached-prop-name [k] + (if (named? k) + (if-some [k' (cache-get prop-name-cache (name k))] + k' + (let [v (util/dash-to-prop-name k)] + (gobj/set prop-name-cache (name k) v) + v)) + k)) + +(declare convert-prop-value) + +(defn kv-conv [o k v] + (doto o + (gobj/set (cached-prop-name k) (convert-prop-value v)))) + +(defn convert-prop-value [x] + (cond (util/js-val? x) x + (named? x) (name x) + (map? x) (reduce-kv kv-conv #js{} x) + (coll? x) (clj->js x) + (ifn? x) (fn [& args] + (apply x args)) + :else (clj->js x))) + +;; Previous few functions copied for custom elements, +;; without mapping from class to className etc. + +(def custom-prop-name-cache #js{}) + +(defn cached-custom-prop-name [k] + (if (named? k) + (if-some [k' (cache-get custom-prop-name-cache (name k))] + k' + (let [v (util/dash-to-prop-name k)] + (gobj/set custom-prop-name-cache (name k) v) + v)) + k)) + +(defn custom-kv-conv [o k v] + (doto o + (gobj/set (cached-custom-prop-name k) (convert-prop-value v)))) + +(defn convert-custom-prop-value [x] + (cond (util/js-val? x) x + (named? x) (name x) + (map? x) (reduce-kv custom-kv-conv #js{} x) + (coll? x) (clj->js x) + (ifn? x) (fn [& args] + (apply x args)) + :else (clj->js x))) + +(defn set-id-class + "Takes the id and class from tag keyword, and adds them to the + other props. Parsed tag is JS object with :id and :class properties." + [props id-class] + (let [id (.-id id-class) + class (.-className id-class)] + (cond-> props + ;; Only use ID from tag keyword if no :id in props already + (and (some? id) + (nil? (:id props))) + (assoc :id id) + + ;; Merge classes + class + ;; Note: someone might use React-style :className property, + ;; this is the only place where that needs special case. Using + ;; :class and :className together is not supported. + (assoc :class (util/class-names class (or (:class props) (:className props))))))) + +(defn convert-props [props ^clj id-class] + (let [class (:class props) + props (-> props + (cond-> class (assoc :class (util/class-names class))) + (set-id-class id-class))] + (if (.-custom id-class) + (convert-custom-prop-value props) + (convert-prop-value props)))) + +;;; Conversion from Hiccup forms + +(defn make-element [this argv component jsprops first-child] + (case (- (count argv) first-child) + ;; Optimize cases of zero or one child + 0 (react/createElement component jsprops) + + 1 (react/createElement component jsprops + (p/as-element this (nth argv first-child nil))) + + (.apply react/createElement nil + (reduce-kv (fn [a k v] + (when (>= k first-child) + (.push a (p/as-element this v))) + a) + #js [component jsprops] argv)))) + +(deftype HiccupTag [tag id className custom]) + +(defn parse-tag [hiccup-tag] + (let [[tag id className] (->> hiccup-tag name (re-matches re-tag) next) + className (when-not (nil? className) + (string/replace className #"\." " "))] + (assert tag (str "Invalid tag: '" hiccup-tag "'" (comp/comp-name))) + (->HiccupTag tag + id + className + ;; Custom element names must contain hyphen + ;; https://www.w3.org/TR/custom-elements/#custom-elements-core-concepts + (not= -1 (.indexOf tag "-"))))) + +(defn reag-element [tag v compiler] + (let [c (comp/as-class tag compiler) + jsprops #js {}] + (set! (.-argv jsprops) v) + (when-some [key (util/react-key-from-vec v)] + (set! (.-key jsprops) key)) + (react/createElement c jsprops))) + +(defn function-element [tag v first-arg compiler] + (let [jsprops #js {}] + (set! (.-reagentRender jsprops) tag) + (set! (.-argv jsprops) (subvec v first-arg)) + ; (set! (.-opts jsprops) opts) + (when-some [key (util/react-key-from-vec v)] + (set! (.-key jsprops) key)) + (react/createElement (comp/functional-render-fn compiler tag) jsprops))) + +(defn maybe-function-element + "If given tag is a Class, use it as a class, + else wrap in Reagent function wrapper." + [tag v compiler] + (if (comp/react-class? tag) + (reag-element tag v compiler) + (function-element tag v 1 compiler))) + +(defn fragment-element [argv compiler] + (let [props (nth argv 1 nil) + hasprops (or (nil? props) (map? props)) + jsprops (or (convert-prop-value (if hasprops props)) + #js {}) + first-child (+ 1 (if hasprops 1 0))] + (when-some [key (util/react-key-from-vec argv)] + (set! (.-key jsprops) key)) + (p/make-element compiler argv react/Fragment jsprops first-child))) + +(def tag-name-cache #js {}) + +(defn cached-parse [x] + (if-some [s (cache-get tag-name-cache x)] + s + (let [v (parse-tag x)] + (gobj/set tag-name-cache x v) + v))) + +(defn native-element [parsed argv first ^p/Compiler compiler] + (let [component (.-tag parsed) + props (nth argv first nil) + hasprops (or (nil? props) (map? props)) + jsprops (or (convert-props (if hasprops props) parsed) + #js {}) + first-child (+ first (if hasprops 1 0))] + (if (input/input-component? component) + (let [input-class (or (.-reagentInput compiler) + (let [x (comp/create-class input/input-spec compiler)] + (set! (.-reagentInput compiler) x) + x))] + (-> [input-class argv component jsprops first-child compiler] + (with-meta (meta argv)) + (->> (p/as-element compiler)))) + (do + (when-some [key (-> (meta argv) util/get-react-key)] + (set! (.-key jsprops) key)) + (p/make-element compiler argv component jsprops first-child))))) + +(defn raw-element [comp argv compiler] + (let [props (nth argv 2 nil) + jsprops (or props #js {})] + (when-some [key (-> (meta argv) util/get-react-key)] + (set! (.-key jsprops) key)) + (p/make-element compiler argv comp jsprops 3))) + +(defn expand-seq [s compiler] + (into-array (map #(p/as-element compiler %) s))) + +(defn expand-seq-dev [s ^clj o compiler] + (into-array (map (fn [val] + (when (and (vector? val) + (nil? (util/react-key-from-vec val))) + (set! (.-no-key o) true)) + (p/as-element compiler val)) + s))) + +(defn expand-seq-check [x compiler] + (let [ctx #js {} + [res derefed] (ratom/check-derefs #(expand-seq-dev x ctx compiler))] + (when derefed + (warn (util/hiccup-err x (comp/comp-name) "Reactive deref not supported in lazy seq, " + "it should be wrapped in doall"))) + (when (.-no-key ctx) + (warn (util/hiccup-err x (comp/comp-name) "Every element in a seq should have a unique :key"))) + res)) + +(defn hiccup-element [v compiler] + (let [tag (nth v 0 nil) + n (name tag) + pos (.indexOf n ">")] + (case pos + -1 (native-element (cached-parse n) v 1 compiler) + 0 (assert (= ">" n) (util/hiccup-err v (comp/comp-name) "Invalid Hiccup tag")) + ;; Support extended hiccup syntax, i.e :div.bar>a.foo + ;; Apply metadata (e.g. :key) to the outermost element. + ;; Metadata is probably used only with sequeneces, and in that case + ;; only the key of the outermost element matters. + (recur (with-meta [(subs n 0 pos) + (assoc (with-meta v nil) 0 (subs n (inc pos)))] + (meta v)) + compiler)))) + +(defn vec-to-elem [v compiler fn-to-element] + (when (nil? compiler) + (js/console.error "vec-to-elem" (pr-str v))) + (assert (pos? (count v)) (util/hiccup-err v (comp/comp-name) "Hiccup form should not be empty")) + (let [tag (nth v 0 nil)] + (assert (valid-tag? tag) (util/hiccup-err v (comp/comp-name) "Invalid Hiccup form")) + (case tag + :> (native-element (->HiccupTag (nth v 1 nil) nil nil nil) v 2 compiler) + :r> (raw-element (nth v 1 nil) v compiler) + :f> (function-element (nth v 1 nil) v 2 compiler) + :<> (fragment-element v compiler) + (cond + (hiccup-tag? tag) + (hiccup-element v compiler) + + (instance? NativeWrapper tag) + (native-element tag v 1 compiler) + + :else (fn-to-element tag v compiler))))) + +(defn as-element [this x fn-to-element] + (cond (util/js-val? x) x + (vector? x) (vec-to-elem x this fn-to-element) + (seq? x) (if (dev?) + (expand-seq-check x this) + (expand-seq x this)) + (named? x) (name x) + (satisfies? IPrintWithWriter x) (pr-str x) + :else x)) + +(defn create-compiler [opts] + (let [id (gensym) + fn-to-element (if (:function-components opts) + maybe-function-element + reag-element)] + (reify p/Compiler + ;; This is used to as cache key to cache component fns per compiler + (get-id [this] id) + (as-element [this x] + (as-element this x fn-to-element)) + (make-element [this argv component jsprops first-child] + (make-element this argv component jsprops first-child))))) + +(def default-compiler* (create-compiler {})) +(def ^:dynamic default-compiler default-compiler*) + +(defn set-default-compiler! [compiler] + (set! default-compiler compiler)) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/util.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/util.cljs new file mode 100644 index 0000000..8c54ff1 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/impl/util.cljs @@ -0,0 +1,246 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util + (:require [clojure.string :as string] + [clojure.walk :refer [prewalk]] + [goog.object :as gobj] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :refer-macros [dev?]])) + +(def is-client (and (exists? js/window) + (-> (.-document js/window) nil? not))) + +(def ^:dynamic ^boolean *non-reactive* false) + +;;; Props accessors + +;; Misc utilities + +(defn memoize-1 [f] + (let [mem (atom {})] + (fn [arg] + (let [v (get @mem arg)] + (if-not (nil? v) + v + (let [ret (f arg)] + (swap! mem assoc arg ret) + ret)))))) + +(def dont-camel-case #{"aria" "data"}) + +(defn capitalize [s] + (if (< (count s) 2) + (string/upper-case s) + (str (string/upper-case (subs s 0 1)) (subs s 1)))) + +(defn dash-to-prop-name [dashed] + (if (string? dashed) + dashed + (let [name-str (name dashed) + [start & parts] (string/split name-str #"-")] + (if (dont-camel-case start) + name-str + (apply str start (map capitalize parts)))))) + +(defn dash-to-method-name [dashed] + (if (string? dashed) + dashed + (let [name-str (name dashed) + name-str (string/replace name-str #"(unsafe|UNSAFE)[-_]" "UNSAFE_") + [start & parts] (string/split name-str #"-")] + (apply str start (map capitalize parts))))) + +(defn fun-name [f] + (let [n (or (and (fn? f) + (or (.-displayName f) + (let [n (.-name f)] + (if (and (string? n) (seq n)) + n)))) + (and (implements? INamed f) + (name f)) + (let [m (meta f)] + (if (map? m) + (:name m))))] + (if n + (string/replace (str n) "$" ".")))) + +(deftype PartialFn [pfn f args] + Fn + IFn + (-invoke [_] + (pfn)) + (-invoke [_ a] + (pfn a)) + (-invoke [_ a b] + (pfn a b)) + (-invoke [_ a b c] + (pfn a b c)) + (-invoke [_ a b c d] + (pfn a b c d)) + (-invoke [_ a b c d e] + (pfn a b c d e)) + (-invoke [_ a b c d e f] + (pfn a b c d e f)) + (-invoke [_ a b c d e f g] + (pfn a b c d e f g)) + (-invoke [_ a b c d e f g h] + (pfn a b c d e f g h)) + (-invoke [_ a b c d e f g h i] + (pfn a b c d e f g h i)) + (-invoke [_ a b c d e f g h i j] + (pfn a b c d e f g h i j)) + (-invoke [_ a b c d e f g h i j k] + (pfn a b c d e f g h i j k)) + (-invoke [_ a b c d e f g h i j k l] + (pfn a b c d e f g h i j k l)) + (-invoke [_ a b c d e f g h i j k l m] + (pfn a b c d e f g h i j k l m)) + (-invoke [_ a b c d e f g h i j k l m n] + (pfn a b c d e f g h i j k l m n)) + (-invoke [_ a b c d e f g h i j k l m n o] + (pfn a b c d e f g h i j k l m n o)) + (-invoke [_ a b c d e f g h i j k l m n o p] + (pfn a b c d e f g h i j k l m n o p)) + (-invoke [_ a b c d e f g h i j k l m n o p q] + (pfn a b c d e f g h i j k l m n o p q)) + (-invoke [_ a b c d e f g h i j k l m n o p q r] + (pfn a b c d e f g h i j k l m n o p q r)) + (-invoke [_ a b c d e f g h i j k l m n o p q r s] + (pfn a b c d e f g h i j k l m n o p q r s)) + (-invoke [_ a b c d e f g h i j k l m n o p q r s t] + (pfn a b c d e f g h i j k l m n o p q r s t)) + (-invoke [_ a b c d e f g h i j k l m n o p q r s t rest] + (apply pfn a b c d e f g h i j k l m n o p q r s t rest)) + IEquiv + (-equiv [_ ^clj other] + (and (instance? PartialFn other) + (= f (.-f other)) + (= args (.-args other)))) + IHash + (-hash [_] (hash [f args]))) + +(defn make-partial-fn [f args] + (->PartialFn (apply partial f args) f args)) + +(defn ^boolean named? [x] + (or (keyword? x) + (symbol? x))) + +(defn class-names + ([]) + ([class] + (if (coll? class) + (let [classes (keep (fn [c] + (if c + (if (named? c) + (name c) + c))) + class)] + (if (seq classes) + (string/join " " classes))) + (if (named? class) + (name class) + class))) + ([a b] + (if a + (if b + (str (class-names a) " " (class-names b)) + (class-names a)) + (class-names b))) + ([a b & rst] + (reduce class-names + (class-names a b) + rst))) + +(defn- merge-class [p1 p2] + (if (or (contains? p1 :class) (contains? p2 :class)) + (assoc p2 :class (class-names (:class p1) (:class p2))) + p2)) + +(defn- merge-style [p1 p2] + (let [style (when-let [s1 (:style p1)] + (when-let [s2 (:style p2)] + (merge s1 s2)))] + (if (nil? style) + p2 + (assoc p2 :style style)))) + +(defn merge-props + ([] nil) + ;; Normalize :class even if there are no merging + ([p] + (if-let [c (:class p)] + (assoc p :class (class-names c)) + p)) + ([p1 p2] + (if (nil? p1) + (if-let [c (:class p2)] + (assoc p2 :class (class-names c)) + p2) + (do + (assert (map? p1) + (str "Property must be a map, not " (pr-str p1))) + (merge p1 (merge-style p1 (merge-class p1 p2)))))) + ([p1 p2 & ps] + (reduce merge-props (merge-props p1 p2) ps))) + +;; TODO: Doesn't look like correct place for this +(def ^:dynamic *always-update* false) + +(defn force-update [^js/React.Component comp deep] + (if deep + (binding [*always-update* true] + (.forceUpdate comp)) + (.forceUpdate comp))) + +(defn shallow-obj-to-map [o] + (let [ks (js-keys o) + len (alength ks)] + (loop [m {} + i 0] + (if (< i len) + (let [k (aget ks i)] + (recur (assoc m (keyword k) (gobj/get o k)) + (inc i))) + m)))) + +(defn ^boolean js-val? [x] + (not (identical? "object" (goog/typeOf x)))) + +;; React key + +(defn try-get-react-key [x] + ;; try catch to avoid clojurescript peculiarity with + ;; sorted-maps with keys that are numbers + (try (get x :key) + (catch :default e))) + +(defn get-react-key [x] + (when (map? x) + (try-get-react-key x))) + +(defn react-key-from-vec [v] + ;; Meta is a map always and is safe to read + (or (:key (meta v)) + (get-react-key (nth v 1 nil)) + ;; :> is a special case because properties map is the first + ;; element of the vector. + ;; TODO: Instead of checking all places for the props, select correct + ;; prosp value before this is called. + (case (nth v 0 nil) + (:> :f>) (get-react-key (nth v 2 nil)) + :r> (some-> (nth v 2 nil) (.-key)) + nil))) + +;; Error messages + +(defn- str-coll [coll] + (if (dev?) + (str (prewalk (fn [x] + (if (fn? x) + (let [n (fun-name x)] + (case n + ("" nil) x + (symbol n))) + x)) coll)) + (str coll))) + +(defn hiccup-err [v comp-name & msg] + (str (apply str msg) ": " (str-coll v) "\n" comp-name)) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.clj b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.clj new file mode 100644 index 0000000..08c343f --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.clj @@ -0,0 +1,20 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.interop) + +; taken from cljs.core +; https://github.com/binaryage/cljs-oops/issues/14 +(defmacro unchecked-aget + ([array idx] + (list 'js* "(~{}[~{}])" array idx)) + ([array idx & idxs] + (let [astr (apply str (repeat (count idxs) "[~{}]"))] + `(~'js* ~(str "(~{}[~{}]" astr ")") ~array ~idx ~@idxs)))) + +; taken from cljs.core +; https://github.com/binaryage/cljs-oops/issues/14 +(defmacro unchecked-aset + ([array idx val] + (list 'js* "(~{}[~{}] = ~{})" array idx val)) + ([array idx idx2 & idxv] + (let [n (dec (count idxv)) + astr (apply str (repeat n "[~{}]"))] + `(~'js* ~(str "(~{}[~{}][~{}]" astr " = ~{})") ~array ~idx ~idx2 ~@idxv)))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.cljs new file mode 100644 index 0000000..dd991ba --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/interop.cljs @@ -0,0 +1,2 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.interop + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.interop])) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.clj b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.clj new file mode 100644 index 0000000..4701472 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.clj @@ -0,0 +1,56 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom + (:refer-clojure :exclude [run!]) + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :as d] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.interop :as interop])) + +(defmacro reaction [& body] + `(re-frisk.inlined-deps.reagent.v1v0v0.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# (re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom/make-reaction (fn [] ~@body) + :auto-run true)] + (deref co#) + co#)) + +(defmacro with-let [bindings & body] + (assert (vector? bindings) + (str "with-let bindings must be a vector, not " + (pr-str bindings))) + (let [v (gensym "with-let") + k (keyword v) + init (gensym "init") + bs (into [init `(zero? (alength ~v))] + (map-indexed (fn [i x] + (if (even? i) + x + (let [j (quot i 2)] + `(if ~init + (interop/unchecked-aset ~v ~j ~x) + (interop/unchecked-aget ~v ~j))))) + bindings)) + [forms destroy] (let [fin (last body)] + (if (and (list? fin) + (= 'finally (first fin))) + [(butlast body) `(fn [] ~@(rest fin))] + [body nil])) + add-destroy (when destroy + `(let [destroy# ~destroy] + (if (re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom/reactive?) + (when (nil? (.-destroy ~v)) + (set! (.-destroy ~v) destroy#)) + (destroy#)))) + asserting (if *assert* true false)] + `(let [~v (re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom/with-let-values ~k)] + (when ~asserting + (when-some [^clj c# re-frisk.inlined-deps.reagent.v1v0v0.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.")) + (set! (.-generation ~v) (.-ratomGeneration c#)))) + (let ~bs + (let [res# (do ~@forms)] + ~add-destroy + res#))))) diff --git a/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.cljs b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.cljs new file mode 100644 index 0000000..62cc847 --- /dev/null +++ b/re-frisk/src/re_frisk/inlined_deps/reagent/v1v0v0/reagent/ratom.cljs @@ -0,0 +1,632 @@ +(ns ^{:mranderson/inlined true} re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom + (:refer-clojure :exclude [atom]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom]) + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.util :as util] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.debug :refer-macros [warn dev?]] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.batching :as batch] + [clojure.set :as s] + [goog.object :as obj])) + +(set! *warn-on-infer* false) + +(declare flush!) + +(declare ^:dynamic *ratom-context*) +(defonce ^boolean debug false) +(defonce ^:private generation 0) +(defonce ^:private -running (clojure.core/atom 0)) + +(defn ^boolean reactive? [] + (some? *ratom-context*)) + + +;;; Utilities + +(defn running [] + (+ @-running)) + +(defn- ^number arr-len [x] + (if (nil? x) 0 (alength x))) + +(defn- ^boolean arr-eq [x y] + (let [len (arr-len x)] + (and (== len (arr-len y)) + (loop [i 0] + (or (== i len) + (if (identical? (aget x i) (aget y i)) + (recur (inc i)) + false)))))) + +(defn- in-context + "When f is executed, if (f) derefs any ratoms, they are then added to 'obj.captured'(*ratom-context*). + + See function notify-deref-watcher! to know how *ratom-context* is updated" + [obj f] + (binding [*ratom-context* obj] + (f))) + +(defn- deref-capture + "Returns `(in-context f r)`. Calls `_update-watching` on r with any + `deref`ed atoms captured during `in-context`, if any differ from the + `watching` field of r. Clears the `dirty?` flag on r. + + Inside '_update-watching' along with adding the ratoms in 'r.watching' of reaction, + the reaction is also added to the list of watches on each ratoms f derefs." + [f ^clj r] + (set! (.-captured r) nil) + (when (dev?) + (set! (.-ratomGeneration r) (set! generation (inc generation)))) + (let [res (in-context r f) + c (.-captured r)] + (set! (.-dirty? r) false) + ;; Optimize common case where derefs occur in same order + (when-not (arr-eq c (.-watching r)) + (._update-watching r c)) + res)) + +(defn- notify-deref-watcher! + "Add `derefed` to the `captured` field of `*ratom-context*`. + + See also `in-context`" + [derefed] + (when-some [^clj r *ratom-context*] + (let [c (.-captured r)] + (if (nil? c) + (set! (.-captured r) (array derefed)) + (.push c derefed))))) + +(defn- check-watches [old new] + (when debug + (swap! -running + (- (count new) (count old)))) + new) + +(defn- add-w [^clj this key f] + (let [w (.-watches this)] + (set! (.-watches this) (check-watches w (assoc w key f))) + (set! (.-watchesArr this) nil))) + +(defn- remove-w [^clj this key] + (let [w (.-watches this)] + (set! (.-watches this) (check-watches w (dissoc w key))) + (set! (.-watchesArr this) nil))) + +(defn- notify-w [^clj this old new] + (let [w (.-watchesArr this) + a (if (nil? w) + ;; Copy watches to array for speed + (->> (.-watches this) + (reduce-kv #(doto %1 (.push %2) (.push %3)) #js[]) + (set! (.-watchesArr this))) + w) + len (alength a)] + (loop [i 0] + (when (< i len) + (let [k (aget a i) + f (aget a (inc i))] + (f k this old new)) + (recur (+ 2 i)))))) + +(defn- pr-atom [a writer opts s v] + (-write writer (str "#object[re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom." s " ")) + (pr-writer (binding [*ratom-context* nil] v) writer opts) + (-write writer "]")) + + +;;; Queueing + +(defonce ^:private rea-queue nil) + +(defn- rea-enqueue [r] + (when (nil? rea-queue) + (set! rea-queue (array)) + (batch/schedule)) + (.push rea-queue r)) + +;;; Atom + +(defprotocol IReactiveAtom) + +(deftype RAtom [^:mutable state meta validator ^:mutable watches] + IAtom + IReactiveAtom + + IEquiv + (-equiv [o other] (identical? o other)) + + IDeref + (-deref [this] + (notify-deref-watcher! this) + state) + + IReset + (-reset! [a new-value] + (when-not (nil? validator) + (assert (validator new-value) "Validator rejected reference state")) + (let [old-value state] + (set! state new-value) + (when-not (nil? watches) + (notify-w a old-value new-value)) + new-value)) + + ISwap + (-swap! [a f] (-reset! a (f state))) + (-swap! [a f x] (-reset! a (f state x))) + (-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) + + IPrintWithWriter + (-pr-writer [a w opts] (pr-atom a w opts "RAtom" {:val (-deref a)})) + + IWatchable + (-notify-watches [this old new] (notify-w this old new)) + (-add-watch [this key f] (add-w this key f)) + (-remove-watch [this key] (remove-w this key)) + + IHash + (-hash [this] (goog/getUid this))) + +(defn atom + "Like clojure.core/atom, except that it keeps track of derefs." + ([x] (->RAtom x nil nil nil)) + ([x & {:keys [meta validator]}] (->RAtom x meta validator nil))) + + +;;; track + +(declare make-reaction) + +(defn- cached-reaction [f ^clj o k ^clj obj destroy] + (let [m (.-reagReactionCache o) + m (if (nil? m) {} m) + r (m k nil)] + (cond + (some? r) (-deref r) + (nil? *ratom-context*) (f) + :else (let [r (make-reaction + f :on-dispose (fn [x] + (when debug (swap! -running dec)) + (as-> (.-reagReactionCache o) _ + (dissoc _ k) + (set! (.-reagReactionCache o) _)) + (when (some? obj) + (set! (.-reaction obj) nil)) + (when (some? destroy) + (destroy x)))) + v (-deref r)] + (set! (.-reagReactionCache o) (assoc m k r)) + (when debug (swap! -running inc)) + (when (some? obj) + (set! (.-reaction obj) r)) + v)))) + +(deftype Track [f args ^:mutable reaction] + IReactiveAtom + + IDeref + (-deref [this] + (if-some [r reaction] + (-deref r) + (cached-reaction #(apply f args) f args this nil))) + + IEquiv + (-equiv [_ ^clj other] + (and (instance? Track other) + (= f (.-f other)) + (= args (.-args other)))) + + IHash + (-hash [_] (hash [f args])) + + IPrintWithWriter + (-pr-writer [a w opts] (pr-atom a w opts "Track" {:val (-deref a) + :f f}))) + +(defn make-track [f args] + (Track. f args nil)) + +(defn make-track! [f args] + (let [t (make-track f args) + r (make-reaction #(-deref t) + :auto-run true)] + @r + r)) + +(defn track [f & args] + {:pre [(ifn? f)]} + (make-track f args)) + +(defn track! [f & args] + {:pre [(ifn? f)]} + (make-track! f args)) + +;;; cursor + +(deftype RCursor [ratom path ^:mutable reaction + ^:mutable state ^:mutable watches] + IAtom + IReactiveAtom + + IEquiv + (-equiv [_ ^clj other] + (and (instance? RCursor other) + (= path (.-path other)) + (= ratom (.-ratom other)))) + + Object + (_peek [this] + (binding [*ratom-context* nil] + (-deref this))) + + (_set-state [this oldstate newstate] + (when-not (identical? oldstate newstate) + (set! state newstate) + (when (some? watches) + (notify-w this oldstate newstate)))) + + IDeref + (-deref [this] + (let [oldstate state + newstate (if-some [r reaction] + (-deref r) + (let [f (if (satisfies? IDeref ratom) + #(get-in @ratom path) + #(ratom path))] + (cached-reaction f ratom path this nil)))] + (._set-state this oldstate newstate) + newstate)) + + IReset + (-reset! [this new-value] + (let [oldstate state] + (._set-state this oldstate new-value) + (if (satisfies? IDeref ratom) + (if (= path []) + (reset! ratom new-value) + (swap! ratom assoc-in path new-value)) + (ratom path new-value)) + new-value)) + + ISwap + (-swap! [a f] (-reset! a (f (._peek a)))) + (-swap! [a f x] (-reset! a (f (._peek a) x))) + (-swap! [a f x y] (-reset! a (f (._peek a) x y))) + (-swap! [a f x y more] (-reset! a (apply f (._peek a) x y more))) + + IPrintWithWriter + (-pr-writer [a w opts] (pr-atom a w opts "RCursor" {:val (-deref a) + :path path})) + + IWatchable + (-notify-watches [this old new] (notify-w this old new)) + (-add-watch [this key f] (add-w this key f)) + (-remove-watch [this key] (remove-w this key)) + + IHash + (-hash [_] (hash [ratom path]))) + +(defn cursor + [^clj src path] + (assert (or (satisfies? IReactiveAtom src) + (and (ifn? src) + (not (vector? src)))) + (str "src must be a reactive atom or a function, not " + (pr-str src) + " while attempting to get path: " + (pr-str path))) + (->RCursor src path nil nil nil)) + + +;;; with-let support + +(defn with-let-destroy [v] + (when-some [f (.-destroy v)] + (f))) + +(defn with-let-values [key] + (if-some [c *ratom-context*] + (cached-reaction array c key nil with-let-destroy) + (array))) + + +;;;; reaction + +(defprotocol IDisposable + (dispose! [this]) + (add-on-dispose! [this f])) + +(defprotocol IRunnable + (run [this])) + +(defn- handle-reaction-change [^clj this sender old new] + (._handle-change this sender old new)) + +;; Fields of a Reaction javascript object +;; - auto_run +;; - captured +;; - caught +;; - f +;; - ratomGeneration +;; - state +;; - watches +;; - watching +(deftype Reaction [f ^:mutable state ^:mutable ^boolean dirty? ^boolean nocache? + ^:mutable watching ^:mutable watches ^:mutable auto-run + ^:mutable caught] + IAtom + IReactiveAtom + + IWatchable + (-notify-watches [this old new] (notify-w this old new)) + (-add-watch [this key f] (add-w this key f)) + (-remove-watch [this key] + (let [was-empty (empty? watches)] + (remove-w this key) + (when (and (not was-empty) + (empty? watches) + (nil? auto-run)) + (dispose! this)))) + + IReset + (-reset! [a newval] + (assert (fn? (.-on-set a)) "Reaction is read only; on-set is not allowed") + (let [oldval state] + (set! state newval) + (.on-set a oldval newval) + (notify-w a oldval newval) + newval)) + + ISwap + (-swap! [a f] (-reset! a (f (._peek-at a)))) + (-swap! [a f x] (-reset! a (f (._peek-at a) x))) + (-swap! [a f x y] (-reset! a (f (._peek-at a) x y))) + (-swap! [a f x y more] (-reset! a (apply f (._peek-at a) x y more))) + + Object + (_peek-at [this] + (binding [*ratom-context* nil] + (-deref this))) + + (_handle-change [this sender oldval newval] + (when-not (or (identical? oldval newval) + dirty?) + (if (nil? auto-run) + (do + (set! dirty? true) + (rea-enqueue this)) + (if (true? auto-run) + (._run this false) + (auto-run this))))) + + (_update-watching [this derefed] + (let [new (set derefed) + old (set watching)] + (set! watching derefed) + (doseq [w (s/difference new old)] + (-add-watch w this handle-reaction-change)) + (doseq [w (s/difference old new)] + (-remove-watch w this)))) + + (_queued-run [this] + (when (and dirty? (some? watching)) + (._run this true))) + + (_try-capture [this f] + (try + (set! caught nil) + (deref-capture f this) + (catch :default e + (set! state e) + (set! caught e) + (set! dirty? false)))) + + (_run [this check] + (let [oldstate state + res (if check + (._try-capture this f) + (deref-capture f this))] + (when-not nocache? + (set! state res) + ;; Use = to determine equality from reactions, since + ;; they are likely to produce new data structures. + (when-not (or (nil? watches) + (= oldstate res)) + (notify-w this oldstate res))) + res)) + + (_set-opts [this {:keys [auto-run on-set on-dispose no-cache]}] + (when (some? auto-run) + (set! (.-auto-run this) auto-run)) + (when (some? on-set) + (set! (.-on-set this) on-set)) + (when (some? on-dispose) + (set! (.-on-dispose this) on-dispose)) + (when (some? no-cache) + (set! (.-nocache? this) no-cache))) + + IRunnable + (run [this] + (flush!) + (._run this false)) + + IDeref + (-deref [this] + (when-some [e caught] + (throw e)) + (let [non-reactive (nil? *ratom-context*)] + (when non-reactive + (flush!)) + (if (and non-reactive (nil? auto-run)) + (when dirty? + (let [oldstate state] + (set! state (f)) + (when-not (or (nil? watches) (= oldstate state)) + (notify-w this oldstate state)))) + (do + (notify-deref-watcher! this) + (when dirty? + (._run this false))))) + state) + + IDisposable + (dispose! [this] + (let [s state + wg watching] + (set! watching nil) + (set! state nil) + (set! auto-run nil) + (set! dirty? true) + (doseq [w (set wg)] + (-remove-watch w this)) + (when (some? (.-on-dispose this)) + (.on-dispose this s)) + (when-some [a (.-on-dispose-arr this)] + (dotimes [i (alength a)] + ((aget a i) this))))) + + (add-on-dispose! [this f] + ;; f is called with the reaction as argument when it is no longer active + (if-some [a (.-on-dispose-arr this)] + (.push a f) + (set! (.-on-dispose-arr this) (array f)))) + + IEquiv + (-equiv [o other] (identical? o other)) + + IPrintWithWriter + (-pr-writer [a w opts] (pr-atom a w opts "Reaction" {:val (-deref a)})) + + IHash + (-hash [this] (goog/getUid this))) + +(defn flush! [] + (loop [] + (let [q rea-queue] + (when-not (nil? q) + (set! rea-queue nil) + (dotimes [i (alength q)] + (let [^Reaction r (aget q i)] + (._queued-run r))) + (recur))))) + +(set! batch/ratom-flush flush!) + +(defn make-reaction [f & {:keys [auto-run on-set on-dispose]}] + (let [reaction (->Reaction f nil true false nil nil nil nil)] + (._set-opts reaction {:auto-run auto-run + :on-set on-set + :on-dispose on-dispose}) + reaction)) + + + +(def ^:private temp-reaction (make-reaction nil)) + + +(defn run-in-reaction + "Evaluates `f` and returns the result. If `f` calls `deref` on any ratoms, + creates a new Reaction that watches those atoms and calls `run` whenever + any of those watched ratoms change. Also, the new reaction is added to + list of 'watches' of each of the ratoms. The `run` parameter is a function + that should expect one argument. It is passed `obj` when run. The `opts` + are any options accepted by a Reaction and will be set on the newly created + Reaction. Sets the newly created Reaction to the `key` on `obj`." + [f obj key run opts] + (let [r temp-reaction + res (deref-capture f r)] + (when-not (nil? (.-watching r)) + (set! temp-reaction (make-reaction nil)) + (._set-opts r opts) + (set! (.-f r) f) + (set! (.-auto-run r) #(run obj)) + (obj/set obj key r)) + res)) + +(defn check-derefs [f] + (let [ctx (js-obj) + res (in-context ctx f)] + [res (some? (.-captured ctx))])) + + +;;; wrap + +(deftype Wrapper [^:mutable state callback ^:mutable ^boolean changed + ^:mutable watches] + + IAtom + + IDeref + (-deref [this] + (when (dev?) + (when (and changed (some? *ratom-context*)) + (warn "derefing stale wrap: " + (pr-str this)))) + state) + + IReset + (-reset! [this newval] + (let [oldval state] + (set! changed true) + (set! state newval) + (when (some? watches) + (notify-w this oldval newval)) + (callback newval) + newval)) + + ISwap + (-swap! [a f] (-reset! a (f state))) + (-swap! [a f x] (-reset! a (f state x))) + (-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))) + + IEquiv + (-equiv [this ^clj other] + (and (instance? Wrapper other) + ;; If either of the wrappers have changed, equality + ;; cannot be relied on. + (not changed) + (not (.-changed other)) + (= state (.-state other)) + (= callback (.-callback other)))) + + IWatchable + (-notify-watches [this old new] (notify-w this old new)) + (-add-watch [this key f] (add-w this key f)) + (-remove-watch [this key] (remove-w this key)) + + IPrintWithWriter + (-pr-writer [a w opts] (pr-atom a w opts "Wrapper" {:val (-deref a)}))) + +(defn make-wrapper [value callback-fn args] + (->Wrapper value + (util/make-partial-fn callback-fn args) + false nil)) + + + + +#_(do + (defn ratom-perf [] + (set! debug false) + (dotimes [_ 10] + (let [nite 100000 + a (atom 0) + f (fn [] + (quot @a 10)) + mid (make-reaction f) + res (track! (fn [] + ;; (with-let [x 1]) + ;; @(track f) + (inc @mid) + ))] + @res + (time (dotimes [x nite] + (swap! a inc) + (flush!))) + (dispose! res)))) + (ratom-perf)) diff --git a/re-frisk/src/re_frisk/subs_graph.cljs b/re-frisk/src/re_frisk/subs_graph.cljs index e38f04a..37e307e 100644 --- a/re-frisk/src/re_frisk/subs_graph.cljs +++ b/re-frisk/src/re_frisk/subs_graph.cljs @@ -1,6 +1,6 @@ (ns re-frisk.subs-graph (:require [re-frisk.ui.components.colors :as colors] - [reagent.core :as reagent])) + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent])) (defonce network (atom nil)) (defonce reaction->operation (reagent/atom {})) diff --git a/re-frisk/src/re_frisk/ui.cljs b/re-frisk/src/re_frisk/ui.cljs index d24afd1..653d3cf 100644 --- a/re-frisk/src/re_frisk/ui.cljs +++ b/re-frisk/src/re_frisk/ui.cljs @@ -1,8 +1,8 @@ (ns re-frisk.ui - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require [re-frisk.utils :as utils] [re-frisk.ui.style :as style] - [reagent.dom :as rdom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom :as rdom] [re-frisk.ui.components.drag :as drag] [re-frisk.ui.external-hml :as external-hml] [re-frisk.db :as db] diff --git a/re-frisk/src/re_frisk/ui/components/drag.cljs b/re-frisk/src/re_frisk/ui/components/drag.cljs index bded529..765aee2 100644 --- a/re-frisk/src/re_frisk/ui/components/drag.cljs +++ b/re-frisk/src/re_frisk/ui/components/drag.cljs @@ -1,6 +1,6 @@ (ns re-frisk.ui.components.drag (:require [goog.events :as goog-events] - [reagent.core :as reagent]) + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent]) (:import [goog.events EventType])) (defonce draggable (reagent/atom {})) diff --git a/re-frisk/src/re_frisk/ui/components/frisk.cljs b/re-frisk/src/re_frisk/ui/components/frisk.cljs index b531dd7..be63c67 100644 --- a/re-frisk/src/re_frisk/ui/components/frisk.cljs +++ b/re-frisk/src/re_frisk/ui/components/frisk.cljs @@ -2,9 +2,8 @@ (:require [clojure.set :as set] [re-frisk.filter.filter-parser :as filter-parser] [re-frisk.filter.filter-matcher :as filter-matcher] - [re-com.core :as re-com] [re-frisk.ui.components.components :as components] - [reagent.core :as reagent] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-frisk.clipboard :as clipboard] cljs.pprint)) @@ -69,9 +68,9 @@ (reset! inp-val "") (emit-fn :filter-change "" 0))} "X"]) -(defn node-clicked [{:keys [event emit-fn path] :as all}] +(defn node-clicked [{:keys [event emit-fn path]}] (.stopPropagation event) - (emit-fn :filter-change (str path) 0)) + (emit-fn :filter-change-exp (str path) 0)) (defn NilText [] [:span {:style (:nil styles)} (pr-str nil)]) @@ -289,6 +288,10 @@ :filter-ref (swap! filter-refs #(if (second args) (assoc % (first args) (second args)) (dissoc % (first args)))) + :filter-change-exp + (do + (reset! inp-val (first args)) + (swap! state-atom apply-filter id (first args))) :filter-change (do (reset! inp-val (first args)) @@ -298,6 +301,13 @@ (swap! swappable assoc-in path value) (reset! swappable value)))))) +(defn emit-fn-factory-simple [state-atom id] + (fn [event & args] + (case event + :expand (swap! state-atom update-in [:data-frisk id :expanded-paths] conj-to-set (first args)) + :contract (swap! state-atom update-in [:data-frisk id :expanded-paths] disj (first args)) + nil))) + (defn walk-paths ([data] (walk-paths [] data)) @@ -361,43 +371,30 @@ matching (matching-paths data filter) expanded-matching (expanded-matching-paths matching) emit-fn (emit-fn-factory state-atom id swappable filter-refs inp-val)] - [re-com/v-box :style {:background-color "#f3f3f3" :color "#444444"} - :size "1" - :children - [[:div {:style {:padding "4px 2px" :display "flex"}} - [ExpandAllButton emit-fn data] - [CollapseAllButton emit-fn] - [:div {:style {:padding "2px" :margin-left "4px" :background-color "#fff9db"}} (count matching)] - [button "↑" #(scroll-frisk-list-item filter-refs current-search-index true)] - [button "↓" #(scroll-frisk-list-item filter-refs current-search-index false)] - [FilterEditBox emit-fn inp-val] - [FilterReset emit-fn inp-val]] - [components/scroller - [DataFrisk {:data data - :swappable swappable - :path [] - :expanded-paths (get-in data-frisk [id :expanded-paths]) - :matching-paths matching - :expanded-matching-paths expanded-matching - :emit-fn emit-fn}]]]])))) + [:div {:style {:background-color "#f3f3f3" :color "#444444" :flex 1 :display :flex :flex-direction :column}} + [:div {:style {:padding "4px 2px" :display :flex}} + [ExpandAllButton emit-fn data] + [CollapseAllButton emit-fn] + [:div {:style {:padding "2px" :margin-left "4px" :background-color "#fff9db"}} (count matching)] + [button "↑" #(scroll-frisk-list-item filter-refs current-search-index true)] + [button "↓" #(scroll-frisk-list-item filter-refs current-search-index false)] + [FilterEditBox emit-fn inp-val] + [FilterReset emit-fn inp-val]] + [components/scroller + [DataFrisk {:data data + :swappable swappable + :path [] + :expanded-paths (get-in data-frisk [id :expanded-paths]) + :matching-paths matching + :expanded-matching-paths expanded-matching + :emit-fn emit-fn}]]])))) + +(def expand-by-default (reduce #(assoc-in %1 [:data-frisk %2 :expanded-paths] #{[]}) {} (range 1))) (defn Root-Simple [_ _ _] - (let [filter-refs (atom {}) - inp-val (reagent/atom "")] - (fn [data id state-atom] - (let [data-frisk (:data-frisk @state-atom) - swappable (when (satisfies? IAtom data) - data) - filter (or (get-in data-frisk [id :filter]) []) - matching (matching-paths data filter) - expanded-matching (expanded-matching-paths matching) - emit-fn (emit-fn-factory state-atom id swappable filter-refs inp-val)] - [DataFrisk {:data data - :swappable swappable - :path [] - :expanded-paths (get-in data-frisk [id :expanded-paths]) - :matching-paths matching - :expanded-matching-paths expanded-matching - :emit-fn emit-fn}])))) - -(def expand-by-default (reduce #(assoc-in %1 [:data-frisk %2 :expanded-paths] #{[]}) {} (range 1))) \ No newline at end of file + (let [state-atom (reagent/atom expand-by-default)] + (fn [data] + [DataFrisk {:data data + :path [] + :expanded-paths (get-in @state-atom [:data-frisk 0 :expanded-paths]) + :emit-fn (emit-fn-factory-simple state-atom 0)}]))) \ No newline at end of file diff --git a/re-frisk/src/re_frisk/ui/components/recom.clj b/re-frisk/src/re_frisk/ui/components/recom.clj new file mode 100644 index 0000000..ee89028 --- /dev/null +++ b/re-frisk/src/re_frisk/ui/components/recom.clj @@ -0,0 +1,33 @@ +(ns re-frisk.ui.components.recom) + +;; There is a trap when writing DOM event handlers. This looks innocent enough: +;; +;; :on-mouse-out #(reset! my-over-atom false) +;; +;; But notice that it inadvertently returns false. returning false means something!! +;; v0.11 of ReactJS will invoke both stopPropagation() and preventDefault() +;; on the event. Almost certainly not what we want. +;; +;; Note: v0.12 of ReactJS will do the same as v0.11, except it also issues a +;; deprecation warning about false returns. +;; +;; Note: ReactJS only tests explicitly for false, not falsy values. So 'nil' is a +;; safe return value. +;; +;; So 'handler-fn' is a macro which will stop you from inadvertently returning +;; false in a handler. +;; +;; +;; Examples: +;; +;; :on-mouse-out (handler-fn (reset! my-over-atom false)) ;; notice no # in front reset! form +;; +;; +;; :on-mouse-out (handler-fn +;; (reset! over-atom false) ;; notice: no need for a 'do' +;; (now do something else) +;; (.preventDefault event)) ;; notice access to the 'event' + +(defmacro handler-fn + ([& body] + `(fn [~'event] ~@body nil))) ;; force return nil diff --git a/re-frisk/src/re_frisk/ui/components/splits.cljs b/re-frisk/src/re_frisk/ui/components/splits.cljs index d21b6fc..9f62cfa 100644 --- a/re-frisk/src/re_frisk/ui/components/splits.cljs +++ b/re-frisk/src/re_frisk/ui/components/splits.cljs @@ -1,14 +1,52 @@ (ns re-frisk.ui.components.splits - (:require-macros [re-com.core :refer [handler-fn]]) - (:require [re-com.util :refer [sum-scroll-offsets]] - [re-com.box :refer [flex-child-style flex-flow-style]] - [reagent.core :as reagent])) + (:require-macros [re-frisk.ui.components.recom :refer [handler-fn]]) + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] + [clojure.string :as string])) ;;TODO copy https://github.com/Day8/re-com/blob/master/src/re_com/splits.cljs ;; fixed :on-mouse-leave https://github.com/Day8/re-com/issues/158 ;; (.getElementById document container-id), document provided from outside, because re-frisk window is not a root window +(defn sum-scroll-offsets + "Given a DOM node, I traverse through all ascendant nodes (until I reach body), summing any scrollLeft and scrollTop values + and return these sums in a map" + [node] + (loop [current-node (.-parentNode node) ;; Begin at parent + sum-scroll-left 0 + sum-scroll-top 0] + (if (not= (.-tagName current-node) "BODY") + (recur (.-parentNode current-node) + (+ sum-scroll-left (.-scrollLeft current-node)) + (+ sum-scroll-top (.-scrollTop current-node))) + {:left sum-scroll-left + :top sum-scroll-top}))) + +(defn flex-child-style + [size] + (let [split-size (string/split (string/trim size) #"\s+") ;; Split into words separated by whitespace + split-count (count split-size) + _ (assert (contains? #{1 3} split-count) "Must pass either 1 or 3 words to flex-child-style") + size-only (when (= split-count 1) (first split-size)) ;; Contains value when only one word passed (e.g. auto, 60px) + split-size-only (when size-only (string/split size-only #"(\d+)(.*)")) ;; Split into number + string + [_ num units] (when size-only split-size-only) ;; grab number and units + pass-through? (nil? num) ;; If we can't split, then we'll pass this straign through + grow-ratio? (or (= units "%") (= units "") (nil? units)) ;; Determine case for using grow ratio + grow (if grow-ratio? num "0") ;; Set grow based on percent or integer, otherwise no grow + shrink (if grow-ratio? "1" "0") ;; If grow set, then set shrink to even shrinkage as well + basis (if grow-ratio? "0px" size) ;; If grow set, then even growing, otherwise set basis size to the passed in size (e.g. 100px, 5em) + flex (if (and size-only (not pass-through?)) + (str grow " " shrink " " basis) + size)] + {:-webkit-flex flex + :flex flex})) + +(defn flex-flow-style + "A cross-browser helper function to output flex-flow with all it's potential browser prefixes" + [flex-flow] + {:-webkit-flex-flow flex-flow + :flex-flow flex-flow}) + (defn drag-handle "Return a drag handle to go into a vertical or horizontal splitter bar: orientation: Can be :horizonal or :vertical diff --git a/re-frisk/src/re_frisk/ui/events.cljs b/re-frisk/src/re_frisk/ui/events.cljs index 8e25c37..4d7ec96 100644 --- a/re-frisk/src/re_frisk/ui/events.cljs +++ b/re-frisk/src/re_frisk/ui/events.cljs @@ -1,8 +1,8 @@ (ns re-frisk.ui.events - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require - [reagent.core :as reagent] - [reagent.dom :as rdom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom :as rdom] [clojure.string :as string] [re-com.core :as re-com] [re-frisk.ui.components.frisk :as frisk] @@ -97,9 +97,11 @@ :children [[re-com/box :size "1" :child - [re-com/input-text :style {:height :auto :padding "0" } :width "100%" - :model text-val :change-on-blur? false :placeholder "Filter events" - :on-change #(reset! text-val %)]] + [:input {:type "text" + :style {:height :auto :padding "0" :width "100%"} + :value @text-val + :placeholder "Filter events" + :on-change #(reset! text-val (-> % .-target .-value))}]] [components/small-button {:on-click #(reset! text-val "") :active? false} "X"]]] ;truncate checkbox [re-com/h-box :gap "5px" @@ -115,9 +117,11 @@ [re-com/gap :size "100%"] [re-com/h-box :children - [[re-com/input-text :style {:height "20px" :padding "0"} :width "30px" - :model max-text-val :change-on-blur? false :placeholder "max" - :on-change #(reset! max-text-val %)] + [[:input {:type "text" + :style {:height "20px" :padding "0" :width "30px"} + :value @max-text-val + :placeholder "max" + :on-change #(reset! max-text-val (-> % .-target .-value))}] [components/small-button {:on-click #(reset! max-text-val nil) :active? false} "X"]]]]] ;events [events-scroller sorted-events tool-state @checkbox-trace-val]]]))) diff --git a/re-frisk/src/re_frisk/ui/external_hml.cljs b/re-frisk/src/re_frisk/ui/external_hml.cljs index 693ed9d..366a8a6 100644 --- a/re-frisk/src/re_frisk/ui/external_hml.cljs +++ b/re-frisk/src/re_frisk/ui/external_hml.cljs @@ -4,4 +4,4 @@ ;slurp can't find path when running project with re-frisk ;(def html-doc (slurp "src/re_frisk/ui/external.html")) -(def html-doc "\n\n\n\n re-frisk debugger\n \n \n \n \n \n \n \n\n\n\n
\n

re-frisk debugger

\n

ENJOY!

\n
\n\n") \ No newline at end of file +(def html-doc "\n\n\n\n re-frisk debugger\n \n \n \n \n \n \n \n\n\n\n
\n

re-frisk debugger

\n

ENJOY!

\n
\n\n") \ No newline at end of file diff --git a/re-frisk/src/re_frisk/ui/reagent_views.cljs b/re-frisk/src/re_frisk/ui/reagent_views.cljs index dfef588..e49dd8b 100644 --- a/re-frisk/src/re_frisk/ui/reagent_views.cljs +++ b/re-frisk/src/re_frisk/ui/reagent_views.cljs @@ -1,32 +1,42 @@ (ns re-frisk.ui.reagent-views (:require [re-frisk.ui.components.components :as components] [re-frisk.subs-graph :as subs-graph] - [reagent.core :as reagent] [re-frisk.ui.components.frisk :as frisk] - [re-frisk.ui.components.colors :as colors])) + [re-frisk.ui.components.colors :as colors] + [re-com.core :as re-com] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent])) -(defn input-signals [_ _] - (let [state-atom (reagent/atom frisk/expand-by-default)] - (fn [name subs] - (when-let [signals (get @subs-graph/view->reactions name)] - [frisk/Root-Simple (into {} - (map (fn [item] - (let [op (get @subs-graph/reaction->operation item)] - (if op - {op (get subs [[op] []])} - {:reagent :atom}))) - signals)) - 0 state-atom])))) +(defn input-signals [name subs] + (when-let [signals (get @subs-graph/view->reactions name)] + [frisk/Root-Simple (into {} + (map (fn [item] + (let [op (get @subs-graph/reaction->operation item)] + (if op + {op (get subs [[op] []])} + {:reagent :atom}))) + signals))])) -(defn views [re-frame-data] - (let [data @(:views re-frame-data) - subs @(:subs re-frame-data)] - [:div {:style {:display :flex :flex 1 :background-color "#f3f3f3" :color "#444444" - :padding 8 :flex-direction :column}} - [:div {:style {:margin-bottom 10 :border-bottom "solid 1px #000000"}} "Mounted views (" (count data) ") in mount order"] - [components/scroller - (for [{:keys [name]} (sort-by :order (vals data))] - ^{:key (str "item" name)} - [:div {:style {:display :flex :flex-direction :column :border-bottom "solid 1px #CCCCCC"}} - [:div {:style {:min-width "200" :color colors/render}} name] - [input-signals name subs]])]])) +(defn views [_] + (let [checkbox-sorted-val (reagent/atom false)] + (fn [re-frame-data] + (let [data @(:views re-frame-data) + subs @(:subs re-frame-data) + chb-val @checkbox-sorted-val + view->reactions @subs-graph/view->reactions] + [:div {:style {:display :flex :flex 1 :background-color "#f3f3f3" :color "#444444" + :padding 8 :flex-direction :column}} + [:div {:style {:margin-bottom 10 :border-bottom "solid 1px #000000" :display :flex + :flex-direction :row}} + "Mounted views (" (count data) ") in mount order" + [:div {:style {:width 10 :margin-left 10}} " | "] + [re-com/checkbox + :model checkbox-sorted-val + :on-change #(do (swap! checkbox-sorted-val not) nil) + :label "subs"]] + [components/scroller + (for [{:keys [name]} (sort-by :order (vals data))] + (when (or (not chb-val) (get view->reactions name)) + ^{:key (str "item" name)} + [:div {:style {:display :flex :flex-direction :column :border-bottom "solid 1px #CCCCCC"}} + [:div {:style {:min-width "200" :color colors/render}} name] + [input-signals name subs]]))]])))) diff --git a/re-frisk/src/re_frisk/ui/stat.cljs b/re-frisk/src/re_frisk/ui/stat.cljs index 167a1c5..b259cef 100644 --- a/re-frisk/src/re_frisk/ui/stat.cljs +++ b/re-frisk/src/re_frisk/ui/stat.cljs @@ -1,5 +1,5 @@ (ns re-frisk.ui.stat - (:require [reagent.core :as reagent] + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-frisk.ui.components.components :as components] [re-frisk.utils :as utils] [re-frisk.clipboard :as clipboard])) diff --git a/re-frisk/src/re_frisk/ui/subs.cljs b/re-frisk/src/re_frisk/ui/subs.cljs index 67c4666..35d3a2f 100644 --- a/re-frisk/src/re_frisk/ui/subs.cljs +++ b/re-frisk/src/re_frisk/ui/subs.cljs @@ -1,5 +1,5 @@ (ns re-frisk.ui.subs - (:require [reagent.core :as reagent] + (:require [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-frisk.subs-graph :as subs-graph])) (defn global-subs-graph-container [] diff --git a/re-frisk/src/re_frisk/ui/timeline.cljs b/re-frisk/src/re_frisk/ui/timeline.cljs index 0e31efc..c72db5d 100644 --- a/re-frisk/src/re_frisk/ui/timeline.cljs +++ b/re-frisk/src/re_frisk/ui/timeline.cljs @@ -1,5 +1,5 @@ (ns re-frisk.ui.timeline - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require [re-frisk.ui.components.components :as components] [re-frisk.utils :as utils])) diff --git a/re-frisk/src/re_frisk/ui/trace.cljs b/re-frisk/src/re_frisk/ui/trace.cljs index 8b4493f..e5ec44b 100644 --- a/re-frisk/src/re_frisk/ui/trace.cljs +++ b/re-frisk/src/re_frisk/ui/trace.cljs @@ -1,5 +1,5 @@ (ns re-frisk.ui.trace - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require [re-frisk.ui.components.components :as components] [re-frisk.utils :as utils] [re-frisk.ui.components.colors :as colors])) diff --git a/re-frisk/src/re_frisk/ui/views.cljs b/re-frisk/src/re_frisk/ui/views.cljs index 6de78e5..b1d654a 100644 --- a/re-frisk/src/re_frisk/ui/views.cljs +++ b/re-frisk/src/re_frisk/ui/views.cljs @@ -1,7 +1,7 @@ (ns re-frisk.ui.views - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require - [reagent.core :as reagent] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.core :as reagent] [re-com.core :as re-com] [re-frisk.ui.events :as events] [re-frisk.ui.components.splits :as splits] @@ -19,13 +19,35 @@ (fn [_] [frisk/Root (utils/sort-map @subs @checkbox-sorted-val checkbox-sorted-val) 0 state-atom]))) +(defn watch-item [frisk-data item watchers] + [re-com/v-box + :children + [[re-com/h-box :style {:background-color "#4e5d6c"} + :children + [[:div (str "Watching " item)] + [re-com/gap :size "10px"] + [components/label-button {:on-click #(swap! watchers disj item) + :active? false} + "Stop"]]] + [re-com/v-box :style {:padding 10 :color "#444444"} + :children + [[frisk/Root-Simple frisk-data]]]]]) + (defn app-db-view [app-db tool-state] (let [state-atom (reagent/atom frisk/expand-by-default) + watchers (reagent/atom #{}) checkbox-sorted-val (reagent/atom true)] (fn [_] [re-com/v-box :size "1" :children - [[re-com/h-box + [(when (seq @watchers) + (let [app-db-derefed @app-db] + [components/scroller + {:style {:background-color "#f3f3f3"}} + (for [watcher @watchers] + ^{:key watcher} + [watch-item (get-in app-db-derefed watcher) watcher watchers])])) + [re-com/h-box :children [[re-com/label :label "app-db"] [re-com/gap :size "20px"] @@ -34,7 +56,13 @@ :on-change (utils/on-change-sort app-db checkbox-sorted-val :re-frisk-sorted) :label "sort"] (when (:app-db-delta-error @tool-state) - [re-com/label :label "update error" :style {:margin-left "4px" :color "#df691a"}])]] + [re-com/label :label "update error" :style {:margin-left "4px" :color "#df691a"}]) + [re-com/gap :size "48px"] + (when-let [filter (get-in @state-atom [:data-frisk 0 :filter])] + (when (contains? (first filter) :expr) + [components/label-button {:on-click #(swap! watchers conj (mapv :expr filter)) + :active? false} + "Watch"]))]] [frisk/Root (utils/sort-map @app-db @checkbox-sorted-val checkbox-sorted-val) 0 state-atom]]]))) (defn frisks-view [re-frame-data tool-state doc] diff --git a/resources/public/js/main.js b/resources/public/js/main.js index e51fd1f..c6f004d 100644 --- a/resources/public/js/main.js +++ b/resources/public/js/main.js @@ -685,7 +685,7 @@ k.lastIndexOf=function(){function a(c){return jf(this,c,K(this))}var b=null;b=fu k.O=function(a,b){return mf(this,b)};k.wa=function(){return Me};k.La=function(a,b){return of(b,this)};k.Ma=function(a,b,c){return qf(b,c,this)};k.Pa=function(){return this.na.Pa(null).A};k.Ta=function(){var a=(null!=this.na?this.na.l&128||n===this.na.Hd||(this.na.l?0:Pc(nd,this.na)):Pc(nd,this.na))?this.na.Ka(null):G(this.na);return null!=a?new dk(a,null):Me};k.ja=function(){return this};k.ha=function(a,b){return b===this.oc?this:new dk(this.na,b)};k.ra=function(a,b){return nf(b,this)}; dk.prototype[Tc]=function(){return Oe(this)};function Xi(a){return(a=E(a))?new dk(a,null):null}function zi(a){return xd(a)}var ek=function ek(a){for(var c=[],d=arguments.length,e=0;;)if(e=b||b>=2+K(a))return tf.a(wi(nf("",Gh.a(u,E(a)))),"");if(r(qg?Nd(1,b):pg.call(null,1,b)))return new Y(null,1,5,Z,[a],null);if(r(qg?Nd(2,b):pg.call(null,2,b)))return new Y(null,2,5,Z,["",a],null);b-=2;return tf.a(wi(nf("",Fi.h(wi(Gh.a(u,E(a))),0,b))),a.substring(b))}function NB(a,b){return OB(a,b,0)} -function OB(a,b,c){if("/(?:)/"===u.g(b))b=MB(a,c);else if(1>c)b=wi(u.g(a).split(b));else a:for(var d=c,e=uf;;){if(1===d){b=tf.a(e,a);break a}var f=Ek(b,a);if(null!=f){var g=a.indexOf(f);f=a.substring(g+K(f));--d;e=tf.a(e,a.substring(0,g));a=f}else{b=tf.a(e,a);break a}}if(0===c&&1a?null:a};var fD={};var gD={},QB="undefined"!==typeof window&&null!=window.document,RB=new jk(null,new p(null,2,["aria",null,"data",null],null),null);function SB(a){return 2>K(a)?a.toUpperCase():[a.substring(0,1).toUpperCase(),a.substring(1)].join("")}function TB(a){if("string"===typeof a)return a;a=Ag(a);var b=NB(a,/-/),c=E(b);b=F(c);c=G(c);return r(RB.g?RB.g(b):RB.call(null,b))?a:U.h(u,b,Gh.a(SB,c))} -function UB(a){var b=function(){if(Af(a)){var c=a.displayName;r(c)||(c=a.name,c="string"===typeof c&&E(c)?c:null)}else c=!1;if(r(c))return c;c=null!=a&&(a.N&4096||n===a.af)?Ag(a):!1;if(r(c))return c;c=Df(a);return Lf(c)?ss.g(c):null}();return r(b)?KB(u.g(b),"$","."):null}function VB(a){return a instanceof z||a instanceof Ge} -var WB=function WB(a){switch(arguments.length){case 0:return WB.C();case 1:return WB.g(arguments[0]);case 2:return WB.a(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(ec)b=wi(u.g(a).split(b));else a:for(var d=c,e=uf;;){if(1===d){b=tf.a(e,a);break a}var f=Ek(b,a);if(null!=f){var g=a.indexOf(f);f=a.substring(g+K(f));--d;e=tf.a(e,a.substring(0,g));a=f}else{b=tf.a(e,a);break a}}if(0===c&&1a?null:a};var Sl={},km={},ym={},Gm={},dn={};var hn={},Un="undefined"!==typeof window&&null!=window.document,co=new jk(null,new p(null,2,["aria",null,"data",null],null),null);function Lo(a){return 2>K(a)?a.toUpperCase():[a.substring(0,1).toUpperCase(),a.substring(1)].join("")}function ip(a){if("string"===typeof a)return a;a=Ag(a);var b=NB(a,/-/),c=E(b);b=F(c);c=G(c);return r(co.g?co.g(b):co.call(null,b))?a:U.h(u,b,Gh.a(Lo,c))} +function jp(a){var b=function(){if(Af(a)){var c=a.displayName;r(c)||(c=a.name,c="string"===typeof c&&E(c)?c:null)}else c=!1;if(r(c))return c;c=null!=a&&(a.N&4096||n===a.af)?Ag(a):!1;if(r(c))return c;c=Df(a);return Lf(c)?ss.g(c):null}();return r(b)?KB(u.g(b),"$","."):null}function vp(a){return a instanceof z||a instanceof Ge} +var Kp=function Kp(a){switch(arguments.length){case 0:return Kp.C();case 1:return Kp.g(arguments[0]);case 2:return Kp.a(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e=K(b)&&nh(function(c){return Vf(a,c)},b)};var nC; -function oC(a,b){b.captured=null;a:{var c=nC;nC=b;try{var d=a.C?a.C():a.call(null);break a}finally{nC=c}d=void 0}var e=b.captured;b.Rc=!1;a:if(a=b.gd,c=null==e?0:e.length,c===(null==a?0:a.length))for(var f=0;;){var g=f===c;if(g){a=g;break a}if(e[f]===a[f])f+=1;else{a=!1;break a}}else a=!1;if(!a)a:{a=ok(e);c=ok(b.gd);b.gd=e;e=E(lC.a(a,c));f=null;for(var h=g=0;;)if(h=e&&f.push(lD(a,h));return f},[c,d],b))}}function mD(a,b,c,d){this.tag=a;this.id=b;this.className=c;this.ah=d} -function XL(a,b,c){var d=Hb(a,jD(c));null==d?KC(a)?a=rD(c,a,a):(d=Df(a),d=S.h(d,bz,a),d=VC(d,c),a=rD(c,a,d)):a=d;c={};c.argv=b;b=iD(b);null!=b&&(c.key=b);return GB.createElement(a,c)}function PN(a,b,c,d){var e={};e.Ef=a;e.argv=Fi.a(b,c);b=iD(b);null!=b&&(e.key=b);return GB.createElement(eE(d,a),e)}function UO(a,b,c){var d;if(d=Af(a))d=null==a?null:a.prototype,d=null!=(null==d?null:d.render);return d?XL(a,b,c):PN(a,b,1,c)}var pD={}; -function qD(a,b,c,d){var e=a.tag,f=Q(b,c,null),g=null==f||Lf(f),h=function(){var m=g?f:null;var q=gA.g(m);m=WL(r(q)?S.h(m,gA,WB.g(q)):m,a);m=r(a.ah)?cD(m):$C(m);return r(m)?m:{}}();c+=g?1:0;a:switch(e){case "input":case "textarea":var l=!0;break a;default:l=!1}if(l)return l=function(){var m=d.ai;if(r(m))return m;m=VC(JG,d);return d.ai=m}(),lD(d,Cf(new Y(null,6,5,Z,[l,b,e,h,c,d],null),Df(b)));l=hD(Df(b));null!=l&&(h.key=l);return nD(d,b,e,h,c)} -function tD(a,b){return Wc(Gh.a(function(c){return lD(b,c)},a))} -function sD(a,b,c){null==b&&console.error("vec-to-elem",YS.j(P([a])));var d=Q(a,0,null);switch(d instanceof z?d.W:null){case "\x3e":return c=Q(a,1,null),qD(new mD(c,null,null,null),a,2,b);case "r\x3e":c=Q(a,1,null);d=Q(a,2,null);d=r(d)?d:{};var e=hD(Df(a));null!=e&&(d.key=e);return nD(b,a,c,d,3);case "f\x3e":return PN(Q(a,1,null),a,2,b);case "\x3c\x3e":return d=Q(a,1,null),c=null==d||Lf(d),d=$C(c?d:null),d=r(d)?d:{},c=1+(c?1:0),e=iD(a),null!=e&&(d.key=e),nD(b,a,GB.Fragment,d,c);default:if(VB(d)|| -"string"===typeof d)a:for(;;)switch(c=Q(a,0,null),c=Ag(c),d=c.indexOf("\x3e"),d){case -1:d=YC(pD,c);if(null==d){var f=G(Dk(WC,Ag(c)));d=Q(f,0,null);e=Q(f,1,null);f=Q(f,2,null);f=null==f?null:KB(f,/\./," ");var g=Wg.a(-1,d.indexOf("-"));d=new mD(d,e,f,g);c=pD[c]=d}else c=d;a=qD(c,a,1,b);break a;case 0:a=null;break a;default:a=Cf(new Y(null,2,5,Z,[c.substring(0,d),S.h(Cf(a,null),0,c.substring(d+1))],null),Df(a))}else a=c.h?c.h(d,a,b):c.call(null,d,a,b);return a}} -var VO=function(a){var b=al("G__"),c=r(LC.g(a))?UO:XL;if("undefined"===typeof fD||"undefined"===typeof gD||"undefined"===typeof KG||"undefined"===typeof oJ)oJ=function(d,e,f,g){this.Tc=d;this.id=e;this.Vh=f;this.Zh=g;this.l=393216;this.N=0},oJ.prototype.ha=function(d,e){return new oJ(this.Tc,this.id,this.Vh,e)},oJ.prototype.ga=function(){return this.Zh},oJ.prototype.$h=function(){return this.id},oJ.prototype.Wh=function(d,e){d=this.Vh;return"object"!==sa(e)?e:Nf(e)?sD(e,this,d):Rf(e)?tD(e,this):VB(e)? -Ag(e):(null!=e?e.l&2147483648||n===e.qa||(e.l?0:Pc(Xd,e)):Pc(Xd,e))?YS.j(P([e])):e},oJ.prototype.Xh=function(d,e,f,g,h){return kD(this,e,f,g,h)},oJ.Qc=!0,oJ.sc="reagent.impl.template/t_reagent$impl$template14046",oJ.Wc=function(d){return Wd(d,"reagent.impl.template/t_reagent$impl$template14046")};return new oJ(a,b,c,Zg)}(Zg);var uD=Ah(Zg);function vD(a,b,c){var d=XB;XB=!0;try{return HB.render(a.C?a.C():a.call(null),b,function(){var e=XB;XB=!1;try{return Dh.v(uD,S,b,a),dC(gC),null!=c?c.C?c.C():c.call(null):null}finally{XB=e}})}finally{XB=d}}function wD(){var a=new Y(null,4,5,Z,[xD,yD,zD,document],null),b=document.getElementById("app");wC();var c=Af(VO)?new Y(null,2,5,Z,[VO,VO],null):new Y(null,2,5,Z,[VO,NC.g(VO)],null),d=Q(c,0,null);c=Q(c,1,null);return vD(function(){return lD(d,Af(a)?a.C?a.C():a.call(null):a)},b,c)};var BD={},CD,DD,ED,FD={};function GD(a,b){if(null!=a&&null!=a.kf)a=a.kf(a,b);else{var c=GD[sa(null==a?null:a)];if(null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else if(c=GD._,null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else throw Rc("ReadPort.take!",a);}return a}function HD(a,b,c){if(null!=a&&null!=a.pe)a=a.pe(a,b,c);else{var d=HD[sa(null==a?null:a)];if(null!=d)a=d.h?d.h(a,b,c):d.call(null,a,b,c);else if(d=HD._,null!=d)a=d.h?d.h(a,b,c):d.call(null,a,b,c);else throw Rc("WritePort.put!",a);}return a} +lC.J=function(a){var b=F(a),c=G(a);a=F(c);c=G(c);return this.j(b,a,c)};lC.H=2;function mC(a,b){return K(a)>=K(b)&&nh(function(c){return Vf(a,c)},b)};var uv;function vv(a,b){b.captured=null;a:{var c=uv;uv=b;try{var d=a.C?a.C():a.call(null);break a}finally{uv=c}d=void 0}a=b.captured;b.Rc=!1;a:{c=b.gd;var e=null==a?0:a.length;if(e===(null==c?0:c.length))for(var f=0;;){var g=f===e;if(g){c=g;break a}if(a[f]===c[f])f+=1;else{c=!1;break a}}else c=!1}c||b.Ui(a);return d}function Ev(a){var b=uv;if(null!=b){var c=b.captured;null==c?b.captured=[a]:c.push(a)}}function Vv(a,b,c){a.vb=S.h(a.vb,b,c);return a.Of=null} +function Rw(a,b){a.vb=zf.a(a.vb,b);return a.Of=null}function dx(a,b,c){var d=a.Of;d=null==d?a.Of=eg(function(l,m,q){l.push(m);l.push(q);return l},[],a.vb):d;for(var e=d.length,f=0;;)if(f=e&&f.push(Xu(a,h));return f},[c,d],b))}}function cW(a,b,c,d){this.tag=a;this.id=b;this.className=c;this.ah=d} +function dW(a,b,c){var d=Hb(a,Pu(c));null==d?XB(a)?a=OP(c,a,a):(d=Df(a),d=S.h(d,bz,a),d=VO(d,c),a=OP(c,a,d)):a=d;c={};c.argv=b;b=zq(b);null!=b&&(c.key=b);return GB.createElement(a,c)}function eW(a,b,c,d){var e={};e.Ef=a;e.argv=Fi.a(b,c);b=zq(b);null!=b&&(e.key=b);return GB.createElement(oQ(d,a),e)}function SX(a,b,c){var d;if(d=Af(a))d=null==a?null:a.prototype,d=null!=(null==d?null:d.render);return d?dW(a,b,c):eW(a,b,1,c)}var IZ={}; +function JZ(a,b,c,d){var e=a.tag,f=Q(b,c,null),g=null==f||Lf(f),h=function(){var m=g?f:null;var q=gA.g(m);m=aW(r(q)?S.h(m,gA,Kp.g(q)):m,a);m=r(a.ah)?XV(m):LV(m);return r(m)?m:{}}();c+=g?1:0;a:switch(e){case "input":case "textarea":var l=!0;break a;default:l=!1}if(l)return l=function(){var m=d.ai;if(r(m))return m;m=VO(uQ,d);return d.ai=m}(),Xu(d,Cf(new Y(null,6,5,Z,[l,b,e,h,c,d],null),Df(b)));l=xq(Df(b));null!=l&&(h.key=l);return bv(d,b,e,h,c)} +function KZ(a,b){return Wc(Gh.a(function(c){return Xu(b,c)},a))} +function LZ(a,b,c){null==b&&console.error("vec-to-elem",YS.j(P([a])));var d=Q(a,0,null);switch(d instanceof z?d.W:null){case "\x3e":return c=Q(a,1,null),JZ(new cW(c,null,null,null),a,2,b);case "r\x3e":c=Q(a,1,null);d=Q(a,2,null);d=r(d)?d:{};var e=xq(Df(a));null!=e&&(d.key=e);return bv(b,a,c,d,3);case "f\x3e":return eW(Q(a,1,null),a,2,b);case "\x3c\x3e":return d=Q(a,1,null),c=null==d||Lf(d),d=LV(c?d:null),d=r(d)?d:{},c=1+(c?1:0),e=zq(a),null!=e&&(d.key=e),bv(b,a,GB.Fragment,d,c);default:if(vp(d)|| +"string"===typeof d)a:for(;;)switch(c=Q(a,0,null),c=Ag(c),d=c.indexOf("\x3e"),d){case -1:d=EQ(IZ,c);if(null==d){var f=G(Dk(xQ,Ag(c)));d=Q(f,0,null);e=Q(f,1,null);f=Q(f,2,null);f=null==f?null:KB(f,/\./," ");var g=Wg.a(-1,d.indexOf("-"));d=new cW(d,e,f,g);c=IZ[c]=d}else c=d;a=JZ(c,a,1,b);break a;case 0:a=null;break a;default:a=Cf(new Y(null,2,5,Z,[c.substring(0,d),S.h(Cf(a,null),0,c.substring(d+1))],null),Df(a))}else a=c.h?c.h(d,a,b):c.call(null,d,a,b);return a}} +var ZZ=function(a){var b=al("G__"),c=r(LC.g(a))?SX:dW;if("undefined"===typeof Sl||"undefined"===typeof km||"undefined"===typeof ym||"undefined"===typeof Gm||"undefined"===typeof dn||"undefined"===typeof hn||"undefined"===typeof vQ||"undefined"===typeof wQ)wQ=function(d,e,f,g){this.Tc=d;this.id=e;this.Vh=f;this.bj=g;this.l=393216;this.N=0},wQ.prototype.ha=function(d,e){return new wQ(this.Tc,this.id,this.Vh,e)},wQ.prototype.ga=function(){return this.bj},wQ.prototype.cj=function(){return this.id},wQ.prototype.$i= +function(d,e){d=this.Vh;return"object"!==sa(e)?e:Nf(e)?LZ(e,this,d):Rf(e)?KZ(e,this):vp(e)?Ag(e):(null!=e?e.l&2147483648||n===e.qa||(e.l?0:Pc(Xd,e)):Pc(Xd,e))?YS.j(P([e])):e},wQ.prototype.aj=function(d,e,f,g,h){return bW(this,e,f,g,h)},wQ.Qc=!0,wQ.sc="re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template/t_re_frisk$inlined_deps$reagent$v1v0v0$reagent$impl$template14796",wQ.Wc=function(d){return Wd(d,"re-frisk.inlined-deps.reagent.v1v0v0.reagent.impl.template/t_re_frisk$inlined_deps$reagent$v1v0v0$reagent$impl$template14796")}; +return new wQ(a,b,c,Zg)}(Zg);var $Z=Ah(Zg);function a_(a,b,c){var d=bq;bq=!0;try{return HB.render(a.C?a.C():a.call(null),b,function(){var e=bq;bq=!1;try{return Dh.v($Z,S,b,a),wt.Ri(),null!=c?c.C?c.C():c.call(null):null}finally{bq=e}})}finally{bq=d}} +function b_(){var a=new Y(null,4,5,Z,[xD,yD,zD,document],null),b=document.getElementById("app");Zy();var c=Af(ZZ)?new Y(null,2,5,Z,[ZZ,ZZ],null):new Y(null,2,5,Z,[ZZ,NC.g(ZZ)],null),d=Q(c,0,null);c=Q(c,1,null);return a_(function(){return Xu(d,Af(a)?a.C?a.C():a.call(null):a)},b,c)};var BD={},CD,DD,ED,FD={};function GD(a,b){if(null!=a&&null!=a.kf)a=a.kf(a,b);else{var c=GD[sa(null==a?null:a)];if(null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else if(c=GD._,null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else throw Rc("ReadPort.take!",a);}return a}function HD(a,b,c){if(null!=a&&null!=a.pe)a=a.pe(a,b,c);else{var d=HD[sa(null==a?null:a)];if(null!=d)a=d.h?d.h(a,b,c):d.call(null,a,b,c);else if(d=HD._,null!=d)a=d.h?d.h(a,b,c):d.call(null,a,b,c);else throw Rc("WritePort.put!",a);}return a} function ID(a){if(null!=a&&null!=a.Jd)a=a.Jd(a);else{var b=ID[sa(null==a?null:a)];if(null!=b)a=b.g?b.g(a):b.call(null,a);else if(b=ID._,null!=b)a=b.g?b.g(a):b.call(null,a);else throw Rc("Channel.close!",a);}return a}function JD(a){if(null!=a&&null!=a.Hb)a=a.Hb(a);else{var b=JD[sa(null==a?null:a)];if(null!=b)a=b.g?b.g(a):b.call(null,a);else if(b=JD._,null!=b)a=b.g?b.g(a):b.call(null,a);else throw Rc("Handler.active?",a);}return a} function KD(a){if(null!=a&&null!=a.Bb)a=a.Bb(a);else{var b=KD[sa(null==a?null:a)];if(null!=b)a=b.g?b.g(a):b.call(null,a);else if(b=KD._,null!=b)a=b.g?b.g(a):b.call(null,a);else throw Rc("Handler.commit",a);}return a}function LD(a,b){if(null!=a&&null!=a.jf)a=a.jf(a,b);else{var c=LD[sa(null==a?null:a)];if(null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else if(c=LD._,null!=c)a=c.a?c.a(a,b):c.call(null,a,b);else throw Rc("Buffer.add!*",a);}return a} var MD=function MD(a){switch(arguments.length){case 1:return MD.g(arguments[0]);case 2:return MD.a(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",u.g(arguments.length)].join(""));}};MD.g=function(a){return a};MD.a=function(a,b){return LD(a,b)};MD.H=2;function ND(a,b,c,d,e){for(var f=0;;)if(fthis.head?(ND(this.o,this.tail,a,0,this.o.length-this.tail),ND(this.o,0,a,this.o.length-this.tail,this.head),this.tail=0,this.head=this.length,this.o=a):this.tail===this.head?(this.head=this.tail=0,this.o=a):null}; function QD(a,b){for(var c=a.length,d=0;;)if(d=this.n};SD.prototype.jf=function(a,b){PD(this.ba,b);return this};SD.prototype.la=function(){return this.ba.length};function TD(a,b){this.ba=a;this.n=b;this.l=2;this.N=0}TD.prototype.oe=function(){return!1}; -TD.prototype.jf=function(a,b){this.ba.length===this.n&&this.ba.pop();this.ba.unshift(b);return this};TD.prototype.la=function(){return this.ba.length};function UD(a){return new TD(RD(a),a)};function VD(){return dc("iPhone")&&!dc("iPod")&&!dc("iPad")};var WD=dc("Opera"),XD=dc("Trident")||dc("MSIE"),YD=dc("Edge"),ZD=dc("Gecko")&&!(Wb("WebKit")&&!dc("Edge"))&&!(dc("Trident")||dc("MSIE"))&&!dc("Edge"),$D=Wb("WebKit")&&!dc("Edge");$D&&dc("Mobile");dc("Macintosh");dc("Windows");dc("Linux")||dc("CrOS");var m_=oa.navigator||null;m_&&(m_.appVersion||"").indexOf("X11");dc("Android");VD();dc("iPad");dc("iPod");VD()||dc("iPad")||dc("iPod");Wb("KaiOS");Wb("GAFP");function bE(){var a=oa.document;return a?a.documentMode:void 0}var cE; -a:{var n_="",M0=function(){var a=Xb;if(ZD)return/rv:([^\);]+)(\)|;)/.exec(a);if(YD)return/Edge\/([\d\.]+)/.exec(a);if(XD)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if($D)return/WebKit\/(\S+)/.exec(a);if(WD)return/(?:Version)[ \/]?(\S+)/.exec(a)}();M0&&(n_=M0?M0[1]:"");if(XD){var N0=bE();if(null!=N0&&N0>parseFloat(n_)){cE=String(N0);break a}}cE=n_}var La={}; -function gE(a){return Ja(a,function(){for(var b=0,c=Vb(String(cE)).split("."),d=Vb(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&fparseFloat(i_)){cE=String(n_);break a}}cE=i_}var La={}; +function gE(a){return Ja(a,function(){for(var b=0,c=Vb(String(cE)).split("."),d=Vb(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&fa)){a+=1;continue}break}lE=!1;return 0this.wd){var a=this.da.charAt(this.wd);this.wd+=1;return a}return null};AG.prototype.Cc=function(){return this.wg>this.wd?this.da.charAt(this.wd):null};function BG(a,b){this.rg=a;this.ba=b;this.Yb=this.Re=1}BG.prototype.Ca=function(){var a=this.Ybc)b[c]=F(d),c+=1,d=G(d);else break a;else for(c=0;;)if(1>c)b[c]=null,c+=1;else break}return new BG(a,b)};function EG(a,b,c,d){var e=K(b);a=r(a)?0:10c)b[c]=F(d),c+=1,d=G(d);else break a;else for(c=0;;)if(1>c)b[c]=null,c+=1;else break}return new BG(a,b)};function EG(a,b,c,d){var e=K(b);a=r(a)?0:10a?'..."':'"',d=b.length;return['"',u.g(b.substring(0,ad?"...}":"}")});FG.gi(null,yv,function(a,b){return EG(a,b,"#{","}")});FG.gi(null,fr,function(a,b){return EG(a,b,"[","]")});FG.gi(null,Dl,function(a,b){return YS.j(P([Qc(b)]))});function LG(a,b,c){b=new p(null,2,[ho,bp,Xw,b],null);a=CG(a)?S.j(b,Nx,zG(a),P([cm,xG(a),yo,yG(a)])):b;var d=Nx.g(a);b=cm.g(a);var e=yo.g(a);d=r(d)?[u.g(d)," "].join(""):null;b=r(b)?["[line ",u.g(b),", col ",u.g(e),"]"].join(""):null;c=U.U(u,d,b,r(r(d)?d:b)?" ":null,c);throw Il(c,a);}function MG(a,b){return LG(a,ko,P([U.a(u,b)]))}function NG(a,b){return LG(a,nv,P([U.a(u,b)]))}function OG(a,b){return LG(a,Br,P([U.a(u,b)]))} function PG(a,b,c,d,e){return OG(a,P(["Unexpected EOF while reading ",r(e)?["item ",u.g(e)," of "].join(""):null,Ag(b),r(c)?[", starting at line ",u.g(c)," and column ",u.g(d)].join(""):null,"."]))}function QG(a,b,c,d){MG(a,P(["The map literal starting with ",FG.a(!1,F(d)),r(b)?[" on line ",u.g(b)," column ",u.g(c)].join(""):null," contains ",K(d)," form(s). Map literals must contain an even number of forms."]))}function RG(a){throw NG(null,P(["Invalid unicode literal: \\",a,"."]));} @@ -1065,7 +1063,7 @@ var lJ=Ah(null),mJ=Ah(ek.j(P([new p(null,4,[os,function(a){if("string"===typeof (d=F(a),c=Q(d,0,null),d=Q(d,1,null),c=Ag(c),b[c]=d,a=G(a),c=null,d=0),e=0;else break;return b}throw Error("JS literal expects a vector or map containing only string or unqualified keyword keys");}],null),Zg])));function nJ(a,b){var c=Array.prototype.slice.call(arguments),d=c.shift();if("undefined"==typeof d)throw Error("[goog.string.format] Template required");return d.replace(/%([0\- \+]*)(\d+)?(\.(\d+))?([%sfdiu])/g,function(e,f,g,h,l,m,q,t){if("%"==m)return"%";var v=c.shift();if("undefined"==typeof v)throw Error("[goog.string.format] Not enough arguments");arguments[0]=v;return nJ.Ec[m].apply(null,arguments)})}nJ.Ec={}; nJ.Ec.s=function(a,b,c){return isNaN(c)||""==c||a.length>=Number(c)?a:a=-1Number(a)?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=Number(a)&&(d=f+d);if(isNaN(c)||d.length>=Number(c))return d;d=isNaN(e)?Math.abs(Number(a)).toString():Math.abs(Number(a)).toFixed(e);a=Number(c)-d.length-f.length;0<=b.indexOf("-",0)?d=f+d+jc(" ",a):(b=0<=b.indexOf("0",0)?"0":" ",d=f+jc(b,a)+d);return d};nJ.Ec.d=function(a,b,c,d,e,f,g,h){return nJ.Ec.f(parseInt(a,10),b,c,d,0,f,g,h)}; -nJ.Ec.i=nJ.Ec.d;nJ.Ec.u=nJ.Ec.d;var cW;(cW=!XD)||(cW=9<=Number(XV));var pJ=cW,qJ=XD&&!gE("9"),rJ=function(){if(!oa.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});try{oa.addEventListener("test",qa,b),oa.removeEventListener("test",qa,b)}catch(c){}return a}();function sJ(){0!=tJ&&(uJ[ya(this)]=this);this.pd=this.pd;this.ud=this.ud}var tJ=0,uJ={};sJ.prototype.pd=!1;sJ.prototype.fg=function(){if(!this.pd&&(this.pd=!0,this.Fc(),0!=tJ)){var a=ya(this);if(0!=tJ&&this.ud&&0c.length&&this.Ub.$c){var f=[];for(d=0;d=b.length&&a.kd.$c){f=[];for(e=0;eK(a)?a.toUpperCase():[a.substring(0,1).toUpperCase(),a.substring(1)].join("")}function TB(a){if("string"===typeof a)return a;a=Ag(a);var b=NB(a,/-/),c=E(b);b=F(c);c=G(c);return r(RB.g?RB.g(b):RB.call(null,b))?a:U.h(u,b,Gh.a(SB,c))} +function UB(a){var b=function(){if(Af(a)){var c=a.displayName;r(c)||(c=a.name,c="string"===typeof c&&E(c)?c:null)}else c=!1;if(r(c))return c;c=null!=a&&(a.N&4096||n===a.af)?Ag(a):!1;if(r(c))return c;c=Df(a);return Lf(c)?ss.g(c):null}();return r(b)?KB(u.g(b),"$","."):null}function VB(a){return a instanceof z||a instanceof Ge} +var WB=function WB(a){switch(arguments.length){case 0:return WB.C();case 1:return WB.g(arguments[0]);case 2:return WB.a(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e=e&&f.push(lD(a,h));return f},[c,d],b))}}function mD(a,b,c,d){this.tag=a;this.id=b;this.className=c;this.ah=d} +function XL(a,b,c){var d=Hb(a,jD(c));null==d?KC(a)?a=rD(c,a,a):(d=Df(a),d=S.h(d,bz,a),d=VC(d,c),a=rD(c,a,d)):a=d;c={};c.argv=b;b=iD(b);null!=b&&(c.key=b);return GB.createElement(a,c)}function PN(a,b,c,d){var e={};e.Ef=a;e.argv=Fi.a(b,c);b=iD(b);null!=b&&(e.key=b);return GB.createElement(eE(d,a),e)}function UO(a,b,c){var d;if(d=Af(a))d=null==a?null:a.prototype,d=null!=(null==d?null:d.render);return d?XL(a,b,c):PN(a,b,1,c)}var pD={}; +function qD(a,b,c,d){var e=a.tag,f=Q(b,c,null),g=null==f||Lf(f),h=function(){var m=g?f:null;var q=gA.g(m);m=WL(r(q)?S.h(m,gA,WB.g(q)):m,a);m=r(a.ah)?cD(m):$C(m);return r(m)?m:{}}();c+=g?1:0;a:switch(e){case "input":case "textarea":var l=!0;break a;default:l=!1}if(l)return l=function(){var m=d.ai;if(r(m))return m;m=VC(JG,d);return d.ai=m}(),lD(d,Cf(new Y(null,6,5,Z,[l,b,e,h,c,d],null),Df(b)));l=hD(Df(b));null!=l&&(h.key=l);return nD(d,b,e,h,c)} +function tD(a,b){return Wc(Gh.a(function(c){return lD(b,c)},a))} +function sD(a,b,c){null==b&&console.error("vec-to-elem",YS.j(P([a])));var d=Q(a,0,null);switch(d instanceof z?d.W:null){case "\x3e":return c=Q(a,1,null),qD(new mD(c,null,null,null),a,2,b);case "r\x3e":c=Q(a,1,null);d=Q(a,2,null);d=r(d)?d:{};var e=hD(Df(a));null!=e&&(d.key=e);return nD(b,a,c,d,3);case "f\x3e":return PN(Q(a,1,null),a,2,b);case "\x3c\x3e":return d=Q(a,1,null),c=null==d||Lf(d),d=$C(c?d:null),d=r(d)?d:{},c=1+(c?1:0),e=iD(a),null!=e&&(d.key=e),nD(b,a,GB.Fragment,d,c);default:if(VB(d)|| +"string"===typeof d)a:for(;;)switch(c=Q(a,0,null),c=Ag(c),d=c.indexOf("\x3e"),d){case -1:d=YC(pD,c);if(null==d){var f=G(Dk(WC,Ag(c)));d=Q(f,0,null);e=Q(f,1,null);f=Q(f,2,null);f=null==f?null:KB(f,/\./," ");var g=Wg.a(-1,d.indexOf("-"));d=new mD(d,e,f,g);c=pD[c]=d}else c=d;a=qD(c,a,1,b);break a;case 0:a=null;break a;default:a=Cf(new Y(null,2,5,Z,[c.substring(0,d),S.h(Cf(a,null),0,c.substring(d+1))],null),Df(a))}else a=c.h?c.h(d,a,b):c.call(null,d,a,b);return a}} +(function(a){var b=al("G__"),c=r(LC.g(a))?UO:XL;if("undefined"===typeof fD||"undefined"===typeof gD||"undefined"===typeof KG||"undefined"===typeof oJ)oJ=function(d,e,f,g){this.Tc=d;this.id=e;this.Vh=f;this.Zh=g;this.l=393216;this.N=0},oJ.prototype.ha=function(d,e){return new oJ(this.Tc,this.id,this.Vh,e)},oJ.prototype.ga=function(){return this.Zh},oJ.prototype.$h=function(){return this.id},oJ.prototype.Wh=function(d,e){d=this.Vh;return"object"!==sa(e)?e:Nf(e)?sD(e,this,d):Rf(e)?tD(e,this):VB(e)?Ag(e): +(null!=e?e.l&2147483648||n===e.qa||(e.l?0:Pc(Xd,e)):Pc(Xd,e))?YS.j(P([e])):e},oJ.prototype.Xh=function(d,e,f,g,h){return kD(this,e,f,g,h)},oJ.Qc=!0,oJ.sc="reagent.impl.template/t_reagent$impl$template14046",oJ.Wc=function(d){return Wd(d,"reagent.impl.template/t_reagent$impl$template14046")};return new oJ(a,b,c,Zg)})(Zg);function PO(a){return gC.Pi(a)};var wh=vh.a(Mi,uf);function QO(a,b){return setTimeout(a,b)};var RO=zC.g(Zg);var SO=Ah(new p(null,6,[hm,console.log.bind(console),rA,console.warn.bind(console),Dv,console.error.bind(console),zz,console.debug.bind(console),Lz,r(console.group)?console.group.bind(console):console.log.bind(console),Ut,r(console.groupEnd)?console.groupEnd.bind(console):function(){return Me}],null)),TO=function TO(a){for(var c=[],d=arguments.length,e=0;;)if(eD?-D:null)&&null==(M>v?M-v:null)&&null==(0>V?-V:null)&&null==(B> -C?B-C:null)||!Oc(w(t))||(v=y.getBoundingClientRect(),C=new Y(null,2,5,Z,[(v.right+v.left)/2,(v.bottom+v.top)/2],null),v=Q(C,0,null),C=Q(C,1,null),D=ng(window.innerWidth,3),v=zg.g([C=a?Ch(b,a-1):Dh.a(b,kg):e+1>=a?Ch(b,0):Dh.a(b,Ue),b=x.a(d,e),r(b))?(b=IA.g(b),r(b)?b.scrollIntoView({block:"center"}):null):null} -function rR(){var a=Ah(Zg),b=Ah(0),c=OO("");return function(d,e,f){var g=Pr.g(w(f)),h=(null!=d?d.N&16384||n===d.Gh||(d.N?0:Pc(me,d)):Pc(me,d))?d:null,l=function(){var q=Th(g,new Y(null,2,5,Z,[e,qo],null));return r(q)?q:uf}();l=oR(d,l);var m=U.a(jC,Gh.a(pR,l));f=mR(f,e,h,a,c);return new Y(null,7,5,Z,[lQ,jo,new p(null,2,[Ow,"#f3f3f3",vq,"#444444"],null),bm,"1",mx,new Y(null,2,5,Z,[new Y(null,9,5,Z,[Qn,new p(null,1,[jo,new p(null,2,[Gy,"4px 2px",wA,"flex"],null)],null),new Y(null,3,5,Z,[UQ,f,d],null), -new Y(null,2,5,Z,[VQ,f],null),new Y(null,3,5,Z,[Qn,new p(null,1,[jo,new p(null,3,[Gy,"2px",uu,"4px",Ow,"#fff9db"],null)],null),K(l)],null),new Y(null,3,5,Z,[WQ,"↑",function(){return qR(a,b,!0)}],null),new Y(null,3,5,Z,[WQ,"↓",function(){return qR(a,b,!1)}],null),new Y(null,3,5,Z,[XQ,f,c],null),new Y(null,3,5,Z,[YQ,f,c],null)],null),new Y(null,2,5,Z,[PQ,new Y(null,2,5,Z,[fR,new p(null,7,[mm,d,Sz,h,Ny,uf,Mt,Th(g,new Y(null,2,5,Z,[e,Mt],null)),Dt,l,ps,m,to,f],null)],null)],null)],null)],null)}} -function F1(){var a=Ah(Zg),b=OO("");return function(c,d,e){var f=Pr.g(w(e)),g=(null!=c?c.N&16384||n===c.Gh||(c.N?0:Pc(me,c)):Pc(me,c))?c:null,h=Th(f,new Y(null,2,5,Z,[d,qo],null));h=oR(c,r(h)?h:uf);var l=U.a(jC,Gh.a(pR,h));e=mR(e,d,g,a,b);return new Y(null,2,5,Z,[fR,new p(null,7,[mm,c,Sz,g,Ny,uf,Mt,Th(f,new Y(null,2,5,Z,[d,Mt],null)),Dt,h,ps,l,to,e],null)],null)}}var sR=Xc.h(function(a,b){return Vh(a,new Y(null,3,5,Z,[Pr,b,Mt],null),mk([uf]))},Zg,xk(0,1));function tR(a,b,c,d){return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,4,[wA,am,ds,Tu,Xx,10,Ym,et],null)],null),a,new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,2,[wA,am,ds,Tu],null)],null),r(b)?new Y(null,3,5,Z,[Qn,new p(null,1,[jo,new p(null,7,[wA,am,an,5,Wr,4,jB,4,Ow,c,Qt,4,vq,Wl],null)],null),b],null):null,d],null)],null)} +function rR(){var a=Ah(Zg),b=Ah(0),c=X_("");return function(d,e,f){var g=Pr.g(w(f)),h=(null!=d?d.N&16384||n===d.Gh||(d.N?0:Pc(me,d)):Pc(me,d))?d:null,l=function(){var q=Th(g,new Y(null,2,5,Z,[e,qo],null));return r(q)?q:uf}();l=oR(d,l);var m=U.a(jC,Gh.a(pR,l));f=mR(f,e,h,a,c);return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,5,[Ow,"#f3f3f3",vq,"#444444",am,1,wA,am,Ym,et],null)],null),new Y(null,9,5,Z,[Qn,new p(null,1,[jo,new p(null,2,[Gy,"4px 2px",wA,am],null)],null),new Y(null,3,5,Z,[UQ,f,d], +null),new Y(null,2,5,Z,[VQ,f],null),new Y(null,3,5,Z,[Qn,new p(null,1,[jo,new p(null,3,[Gy,"2px",uu,"4px",Ow,"#fff9db"],null)],null),K(l)],null),new Y(null,3,5,Z,[WQ,"↑",function(){return qR(a,b,!0)}],null),new Y(null,3,5,Z,[WQ,"↓",function(){return qR(a,b,!1)}],null),new Y(null,3,5,Z,[XQ,f,c],null),new Y(null,3,5,Z,[YQ,f,c],null)],null),new Y(null,2,5,Z,[PQ,new Y(null,2,5,Z,[fR,new p(null,7,[mm,d,Sz,h,Ny,uf,Mt,Th(g,new Y(null,2,5,Z,[e,Mt],null)),Dt,l,ps,m,to,f],null)],null)],null)],null)}} +var sR=Xc.h(function(a,b){return Vh(a,new Y(null,3,5,Z,[Pr,b,Mt],null),mk([uf]))},Zg,xk(0,1));function F1(){var a=X_(sR);return function(b){return new Y(null,2,5,Z,[fR,new p(null,4,[mm,b,Ny,uf,Mt,Th(w(a),new Y(null,3,5,Z,[Pr,0,Mt],null)),to,l0(a)],null)],null)}};function tR(a,b,c,d){return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,4,[wA,am,ds,Tu,Xx,10,Ym,et],null)],null),a,new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,2,[wA,am,ds,Tu],null)],null),r(b)?new Y(null,3,5,Z,[Qn,new p(null,1,[jo,new p(null,7,[wA,am,an,5,Wr,4,jB,4,Ow,c,Qt,4,vq,Wl],null)],null),b],null):null,d],null)],null)} function uR(a){var b=null!=a&&(a.l&64||n===a.K)?U.a(Zj,a):a;a=x.a(b,Ts);var c=x.a(b,Ds),d=x.a(b,P_),e=x.a(b,Sw),f=x.a(b,R_),g=x.a(b,Pp),h=x.a(b,HZ),l=x.a(b,yq),m=x.a(b,Q_),q=x.a(b,$V),t=x.a(b,Ez),v=x.a(b,Ap),y=x.a(b,Gv),C=x.a(b,Uy),B=x.a(b,$z),D=x.a(b,KV),M=x.a(b,vz);b=x.a(b,Jy);return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,6,[wA,am,am,1,Ow,"#f3f3f3",vq,"#444444",Gy,8,Ym,et],null)],null),new Y(null,13,5,Z,[Qn,new p(null,1,[jo,new p(null,4,[wA,am,Ym,ax,Mv,8,lo,"solid 1px #CCCCCC"],null)], null),new Y(null,5,5,Z,[tR,"Total time",null,null,b],null),new Y(null,2,5,Z,[Qn,new p(null,1,[jo,new p(null,4,[Xn,1,uz,"90%",Ow,"#CCCCCC",Xx,10],null)],null)],null),0c:b}())){Dh.v(a,Xh,pv,function(e){return r(b)?e+(.1>c?.01:c):e-(.1>=c?.01:c/2)});var d=Th(w(a),new Y(null,2,5,Z,[Qz,zy],null));if(r(d))return r(w(LR))&&clearTimeout(w(LR)),Ch(LR,setTimeout(function(){return AP(Nr.g(w(a)),d)},500))}return null} function NR(a){return new Y(null,3,5,Z,[Qn,new p(null,1,[jo,new p(null,3,[Xq,aq,ro,70,em,0],null)],null),new Y(null,5,5,Z,[Qn,new p(null,1,[jo,new p(null,2,[wA,am,Ym,ax],null)],null),new Y(null,3,5,Z,[NQ,new p(null,1,[Fu,function(){return MR(a,!1)}],null),"-"],null),new Y(null,2,5,Z,[Qn,new p(null,1,[jo,new p(null,1,[Xn,5],null)],null)],null),new Y(null,3,5,Z,[NQ,new p(null,1,[Fu,function(){return MR(a,!0)}],null),"+"],null)],null)],null)} -function OR(a,b){var c=EC(function(){return Th(w(b),new Y(null,2,5,Z,[Qz,zy],null))}),d=EC(function(){return pv.g(w(b))}),e=EC(function(){return Ck(Gh.a(function(f){return S.j(f,Pn,I.a(w(c),zy.g(f)),P([Xn,function(){var g=Oo.g(f)*w(d);return(2>g?2:g)|0}(),vq,I.a(w(c),zy.g(f))?"#df691a":I.a(ux.g(f),Hv)?Am:"#219653"]))},w(Sv.g(a))))});return function(){var f=w(d),g=200/f,h=w(e),l=xr.g(sf(h))-Cu.g(F(h))+g|0;return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,6,[uz,100,Xn,"100%",Yl,uo,Vl,Rm,Ow,"#f3f3f3", +function OR(a,b){var c=fz(function(){return Th(w(b),new Y(null,2,5,Z,[Qz,zy],null))}),d=fz(function(){return pv.g(w(b))}),e=fz(function(){return Ck(Gh.a(function(f){return S.j(f,Pn,I.a(w(c),zy.g(f)),P([Xn,function(){var g=Oo.g(f)*w(d);return(2>g?2:g)|0}(),vq,I.a(w(c),zy.g(f))?"#df691a":I.a(ux.g(f),Hv)?Am:"#219653"]))},w(Sv.g(a))))});return function(){var f=w(d),g=200/f,h=w(e),l=xr.g(sf(h))-Cu.g(F(h))+g|0;return new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,6,[uz,100,Xn,"100%",Yl,uo,Vl,Rm,Ow,"#f3f3f3", ht,100],null)],null),new Y(null,4,5,Z,[Qn,new p(null,1,[jo,new p(null,6,[wA,am,Ym,ax,Xn,"100%",uz,100,Xq,Bw,Yl,uo],null)],null),function(){return function t(q){return new Bg(null,function(){for(;;){var v=E(q);if(v){if(Of(v)){var y=ie(v),C=K(y),B=Fg(C);a:for(var D=0;;)if(D div { display: inline; } - +input { + outline:none; +} diff --git a/src/re_frisk_remote/server/client/main.cljs b/src/re_frisk_remote/server/client/main.cljs index ec6537f..2b02abb 100644 --- a/src/re_frisk_remote/server/client/main.cljs +++ b/src/re_frisk_remote/server/client/main.cljs @@ -1,7 +1,7 @@ (ns re-frisk-remote.server.client.main - (:require-macros [reagent.ratom :refer [reaction]]) + (:require-macros [re-frisk.inlined-deps.reagent.v1v0v0.reagent.ratom :refer [reaction]]) (:require - [reagent.dom :as rdom] + [re-frisk.inlined-deps.reagent.v1v0v0.reagent.dom :as rdom] [taoensso.sente :as sente] [taoensso.sente.packers.transit :as sente-transit] [re-frisk.core :as re-frisk]