-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using external react components #20
Comments
When you write Just create component with interop syntax, e.g. |
@abhishiv have you solved this? |
I had no problem using a react-treeview component with rum. May be worth mentioning that rum is compatible w/ react components. I know that quiescent does |
Is there an easy way to compose external react components, like say js/ReactBootstrap.ModalDialog? I've only been able to create external react components with a (js/React.createElement js/ReactBootstrap.Button (clj->js args) content) command, which is not composable. I know in Reagent, you can just say [ReactBootstrap.Button args "label"] |
I think this could be clear in docs. Reagent has a function to adapt class, and I saw something similar in a cljs-material-ui wrapper, "adapt-rum-class" (https://github.com/madvas/cljs-react-material-ui/blob/f66e8047b556e41dce45b1391cae9ca13f25242f/src/cljs_react_material_ui/core.clj). Is it needed? |
Ran into this today...
Would really appreciate it if an utility like this can be added to rum. It seems like a natural thing to want to do. |
Thanks for this, I adapted this for use within my Antizer library, but also added a few things:
(require '[clojure.string :as string])
(require '[clojure.walk :as w])
(defn kebab-case->camel-case
"Converts from kebab case to camel case, eg: on-click to onClick"
[input]
(let [words (string/split input #"-")
capitalize (->> (rest words)
(map #(apply str (string/upper-case (first %)) (rest %))))]
(apply str (first words) capitalize)))
(defn map-keys->camel-case
"Stringifys all the keys of a cljs hashmap and converts them
from kebab case to camel case. If :html-props option is specified,
then rename the html properties values to their dom equivalent
before conversion"
[data & {:keys [html-props]}]
(let [convert-to-camel (fn [[key value]]
[(kebab-case->camel-case (name key)) value])]
(w/postwalk (fn [x]
(if (map? x)
(let [new-map (if html-props
(rename-keys x {:class :className :for :htmlFor})
x)]
(into {} (map convert-to-camel new-map)))
x))
data)))
(defn adapt-class [react-class & args]
(let [[opts children] (if (map? (first args))
[(first args) (rest args)]
[{} args])
type# (first children)
;; we have to make sure to check if the children is sequential
;; as a list can be returned, eg: from a (for)
new-children (if (sequential? type#)
[(sablono.interpreter/interpret children)]
children)
;; convert any options key value to a react element, if
;; a valid html element tag is used, using sablono
vector->react-elems (fn [[key val]]
(if (sequential? val)
[key (sablono.interpreter/interpret val)]
[key val]))
new-options (into {} (map vector->react-elems opts))]
(apply js/React.createElement react-class
;; sablono html-to-dom-attrs does not work for nested hash-maps
(clj->js (map-keys->camel-case new-options :html-props true))
new-children))) |
@priornix 's solution above has the problem where any data prop you pass in to the component, if it's in the form of a hash-map, will get keys mangled. |
We'll probably introduce something like this. @piranha @martinklepsch Do you have anything like that in your code? |
We don't have a lot of external React components and for those we have integration is just some custom code. We used antizer in Suppliers UI though and I didn't touch that for a while, but I think it worked well. :) And we have more external deps there. |
Actually, since we are going to fork Sablono I'm more into introducing |
Maybe... I'm not a fan of that cryptic stuff (hard to search for, hard to understand if you're seeing it for the first time). I'd prefer something like |
I'm perhaps biased since I'm using Reagent now and it feels good to be able to use JS components inline, w/o making another def using class adapter. But I'm also fine with going both ways. |
Fixed in 3938ac1 |
This might be be just something missing from documentation, but I'm having a small issue getting external components to work. I'm using that like this:
[(.-Route js/ReactRouter) {:name "home"} ]
where window.ReactRouter.Route is the component I want to use. It throws an error from this function.
Any pointers on how to get non rum components to work?
The text was updated successfully, but these errors were encountered: