Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

logo

React Native Reflect

Responsive, theme-based style system for React Native and React Native Web

spectrum-badge MIT License Types

npm i react-native-reflect

Description

Reflect makes it easy to create universal React Native applications for Native and Web by providing tools for responsive styles and props, a theme system and other utilities.

Reflect is an alternative to libraries such as Styled Components and Styled System, built from the ground up for React Native and React Native Web. It provides exports such as: styled(), useStyled() and ThemeProvider, with an API that is React Native friendly.

The library is also minimal, has no dependencies on other styling libraries and it is designed to be used alone or with other React Native UI libraries such as React Native Elements. Use it to define styling for a whole application, as the building blocks for creating your own UI library, or just as needed, to handle different screen sizes or platforms.

Features

  • Built from the ground up for React Native and React Native Web
  • Quickly create theme-based, responsive styles (fontSize, margin, etc.)
  • Easily make any prop responsive and platform conditional
  • Integrates nicely with other UI Libraries, such as React Native Elements
  • Provides similar functionality to Styled Components and Styled System
  • Thoroughly unit tested

Getting Started

The following example shows how to use Reflect to create theme-based responsive components. The components created will display as a single column on small screens and as two columns on larger screens.

Getting Started Example

Installation

Create an Expo project and install Reflect:

expo init my-reflect-app
cd my-reflect-app

# with yarn
yarn add react-native-reflect

# with npm
npm i react-native-reflect

Usage

Replace contents of App.js or App.tsx with the code below:

import React from "react";
import { View, SafeAreaView } from "react-native";
import { styled, ThemeProvider, defaultTheme } from "react-native-reflect";

// (1) Define your theme
const theme = {
  ...defaultTheme,
  colors: {
    red: "#FF4B48",
    blue: "#2AB7CA",
    yellow: "#FFD766",
    grey: "#E6E6EA",
  },
};

// (2) Define your theme-based, responsive components
const Flex = styled(View, {
  display: "flex",
  flexDirection: "row",
  flexWrap: "wrap",
});

const Box = styled(View, {
  // Responsive -> 100% on smaller screens, 50% on larger screens
  width: ["100%", "50%"],
  // Theme based values -> height: 6 = theme.size[6] = 96
  height: 6,
});

// (3) Create variations of your components
const RedBox = styled(Box, { backgroundColor: "red" });
const BlueBox = styled(Box, { backgroundColor: "blue" });
const YellowBox = styled(Box, { backgroundColor: "yellow" });
const GreyBox = styled(Box, { backgroundColor: "grey" });

// (4) Enjoy a fully responsive native/web UI with a clean markup!
export default function App() {
  return (
    <SafeAreaView>
      <ThemeProvider value={theme}>
        <Flex>
          <RedBox />
          <BlueBox />
          <YellowBox />
          <GreyBox />
        </Flex>
      </ThemeProvider>
    </SafeAreaView>
  );
}

All examples are included in the Reflect Examples Expo App

Start Expo app and run it on a web browser and on a simulator. From the command line: "Press a for Android emulator, or i for iOS simulator, or w to run on web."

# with yarn
yarn start

# with npm
npm run start

styled()

styled(Component, StyleSheet)

styled(Component, MultipleStyleSheets)

styled(Component, StyleSheets, Props)

styled(Component, MultipleStyleSheets, Props)

Use styled() to create theme-based, responsive components. StyleSheets are React Native style sheets with some extra value types such as arrays. An array value is a shorthand for responsive values. Look at the examples below for more.

Single Style

styled(Component, StyleSheet)

Calling styled() with a single style sheet creates a styled component with a single responsive style prop.

const Title = styled(Text, {
  textAlign: "center",
  fontSize: [3, 4], // 3, 4 are values from theme.fontSizes[3],
  // and theme.fontSizes[4]
});

The example below demonstrates how theme-based responsive style sheets work. Run the Reflect Examples Expo App and follow the comments in the code:

import * as React from "react";
import { View, Text } from "react-native";
import { styled, defaultTheme } from "react-native-reflect";

// (1) Look at defaultTheme output in the console.
//
// - defaultTheme.breakpoints  determine the device's width ranges for
//                             responsive behavior. breakpoints contain 4
//                             values which will generate 5 breakpoints (xs,
//                             sm, md, lg, xl)
//
// - defaultTheme.fontSizes    are the list of font sizes our theme is using
//
// - defaultTheme.space        are the theme's list of spacing values used for
//                             margin, padding, etc.
//
console.log(defaultTheme);

// (2) Margin themed values are taken from theme.space, for example:
//
// - marginLeft: 4 = defaultTheme.space[4] = 24
//
const Container = styled(View, {
  marginLeft: 4,
  marginTop: 4,
});

