Skip to content
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

Styling Brainstorming #533

Open
jkelleyrtp opened this issue Jul 20, 2019 · 16 comments
Open

Styling Brainstorming #533

jkelleyrtp opened this issue Jul 20, 2019 · 16 comments
Labels

Comments

@jkelleyrtp
Copy link

@jkelleyrtp jkelleyrtp commented Jul 20, 2019

I'd like to add a styling system to yew - not having a built-in way of styling components seems a bit unfinished to me. If we want to build better, bigger, and faster web apps, then we need a way of managing styles that doesn't clobber a global namespace and makes sense when looking at the components.

I'd like to see a Stylable trait where we can pull in an existing stylesheet (using css-parser for the servo project), modify it (override the defaults), and then set that as the element style.

We could also have a special style property for each element where we can inject style into even the subdivs of elements.

I personally favor parsing an external stylesheet and doing inline modification because of autocompletes working with .css files, but there is also room for a css! macro and reserve a keyword for the element that the style is being applied to, to access subdivs in that element.

Curious what the thoughts of the community is before I try pull my changes into the project.

@ThomasdenH

This comment has been minimized.

Copy link

@ThomasdenH ThomasdenH commented Jul 21, 2019

I think the system for styling would be best as a separate system, where individual properties are ideally strictly typed. Then the library could be integrated here.

@jstarry

This comment has been minimized.

Copy link
Member

@jstarry jstarry commented Jul 21, 2019

I agree with @ThomasdenH and think this could start out as a separate crate but could eventually get added to yew later as it matures, perhaps in the form of "styled components".

@jkelleyrtp are you thinking of taking approach like https://cssinjs.org/? I would love having a way to use declarative styles like this. Then the integration with yew is as simple as setting the class name

@jkelleyrtp

This comment has been minimized.

Copy link
Author

@jkelleyrtp jkelleyrtp commented Jul 21, 2019

@jstarry I was definitely feeling inline CSS in the same way that JSS works - I like having the state of the component directly tied to its appearance. I'm going to approach this in the same way that styled-components work so we can just drop existing stylesheets into components but also be able to modify them on component updates.

@matiu2

This comment has been minimized.

Copy link

@matiu2 matiu2 commented Jul 23, 2019

Personally I just use bootstrap. Then apply the class attributes as needed: https://hackerthemes.com/bootstrap-cheatsheet/

I don't use the JS part of it; just the stylesheets.

I can imagine possibly a high level API that just applies those, but I think I would prefer to just apply them myself.

The question is where does the scope of yew end ? perhaps what's needed is a separate yew-styling plugin/library ?

@hgzimmerman

This comment has been minimized.

Copy link
Member

@hgzimmerman hgzimmerman commented Sep 25, 2019

@jkelleyrtp Have you made any progress towards this?
I have a loosely defined proposal on how to implement this typed up and would love to give it a shot in building it, but if you have something in the works, I would rather hold off and wait on that.

@hgzimmerman

This comment has been minimized.

Copy link
Member

@hgzimmerman hgzimmerman commented Sep 26, 2019

Nevermind, I've got a prototype in the works here in case anyone wants to check it out:
https://github.com/hgzimmerman/yew_css

@MuhannadAlrusayni

This comment has been minimized.

Copy link

@MuhannadAlrusayni MuhannadAlrusayni commented Dec 17, 2019

Here is my thoughts on building styling system.

I think there are two different places that we need to handle style:

  1. a default style for every component.
  2. a unique style for every component instate.

A default style for every component

Every component can have it's own default style, let's say a Button component have this default style:

color: black;
background: white;
border: 1px solid black;
border-radius: 4px;

At this point we need to defined the behavior of the styling system, thus we need to answer these questions:

  • How the styling system will get these default styles? and from where?
  • How the styling system will apply these default styles to the components ?

A unique style for every component instate

Some times we change style for component instate, by adding, removing .. etc styles to the component instate, thus we need to defined a how the styling system would allow us to do that.

possible answer for the 1st question

How the styling system will get these default styles? and from where?
By using trait Theme that would return Style struct that contains CssName and CssValue pairs, for the component. Every theme struct would implement this trait.

Theme that uses classes

