Skip to content

Commit

Permalink
Added aliases and default styles
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-levy committed Jun 23, 2023
1 parent e01f8b2 commit 52c0636
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 64 deletions.
61 changes: 54 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
Apply styles directly to your React Native components via props!

- Fully typed
- No more `StyleSheet.create` or `styles={{ ... }}
- Same naming conventions as the style object
- Faster development
- No more `StyleSheet.create` or `styles={{ ... }}`
- Faster prototyping
- Custom aliases
- Default styles

## Installation

Expand All @@ -15,16 +16,18 @@ yarn add style-direct-club

## Usage

```js
```tsx
import { TouchableOpacity } from 'react-native';
import { styled } from 'style-direct-club';

// Create a styled component
const StyledTouchableOpacity = styled(TouchableOpacity);

// Or use the out of the box components
const View = styled.View;
const Text = styled.Text;

// Use props to style your components directly
function App() {
return (
<View flex={1} rowGap={10} justifyContent="center" alignItems="center">
Expand All @@ -42,12 +45,56 @@ function App() {
}
```

## Custom Options

### Aliases

You can use aliases to make the style prop names more readable. Agree upon standards with your team and stay consistent!

Format your custom alias object like this: `{ aliasName: originalStyleName }`

```tsx
import { styled, defaultAlias } from 'style-direct-club';
import { View } from 'react-native';

// Use the default aliases
const StyledView = styled(View, {
aliases: {
// Use the default aliases
...defaultAlias,
// Or add your own!
bg: 'backgroundColor',
p: 'padding',
m: 'margin',
mt: 'marginTop',
},
});
```

### Default Styles

You can set common default styles for your components. These styles will be applied to every instance of the component and can be overridden with props.

```tsx
import { styled } from 'style-direct-club';
import { TouchableOpacity } from 'react-native';

const StyledTouchableOpacity = styled(TouchableOpacity, {
defaultStyles: {
backgroundColor: 'blue',
padding: 10,
borderRadius: 8,
},
});
```

## Gotchas

- The `style` prop is still supported, but styles passed in as props will take precedence over the `style` prop object.
- If you want to add these props to a custom component, the component must pass its props to the underlying view.
- Default styles will not respect aliases. You must use the original style prop name.
- When using the built in components, you won't be able to pass additional options.

## To Do
```
- [x] Add out of the box components
- [ ] Add support for aliases (e.g. `backgroundColor` -> `bg`)
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "style-direct-club",
"version": "0.0.4",
"description": "test",
"description": "Apply styles directly to your React Native components via props!",
"main": "lib/commonjs/index",
"module": "lib/module/index",
"types": "lib/typescript/index.d.ts",
Expand Down
39 changes: 39 additions & 0 deletions src/aliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const defaultAlias = {
bg: 'backgroundColor',
p: 'padding',
pt: 'paddingTop',
pr: 'paddingRight',
pb: 'paddingBottom',
pl: 'paddingLeft',
ps: 'paddingStart',
pe: 'paddingEnd',
px: 'paddingHorizontal',
py: 'paddingVertical',
m: 'margin',
mt: 'marginTop',
mr: 'marginRight',
mb: 'marginBottom',
ml: 'marginLeft',
ms: 'marginStart',
me: 'marginEnd',
mx: 'marginHorizontal',
my: 'marginVertical',
w: 'width',
h: 'height',
minW: 'minWidth',
minH: 'minHeight',
maxW: 'maxWidth',
maxH: 'maxHeight',
justify: 'justifyContent',
items: 'alignItems',
self: 'alignSelf',
direction: 'flexDirection',
wrap: 'flexWrap',
basis: 'flexBasis',
grow: 'flexGrow',
shrink: 'flexShrink',
} as const;

// size: 'fontSize',
// weight: 'fontWeight',
// align: 'textAlign',
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { styled } from './styled';
export { defaultAlias } from './aliases';
56 changes: 0 additions & 56 deletions src/index.tsx

This file was deleted.

64 changes: 64 additions & 0 deletions src/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ComponentProps, createElement } from 'react';
import { allowedProps } from './allowedProps';
import { StyleProp, Text, View } from 'react-native';

type Options<T extends React.ComponentType<any>> = {
alias?: Record<string, keyof AliasMap<T>>;
defaultStyles?: AliasMap<T>;
};

type AliasMap<T extends React.ComponentType<any>> = ComponentProps<T> extends {
style?: infer S;
}
? S extends StyleProp<infer P>
? Exclude<P, false | null | undefined>
: {}
: {};

/**
* Creates a styled component, allowing you to pass style props directly to the component
* instead of using the `style` prop or `StyleSheet.create`. Prop names can be aliased, and
* default styles can be provided.
*/
export function styled<
T extends React.ComponentType<any>,
U extends Options<T> = {}
>(component: T, options: U = {} as U) {
type BaseProps = ComponentProps<T>;
type PropsWithAliasMap = BaseProps &
// @ts-ignore
Omit<AliasMap<T>, U['alias'][keyof U['alias']]> & {
// @ts-ignore
[k in keyof U['alias']]?: AliasMap<T>[U['alias'][k]];
};

return function StyledComponent(props: PropsWithAliasMap) {
return createElement(component, {
...props,
style: {
...(options?.defaultStyles || {}),
...props.style,
...mapStyleProps(props, options?.alias),
},
});
};
}

function mapStyleProps(
props: Record<string, any>,
aliasMap?: Record<string, any>
) {
const styleProps: Record<string, any> = {};
if (props) {
Object.keys(props).forEach((key) => {
const keyOrAlias = aliasMap?.[key] || key;
if (allowedProps.includes(keyOrAlias)) {
styleProps[keyOrAlias] = props[key];
}
});
}
return styleProps;
}

styled.Text = styled(Text);
styled.View = styled(View);

0 comments on commit 52c0636

Please sign in to comment.