razorpay / blade

Design System that powers Razorpay
https://blade.razorpay.com
MIT License
483 stars 124 forks source link

[Blade/New]Expose ThemeProvider.Consumer from Blade for use of consumption of theme #370

Closed sidag95 closed 1 year ago

sidag95 commented 2 years ago

What is this issue about?

Blade provides a useTheme hook to consume the theme and use it in the Application at each component level. This gives a lot of flexibility to use the theme in a function component.

Example usage from the repo (some details removed for brevity)

Setup theme using BladeProvider

<BladeProvider themeTokens={paymentTheme} colorScheme="system">
   <Card />
</BladeProvider>

And then inside the Card component,

const { theme } = useTheme();

return (
  <StyledCard theme={theme}>
      <LeadBold theme={theme}>Total Repayable Amount</LeadBold>
      <DisplayMedium theme={theme}>₹16,666.67</DisplayMedium>
      <AlertInformation theme={theme}>...</AlertInformation>
      <Divider theme={theme} />
      <CaptionRegular theme={theme}>...</CaptionRegular>
  </StyledCard>
);

However, it is a little cumbersome for projects where large parts are using the same theme. Each core component will have to get the theme value from the useTheme hook and then pass it to individual components.

Alternate approach

Instead of the aforementioned example usage of theme, there is an alternate approach that we can take for projects using StyledComponents. We can supply the theme once to styled-components's built-in ThemeProvider. This will automatically make the theme object available to each component.

Example

Setup theme using BladeProvider

<BladeProvider themeTokens={paymentTheme} colorScheme="system">
   <StyledThemeProvider theme={theme}> // Somehow get the theme here from Blade
      <Card />
   </StyledThemeProvider>
</BladeProvider>

And then inside the Card component,

return (
  <StyledCard>
      <LeadBold>Total Repayable Amount</LeadBold>
      <DisplayMedium>₹16,666.67</DisplayMedium>
      <AlertInformation>...</AlertInformation>
      <Divider />
      <CaptionRegular>...</CaptionRegular>
  </StyledCard>
);

This approach has two advantages

  1. Make the component API leaner
  2. Reduce the scope of errors by reducing the API

This is possible with the current API provided by Blade, what is the issue?

While this approach can still be followed with the current API provided by Blade, it is cumbersome to get the Theme value as an additional component is required to get the theme. For example

<BladeProvider themeTokens={paymentTheme} colorScheme="system">
   <MyThemeProvider />
</BladeProvider>

Then, inside MyThemeProvider

const { theme } = useTheme();
return (
   <StyledThemeProvider theme={theme}> // Somehow get the theme here from Blade
      <Card />
   </StyledThemeProvider>
)

Proposed Solution

The proposed solution removes the aforementioned extra component in the usage. If we expose ThemeContext.Consumer from within useTheme.js, the aforementioned solution can be reduced to the following

<BladeProvider themeTokens={paymentTheme} colorScheme="system">
   <BladeThemeConsumer> // example name for the exposed ContextConsumer
      {(theme) => (
         <StyledThemeProvider theme={theme}> // Somehow get the theme here from Blade
            <Card />
         </StyledThemeProvider>
      )}
   <MyThemeProvider />
</BladeProvider>

Benefits

While there is not a significant functional benefit of adding this API, there are cosmetic benefits from the libraries' usage point of view.

kkyusufk commented 1 year ago

Hey everyone, On digging further in this repo, I see that this is already implemented. I think this issue was not linked to the original PR which solved this problem. Anyway, here is the PR: https://github.com/razorpay/blade/pull/442 @sidag95 Please let me know if that is what you wanted as the outcome of this issue.

cc: @chaitanyadeorukhkar

sidag95 commented 1 year ago

Hey @kkyusufk yes, it seems like this should solve our use case. I will update to the latest blade version and verify this.

Side note: @chaitanyadeorukhkar Seems like we are now using StyledComponents by default. Will this have an impact on the bundle size and runtime performance of Blade and especially on projects that do not use Styled components?

Also, how about the projects that just want to utilize our tokens and not the components? Will all such projects be required to have styled-components as their dependency?

kamleshchandnani commented 1 year ago

Hey @kkyusufk yes, it seems like this should solve our use case. I will update to the latest blade version and verify this.

Side note: @chaitanyadeorukhkar Seems like we are now using StyledComponents by default. Will this have an impact on the bundle size and runtime performance of Blade and especially on projects that do not use Styled components?

Also, how about the projects that just want to utilize our tokens and not the components? Will all such projects be required to have styled-components as their dependency?

Yes, we use StyledComponents and we list it as peerDependency to use Blade.

If any projects want to use tokens they can directly import from @razorpay/blade/tokens without installing styled-components. But if you use our theme provider(which is what we recommend) then you get a lot of things out of the box for eg: color schemes: dark/light mode, auto handling of responsiveness when the screen size changes, etc., and for that projects do need to install styled-components.

talking about the bundlesize we haven't yet directly verified that, but assuming things are tree shakeable it won't bloat up bundlesize.

divyanshu013 commented 1 year ago

Closing as it seems to be working for the usecase link to comment