Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Custom theme keys with typescript #140

Closed
cmaycumber opened this issue Oct 30, 2021 · 5 comments
Closed

Custom theme keys with typescript #140

cmaycumber opened this issue Oct 30, 2021 · 5 comments

Comments

@cmaycumber
Copy link
Contributor

Are custom theme keys currently supported with typescript?

Using the following code:

export const theme = {
  Collapse: {},
};

const defaultTheme = makeTheme(theme);

type MyTheme = typeof defaultTheme;

declare module 'dripsy' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  interface DripsyCustomTheme extends MyTheme {}
}

I get the error { Collapse: {} } has no property in common w/ the theme.

I thought I had it working in a separate project. Could the error be because of where I'm creating my custom components?

@nandorojo
Copy link
Owner

You should be writing the theme directly inside of makeTheme, rather than as a separate variable.

that said, I don’t know if this is valid. I think you have to use the keys provided by the theme

@cmaycumber
Copy link
Contributor Author

Got it. Do you have recommendations on how you would handle variants for a Button component for example like primary, secondary, etc.?

@nandorojo
Copy link
Owner

nandorojo commented Nov 1, 2021

I've been thinking about this in general: is Dripsy theming enough to be the backbone of a scalable design system?

For example, take a card:

const theme = {
  cards: {
   container: { bg: '$muted' },
   content: { p: '$3', borderRadius: '$3' }
  }
}

const Card = styled(View, { themeKey: 'cards' })({ variant: 'container' })
Card.Content = styled(View, { themeKey: 'cards' })({ variant: 'content' })

<Card>
  <Card.Content></Card.Content>
</Card>

I think that works pretty well. The issue is, Dripsy's variant system follows the theme-ui spec, which is a bit static. They want your theme represented as a JSON file. This has its benefits: what you see is what you get.

But there are, of course, some limitations.

From the outside, I think the Stitches approach to variants is better: you can have many variant options, such as size, color, etc.

A key example is a Button, like @cmaycumber mentioned.

Say your color scheme looks like this:

const theme = {
  colors: {
    primary: mauve.mauve9,
    primaryText: mauve.mauve12,
    secondary: crimson.crimson9,
    secondaryText: crimson.crimson12
  }
}

Here we have a primary and a secondary. The palette I have in mind comes from Radix Colors.

So, how do we compose a button from this color scheme, such that the label uses the ${color}Text, and the button uses the ${color}.

A few options:

  1. Currently, this can be done with the styled API.
type Color = Theme['colors']

type Props = { color: Color }

const Button = styled(View)(({ color }: Props) => ({ bg: `${color}` }))
Button.Label = styled(Text)(({ color }: Props) => ({ color: `${color}Text` }))

<Button>
  <Button.Label>Text here</Button.Label>
</Button>

And, perhaps you'd wrap your button to pass the color prop to all of them together.

However, for a theme-based style system, I'm not sure if this is the optimal solution. Perhaps it is. But I wonder, could this logic, for such a reused component that literally every app needs, live in a theme instead?

After all, every React Native button needs a container and a label.

In the spirit of a theme-centric design system, I wonder if something more like this could work. It’s similar to the Card, except that it allows props to be passed to the theme…

const theme = {
  buttons: {
    container: ({ color }: Props) => ({ color: `${color}Background` })
  },
  text: {
    buttonLabel: ({ color }: Props) => ({ color: `${color}Text` })
  }
}


type Color = Theme['colors']

type Props = { color: Color }

const Button = styled(View, { themeKey: 'buttons' })({ variant: 'container' })
Button.Label = styled(Text, { themeKey: 'text' })({ variant: 'buttonLabel' })

<Button color="primary">
  <Button.Label color="primary"></Button.Label>
</Button>

This would be more inspired by the Stitches variants option in styled.

Notice here that buttons.container takes a function.

The difference with stitches being, you define these styles in theme, so you can port them from project to project easily. Now, I'm not sure if that's the best thing to optimize around or not. But maybe it is. I'm thinking out loud a bit here.

I mentioned this idea to @axeldelafosse a bit back. I'll keep playing with it...

@cmaycumber
Copy link
Contributor Author

Yeah, this all makes sense to me. I'm running into this now more than ever because I'm finding it hard to make a component library on top of dripsy that's as extensible as possible.

I'm a huge fan of the stitches approach. I definitely think if there's a way to incorporate something similar into a theme-based approach that would be ideal for my use case.

@nandorojo
Copy link
Owner

I'll give it some thought.

Maybe I should convert this from an issue to a discussion?

Repository owner locked and limited conversation to collaborators Nov 2, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants