google / mesop

Rapidly build AI apps in Python
https://google.github.io/mesop/
Apache License 2.0
5.64k stars 272 forks source link

Apply component Styles as css instead of inline styles #115

Open richard-to opened 7 months ago

richard-to commented 7 months ago

For the Mesop API, I like applying styles on the components directly. But for what is implemented under the hood, I was wondering if we could apply those styles from the Style class as CSS.

The CSS selectors, we'd use would be as specific as possible. This means that it would have the same affect as inline styles. No cascading behavior.

I'm not familiar enough with Angular to know how this would work though.

But I think we'd just need autogenerated unique IDs applied to each component.

So box could be rendered as <div id="box-1234"></div>

And then we'd generate appropriate css:

#box-1234 {
   width: 1000px;
  // etc
}

Some potential benefits

Allows us to use media queries which would make some of the responsive css easier to write. Would need to update the Style class API.

We can also get some some style support for the Markdown component (#98) or other components that generate child elements, such as the table component. Again haven't considered what the API would like like.

Here, we could update the Markdown component to have attributes to control style for H1, H2, P, A, etc. Although that could add a lot of attributes.

For Markdown, we could target the specific selectors there, such as the headers.

#markdown-1234 h1 {
   font-size: 20px;
  // etc
}

#markdown-1234 h2 {
   font-size: 10px;
  // etc
}

For the table component, the docs say the columns can be styled: https://material.angular.io/components/table/overview#styling-columns

So something like this could be possible under the hood:

#table-1234 mat-column-NAME {
  // ...
}

The ID attribute could also help with the proto diffing (#62)

wwwillchen commented 7 months ago

I think this is a good idea. Re: implementation - I'm guessing we'd end up doing some manual DOM manipulation in vanilla JS to construct the stylesheet and inject it (basically circumventing Angular's normal component styling mechanism).

Another idea, which is an optimization, is to use a hash of the style object instead of a autogenerated random id. For example, oftentimes you'll have many instances of a component (e.g. box) with the exact same style (a list of cards / chat messages) and we could essentially de-dupe the styles by extracting the inline styles and turning it into a map <hash, style contents> as part of the proto/wire format. There could also be some client-side performance wins with this approach too (although not 100% sure).

This is a similar design as CSS-in-JS libraries which are quite popular for React. For example StyleX does this (docs, implementation: https://github.com/facebook/stylex/blob/87e718e6f07359a5e7cfce59da6ea89f70917bed/packages/shared/src/convert-to-className.js#L26

On a related note: when we do want to support media query-like style API (as a follow-up to this issue), we can get inspiration from StyleX's media query API - overall I think StyleX has a pretty nice API.