An open API service indexing awesome lists of open source software.

https://github.com/eightyfive/react-native-themesheet

Lightweight alternative to @shopify/restyle
https://github.com/eightyfive/react-native-themesheet

Last synced: 5 months ago
JSON representation

Lightweight alternative to @shopify/restyle

Awesome Lists containing this project

README

          

# `react-native-themesheet`

Lightweight alternative to [@shopify/restyle](https://github.com/Shopify/restyle).

## Install

```bash
yarn add react-native-themesheet
```

## Usage

### Create theme

A Theme consist of a set of `colors` & a set of `sizes`.

```ts
// src/views/theme.ts

export const { createBox, createStyles, createVariants } = createTheme(
{
primary: 'black',
accent: 'white',
//
onPrimary: 'white',
onAccent: 'black',
},
{
s: 4,
m: 8,
l: 16,
roundness: 10,
},
);
```

### Create styles

`createStyles` allows you to create normal `react-native` styles with spacing shorthands & Theme color mapping.

```ts
// src/views/home.tsx

import { createStyles } from './theme';

const $ = createStyles({
container: {
backgroundColor: 'primary', // <-- color name
borderColor: 'accent', // <-- color name
borderRadius: 'roundness', // <-- size name
px: 's', // <-- `paddingHorizontal` shorthand + size name
my: 'm', // <-- `marginVertical` shorthand + size name
marginLeft: 30, // <-- no shorthand, normal `number` value
col: 5, // <-- Flex positioning (see API)
},
text: {
color: 'onPrimary', // <-- color name
pl: 'l', // <-- `paddingLeft` shorthand + size name
},
});

export function Home(props) {
return (

Hello !

);
}
```

### Create variants

`createVariants` allows you to easily compose a component "variant" style.

```ts
// src/views/lib/button.tsx

import { createVariants } from '../theme';

const $ = createVariants(
// defaults
{
borderRadius: 'roundness',
borderWidth: 1,
p: 'm',
},
// variants
{
primary: {
backgroundColor: 'onPrimary',
borderColor: 'onPrimary',
},
accent: {
backgroundColor: 'accent',
borderColor: 'accent',
},
secondary: {
backgroundColor: 'transparent',
borderColor: 'onPrimary',
},
},
// modifiers
{
disabled: {
opacity: 0.75,
},
compact: {
p: 's',
},
},
);

type Props = {
children: string;
compact?: boolean;
disabled?: boolean;
loading?: boolean;
variant?: 'primary' | 'accent' | 'secondary';
};

export function Button({
children,
compact = false,
disabled = false,
loading = false,
variant = 'primary',
}: Props) {
//
// ¡¡ `$` is function here !! (see API)
const styles = $(variant, {
disabled: disabled || loading,
compact,
});

// styles = [
// ,
// | | ,
// (disabled || loading) && ,
// compact &&
// ]

return (

{children}

);
}
```

### Create boxes

`createBox` enhance a component with spacing shorthand properties.

```ts
// src/views/lib.ts

import { Text as RNText, TextProps, View, ViewProps } from 'react-native';

import { createBox } from './theme';

export const Col = createBox(View);

export const Text = createBox(RNText);

export const Title = createBox((props: TextProps) => (

));
```

Later in app:

```ts
// src/views/header.tsx

import { Col, Text, Title } from './lib';

type Props = {
title: string;
subtitle?: string;
};

export function Header({ title, subtitle }: Props) {
return (

{title}
{subtitle ? (

{subtitle}

) : null}

);
}
```

## API

### `createTheme(colors, sizes)`

```ts
type Colors = Record

type Sizes = Record

createTheme(colors: C, sizes: S): {
colors,
sizes,
//
createBox,
createStyles,
createVariants
}
```

This is the only public API available. All utility functions are exported from it.

```ts
// src/views/theme.ts

import { createTheme } from 'react-native-themesheet';

export const { colors, createBox, createStyles, createVariants, sizes } =
createTheme(
{
primary: '#000',
accent: '#ffffff',
},
{
s: 4,
m: 8,
},
);
```

### `Theme.createBox(BaseComponent)`

```ts
createBox(BaseComponent: ComponentType)
```

Enhance `BaseComponent` with spacing shorthand properties:

| Shorthand | Property |
| --------- | ------------------- |
| `m` | `margin` |
| `mt` | `marginTop` |
| `mr` | `marginRight` |
| `mb` | `marginBottom` |
| `ml` | `marginLeft` |
| `my` | `marginVertical` |
| `mx` | `marginHorizontal` |
| `ms` | `marginStart` |
| `me` | `marginEnd` |
| `p` | `padding` |
| `pt` | `paddingTop` |
| `pr` | `paddingRight` |
| `pb` | `paddingBottom` |
| `pl` | `paddingLeft` |
| `py` | `paddingVertical` |
| `px` | `paddingHorizontal` |
| `ps` | `paddingStart` |
| `pe` | `paddingEnd` |

```ts
import { Text, TextProps, View, ViewProps } from 'react-native';

import { createBox } from './theme';

const Box = createBox(View);

const Title = createBox(Text);
```

### `Theme.createStyles(styles)`

```ts
createStyles(styles: Record)
```

A `Style` accepts all normal `react-native` style properties as well as `FlexStyle` & `SpacingStyle` properties:

```ts
type FlexStyle = {
col?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
row?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
};

type SpacingStyle = Partial>;
```

The following "color" properties will only accepts color names from the Theme:

- `backgroundColor`
- `borderColor`
- `color`
- `tintColor`

Finally `borderRadius` accepts both a size name from the Theme, as well as a normal `number` value.

```ts
import { createStyles } from './theme';

const $ = createStyles({
card: {
col: 5,
backgroundColor: 'primary',
borderRadius: 'roundness', // | 100
p: 'm',
},
});
```

#### Note about `FlexStyle`

A `FlexStyle` is a shorthand describing Flexbox properties.

It's based on the clever "dial" idea initially brought by [`react-native-row`](https://github.com/hyrwork/react-native-row).

Basically you can think of a Flex container as a dial number pad:

```
┌─────────────┐
│ 1 2 3 │
│ │
│ 4 5 6 │
│ │
│ 7 8 9 │
└─────────────┘
```

And when creating styles using the `{ (col|row): [1-9] }` shorthand, it will generate the corresponding Flexbox style:

```ts
const $ = createStyles({
colC: {
col: 5,
},
// $.colC = { flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }

rowBR: {
row: 9,
},
// $.rowL = { flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'flex-end' }

rowLR: {
row: 4,
justifyContent: 'space-between',
},
// $.rowLR = { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }

colLRB: {
col: 8,
alignItems: 'stretch',
},
// $.colLRB = { flexDirection: 'column', justifyContent: 'flex-end', alignItems: 'stretch' }
});
```

For an even more semantic way to express Flexbox positioning, check out [`react-native-col`](https://github.com/eightyfive/react-native-col).

### `Theme.createVariants(defaults, variants, modifiers)`

```ts
createVariants(defaults: Style, variants: Record, modifiers: Record)
```

`createVariants` returns a function helper to easily pick a component "variant" style:

```ts
import { createVariants } from './theme';

const $ = createVariants(
// defaults
{
borderWidth: 1,
},
// variants
{
primary: {
borderColor: 'primary',
},
accent: {
borderColor: 'accent',
},
},
// modifiers
{
disabled: {
opacity: 0.5,
},
},
);

$('primary', { disabled: false }); // --> [{ borderWidth: 1}, { borderColor: colors.primary }]

$('accent', { disabled: true }); // --> [{ borderWidth: 1}, { borderColor: colors.accent }, { opacity: 0.5 }]

$('secondary', { disabled: true }); // TS error (variant not found)

$('primary', { compact: true }); // TS error (modifier not found)
```