GithubHelp home page GithubHelp logo

[RFC] MacawUI Design System about macaw-ui HOT 7 CLOSED

saleor avatar saleor commented on September 21, 2024 4
[RFC] MacawUI Design System

from macaw-ui.

Comments (7)

witoszekdev avatar witoszekdev commented on September 21, 2024 4

First off: what a great RFC, loved the examples for each styling solution and the clear introduction of design tokens โค๏ธ and separation between theme (e.g. colors) and it's intended usage (e.g. text primary foreground).

I have some questions though ๐Ÿ˜…

General thoughs

1. Exporting colors

Colors won't be exported from macaw anymore? From my understanding we would have only classes for specific use-cases e.g. text-primary-foreground

2. Expose all props

If a component is simple like a button or text we should expose all props

Honestly, I don't think that's a good idea for a couple of reasons:

  • Intelisense gets very crowded with properties you'd never use
  • You still can't pass refs easily, unlike regular HTML elements
  • We lose control of our design systems - consumers can misuse the components by overriding props
  • If you need a custom component in your app that doesn't make sense in component library, then using design tokens along with basic HTML elements is a superior solution

3. as prop

We also shouldn't introduce as prop. In my previous experience, such polymorphic components create more issues than they solve:

  • Types become a mess
  • You cannot assert that your components are accessible
  • as prop + Typescript + forwardRef = mess

Instead, we could have a single polymorphic components (e.g. Box) that exposes our design tokens more easily:

4. Internals of the design system

UI components API shouldnโ€™t expose the internals of the design system e.g what library we use to build component primitives or what tool we are using as CSS foundation.

I think in the end we can't avoid that for our CSS foundation - if we want to expose our design tokens then we need to export them, which exposes library consumers to our solution. See Polaris Design Tokens library.
In the end, all of our proposed solutions are framework-agnostic, which means we don't force our users into using a specific UI framework if they want to just access our styles.

5. Visual regression

  1. For visual regression testing, we can use:

Legacy migration

Why do we want to keep the legacy code inside macaw? IMHO, this just creates more maintenance burden and bias towards re-creating components that we already had, than just starting from a clean slate. This would also cause issues with tooling (e.g. if we had to upgrade Storybook to a new version) or if we'd like to use something new (e.g. Vitest instead of Jest, Vite instead of Webpack, etc.). This just gives us more flexibility. Also, as you've mentioned:

Since our library now exposes old and new components, undoubtedly we will face naming conflicts

I think we would be better off with either:

  • completely new package on NPM
  • new version of the same package (e.g. legacy is v1 and next is v2)
    • we could also treat the v2 as alpha until it's more or less done
    • we don't need to rebrand our library

We can create new repo or move the old version to legacy branch and the new version to main or reversed (Material UI had "next" version on a separate branch until it was released as stable).

We can still use two versions of the library (see example) and we wouldn't have namespace conflicts.

Using an object as a namespace

This can be good for a component that has multiple parts (e.g. see Radix UI components), but not entire library

Styling solutions

CSS Modules

CSS modules - this doesn't provide any value we could have from CSS-in-JS (e.g. dynamic themes), it's basically what JSS does and done worse

Tailwind

Please, please, don't use Tailwind

  • It reinvents the existing styling solution we have for the web: Cascading Style Sheets :)
  • You need to re-learn pretty much every CSS property instead of using what you already know
  • You don't have the flexibility of your own CSS variables
  • The code is basically unreadable after we add a lot of styles
  • Extracting component classes into a separate file introduces name collision issues, something we don't have with CSS modules or Vanilla Extract
  • Tailwind locks you into utility classes paradigm

In the end, if we'd like to have utility classes there are better ways to do it

  • Box component (see above)
  • Design tokens exported from the library (e.g. see Polaris)

I'd like to elaborate more on that and invite you to think: "do we even need utility classes?"

In the end, they are an override of the design system components. If we need to override stuff, that usually means we need to re-think the composition of our components or to expose more API to control them. Having a couple of utility classes and overrides is OK. Making it a norm always backfires in the long run in my experience.

Vanilla Extract

Note: I am biased here, because I already considered it as a replacement of Macaw styling over a year ago ๐Ÿ˜…

That being said, I think it is a no-brainer to choose it over other styling solutions.

Starting with a polemic on the "cons":