// (3) Array values are responsive, resize browser window to test how values
// change based on window width.
//
// - color and fontSize change on every breakpoint (xs, sm, md, lg, xl)
// - marginTop changes at the middle of breakpoints (<= sm, >= md)
// - fontWeight changes as follows: (<= sm, md, >= lg)
//
const Title = styled(Text, {
  color: ["primary", "secondary", "success", "error", "warning"],
  fontSize: [3, 4, 5, 6, 7],
  marginTop: [5, 6],
  fontWeight: ["normal", "medium", "bold"],
  textAlign: "center",
});

const SingleStyle = ({ navigation }) => {
  return (
    <Container>
      <Title>Single Style Example</Title>
    </Container>
  );
};

export default SingleStyle;

Run all examples by installing the Reflect Examples Expo App

Multiple Styles

styled(Component, MultipleStyleSheets)

Calling styled() with multiple style sheet objects creates a styled component with multiple responsive style props.

import { Button } from "react-native-elements";
import { styled } from "react-native-reflect";

const MyButton = styled(Button, {
  containerStyle: {
    // 100% on smaller screens, 140 pixels on larger screens
    width: ["100%", 140],
  },
  buttonStyle: {
    // theme.space[3] on smaller screens,
    // theme.space[4] on larger screens
    padding: [3, 4],
    backgroundColor: "primary",
  },
});

The example below demonstrates how to define multiple theme-based, responsive style props. Run the Reflect Examples Expo App and follow the comments in the code:

import * as React from "react";
import { View } from "react-native";
import { styled } from "react-native-reflect";
import { Button } from "react-native-elements";

const Container = styled(View, {
  margin: 4,
});

// Many UI libraries such as React Native Elements provide multiple style props
// to style components. To style this kind of components, add each style prop
// as a nested object as shown below:
const MyButton = styled(Button, {
  containerStyle: {
    // 100% on smaller screens, 140 pixels on larger screens
    width: ["100%", 140],
  },
  buttonStyle: {
    // theme.space[3] on smaller screens,
    // theme.space[4] on larger screens
    padding: [3, 4],
    backgroundColor: "primary",
    width: "100%",
  },
  titleStyle: {
    fontWeight: "bold",
  },
});

const MultipleStyles = () => {
  return (
    <Container>
      <MyButton title="MyButton" />
    </Container>
  );
};

export default MultipleStyles;

Run all examples with the Reflect Examples Expo App

Responsive Props

styled(Component, StyleSheets, Props)

The third optional argument of styled() is used to make any prop of a component responsive.

import { Button } from "react-native-elements";
import { styled } from "react-native-reflect";

const MyButton = styled(
  Button,
  {},
  {
    // "solid" on smaller screens, "clear" on larger screens
    type: ["solid", "clear"],
  }
);

Run the example above and all other example with the Reflect Examples Expo App

useStyled()

useStyled({ style, styles, attrs })

Return value:

{ style, styles, attrs, breakpoint, theme }

Responsive styles and props can also be created by using the usedStyled() hook. This approach could be useful for adding responsive functionality to some props of an existing component without having to create components with styled(). It also allows the creation of more complex components, since the return values of useStyled() can be further processed inside the component.

Single Style Hook

useStyled({ style })

In the example below, we're using a single style with responsive font sizes and dynamically getting the breakpoint index. Resize the browser's screen or test in different devices to see the changing breakpoint index the font size.

import { useStyled } from "react-native-reflect";

const MyComp = () => {
  const { style, breakpoint } = useStyled({
    style: {
      // xs, sm  ->  theme.fontSizes[3]
      // md      ->  theme.fontSizes[4]
      // lg, xl  ->  theme.fontSizes[5]
      fontSize: [3, 4, 5],
    },
  });

  return <Text style={style}>{`Breakpoint Index: ${breakpoint}`}</Text>;
};

Run the example above and all other example with the Reflect Examples Expo App

Multiple Styles Hook

useStyled({ styles })

The following example shows how to use useStyled() hook for creating multiple responsive style sheets.

import { Button } from "react-native-elements";
import { useStyled } from "react-native-reflect";

const MyButton = () => {
  const { styles, breakpoint } = useStyled({
    styles: {
      containerStyle: {
        // 100% on smaller screens, 200 pixels on larger screens
        width: ["100%", 200],
      },
      buttonStyle: {
        backgroundColor: "primary",
      },
    },
  });

  return (
    <Button
      containerStyle={styles.containerStyle}
      buttonStyle={styles.buttonStyle}
      title={`Breakpoint # ${breakpoint}`}
    />
  );
};

Run the example above and all other example with the Reflect Examples Expo App

Responsive Props Hook

useStyled({ attrs })

useStyled() can also be used to create generic responsive values.