This trait uses the class to construct Style for it. this trait is simple to implement but doesn't have full access to the component state. it also can have styles even if we have no components for them, it is easy to reuse existing css libraries with this trait.

    pub trait Theme {
        fn style(&self, class: impl Into<Cow<'static, str>>) -> Option<Style>;
    }

    // example
    pub struct DefaultTheme;

    impl Theme for DefaultTheme {
        fn style(&self, class: impl Into<Cow<'static, str>>) -> Option<Style> {
            match class.into().as_ref() {
                "button" => unimplemented!(),
                "flexbox" => unimplemented!(),
            }
        }
    }

Theme uses components state

This trait uses the component state to build Style for it, it have full access to the component state, but it's not simple to implement as well as it's only support components that are present in Component enum.

    pub trait Theme<Comps> {
        fn style(&self, class: impl Into<Comps>) -> Option<Style>;
    }

    // example
    pub struct DefaultTheme;

    impl<'a> Theme<Components<'a>> for DefaultTheme {
        fn style(&self, comp: impl Into<Components<'a>>) -> Option<Style> {
            match comp.into() {
                Components::Button(btn) => unimplemented!(),
                Components::Flexbox(flexbox) => unimplemented!(),
            }
        }
    }

    pub enum Components<'a> {
        Button(&'a Button),
        Flexbox(&'a Flexbox),
    }

This my try, for sure there are a lot of things that need to be changed for these ideas to fit in Yew. I didn't answer the other questions, since I don't have clear answer for them.

@derekdreery

This comment has been minimized.

Copy link

@derekdreery derekdreery commented Jan 1, 2020

I'm having a play with writing a css parser from rust tokens, and it seems to be going well. It's available at https://github.com/derekdreery/style. The idea is that you can do things like

<div style={{font-size: 10px; flex-direction: column}}></div>

from within a macro in rust code, making using css/styles feel really natural.

@jstarry

This comment has been minimized.

Copy link
Member

@jstarry jstarry commented Jan 6, 2020

Wow, awesome @derekdreery! Looks like the yew html macro could depend on your style macros under the hood. Is that what you had in mind?

@kellytk

This comment has been minimized.

Copy link
Contributor

@kellytk kellytk commented Jan 6, 2020

I agree with

individual properties are ideally strictly typed

from #533 (comment).

@derekdreery

This comment has been minimized.

Copy link

@derekdreery derekdreery commented Jan 6, 2020

Looks like the yew html macro could depend on your style macros under the hood. Is that what you had in mind?

Happy to help out however you want to use them.

There are a couple of small caveats:

  • hex colors are not valid tokens in the rust lexer, so they have to be quoted (e.g. color: #"fff")
  • same goes for lengths that start with e (this is because the lexer tries to interperet the number as a float with an exponent). (e.g. font-size: 1"em")

individual properties are ideally strictly typed

The lib I'm working on does typecheck your CSS, so only valid types of property values are allowed for a given property name.

@fromrileywithlove

This comment has been minimized.

Copy link

@fromrileywithlove fromrileywithlove commented Jan 21, 2020

My preference is to use css modules, or css that's localised to the component, keeping components from conflicting with each other automatically. To this end there is the css-modules crate, which simply aliases all of the class names in a css file and imports a list of those aliases into rust.

The author of the crate was recently harassed into deleting their GitHub account by a group of transphobes but everything still works just fine.

Edit: I forgot to say that I also use it with rollup for post processing.

@bl42

This comment has been minimized.

Copy link

@bl42 bl42 commented Feb 11, 2020

First off, New to rust & New to yew... Figure it would be a great place to learn both!

Recently been using a lot of Svelte and I have really enjoyed their take on styling.

<style>
	p {
		color: purple;
		font-family: 'Comic Sans MS', cursive;
		font-size: 2em;
	}
</style>

<p>Styled!</p>

They do stuff under the hood of generating classes and attaching them to the elements but it avoids concepts of theming and leaves it to the developer/css.

Ideally (for me) an API like so would exist like so where I could leverage css variables to do the theming/customization of a child component in CSS.

impl Component for Model {
  fn style(&self) -> Css {
        css! {
            div {
                background: black;
                --main-text-color: white;
            }
        }
    }
    fn view(&self) -> Html {
        html! {
             <div>
                  <MyComponent /> <!-- changes child's --main-text-color by setting the var -->
             </div>
         }
     }

It may not be possible (still learning) but I would be interested if it does.

@jstarry

This comment has been minimized.

Copy link
Member

@jstarry jstarry commented Feb 11, 2020

@bl42 I like the look of that.

Minor detail: the function signature wouldn't quite work like that if the CSS was generated at compile time since we wouldn't have an instance of the component then.

Ideally (for me) an API like so would exist like so where I could leverage css variables to do the theming/customization of a child component in CSS.

I don't quite understand your vision here, could you elaborate a bit more?

@MuhannadAlrusayni

This comment has been minimized.

Copy link

@MuhannadAlrusayni MuhannadAlrusayni commented Feb 11, 2020

I have developed trait with similar functionality, Component should declare their Style struct that will be used to style the component (e.g. Entry) instead of using some sort of collection that doesn't help at checking the used style if it works with the Component or not.

My project using Seed, but I'm pretty sure this idea is applicable in Yew too.

@bl42

This comment has been minimized.

Copy link

@bl42 bl42 commented Feb 11, 2020

I don't quite understand your vision here, could you elaborate a bit more?

My preferred output would have some "Global Styles" that I can declare for the app (on mount)

Something like

   @import 'google fonts...'
   @import 'css animations lib...'

   html {
      font-size: 65.25%
      --primary-color: #000;
      --primary-text: #fff;
      etc..
   }

and in each component have the ability to call color: var(--primary-text);

We could easily store these values in Rust... but I suggest to let CSS do what it is good at.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants
You can’t perform that action at this time.