Needs plugins for webpack/vite etc

  • other solutions also need a build plugin - Tailwind and CSS Modules all require it :P

Additional tooling needed for removing not used CSS
Same as above, Tailwind uses PurgeCSS under the hood - an additional tool. We can just use it with Vanilla Extract. Or... since Vanilla Extract style files are just TypeScript files that are compiled on build time, we can configure ESLint to check for unused variables and properties like we do in the rest of our code. This way you remove the source of the dead code, not only the output. IMHO, this is far better.

It's young

It's not that young. Essentially, its 3rd iteration of CSS Modules. Next there was treat. Treat is 4 years old, and it's very similar to Vanilla Extract. If Shopify chose it for rewrite of Polaris, I would say it's not an issue ;)

Now for the order "pros" from yours truly:

  • It can output a single CSS file - consumers of the library don't have to use Vanilla Extract, they can just import the styles
  • Everything is typed this prevents a lot of issues that you'd have with other styling solutions, theme contract is automatically enforced
  • Zero runtime cost (unlike CSS modules) and even less so than Tailwind (the output file can be HUGE)

Closing notes

In the end, I am very excited about these changes. No matter what we choose, it's far better than using an existing component library / design system (Material UI) and forcing it into another design system.

from macaw-ui.

krzysztofzuraw avatar krzysztofzuraw commented on September 21, 2024 1

Answers to questions

Thank you @witoszekdev for detailed response and questions - I answered them below ๐Ÿ˜„

  1. Exporting colors

Yes - plan is to export only specific use-case colors.

  1. Expose all props

We can expose default HTML props on elements when they make sense - e.g type="submit|reset" when we need it for our use-case. Thanks to that we will keep our props minimal and tidy.

  1. as prop

Awesome idea with Box component. We can use it as a base for all components.

I'm wondering about <Text/> component though. In such case we can go with as restricted to span|p|h1...h4 or have <Text.h1 /> component that will expose only those props we need.

  1. Internals of the design system

I agree that we will export and allow access to design tokens. Yet, idea here was that components props should not indicate what we are using under the hood e.g padding prop should not be p-2 as in tailwind but space-8 which then corresponds to design token.

Styling solutions and vanilla extract

I've used Vanilla Extract in the past and the main problem were their plugins to build tools. I remember fighting with @vanilla-extract/vite-plugin to make it work with monorepo or updating @vanilla-extract/next-plugin to found out that it is not working correctly with this version of Next.js. I think it is not a deal breaker but something we should know before going into this solution.

My take on possible solutions

Legacy migration

I think it will be the best to have new Macaw as a separate branch with new version on npm. Then we can use npm alias that points to new version and use them both (old and new) in parallel.

Styling solutions

I think we should go with Vanilla Extract. It is build to create design systems and it is very flexible. I really like their API for building styling. There may be some overhead with tooling if you compare it to CSS Modules but overall I think we will be more productive with Vanilla Extract. If we go with CSS Modules we will have to recreate a lot of things that are already done in Vanilla Extract.

from macaw-ui.

andrzejewsky avatar andrzejewsky commented on September 21, 2024

I went through this RFC a few times, I also started to analyze the way how we use MacawUI already, and when it comes to decisions of what I would prefer, is something that will help us provide not only a component library but also something close to the design system. I'm skipping discussing the implementation details, such as how to write components etc. just want to address the key things: migration and which styling solution we want to use:

Migration:

In my opinion, the best option for us is to start work on the new macaw UI as on separate package: a new branch with a brand new macaw-UI, which is published separately, and so on. We can name the package @saleor/macaw-ui-next and start importing new components from this library right away. This is even the most common approach among open-source libraries.

This way is not perfect, but the burden of maintaining two versions in the same codebase is more painful.

It's also possible to provide deprecation messages in the old components, even if we don't share a common codebase, a bit of development is needed here but it's feasible, however, is this really necessary? We don't have that much audience to communicate each change in that sophisticated way, I think proper release notes would be enough (let's think what's really needed, not what's fancy)

The hardest part of this approach is that one day, once re-write the entire macaw-ui, and none of our projects will use that anymore, we will have to switch imports from @saleor/macaw-ui-next to @saleor/macaw-ui (because the new version will be merged to the main branch) which comes with massive import changes in the code, find & replace, but still massive code change is always a risk.

Styling tools:

We are distinguishing the three ways: tailwind, CSS modules, and vanilla extract. I was looking into each in the context of what we want to achieve and here is my conclusion:

Definitely, Tailwind CSS, does not fit here, it's a CSS utility library with configuration, which also provides a sort of customizable design system. Our goal is to make our own design system along with the components that support it. Using here the Tailwind CSS is sort of wrapping the existing design system with our configuration, to provide our own design system.

I would suggest one of these two: CSS modules or vanilla extract:

CSS modules can work here, this is even the safest way, more like pure CSS, without any add-ons, there is no additional framework here, lover learning curve, and less complex code.

Vanilla extract on the other hand is a sort of framework for building themable systems, it may work perfectly for us, but we need to think twice if we actually need a framework for making this work. Perhaps in our case, just CSS modules would be enough. We also don't know what would be the lifetime of this framework...

from macaw-ui.

Cloud11PL avatar Cloud11PL commented on September 21, 2024

Wow, thank you for such a comprehensive and sophisticated RFC!

I don't think I can add more to the conversation than what was already been said in the thread. ๐Ÿ˜…

Migration

I think it would be best if we just create another version of the same library, so current MUI macaw can stay at 0.7.x and we would use 0.8.x or even 1.0.0 for our alpha version. I don't think that creating a separate library (as it was suggested in the thread) just to merge all changes at some point from the newer to the older one is a headache-free solution.

So essentially we could have two versions of macaw in one library and slowly phase out old components once they're ready. We could mark phased-out components as deprecated. The con that we would have to replace all imports at some point can be done with a script and one PR. So I think your proposal of @saleor/macaw-ui/Next is the way to go.

If it was separate library then I don't think I would see the point of using it in Cloud before it's 100% ready.

Styling tools

In terms of the UI library think I would go with Vanilla Extract, although I would also take a look at Stitches, especially if we consider Radix UI for primitives (we do, right? ๐Ÿ˜…).

Questions:
How do we go about all other components that MUI offers? What is the line between what should be done on the project side and the macaw side? I'm talking about components such as Grid, List, Divider etc.

from macaw-ui.

typeofweb avatar typeofweb commented on September 21, 2024

Shipping and exposing bundled code

There's another alternative: two long-living branches on GitHub, and different tags/version on npm. For example, main branch gets released to 1.x.x and @latest on npm while next branch gets released to 2.0.0-x and @next on npm.

But I agree that Using exports and having two entry points defined also looks great. It's the approach that Next.js chose for next/image and it worked fine. It also makes it easier to migrate and use both versions in a single project.

I believe Using an object as a namespace could lead to problems with tree-shaking.

UI components - technology

I love Tailwind but I see a potential problem here: class named p-2 from macaw-ui means something different than class p-2 in saleor-app-checkout (or any app) because we've modified out tailwind.conf.js. So, there's a conflictโ€ฆ that's why I believe CSS Modules would be best here โ€“ encapsulation of internal styles. We can expose a className prop for overriding certain styles as an escape hatch.

from macaw-ui.

lkostrowski avatar lkostrowski commented on September 21, 2024

My 50 cents on this topic

  1. I think we should stick to a minimalistic CSS approach to decrease complexity of framework/build step. CSS is quite powerful now, using CSS Modules, if they are supported widely (I guess they are) seems to be a good fit. This code will be used only by MacawUI contributors, so we don't expose any API outside. I'm afraid any css-in-js will be problematic, e.g. how it will work with some new framework, will it required babel (in Next it opts out swc), will it work with server components etc. I don't have practical experience of vanilla-extract though
  2. I think exports: {} in package.json is the best fit. It works as a public interface for the package and it can point any path (like /next/) to any internal resource. Migration path is easy with any IDE, also we can provide codemod that can fix paths. Using aliases requires clients to deal with our problems, because we didn't solve it internally. It also contributes to common standards.
  3. I'd also consider tree-shakable paths (import Button from @saleor/macaw-ui/next/button)
  4. Internally we can propose anything (like /next + /legacy), they can also contain internal package.json and build scripts, or not. It doesn't matter, because exports:{} will point to proper paths. We will be flexible to change internal structure, keeping stable public interface
  5. I'm against Tailwind, agree with @witoszekdev

from macaw-ui.

stale avatar stale commented on September 21, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

from macaw-ui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.