import { useStyled } from "react-native-reflect";
import { Button } from "react-native-elements";

const MyButton = () => {
  const { attrs } = useStyled({
    attrs: {
      // "solid" on smaller screens, "clear" on larger screens
      type: ["solid", "clear"],
    },
  });

  return <Button type={attrs.type} />;
};

Run the example above and all other example with the Reflect Examples Expo App

os()

os({ web, native }), os({ web, ios, android }), or:

os([ web, native ]), os([ web, ios, android ])

The os() utility lets you succinctly define platform specific values.

Platform Props

The following example shows how to use os() with styled() to create a component with platform specific props.

import { Button } from "react-native-elements";
import { styled, os } from "react-native-reflect";

const MyButton = styled(
  Button,
  {},
  {
    raised: os([true, false]),
    // or   os({ web: true, native: false })

    type: os(["solid", "clear", "outline"]),
    // or os({ web: "solid", ios: "clear", android: "outline" })
  }
);

Run the example above and all other example with the Reflect Examples Expo App

Responsive Platform Props

The os() utility can be used in combination with responsive array values to make values responsive and platform specific.

import { Text } from "react-native";
import { styled, os } from "react-native-reflect";

const MyText = styled(Text, {
  // web    smaller screens  ->  "medium"  ->  "500"
  // web    larger  screens  ->  "normal"  ->  "normal"
  // native smaller screens  ->  "bold"    ->  "bold"
  // native larger  screens  ->  "medium"  ->  "medium"
  //
  fontWeight: [os(["medium", "normal"]), os(["bold", "medium"])],
});

Run the example above and all other example with the Reflect Examples Expo App

Theme

The theme object is based on the System UI Theme Specification and it is used to store design system values and scales. You can import the defaultTheme to get a quick glance at it.

import { defaultTheme } from "react-native-reflect";
console.log(defaultTheme);

Will output an object similar to this:

{
  breakpoints: [375, 768, 1024, 1680],
  colors: {
    primary: "#007BFF",
    secondary: "#6C757D",
    ...
  },
  borderWidths: [1, 2, 4, 8],
  fontSizes: [12, 14, 16, 20, 24, 32, 48, 64],
  space: [0, 3, 6, 12, 24, 48, 96],
  sizes: [0, 3, 6, 12, 24, 48, 96],
  fonts: {
    sans: "system-ui, sans-serif",
    mono: "Menlo, monospace"
  },
  fontWeights: {
    normal: "normal",
    medium: "500",
    bold: "bold"
  }
}

Theme Specifications

Breakpoints

The breakpoints array defines the screen width dimensions at which responsive values change.

breakpoints: [375, 768, 1024, 1680];
Breakpoint index Screen width
0 less than breakpoints[0]
1 in between breakpoints[0] and breakpoints[1]
2 in between breakpoints[1] and breakpoints[2]
3 in between breakpoints[2] and breakpoints[3]
4 greater or equal than breakpoints[3]

The breakpoint index corresponds to the element in a value array. For example:

const Box = styled(View, { width: ["100%", "90%", "80%", "70%", "60%"] });

Box will have a width of 100% when the screen width is less than 375 pixels, 90% when the screen width is between 375 and 768 pixels and so on.

Moreover, it is not necessary to include all 5 entries in a value array. If less than 5 values are supplied, the remaining breakpoints will be inferred from from the closest defined value from the center outwards, as follows:

Value array Processed as
["100%", "60%"] ["100%", "100%", "60%", "60%", "60%"]
["100%", "80%", "60%"] ["100%", "100%", "80%", "60%", "60%"]
["100%", "90%", "80%", "60%"] ["100%", "90%", "80%", "60%", "60%"]

Key Reference

The following is a list of theme keys and their corresponding style properties.

Theme key Style property
color color, backgroundColor, borderColor
borderWidths borderWidth
fontSizes fontSize
space margin, marginTop, marginRight, marginBottom, marginLeft, padding, paddingRight, paddingLeft, paddingTop, paddingBottom
sizes width, height, minWidth, maxWidth, minHeight, maxHeight
fonts fontFamily
fontWeights fontWeight
radii borderRadius
zIndices zIndex

ThemeProvider

To set a global theme for your application, enclose your top-most component with <ThemeProvider> as shown below:

import { ThemeProvider, defaultTheme } from "react-native-reflect";

const theme = {
  ...defaultTheme,
  colors: { red: "#FF4B48", blue: "#2AB7CA" },
  space: [0, 2, 4, 8, 16, 32, 64],
};

const App = () => (
  <ThemeProvider value={theme}>
    <AppContent />
  </ThemeProvider>
);

API / TypeScript

Reflect provides types for it's own methods, components and objects, along with other types which can be useful when working with React Native and Reflect.

Objects

Components

Methods

Tutorials