Skip to content

Commit

Permalink
Add usability improvements and update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
niwinz committed Dec 18, 2024
1 parent 28783a7 commit 178393d
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 527 deletions.
544 changes: 250 additions & 294 deletions doc/user-guide.md

Large diffs are not rendered by default.

75 changes: 37 additions & 38 deletions examples/rumext/examples/binary_clock.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@

(def *bclock-renders (atom 0))

(mf/defc render-count
(mf/defc render-count*
[props]
(let [renders (mf/deref *bclock-renders)]
[:div.stats "Renders: " renders]))

(mf/defc bit
{::mf/wrap-props false}
(mf/defc bit*
[{:keys [n b]}]
(mf/with-effect [n b]
(swap! *bclock-renders inc))
Expand All @@ -22,7 +21,7 @@
[:td.bclock-bit {:style {:background-color color}}]
[:td.bclock-bit {}])))

(mf/defc binary-clock
(mf/defc binary-clock*
[]
(let [ts (mf/deref util/*clock)
msec (mod ts 1000)
Expand All @@ -41,41 +40,41 @@
[:table.bclock
[:tbody
[:tr
[:td] [:& bit {:n hl :b 3}] [:th]
[:td] [:& bit {:n ml :b 3}] [:th]
[:td] [:& bit {:n sl :b 3}] [:th]
[:& bit {:n msh :b 3}]
[:& bit {:n msm :b 3}]
[:& bit {:n msl :b 3}]]
[:td] [:> bit* {:n hl :b 3}] [:th]
[:td] [:> bit* {:n ml :b 3}] [:th]
[:td] [:> bit* {:n sl :b 3}] [:th]
[:> bit* {:n msh :b 3}]
[:> bit* {:n msm :b 3}]
[:> bit* {:n msl :b 3}]]
[:tr
[:td] [:& bit {:n hl :b 2}] [:th]
[:& bit {:n mh :b 2}]
[:& bit {:n ml :b 2}] [:th]
[:& bit {:n sh :b 2}]
[:& bit {:n sl :b 2}] [:th]
[:& bit {:n msh :b 2}]
[:& bit {:n msm :b 2}]
[:& bit {:n msl :b 2}]]
[:td] [:> bit* {:n hl :b 2}] [:th]
[:> bit* {:n mh :b 2}]
[:> bit* {:n ml :b 2}] [:th]
[:> bit* {:n sh :b 2}]
[:> bit* {:n sl :b 2}] [:th]
[:> bit* {:n msh :b 2}]
[:> bit* {:n msm :b 2}]
[:> bit* {:n msl :b 2}]]
[:tr
[:& bit {:n hh :b 1}]
[:& bit {:n hl :b 1}] [:th]
[:& bit {:n mh :b 1}]
[:& bit {:n ml :b 1}] [:th]
[:& bit {:n sh :b 1}]
[:& bit {:n sl :b 1}] [:th]
[:& bit {:n msh :b 1}]
[:& bit {:n msm :b 1}]
[:& bit {:n msl :b 1}]]
[:> bit* {:n hh :b 1}]
[:> bit* {:n hl :b 1}] [:th]
[:> bit* {:n mh :b 1}]
[:> bit* {:n ml :b 1}] [:th]
[:> bit* {:n sh :b 1}]
[:> bit* {:n sl :b 1}] [:th]
[:> bit* {:n msh :b 1}]
[:> bit* {:n msm :b 1}]
[:> bit* {:n msl :b 1}]]
[:tr
[:& bit {:n hh :b 0}]
[:& bit {:n hl :b 0}] [:th]
[:& bit {:n mh :b 0}]
[:& bit {:n ml :b 0}] [:th]
[:& bit {:n sh :b 0}]
[:& bit {:n sl :b 0}] [:th]
[:& bit {:n msh :b 0}]
[:& bit {:n msm :b 0}]
[:& bit {:n msl :b 0}]]
[:> bit* {:n hh :b 0}]
[:> bit* {:n hl :b 0}] [:th]
[:> bit* {:n mh :b 0}]
[:> bit* {:n ml :b 0}] [:th]
[:> bit* {:n sh :b 0}]
[:> bit* {:n sl :b 0}] [:th]
[:> bit* {:n msh :b 0}]
[:> bit* {:n msm :b 0}]
[:> bit* {:n msl :b 0}]]
[:tr
[:th hh]
[:th hl]
Expand All @@ -91,11 +90,11 @@
[:th msl]]
[:tr
[:th {:col-span 8}
[:& render-count {}]]]]]))
[:> render-count* {}]]]]]))

(defonce root
(mf/create-root (dom/getElement "binary-clock")))

(defn ^:after-load mount! []
(mf/render! root (mf/element binary-clock)))
(mf/render! root (mf/element binary-clock*)))

20 changes: 10 additions & 10 deletions examples/rumext/examples/controls.cljs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
(ns rumext.examples.controls
(:require [goog.dom :as dom]
[rumext.v2 :as mf]
[rumext.examples.util :as util]))
(:require
[goog.dom :as dom]
[rumext.v2 :as mf]
[rumext.examples.util :as util]))

;; generic “atom editor” component
(mf/defc input
(mf/defc input*
[{:keys [color] :as props}]
(let [value (mf/deref color)]
[:input {:type "text"
Expand All @@ -13,21 +13,21 @@
:on-change #(reset! color (.. % -target -value))}]))

;; Raw top-level component, everything interesting is happening inside
(mf/defc controls
(mf/defc controls*
[props]
[:dl
[:dt "Color: "]
[:dd
[:& input {:color util/*color}]]
[:> input* {:color util/*color}]]
;; Binding another component to the same atom will keep 2 input boxes in sync
[:dt "Clone: "]
[:dd
(mf/jsx input #js {:color util/*color})]
(mf/jsx input* #js {:color util/*color})]
[:dt "Color: "]
[:dd {} (util/watches-count {:iref util/*color}) " watches"]

[:dt "Tick: "]
[:dd [:& input {:color util/*speed}] " ms"]
[:dd [:> input* {:color util/*speed}] " ms"]
[:dt "Time:"]
[:dd {} (util/watches-count {:iref util/*clock}) " watches"]
])
Expand All @@ -36,5 +36,5 @@
(mf/create-root (dom/getElement "controls")))

(defn ^:after-load mount! []
(mf/render! root (mf/element controls)))
(mf/render! root (mf/element controls*)))

12 changes: 6 additions & 6 deletions examples/rumext/examples/local_state.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[goog.dom :as dom]
[malli.core :as m]
[rumext.v2 :as mf]
[rumext.v2.util :as mfu]
[rumext.examples.util :as util]))

(def schema:label
Expand All @@ -11,11 +12,9 @@
[:title string?]
[:n number?]])

(mf/defc label
(mf/defc label*
{::mf/memo true
::mf/props :react
::mf/schema schema:label
}
::mf/schema schema:label}
[{:keys [class title n] :as props :rest others}]
(let [ref (mf/use-var nil)
props (mf/spread-props others {:class (or class "my-label")})]
Expand All @@ -36,12 +35,13 @@
:n 0}
:counter2 {:title "Counter 2"
:n 0}}))]

[:section {:class "counters" :style {:-webkit-border-radius "10px"}}
[:hr]
(let [{:keys [title n]} (:counter1 @local)]
[:> label {:n n :title title :data-foobar 1 :on-click identity :id "foobar"}])
[:> label* {:n n :title title :data-foobar 1 :on-click identity :id "foobar"}])
(let [{:keys [title n]} (:counter2 @local)]
[:> label {:title title :n n :on-click identity}])
[:> label* {:title title :n n :on-click identity}])
[:button {:on-click #(swap! local update-in [:counter1 :n] inc)} "Increment Counter 1"]
[:button {:on-click #(swap! local update-in [:counter2 :n] inc)} "Increment Counter 2"]]))

Expand Down
1 change: 0 additions & 1 deletion examples/rumext/examples/portals.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
[goog.dom :as dom]))

(mf/defc portal*
{::mf/props :obj}
[{:keys [state]}]
[:div {:on-click (fn [_] (swap! state inc))
:style { :user-select "none", :cursor "pointer" }}
Expand Down
10 changes: 4 additions & 6 deletions examples/rumext/examples/util.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@
(mf/defc watches-count
[{:keys [iref] :as props}]
(let [state (mf/use-state 0)]
(mf/use-effect
(mf/deps iref)
(fn []
(let [sem (js/setInterval #(swap! state inc) 1000)]
#(do
(js/clearInterval sem)))))
(mf/with-effect [iref]
(let [sem (js/setInterval #(swap! state inc) 1000)]
#(do
(js/clearInterval sem))))

[:span (.-size (.-watches ^js iref))]))

Expand Down
84 changes: 43 additions & 41 deletions src/rumext/v2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@
[props params]
(if (seq k-props)
(reduce (fn [[props params] [ks kp]]
;; (prn "KKK" ks kp)
(let [kp (if react-props?
(util/ident->prop kp)
(name kp))]
Expand Down Expand Up @@ -326,6 +325,11 @@
~(when-let [registry (::register meta)]
`(swap! ~registry (fn [state#] (assoc state# ~(::register-as meta (keyword (str cname))) ~cname)))))))

(defmacro deps
"A convenience macro version of mf/deps function"
[& params]
`(cljs.core/array ~@(map (fn [s] `(rumext.v2/adapt ~s)) params)))

(defmacro with-memo
"A convenience syntactic abstraction (macro) for `useMemo`"
[deps & body]
Expand Down Expand Up @@ -442,51 +446,49 @@
[props#]
[:> (deref loadable#) props#])))))))))

(defmacro spread
"A helper for create spread js object operations. Leaves the keys
untouched."
[target & [other :as rest]]
(defmacro spread-object
"A helper for spread two js objects, adapting compile time known
keys to cameCase.
You can pass `:rumext.v2/transform false` on `other` metadata
for disable key casing transformation."
[target other]
(assert (or (symbol? target)
(map? target))
"only symbols or maps accepted on target")
(assert (or (= (count rest) 0)
(and (= (count rest) 1)
(or (symbol? other)
(map? other)))
(and (even? (count rest))
(or (keyword? other)
(string? other))))
"only symbols, map or named parameters allowed for the spread")
(let [other (cond
(> (count rest) 1) (apply hash-map rest)
(= (count rest) 0) {}
:else other)]
(hc/compile-to-js-spread target other identity)))

(assert (or (symbol? other)
(map? other))
"only symbols or map allowed for the spread")

(let [transform? (get (meta other) ::transform true)
compile-prop (if transform?
(partial hc/compile-prop 2)
identity)]
(hc/compile-to-js-spread target other compile-prop)))

(defmacro spread-props
"A helper for create spread js object operations. Adapts compile
time known keys to the react props standard transformations."
[target & [other :as rest]]
"A helper for spread two js objects using react conventions for
compile time known props keys names."
[target other]
(assert (or (symbol? target)
(map? target))
"only symbols or maps accepted on target")
(assert (or (= (count rest) 0)
(and (= (count rest) 1)
(or (symbol? other)
(map? other)))
(and (even? (count rest))
(or (keyword? other)
(string? other))))
"only symbols, map or named parameters allowed for the spread")
(let [other (cond
(> (count rest) 1) (apply hash-map rest)
(= (count rest) 0) {}
:else other)]
(hc/compile-to-js-spread target other hc/compile-prop)))

(defmacro js
"A helper for convert literal datastructures recursivelly into js
data structures at compile time."
[expr]
(binding [hc/*transform-props-recursive* 0]
(hc/compile-prop-value expr)))

(assert (or (symbol? other)
(map? other))
"only symbols or map allowed for the spread")

(hc/compile-to-js-spread target other hc/compile-prop))

(defmacro props
"A helper for convert literal datastructures into js data
structures at compile time using react props convention."
[value]
(let [recursive? (get (meta value) ::recursive false)]
(hc/compile-props-to-js value ::hc/transform-props-recursive recursive?)))

(defmacro object
[value]
(let [recursive? (get (meta value) ::recursive true)]
(hc/compile-coll-to-js value ::hc/transform-props-recursive recursive?)))
Loading

0 comments on commit 178393d

Please sign in to comment.