Fork me on GitHub
#clojurescript
<
2018-08-07
>
idiomancy12:08:35

are there any dominant patterns/consensus in the clojurescript ecosystem for "CSS at scale"? Like, do we use Atomic Design, inline styles a la react, Atomic CSS, something different..?

idiomancy12:08:27

learning CSS in depth for the first time along with reagent, meaning I'm not coming to the table with something I'm already familiar with

idiomancy12:08:38

so, looking for direction. Seems like patterns of the object oriented lineage are all the rage in CSS right now 💤💤

Empperi12:08:08

I've always preferred component based approach

Empperi12:08:19

keep two things separate: theme and component styles

Empperi12:08:35

theme provides basic layout, colors etc

Empperi12:08:58

component styles override those by using a higher specifity

Empperi13:08:03

one can reduce the amount of duplication in component CSS files by referring to common styles. Naturally not that easy in plain CSS but I would guess no one really writes plain CSS these days anymore...

Empperi13:08:48

this can lead to relatively big CSS file in the end footprint wise which is a drawback

Empperi13:08:13

but it keeps everything well organized and understandable

idiomancy13:08:34

by component styles, do you mean inline styling in the hiccup, or do you mean grouping your CSS into components

Empperi13:08:15

well it depends on how you like to build your components but with plain html example:

<div data-component="component-name">
  <span>something</span>
</div>

and in CSS:

[data-component="component-name"] {
  span {
    font-weight: bold;
  }
}

Empperi13:08:45

one doesn't necessarily have to use that way to group components but it's one way I've used in the past succesfully

idiomancy13:08:18

gotcha. I mean that makes sense to me

Empperi13:08:02

that way the component CSS declaration for span has a higher specifity than the styles defined within theme level where it would be just span { <styles here> }

Empperi13:08:16

and thus you can provide basic styling at theme level and override what's needed for component

idiomancy13:08:31

right. lets you work on components in isolation, and lets components be the fundamental blocks of composition

Empperi13:08:51

now things CAN get a bit hairy with nested components 🙂

idiomancy13:08:01

hmmm, yeah, I could see that

Empperi13:08:04

which you will end up using

Empperi13:08:10

but one solves those case by case

Empperi13:08:30

it depends on project and what you are doing what works best

Empperi13:08:52

web components solve all these nasty things

Empperi13:08:27

unfortunately not everything is still supported by major browsers of that spec

idiomancy13:08:03

feels like CSS is a weird orphan of the "modern" web.

Empperi13:08:26

it was never originally designed for the scale it is being used today

Empperi13:08:57

web components provide us shadow dom which allows us to define style definitions in isolation in relation to rest of the DOM

Empperi13:08:21

which will remove the problems with nested components styles getting mixed up

Empperi13:08:36

...and whole bunch of other problems too regarding just javascript

Empperi13:08:55

it has taken a LONG time for that to arrive into browsers though

😩 4
idiomancy13:08:38

Alright, well, I guess I'll just stick to webcomponent styling. That seems like both the path of least resistance (I really don't want to learn pattern libraries and atomic design) and the most compatible with reagent's philosophy. Thanks, @niklas.collin!

Empperi13:08:57

no problem

Empperi13:08:14

that has worked for me quite well, there are some problem areas but one can usually solve those individually case by case

Empperi13:08:25

and in my opinion, going the component way and thinking scales best in general when creating UIs

Empperi13:08:45

requires some discipline though

idiomancy13:08:51

yeah. It's just too weird having 2 different units of composition between javascript and CSS

Empperi13:08:22

one way to handle that mess is to use garden css and inline your styles with the components

Empperi13:08:48

meaning, whole bunch of <style> declarations in DOM inlined

Empperi13:08:11

but there are caveats to that too, mainly caching

Empperi13:08:26

it might be a problem or it might not, it depends

idiomancy13:08:26

That's an interesting point right there. because I'm actually kind of sold on the idea that javascript should dynamically inject classes rather than styles, if for no other reason than j-unit tests target classes

idiomancy13:08:56

so if you've got some cheap testing help, it'd be easier for them to write automation against explicit classes

Empperi13:08:20

I would not start injecting stuff within style attribute

Empperi13:08:52

but use just CSS. But I'm meaning you can have your CSS declarations in a separate file or you can have them within HTML file inlined within <style> element

Empperi13:08:25

if you have a high volume site with a lot of expected full page refreshes (like, a news site) then you should NOT do the inlining

Empperi13:08:02

but if you have a webapp with users logging in once and then hanging on for the whole day then it really doesn't matter that much

Empperi13:08:31

what I'm currently working on is more of the latter and I went with a solution where the whole app, HTML, JS and CSS is embedded into the original HTML file which is transferred gzipped with HTTP. About 200kb in total, single HTTP request.

Empperi13:08:56

totally ruins caching though

idiomancy13:08:58

oh, I see. I mean that if the UI changes state, rather than capturing the change by changing the value of [{:style ...}], you change the value of [{:class ...}]

idiomancy13:08:17

that way, the CSS can change the style and the j-unit tests can assert the difference

Empperi13:08:15

user clicks a button which will expand a div with some information, just add a class called visible or whatever to the div when click happens. Handle rest in CSS

Empperi13:08:35

one can add nice CSS transitions with 3d effects and whatnot

Empperi13:08:39

if that's your thing

idiomancy13:08:03

Awesome. Really good to hear this stuff. This aligns with what I was thinking.

poverholt13:08:48

I have a case where I cannot get rid of the warning "every element in a seq should have a unique :key". I have reduced the problem to code snippet below. In the real problem the final line uses a function, which is why I need to use the cmd-panel3 approach so I can wrap the list of vectors returned in a vector with :div.wrapper at head. Ideas?

Empperi13:08:50

@poverholt I would guess the divs within wrapper are dynamic? Add keys to those

manutter5113:08:49

@poverholt do you get the same result if cmd-panel3 does this instead?

(into [:div.wrapper] '([:div "4"] [:div "5"] [:div "6"]))

idiomancy13:08:52

the key warning is to optimize for performance in the reagent diffing mechanism, @poverholt. It's saying it wants a unique key on each component in a list so it can efficiently check to see if any of them have changed in subsequent diffs. If you aren't concerned about potential performance problems you can safely ignore the warning. Here's some further reading: https://stackoverflow.com/questions/37164091/how-do-i-loop-through-a-subscribed-collection-in-re-frame-and-display-the-data-a/37186230#37186230

danielneal13:08:35

weird that [:div.wrapper [:div "1"] [:div "2"] [:div "3"]] would work but (vec (cons :div.wrapper '([:div "1"] [:div "2"] [:div "3"]))) wouldn't

danielneal13:08:44

I thought they'd be equivalent

idiomancy13:08:18

it happens when hiccup inlines a sequence

idiomancy13:08:52

so reagent assumes [...][...][...] is different from ([...] [...] [...])

danielneal13:08:47

^ sorry for spamming with incorrect syntax 😄

Empperi13:08:18

@idiomancy yeah but that is weird it behaves like that since the code he posted is executed before reagent does anything with it. Those functions are called as functions, not as reagent components

danielneal13:08:59

I wonder if the metadata is not applying correctly in the second case

danielneal13:08:33

@poverholt I agree with @manutter51 - maybe try the into version

Empperi13:08:43

maybe try (with-meta (cons-stuff-code) {:key (:name cmd)})

danielneal13:08:50

yep or this ^

idiomancy13:08:58

yeah, I hear you, but the return value is a sequence. it's the same if you just drop a (for [x stuff] [:div x])

Empperi13:08:08

that way the metadata should definitely be there

danielneal13:08:38

@idiomancy there's a vec call though so would be equivalent to (vec (for [x stuff] [:div x])) I think

idiomancy13:08:05

TIL that the type of sequence makes a difference

idiomancy13:08:19

I had no idea that vectors were treated differently from lists

danielneal13:08:16

I think it's just a reagent thing

danielneal13:08:34

like vectors are the magic syntax for react elements

idiomancy13:08:39

oh... I see... if you put it in a vector, it doesn't see it as a list of components, it sees it as a single component

idiomancy13:08:58

where each item in the vector is an argument to that component

idiomancy13:08:49

thanks for the correction 😅

danielneal13:08:34

TBH I find this stuff hard to get right around the fringes

idiomancy13:08:17

ahhh, gotcha. interesting

idiomancy13:08:21

so vector? just precedes the seq? check

parrot 8
Empperi13:08:00

yup, it's executed before reagent does anything

Empperi13:08:11

the actual problem comes from line 24

Empperi13:08:39

the problem actually MIGHT go away if that would be mapv instead of map

Empperi13:08:47

oh right now I get what is happening, mostly at least. I'm actually surprised that the first case doesn't cause a warning too

Empperi13:08:21

This code is the problem:

[:div
   (top-line pres)
   (map cmd-panel (:cmds pres))])

Empperi13:08:12

it creates something like this (not exact but structure should be representative):

[:div
  [:div.top-line-return-value-dunno]
  '([:div "1"] [:div "2"])]

Empperi13:08:35

now if one would assume the (top-line pres) returns a single element then one could do:

(into
  [:div]
  (concat
    [(top-line pres)]
    (map cmd-panel (:cmd pres))))

Empperi13:08:49

just one example

Empperi13:08:50

that way one should end up with following structure:

[:div
  [:div.top-line-return-value-dunno]
  [:div "1"]
  [:div "2"]]

Empperi13:08:58

and reagent/react should be happy

Empperi13:08:59

now however depending on that the cmd-panel elements actually are it might make more sense to add them to reagent as reagent components

Empperi13:08:17

if that's the case then one should not return [:div "1"] but [some-component-fn] which then renders the div

Empperi13:08:45

and I think if this is done then keys might be a good idea to keep react working quickly

colinkahn13:08:58

I'm trying to package some javascript and having issues, could anyone take a look at my repo and tell me if they see anything wrong? https://github.com/colinkahn/deckgl-cljs

colinkahn13:08:23

I deployed it to clojars using mvn deploy, but when I use it in my project I get a vague error that says to check the file it was imported into. https://clojars.org/org.clojars.protocol55/deckgl

poverholt14:08:03

@danieleneal @niklas.collin @idiomancy @manutter51 Thanks so much. The with-meta worked! - not exactly sure why. Into did not help the problem, but I think it is cleaner syntax than what I had. Thanks.

idiomancy14:08:46

if you're just looking for cleanliness, you could also do ^{:key (:name cmd)} (into [:div.wrapper] '([:div "7"] [:div "8"] [:div "9"]))

idiomancy14:08:55

little reader macro

danielneal14:08:12

(defn cmd-panel4
  [cmd]
  (into [:div.wrapper {:key (:name cmd)] '([:div "7"] [:div "8"] [:div "9"]))))

danielneal14:08:42

^ is what I tend to use

colinkahn15:08:33

I narrowed it down to the :global-exports line, removing that makes it work. Are there any known issues with :global-exports or is my setup just wrong? https://github.com/colinkahn/deckgl-cljs/blob/master/src/deps.cljs#L3

mfikes16:08:30

@colinkahn Did you include the error you received in the backlog?

colinkahn16:08:17

I haven't posted a ticket but I can. Unfortunately the error is very vague, just saying that the file I'm importing the library into failed to compile (I'm using Figwheel, I could try reproducing without it though).

mfikes16:08:49

If this ultimately leads to a JIRA, a repro with just cljs.main would be ideal

colinkahn16:08:46

cool, yeah I'll try with cljs.main and go from there

lwhorton16:08:25

am i just missing a phone number parsing / formatting library in goog closure docs? that seems like something that would exist, given goog-libphonenumber?

lwhorton16:08:06

i dont want the standalone version libphonenumber, mostly because it’s 400+kb optimized(!)

thheller16:08:30

@lwhorton you can take the files here and put them on your classpath. they are written in closure JS so they are fully :advanced compatible. https://github.com/googlei18n/libphonenumber/tree/master/javascript

thheller16:08:19

I only use the java version so I'm not exactly sure how well the JS versions works though

👍 4
jimberlage20:08:05

@lwhorton adding onto that, there’s a cljsjs package for libphonenumber already: https://github.com/cljsjs/packages/tree/master/libphonenumber Looks like that will just pull in the lib, so any unused parts will be optimized out (I think)

takamura23:08:24

Reagent seems to be easier (from a JS react user) than om/om next. But is reagent equivalent to Om/OmNext?

euccastro23:08:20

takamura: do you mean functionality / scope? re-frame wraps reagent to get closer to om/om-next in scope. I'm not familiar enough with either to compare functionality

takamura23:08:26

Also, if I am going to start to use om, I should start using om next, right?

takamura23:08:18

@euccastro I mean more in terms of abstraction. Om next seem to use concepts more advanced than reagent (like using queries parsers mutations, etc)

takamura23:08:36

Actually, I am familiar with ReactJs but not familiar with any clojure react library. I did some tutorials but I am still thinking in what to use

Chris O’Donnell23:08:39

There is much less learning material for om next than there is for re-frame, which is a ui framework more comparable (imo) to om next than reagent.

Chris O’Donnell23:08:37

If you're interested in the om next philosophy I'd recommend checking out fulcro, which has pretty decent documentation.

euccastro23:08:08

I would follow the tutorials for both and see what clicks for you

Chris O’Donnell23:08:20

I usually recommend reagent/re-frame to newcomers because the learning curve is more manageable. Reading some docs from each before making your own decision doesn't hurt, though. :)

lilactown23:08:38

I do wish we had something a bit closer to the metal when it comes to React wrappers

justinlee23:08:20

that’s why we have lilactownware 😉

lilactown00:08:38

hehehehe I’m going to keep complaining until I have something to release 😂

justinlee00:08:26

i like the looks of that macro-free version

lilactown00:08:18

I might publish something in the next few weeks

lilactown00:08:14

I want to see if I can plop it into a re-frame app 😛

euccastro23:08:41

and there's rum with citrus 😛 (sorry to give you one more problem): https://github.com/roman01la/citrus

👍 4
euccastro23:08:12

that's much less used (I think?) than reagent/re-frame, though, so it might be harder to get help if you get stuck somewhere. all in all, I'd second @codonnell's recommendation