react-native-advanced-stylesheet

Yes, it's another library that does very common thing, but it created because of lack of solutions with required functional to live "happy" live as react-native developer.

Usage no npm install needed!

<script type="module">
  import reactNativeAdvancedStylesheet from 'https://cdn.skypack.dev/react-native-advanced-stylesheet';
</script>

README

React Natve Advanced Stylesheet

npm version

Yes, it's another library that does very common thing, but it created because of lack of solutions with required functional to live "happy" live as react-native developer.

RNAS provides functionality for theming your app with dynamically provided ( via react context, NOT with GLOBAL instance of something ) theme defenition, also it provides generation of styles depending on additionally passed values ( just call it props ).

WARNING: Library recently created, and it's can change in near future, so think twice before using it right now ( or stick to specific version of npm package you want ).

So, to get started we need to do few simple steps.

1. Setup provider at top level of your app

import { Provider } from 'react-native-advanced-stylesheet';

// somewhere in your component
// IMPORTANT: you need to pass new theme instance because under the hood it compared by ref equality, so be carefull and not mutate your theme while waiting to something will happen, and also be sure to provide same instance if theme not changing at the moment to avoid of recalculating of ALL currently exsisting styles
<Provider theme={theme}>{/* Your components tree here */}</Provider>;

2. Somwhere in your code define stylesheet.

// define stylesheet
// define has 2 overloads:
// define(() => ({}), { }) // 1 - Dynamic styles 2 - Static styles which will be merged together but will not be recalculated
// define({  }) - 1. Static styles. Just to keep consistant approach in project, probably will be better to use define instead of StyleSheet.create everywhere.
const styleSheet = define((theme, { background }) => ({
  root: {
    backgroundColor: background
  },
  caption: {
    color: 'red'
  }
})); // NOTE: here we have object { dynamic, staticStyles } which is format required for useStyles hook, so if you want to test your styles creator, just use .dynamic() and pass theme, props arguments to call it. Actually define is required for TS typization, because currently i didn't find other way to provide types for strongly type check and get resulting type matching requirements.

// in your component file
const YourComponent: React.FC = ({ background = 'tomato' }) => {
  // styles will be recalculated when theme in provided changed ( new instance passed ), or if second argument ( props ) will fail shallow compare check agains previous render value
  const styles = useStyles(styleSheet, { background });

  return (
    <View style={styles.root}>
      <Text style={styles.caption}>Caption</Text>
    </View>
  );
};

And we are done with setup!

Styles recalculation

There are cases when we will need to recalculate styles and rerender components depending on some external conditions or events. For that reason you may use StyleContext and just hook { recalculate, theme } in your components by yourself. When calling recalculate it will trigger all mounted styles to recalc and rerender component.

Also there is pre made component for defining subscriptions. You can use <RecalculateSubscription /> to do that.

return (
  <View>
    {/* Place it somewhere in your components, but probably on the top level */}
    <RecalculateSubscription
      // called on didmount
      on={recalculate => Dimensions.addEventListener('change', recalculate)}
      // called on willunmount
      off={recalculate => Dimensions.removeEventListener('change', recalculate)}
    />
  </View>
);

Example allows to subscribe on Dimensions change and rerender styled components. For Dimensions tracking already create <DimensionsSubscribtion /> component so you can import it and just place where it needed.

Plans

  1. Add nested styles to allow structuring styles like:
{
    input: {
        color: '#000',
        borderWidth: 1,
        focused: {
            borderColor: 'green'
        }
    }
}
  1. Add some built-in helper functionality like mixins.
  2. Improve TS type support, currently there are few problems needed to be fixed ( for example when you define styles using "define" when first property added, next properties in style object will not be checked by TS to match exsisting in RN style properties )
  3. withStyles decorator ( for those who don't want to use it as hook )
  4. Write more tests. ( partially tested right now ).

Features

If you want to offer some feature, feel free to write issue with request and it can be implemented later.