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

Add createTheme helper function to enforce proper shape for user themes #18

Merged
merged 2 commits into from
Jul 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ Any project using this library should have a global theme object. It specifies s
Below is an example of how a basic theme could look. Make sure to read the sections below for more details on how to set up your different theme values.

```ts
import { createTheme } from '@shopify/restyle'

const palette = {
purpleLight: '#8C6FF7',
purplePrimary: '#5A31F4',
Expand All @@ -97,7 +99,8 @@ const palette = {
white: '#F0F2F3',
};

const theme = {

const theme = createTheme({
colors: {
mainBackground: palette.white,
cardPrimaryBackground: palette.purplePrimary,
Expand All @@ -112,12 +115,14 @@ const theme = {
phone: 0,
tablet: 768,
},
};
});

export type Theme = typeof theme;
export default theme;
```

*Note: `createTheme` doesn't do anything except enforcing the theme to have the same shape as the BaseTheme, but it preserves the types of your user specific values (e.g. what colors the theme has) so you don't lose typesafety as a result of the `{ [key:string]: any }` in BaseTheme*

This theme should be passed to a `ThemeProvider` at the top of your React tree:

```tsx
Expand Down Expand Up @@ -149,14 +154,14 @@ const palette = {
white: '#F0F2F3',
};

const theme = {
const theme = createTheme({
colors: {
mainBackground: palette.white,
mainForeground: palette.black,
cardPrimaryBackground: palette.purplePrimary,
buttonPrimaryBackground: palette.purplePrimary,
},
};
});
```

Taking the time to define these semantic meanings comes with a number of benefits:
Expand All @@ -171,28 +176,29 @@ Taking the time to define these semantic meanings comes with a number of benefit
Spacing tends to follow multiples of a given base spacing number, for example `8`. We prefer using the t-shirt size naming convention, because of the scalability of it (any number of `x`'s can be prepended for smaller and larger sizes):

```ts
const theme = {

const theme = createTheme({
spacing: {
s: 8,
m: 16,
l: 24,
xl: 40,
},
};
});
```

#### Breakpoints

Breakpoints are defined as minimum widths (inclusive) for different target screen sizes where we want to apply differing styles. Consider giving your breakpoints names that give a general idea of the type of device the user is using:

```ts
const theme = {
const theme = createTheme({
breakpoints: {
phone: 0,
tablet: 768,
largeTablet: 1024,
},
};
});
```

See the [Responsive Values](#responsive-values) section to see how these can be used.
Expand Down Expand Up @@ -245,7 +251,7 @@ The Text component comes with the following [Restyle functions](#predefined-rest

```tsx
// In your theme
const theme = {
const theme = createTheme({
...,
textVariants: {
header: {
Expand All @@ -269,7 +275,7 @@ const theme = {
color: 'black',
},
},
}
});

// In a component
<Text variant="header">Header</Text>
Expand Down Expand Up @@ -394,7 +400,7 @@ A variant is a form of Restyle function that maps a prop into multiple other pro

```ts
// In theme
const theme = {
const theme = createTheme({
// ...
spacing: {
s: 8,
Expand Down Expand Up @@ -428,7 +434,7 @@ const theme = {
elevation: 5,
}
}
}
})

import {createVariant, createRestyleComponent, VariantProps} from '@shopify/restyle'
const variant = createVariant<Theme>({themeKey: 'cardVariants', defaults: {
Expand Down Expand Up @@ -456,13 +462,13 @@ Any prop powered by Restyle can optionally accept a value for each screen size,

```tsx
// In your theme
const theme = {
const theme = createTheme({
// ...
breakpoints: {
phone: 0,
tablet: 768,
}
}
})

// Props always accept either plain values
<Box flexDirection="row" />
Expand Down Expand Up @@ -502,7 +508,7 @@ export const palette = {
lightGray: '#EEE',
};

const theme = {
const theme = createTheme({
spacing: {
s: 8,
m: 16,
Expand Down Expand Up @@ -534,11 +540,11 @@ const theme = {
shadowOpacity: 0.1,
},
},
};
});

type Theme = typeof theme;

const darkTheme = {
const darkTheme: Theme = {
...theme,
colors: {
...theme.colors,
Expand Down
6 changes: 6 additions & 0 deletions src/createTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {BaseTheme} from './types';

// Enforces proper shape for theme without throwing away the user specific values
const createTheme = <T extends BaseTheme>(themeObject: T): T => themeObject;

export default createTheme;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export {default as createText} from './createText';
export {ThemeProvider} from './context';
export {default as useTheme} from './hooks/useTheme';
export {default as useRestyle} from './hooks/useRestyle';
export {default as createTheme} from './createTheme';
export {default as createRestyleFunction} from './createRestyleFunction';
export {default as createRestyleComponent} from './createRestyleComponent';