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

Beta: theme improvements, component specific themes, animations #41

Merged
merged 211 commits into from
May 2, 2022

Conversation

natew
Copy link
Member

@natew natew commented Mar 14, 2022

This PR is growing a bit, it started as an experiment with animations, but in doing so I think I've figured out a few problems and solutions within themes. There's a lot of improvements overall, so I've decided to just turn it into a big "beta" PR that once merged should be ready for a beta release.

Along with that, I'll aim to really break as many API's at once here (rip the band-aid, so to speak).

There are big upgrades already in place, and now just want to fix, polish, optimize and finish them:

Themes

Theme's worked, but didn't really give you much flexibility on a component level at all. This is fixed now. Previously I'd just went for each theme having a variety of shades, like bg, bg2, etc, and then letting components use any shade they wanted . There were a variety of problems with this:

  1. You can't customize themes per-component (Buttons always had a dull look for example)
  2. Components grabbed arbitrary theme values (Buttons used bg2 for background, bg3 for hover...)

The fix comes in two parts. First, instead of shades each theme just represents a single set of colors across all states:

  • Instead of confusing bg, bg2 Tamagui now just maps to states background, backgroundHover, backgroundPress, backgroundFocus
  • The same states should be set now across all other color values (eg: borderColor, borderColorHover, ....)

This doesn't really solve either problem beyond giving us much more consistent naming and avoiding the idea of shades within a single theme.

Next, we need a way to have buttons for example be themed differently from inputs.

I explored for a while various ideas on this, the obvious one was something like buttonBackground, buttonBackgroundHover, etc. But this raised tons of issues:

  • How does this fallback if not defined? Does buttonBackground just grab background? We can’t expect themes to define colors for every component (think Separator, where borderColor should be a very reasonable default). But at the same time every component should be customizable.
  • So then we need some syntax to define a fallback, like styled(Stack, { backgroundColor: ['$buttonBackgroundColor', '$backgroundColor'] }). This would be a nightmare to implement in terms of complexity, you'd have to implement it at runtime, compile-time, and in types.

It wasn't until playing with animations on a small sandbox project that a much simpler, and solution we already have existing today would work: Sub-themes to the rescue!

Sub-themes already work, and are a hugely helpful feature. You could use them to get around some of the limitation already, but you'd be forced to specify a theme prop on every button. So right now you could now define a light theme and a light-button theme and theme do:

<Theme name="light">
  <Paragraph>Hello</Paragraph>
  <Button theme="button">World</Button>
</Theme>

And technically you'd have a nice way of fully controlling themes of buttons. But it's brittle in a few ways. First is that the theme prop only works if you wrap a component with themeable, it doesn't come out of the box if you just make a styled component. That's something I'm exploring enabling in this PR as well - it has some complexity that needs accounting for. Luckily, it's not necessary to solve immediately, because...

Tamagui will automatically find component themes

Instead of having one giant theme (background etc) with all sorts of component specific keys (like buttonBackground, separatorBackground, etc)... instead, have a as many small themes as you want. Something like:

export default {
  light: { color: '#000', background: '#fff' },
  light_Button: { color: '#fff', background: '#000' },
}

This should also work with tinting/shading/sub-themes (whatever you want to call it):

export default {
  light: { color: '#000', background: '#fff' },
  light_blue: { color: 'darkblue', background: 'lightblue' },
  light_blue_Button: { color: 'lightblue', background: 'darkblue' },
}

Even better, it lets you set up a bunch of base shaded themes and then just choose/share them across components as needed:

const lightBlueTheme = { color: 'darkblue', background: 'lightblue' }
const darkBlueTheme = { color: 'lightblue', background: 'darkblue' }

export default {
  light: { color: '#000', background: '#fff' },
  light_blue: lightBlueTheme,
  light_blue_Button: darkBlueTheme,
  dark_blue: darkBlueTheme
  dark_blue_Button: lightBlueTheme,
}

Nice! This is incredibly flexible, giving you full power to override themes for every component, across every shade, all while sharing the same themes so there's no real extra object keys and values.

Typings get some fixes too so <Theme name="blue"> is accepted as valid, and like it works now, so long as you have a parent <Theme name="light"> you'll automatically get the light-blue theme ✨.

This is really exciting stuff. I need to finish some component-specific pieces here, but there's nothing major blocking for this to land now most of the hard work is in place.

Animations

Animations! This was supposed to be the big part of this branch, but turns out themes were really the star. I'll write a lot more, but this is also really cool. Tamagui really needed to have animations solved before going deeper into a variety of fixes, improvements and other components up next. For newly landed components like Tooltip, it was clear figuring out animations up front is necessary or else we end up with lots of baggage.

I won't go too deep, but basically createTamagui accepts an animations key now, and you can swap out your entire animation driver based on the platform 🤯.

So your animations.native.ts can have:

import { createAnimations } from '@tamagui/animations-reanimated'

export const animations = createAnimations({
  springy: {
    type: 'spring',
    damping: 20,
    stiffness: 90,
  },
})

But your animations.web.ts instead can do:

import { createAnimations } from '@tamagui/animations-css'

export const animations = createAnimations({
  springy: 'ease-in-out 300ms',
})

And we can then have anyone add other drivers, like motion for example.

More to come!

@natew natew force-pushed the nate/animation branch 6 times, most recently from 8f6d2ae to e259f27 Compare March 20, 2022 08:02
@natew natew force-pushed the nate/animation branch 10 times, most recently from dabe600 to 17a585e Compare March 23, 2022 08:11
@natew natew force-pushed the nate/animation branch 10 times, most recently from 6c8f3ee to cb28d03 Compare March 28, 2022 02:42
@vercel vercel bot temporarily deployed to Preview May 2, 2022 07:39 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 07:41 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 08:01 Inactive
@natew natew force-pushed the nate/animation branch 2 times, most recently from df49676 to 79c95d8 Compare May 2, 2022 08:18
@vercel vercel bot temporarily deployed to Preview May 2, 2022 08:20 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 08:24 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 08:40 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 08:48 Inactive
@natew natew force-pushed the nate/animation branch 2 times, most recently from a20aaf9 to 5490013 Compare May 2, 2022 08:57
@vercel vercel bot temporarily deployed to Preview May 2, 2022 09:00 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 09:09 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 09:18 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 09:26 Inactive
@vercel vercel bot temporarily deployed to Preview May 2, 2022 09:53 Inactive
@natew natew merged commit 9443de6 into master May 2, 2022
@natew natew deleted the nate/animation branch May 2, 2022 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant