Skip to content

velsa/styled-rn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub license Npm package total downloads GitHub forks GitHub stars

TypeScript

💄 Styled-RN

Styled Components for React Native the way they should have been.

Inspired by this article


Intro

Why 💄 styled-rn it better than 💅🏼 styled-components/native ?

Well, first of all, using styled components should be fun, but using css to style a React Native app is cumbersome and often ends up to be very messy.

Also:

  • styled-rn gives you access to ALL React Native style props
  • styled-rn is faster because it does not do tedious string template processing
  • styled-rn is easier to use (again, no messy string templates)
  • styled-rn is fully typed and has a nice API
  • styled-rn supports custom props, theme via ThemeProvider, multiple style objects and more..
  • styled-rn has a shorter name ;)

Installing:

npm i styled-rn

Dependencies

Styled-RN depends on react-native-safe-area-context to provide insets for the ctx prop. See below for more details.

npm i react-native-safe-area-context

Usage:

import { styled } from "styled-rn";

// Basic usage
export const Container = styled.View({
  flexDirection: "row",
  backgroundColor: "cyan",
});

// Use with any component
export const CoolAndBoldComponent = styled(CoolComponent, {
  fontWeight: "bold",
});

// Pass props to the styled component (attrs)
export const NonWrappingText = styled.Text(
  {
    color: "blue",
  },
  {
    attrs: {
      numberOfLines: 1,
      ellipsizeMode: "tail",
    },
  }
);

Theming:

You will need to do a few things in order to propagate the theme prop into all of your styled components:

  1. Define your theme object and the type for it
  2. Augment the Theme type
  3. Wrap your app in ThemeProvider

First, define your theme:

// mytheme.ts

export const theme = {
    primary: "blue",
    background: "white",
    ...
} as const;

export type MyAppTheme = typeof theme;

TODO: add example on how to use multiple themes

Now you need to augment the default Theme type with your own type. In order to do that, create a definitions file at the root of your source tree (e.g. global.d.ts) and add the following to it:

import { MyAppTheme } from "./mytheme.ts";

declare module "styled-rn" {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  interface Theme extends MyAppTheme {}
}

And finally, the wrapping, as usual:

// App.tsx

import { ThemeProvider } from "styled-rn";
import { theme } from "./mytheme.ts";

export default function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* your app components */}
    </ThemeProvider>;
  )
}

And that's it! You can now access your theme in any styled component:

export const Button = styled.TouchableOpacity(({ theme }) => ({
  backgroundColor: theme.background,
}));

If you want to use custom props in your styled component, make sure that your custom props interface extends StyledProps. E.g.

// Important:         👇
interface ButtonProps extends StyledProps {
  disabled?: boolean;
}

export const Button = styled.TouchableOpacity(({ disabled, theme }: ButtonProps) => ({
  opacity: disabled ? 0.3 : 1,
  backgroundColor: theme.background,
}));

// Using conditional styles with custom props
interface SmartComponentProps extends StyledProps {
  active?: boolean;
}
export const SmartComponent = styled.TouchableOpacity(({ active, theme }: SmartComponentProps) => [
  {
    fontSize: 16,
  },
  active && {
    fontWeight: theme.activeFontWeight,
    color: theme.activeColor,
  },
]);

You can also use theme in your components by calling the useTheme() hook or by wrapping your component with withTheme() HOC.

import { useTheme } from "styled-rn";

export const MyComponent = () => {
  const theme = useTheme();
};

Context

There is also a special ctx prop which you access easily from your styled component. It contains insets and window objects, which are the values returned by useSafeAreaInsets() and useWindowDimensions() respectively.

For example:

const TopBackButtonContainer = styled.TouchableOpacity(
  ({ theme, ctx }) =>
    ({
      color: theme.primary,
      position: "absolute",
      top: ctx.insets.top || theme.spacing[1],
      left: ctx.insets.left || theme.spacing[2],
      zIndex: 10,
    })
);

Known Issues

  • When component returns the style from inline function sometimes the style object has to be type casted to ViewStyle, TextStyle, etc... Otherwise, you'll get a weird TS error. It looks like a TS bug. If you don't want to cast your styles, make sure that you pass props to the function and USE THE PROPS in your styles.

Contributing

Issues and Pull Requests are always welcome.

About

Styled React Native Components

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published