helix

https://github.com/Lokeh/helix
lilactown 2020-02-14T02:29:34.235800Z

wrote up some thoughts on “Why Helix”: https://github.com/Lokeh/helix/blob/master/docs/motivation.md also some FAQs, like “What about hx?” and “What about hiccup?“: https://github.com/Lokeh/helix/blob/master/docs/faq.md the “What about hiccup?” FAQ goes into some of the the tradeoffs that hiccup parsing has and also explains some of the motivations to move away from Reagent’s all-state-belongs-in-a-reactive-atom

👍 5
Derek Passen 2020-02-14T15:11:28.241400Z

The link to ‘creating a custom macro’ at the bottom of the FAQ has an extra /docs/ in it.

lilactown 2020-02-14T16:25:51.241700Z

Thanks!

alidlorenzo 2020-02-14T02:38:58.236900Z

currently setting up a project that uses both helix and fulcro 🙂

lilactown 2020-02-14T02:59:41.237300Z

nice! what's the use-case for using helix and fulcro together?

lilactown 2020-02-14T03:00:14.237900Z

(I don't know much about fulcro, other than I know it has ways of creating components and elements)

alidlorenzo 2020-02-14T03:21:57.240200Z

i'd rather use react hooks for handling component local state i find it easier to keep state in sync that way (rather than messing with componentDidMount and componentDidUpdate hooks)

alidlorenzo 2020-02-14T03:22:59.241Z

still learning fulcro but looks like it encourages making most state global, which I dislike, so definitely want to have full power of react hooks at my disposal

y.khmelevskii 2020-02-14T20:59:46.245Z

Hi @lilactown! It would be great to add support react defaultProps . Currently I should do something like this

(defnc <Button>
  [props]
  (d/button props))

(set! (.-defaultProps <Button>) #js {:type :submit})
I’m not sure about best interface but I can see 2 ways to manage it: 1.
(defnc <Button>
  [props]
  {:default {:type :submit}}
  (d/button props))
2.
(defnc <Button>
  [props]
  (d/button props))

(defdefp <Button>
  {:type :submit})
Does it make sense? If yes, I think I will be able to implement it and push PR

lilactown 2020-02-14T21:24:08.248Z

@y.khmelevskii you can specify defaults in two ways (depending on what you need):

(defnc Button
  [{:keys [type] :or {type :submit}}]
  ;; use `type` inside the body. if it's not passed it will default to `:submit`
  ...)
or, if you need to pass it to a child with a default:
(defnc Button
  [props]
  (d/button {& (merge {:type :submit} props)}))

lilactown 2020-02-14T21:24:50.248800Z

both of these just use native ClojureScript features and have nothing to do with React defaultProps, which IMO are an anti-pattern and might be deprecated. See https://github.com/reactjs/rfcs/pull/107

y.khmelevskii 2020-02-14T21:43:59.251100Z

hmm, it’s surprising for me to know that default props could be deprecated. In my case both of your examples doesn’t work. But anyway I will think about another approach, thank you

lilactown 2020-02-14T21:46:02.251400Z

what do you mean they don’t work? how do they not work?

lilactown 2020-02-14T21:46:54.251900Z

if they do not work, there’s a bug in helix and I should fix it. please let me know more information

y.khmelevskii 2020-02-14T21:50:34.253300Z

my case a little bit difficult then I described above. I’m trying to describe correctly my case

y.khmelevskii 2020-02-14T22:26:07.257600Z

so, I created a tiny wrapper for emotion (styled components) js lib https://emotion.sh/docs/styled If removing all macros and create styled component using interop I have something like this:

["@emotion/styled" :as styled]
...
(defnc button
  [props]
  (d/button {& props}))

;; (set! (.-defaultProps button) #js {:kind :primary})

(def <Button>
  ((.default styled button)
   (clj->js
    [{:color :red}
     #(when (= (-> % js->clj (get "kind"))
               :primary)
        (clj->js {:color :green}))])))
I need to apply color: green if :kind prop is :primary. By default this prop should be :primary. So, this example works only when I uncomment set! line. Of course with a few macros syntax looks much better

lilactown 2020-02-14T22:36:40.260500Z

(def <Button>
  (-> #js [#js {:color :red}
           (fn [props]
             (let [{:keys [type] :or {type :primary}} (cljs-bean.core/bean props)]
               (when (= :primary type)
                 #js {:color "green"})))]
      ((.default styled button)))

y.khmelevskii 2020-02-14T22:47:55.264600Z

yes, I understand :) you moved defaults to styled component. But it’s not a convenient because I need to check type props in many css rules and in your approach I always should define default value:

(def <Button>
  (-> #js [#js {:color :red}
           ;; type
           (fn [props]
             (let [{:keys [type] :or {type :primary}} (cljs-bean.core/bean props)]
               (when (= :primary type)
                 #js {:color "green"})))
           ;; disable?
           (fn [props]
             (let [{:keys [disable? type] :or {type :primary}} (cljs-bean.core/bean props)]
               (when (and disable? (= :primary type))
                 #js {:color "gray"})))]
      ((.default styled button)))
of course it’s artificial example

y.khmelevskii 2020-02-14T22:49:32.265800Z

There is more realistic example

(defcss-when --primary [{:keys [kind]}]
  (= kind :primary)
  {:color :green})

(defcss-when --disable? [{:keys [disable? kind]}]
  (and disable? (= kind :primary))
  {:color :gray})

(defstyled <Button> button
  {:border-radius 8
   :padding       "12px 32px"
   :border        :none
   :text-align    :center
   :cursor        :pointer}
  --primary
  --disabled?)
in your case I should do
(defcss-when --primary [{:keys [kind] :or {kind :primary}}]
and
(defcss-when --disable? [{:keys [disable? kind] :or {kind :primary}}]
but I want set default properties once

lilactown 2020-02-14T23:05:31.266900Z

yeah in this case I guess you do want to set default props because styled components tries to be smart and read the .-defaultProps property on the component you pass in

lilactown 2020-02-14T23:10:24.271300Z

FWIW I do not like styled components. I vastly prefer just generating the classes and using them in a component:

(defcss --primary
  {:color :green})

(defcss --disabled
  {:color :gray})

(defcss default
  {:border-radius 8
   :padding "12px 32px"
   :border :none
   :text-align :center
   :cursor :pointer})

(defnc Button
  [{:keys [type disable?] :or {type :primary}]
  (let [primary? (= :primary type)]
    (d/button {:class (cx default 
                          {primary? --primary}
                          {(and primary? disable?) --disabled})
               & props))

lilactown 2020-02-14T23:10:44.271800Z

cx is a wrapper around emotion/cx

lilactown 2020-02-14T23:10:58.272200Z

that’s pretty much verbatim how we write code at work

lilactown 2020-02-14T23:13:10.273Z

this way your styling isn’t coupled to the props shape of your component. so you don’t end up repeating yourself over and over