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

bop it #1441

Closed
wants to merge 10 commits into from
Closed

bop it #1441

wants to merge 10 commits into from

Conversation

estrattonbailey
Copy link
Member

@estrattonbailey estrattonbailey commented Sep 12, 2023

Update: refactored the ToggleButton as an example, see latest commit.


This PR is based around a hook that can be used in various situations.

I also want to highlight the intellisense available on Box and Text, but also within useStyle and other utils.
Screen Shot 2023-09-13 at 5 01 05 PM
Screen Shot 2023-09-13 at 5 01 12 PM

useStyle

The goal here was a mid-level (as opposed to low (like theme.style or high-level (like Box)) util that can be used for defining more complex components like a button, or for styling 3rd party libraries.

It accepts any style props configured by us via properties on the theme.

const styles = useStyle({
  c: 'text',
})

console.log(styles) // => { color: '#333' }

So like for a button, we could make a component like this (this is rough):

import { ComponentProps, useStyle } from 'lib/design-system'

export type ButtonProps = ComponentProps & {
  variant: 'primary' | 'secondary'
} 

export function Button({ children, variant, style, ...rest }: ButtonProps) {
  const { styles, props } = usePick<ViewProps>(rest)
  const styles = useStyle({
    px: 's',
    py: 'xs',
    gtPhone: {
      px: 'm',
      py: 's',
    },
    ...({
      primary: { bg: 'theme', c: 'light' },
      secondary: { bg: 'secondary', c: 'dark' },
    }[variant]),
  })

  return <View accessibilityRole='button' {...props} style={[styles, style]} />
}

Similarly for a 3rd party component like a dropdown or something:

export function DateInput() {
  const styles = useStyle({ ... })
  return <DateLibrary style={styles} />
}

I also added (as an example) what a more familiar (like StyleSheet.create) pattern could look like with useStyles (plural, formerly useMultiStyle):

const { container } = useStyles({
  container: {
    px: 's',
    gtPhone: {
      px: 'm',
    }
  }
})

Which gives nice intellisense.
Screen Shot 2023-09-13 at 4 54 56 PM


So otherwise, typical usage as primitive components looks like this:

<Box
  inline
  pa='m'
  bg='dark'
  gtPhone={{
    padding: 50
  }}
/>

Main things to note from this example

Properties can be longhand or shorthand, whatever we configure. These could even match like, Tailwind or something if we wanted.

Properties apply in-order, and override just like a normal object i.e. both of the following will result in backgroundColor: 'dark'

<Box bg='theme' backgroundColor='dark' />
// and
<Box backgroundColor='theme' bg='dark' />

gtPhone is a breakpoint, which is only applied above the value configured in the theme. We can name these anything we want, I just took a page from Tamagui's book for this convention. We can have multiple breakpoints. They only update and re-render when the browser window crosses the threshold of a new breakpoint. I also designed this in a way that we should be able to just disable breakpoints on mobile/tablet and basically apply whatever screen size the device has, then never update again (may not want this if we aim to support landscape orientation too, but just thinking ahead).

Most properties can also accept non-theme values, like padding above falls back to DimensionValue from RN.

Properties defined as macros can be boolean, meaning no need to pass a value i.e. inline above that applies { flexDirection: row }

Theming stuff

Themes are created using a factory function. The idea here was just to create types based on what's passed in instead of extending a namespace like some other libraries. Little easier to reason about.

tokens are "design tokens" and correspond to their CSS property names, with the exception of space, which is manually mapped to properties using specialTokenMapping here. There are a few properties mapped to color tokens as well, like backgroundColor and borderColor, etc. Otherwise stuff like fontSize corresponds directly to fontSize property definitions on components.

properties on the theme includes all valid CSS properties by default, and as you can see we can extend them to include "aliases" or "shorthands".

macros are basically custom props. Pass in a value and return a style object. They're useful for boolean attributes, like inline above. But also good for stuff like font that needs to apply a different font family depending on fontFamily and fontWeight attributes i.e. we could pass in like font='sans bold' and map that to { fontFamily: 'InterBold' }.

Ideas

Values like '100vh' work on web but not mobile, so we should export a util like web('100vh') that tells TypeScript that it's valid and prevents that value from being applied if outside a web env.

useStyle could accept a function which gets passed the whole theme object or something too if we want to access it or the tokens within it.

(cherry picked from commit a5ea4d866241ce9794f1087a8218b71d95cdf7b7)
Comment on lines 14 to 31
<ThemeProvider theme={themes.dark}>
<Box pa="m" gtPhone={{padding: 'l'}}>
<H2 as="h1" c="theme" gtPhone={{mb: 'm', marginTop: 'l'}} debug>
Heading 1
</H2>
<H1 as="h2" c="theme" style={{color: 'tomato'}}>
Heading 2
</H1>
<H3 lh="xl">Heading 3</H3>
<P caps>Paragraph</P>

<Box inline aic gap="m" my="l">
<Box w={100} h={100} bg="theme" />
<Box w={50} h={50} bg="text" />
<Text font="mono">Monospace</Text>
</Box>
</Box>
</ThemeProvider>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What it boils down to

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is useStyles being used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it only meant to be used by our custom components?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it just returns one styles variable

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh yeah I should write a few docs to explain this idea better, will do that this morning

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Themes configured here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library itself

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically the components portion of the library

m: 16,
l: 24,
},
color: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. We probably want to add the colors from the existing theme.ts file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we'd need to bike shed some naming and stuff too

@estrattonbailey
Copy link
Member Author

I think we're as close to Tamagui as we can get without getting our eyes wet. We're at a point where we should have a closer look at it as an option, and only come back here if new concerns arise.

Atm the only cons I can think of around using Tamagui is that it's a little more of an all-or-nothing approach (can still do incrementally), and may not be as smooth of a transition going from StyleSheet to XStack (Box) syntax without a useStyle hook like we have here. If we can get it configured and working smoothly then the fact that it brings a whole component ecosystem with it could be a boon.

Closing for now!

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.

2 participants