mdgriffith / style-elements

Create styles that don't mysteriously break!
http://package.elm-lang.org/packages/mdgriffith/style-elements/latest
BSD 3-Clause "New" or "Revised" License
445 stars 49 forks source link

Can't encapsulate styles easily #140

Open ghost opened 6 years ago

ghost commented 6 years ago

The elm architecture pattern is normally to create child components that know nothing about their parents, and let the parents decide how their children should inter-operate. For example, say there's a parent Nav with a child Contact. Contact would have its own message types, and views to go with it. In the Nav component, you would import Contact, and create a wrapper message for it:

type NavMsg
  = Contact ContactMsg
  | ...

And you would use Html.map, Cmd.map, etc to bring that component into the Nav. We are all familiar and comfortable with this pattern of encapsulation since it's the default pattern in Elm.

Stylesheets don't work this way. Sure, the APIs are all there, leading you to believe it works this way but it just doesn't. At least, not as far as I can see. Using Element.mapAll to change style types ensures that the styles you defined will never be used because after you map the element, you can only use the parent's stylesheet in Element.layout and Element.viewport.

lsunsi commented 6 years ago

I just started learning this library and to be honest I thought I was missing something. It seems counter intuitive that I have to define all styles globally and feels really reminiscent of CSS classes, much more than I would like. styled-components made me think in terms of component and as much as I really like the ambition behind style-elements, I can't seem to get my head around the style patterns.

@adam-becker Does something like this work so we can declare all styles locally and merge together on a root stylesheet?

ghost commented 6 years ago

@lsunsi that looks like it might do the trick. I wouldn't invest too heavily into this pattern though, since I believe 5.0.0 will handle styles much differently. I believe the idea is to use inline styles for everything, and creating functions for specific reusable elements.

buttonPrimary msg str =
  let style =
    [ Border.rounded 6
    , Color.background blue
    , Color.text white
    ]
  in
    button
      [ onClick msg, inlineStyle style, padding 3 ]
      ( text str )

I like this idea more, and I've converted most of my code to use this approach with an empty style sheet to satisfy the viewport function. All of the code for rendering a specific type of button is encapsulated and in one spot, while also allowing the styles to be shared and mixed however you'd like by using basic List operations.

This method also keeps the wall between Style and Layout in place, so it's still a step above a basic Html and Css approach.

lsunsi commented 6 years ago

@adam-becker Yeah, that makes perfect sense to be honest. Also, this is perfectly inline with styled-components-like approach, right? Or class-less, if you will haha.

Can you think of any disadvantages on following this approach? I just started a large project and I'm still on a position to change my codebase, so I'm very inclined to.

Further, doesn't inlineStyle take a list of string tuples as parameter? :(