Fork me on GitHub
#helix
<
2020-05-31
>
geraldodev14:05:50

@lilactown Do you advise some integration with css-in-js like $ ? Material-ui for example, it bundles a js-in-css solution https://gist.github.com/geraldodev/a9b60dd611d1628f9413dd6de6c3c974#file-material_ui_helix-cljs-L14 . It avoids global css which is a good thing.

wilkerlucio19:05:58

I'm playing with Helix and React Native, I'm trying to understand the error here:

(apply $ rn/View {:style #js {:flex 1 :alignItems "center" :justifyContent "center"}}
      [(rnc/text {:style #js {:fontSize 36}} "Hello Helix!")
       (rnc/button {:title "Click me"})])

wilkerlucio19:05:20

the code is for experimenting purposes (trying to wrap react native stuff with factory)

wilkerlucio19:05:43

but that code doesn't work, it errors with [object Object] is not ISeqable

wilkerlucio19:05:13

the stack from RN is quite incomplete, so not sure, I was using the apply $ to isolate the constructor

wilkerlucio19:05:25

when I use createElement directly from React it works fine

wilkerlucio19:05:31

digging a bit, the problem is happening during -native-props call

alidlorenzo20:05:22

doing this (apply helix.core/$ rn/Text {:style #js {:flex 1}} ["Hello" "World"]) works for me so I imagine the error has to do with the component children

wilkerlucio21:05:11

@alidcastano I ran a couple of experiments to test that, but in the end, when I kept the props clean, it failed, when used the :style, it broke

wilkerlucio21:05:51

was specifically problem with rn/View from React Native from MacOS, and I can see a difference, the View is a string component (native component), the others are not

wilkerlucio21:05:06

so I'm guessing the issue is with the fn version of $ when used with native elements

wilkerlucio21:05:28

you can break any with: (apply $ "div" {:style #js {:flex 1}} ["child"])

wilkerlucio21:05:48

actually, I'm writing an issue, but as I test more (not on RN now, just on regular react on browser) I see it breaks with this: ($ "div" {:style #js {:flex 1}})

alidlorenzo22:05:21

you might want to pass ^:native to $ that might fix it

wilkerlucio22:05:27

@alidcastano I figured a different problem, not really an issue per se, but a confusing situation

alidlorenzo22:05:27

but this looks to still be a bug

lilactown23:05:39

@wilkerlucio is there a particular reason you’re passing in styles as a JS object instead of a map?

wilkerlucio23:05:04

the trick part is because its not clear with RN components are native and which are not

wilkerlucio23:05:34

and that may vary depending on which RN impl its being targetted (mac os RN may have different settings than Windows, than ios, etc... and those can change over time)

lilactown23:05:46

the idea is that if you’re using $ then you should be able to just passing in maps

lilactown23:05:03

so I’m not sure yet why you’d want to literally pass in a JS obj yet

wilkerlucio23:05:12

for example, Button in RN for MacOS is not a native component

lilactown23:05:29

what do you mean by “native” exactly?

wilkerlucio23:05:46

the same thing you mean in helix when you check for native when running $

wilkerlucio23:05:56

if its a string or keyword

wilkerlucio23:05:05

or if its a component

lilactown23:05:09

okay, it’s a bit of a leaky thing beyond react-dom so that’s why i’m asking

wilkerlucio23:05:15

yeah, so using the js-obj could be the safe version for incosistent situations like this

lilactown23:05:45

yeah there’s a couple ways to handle this, at the application level and at the library (helix level)

lilactown23:05:23

one thing you can do is annotate the Button symbol with ^:native

lilactown23:05:34

e.g. ($ ^:native rn/Button {:style {:flex 1}})

wilkerlucio23:05:16

but then I have to know which component is which (native or not)

wilkerlucio23:05:29

if I could just throw #js in all of then, I can avoid caring about it

wilkerlucio23:05:53

also, I fear changes between versions, a non-native component today may be turned native on the next version

lilactown23:05:31

the “native” classification is not really useful beyond react-dom

lilactown23:05:52

I regret adding it tbh

lilactown23:05:09

the only thing that really matters is whether a component expects :style as a JS object or not

lilactown23:05:26

so all react-native components are “native” in that sense

wilkerlucio23:05:41

yeah, but in impl that varies, which is the issue (which is not true for react dom)

lilactown23:05:11

when you use the $ macro it doesn’t really tho

lilactown23:05:29

($ foo) is always assumed to be non-“native”

lilactown23:05:36

because it’s a symbol

wilkerlucio23:05:45

yeah, I only have problems when using props with :style

wilkerlucio23:05:59

ah, sorry, gotcha

wilkerlucio23:05:14

yeah, I got the problem because I'm wrapping the components with factory

lilactown23:05:40

it sounds like e.g. rn/View is actually a string?

wilkerlucio23:05:53

that's what I mean by native 😛

lilactown23:05:54

I never expected that

wilkerlucio23:05:05

rn/View
=> "RCTView"
rn/Text
=>
#js{"$$typeof" "Symbol(react.forward_ref)",
    :render #object[Text],
    :displayName "Text",
    :propTypes #js{:ellipsizeMode #object[bound checkType],
                   :numberOfLines #object[bound checkType],
                   :textBreakStrategy #object[bound checkType],
                   :onLayout #object[bound checkType],
                   :onPress #object[bound checkType],
                   :onLongPress #object[bound checkType],
                   :pressRetentionOffset #object[bound checkType],
                   :selectable #object[bound checkType],
                   :selectionColor #object[bound colorPropType],
                   :suppressHighlighting #object[bound checkType],
                   :style #object[Function],
                   :testID #object[bound checkType],
                   :nativeID #object[bound checkType],
                   :allowFontScaling #object[bound checkType],
                   :maxFontSizeMultiplier #object[bound checkType],
                   :accessible #object[bound checkType],
                   :adjustsFontSizeToFit #object[bound checkType],
                   :minimumFontScale #object[bound checkType],
                   :disabled #object[bound checkType],
                   :dataDetectorType #object[bound checkType]}}
rn/Button
=> #object[Button]

lilactown23:05:27

I don’t really exercise the runtime version of $ much

wilkerlucio23:05:12

no worries, I'm just a new user hitting unexplored code paths 🙂

lilactown23:05:22

FWIW what I’d like to do is create a namespace of macros similar to helix.dom

wilkerlucio23:05:50

@lilactown and you plan to also support #js style on native?

wilkerlucio23:05:08

I think the macro ns may be a problem, because you can't know what to expect from the components

wilkerlucio23:05:28

even though Button is not native on MacOS RN, it may be native in other impls

wilkerlucio23:05:42

so we can't know for sure what each is, makes sense?

lilactown23:05:56

@wilkerlucio using a macro routes around this problem completely

lilactown23:05:09

the macro $ is completely consistent

lilactown23:05:51

($ ^:native rn/View {:style {flex 1}}) will always convert the :style prop to a JS object

lilactown23:05:23

$ checks at macro time whether the first argument is a string/keyword or a symbol

lilactown23:05:44

if it’s a symbol, it treats it as “non-native” unless it’s annotated with ^:native metadata

lilactown23:05:07

so rn/View can go from at runtime being a string, function, class, memoized, whatever, it doesn’t matter

lilactown23:05:14

a macro would do something like: (defmacro view [& args] `($ ^:native rn/View [email protected])) which would always be unambiguous. no matter what rn/View is at runtime, it would always have the same behavior

lilactown23:05:11

let’s define native to be: “a component which requires transformation of props before construction, e.g. :style prop to be a JS object, :class to be renamed to :className, etc.”

lilactown23:05:01

then whether or not rn/View is a string or not is irrelevant, it will always be “native”. the detection of string/keyword is just a dumb heuristic to try and get that information at compile time

lilactown23:05:00

the inconsistency we’re running into now is that if you apply this same heuristic at runtime, it’s even dumber, because apparently React Native has some of it’s “native” components as strings and other “native” components as functions / memoized components /etc.

lilactown23:05:27

so the easy answer is: don’t do this at runtime :P

lilactown23:05:40

but I’ll have to think more about this issue before coming up with an encompassing solution

lilactown23:05:51

I won’t be at a computer today, so fix will have to wait until later this week

lilactown23:05:05

for now, I can probably put a bandaid on it by not blowing up if you pass in a JS object

lilactown23:05:25

but ultimately I need to think harder on the API of $ and how it extends beyond react-dom