Skip to content

A one stop shop to solve all your css issues with React

License

Notifications You must be signed in to change notification settings

Bamieh/react-inline-styler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

npm version Build Status Gzipped size Coverage Status: coveralls Coverage Status: codecov Dependency Status License: MIT

React Inline Styler

React inline styler is a full solution for using inline styles in react. The library setup is similar to react redux by using a Provider component on the app level, and a HOC to wrap the components with to provide the proccessed styles.

Features

  • Fully configurable: you can add a theme, helpers, processor configurations, etc.
  • Super simple: the styles in javascript are just an object or a function.
  • Easy setup: the setup process is inspired from react-redux, the only thing you need to do is to add a Provider on the app level, and wrap your functions with an injectStyles HOC function.
  • Plug-and-play solution to proccess the styles, adding RTL support, dynamic prefixing, and much more!
  • Works with isomorphic apps and supports HOT reloads.
  • Utilities to merge styles and proccess styles dynamically during the component life cycle.
  • Modular way for using js inline styles in react instead of having them inside the render function or such.
  • Continuously maintained, unit tested, and used in production on large scale apps.

Getting started

npm install react-inline-styler

Prelude

During the development of Yamsafer website using react, our team tried almost every solution proposed by the community to style our components, but each had its shortcomings.

In late 2016 we migrated from Polymer to React (but thats for another story), we used to have a full powerful SCSS styles solution baked into our components, hence we used Airbnb's awesome library react-with-styles and in theory, this library was perfect for us, we used webpack to read scss files into our components, classnames for merging styles, and the setup was fairly easy by directly injecting their configurations into our application's context, soon we realized that directly playing with the context is a big no-no, as it is harder to maintain and adds more barrier to entry for new comers to react and the project. More importantly, the real issue was with overriding the styles from outside, this was not possible with sass styles as the overriding happens by the order of precedence in the scss files, instead of merging styles like that in javascript inline styles.

Based on the customization we needed to provide to components as props, we started looking for other solution using javascript styles. needless to say, some are very weird to implement with weird syntax that "just doesnt feel right", and some try to mimic writing styles in pure sass or css manner via javascript, which all by itself felt wrong to us aswell. some had huge performance dips, and mostly, non of them were easily configurable to enable us to add RTL support for arabic language and such, or add prefixes and other cool features.

And this is how React Inline Styler was born, it is a solution for scalable, optimized styles in javascript for React *Psst, React native very soon.

Example Usage

Check the example file for a full working example, that uses a custom processing pipeline, and configurations.

Step 1: Wrapping the app with a Provider

Notice that you can have multiple providers nested inside each other within the app.

import React, {Component} from 'react'
import {InlineStylerProvider} from 'react-inline-styler'

class App extends Component {
  render() {
    return (
      <InlineStylerProvider>
        App Content
      </InlineStylerProvider>
    )
  }
} 

Step 2: Injecting Processed styles to the Component

import React, {Component} from 'react'
import injectStyles from 'react-inline-styler'
import stylesToInject from './styles'

class MyComponent extends Component {
  render() {
    const {
      rootStyle,
    } = this.props.styles;

    return (
      <div style={rootStyle}>
        root Style
      </div>
    )
  }
}

export default injectStyles(stylesToInject)(MyComponent)

Step 3: Configuring the Styler

Configurations and Theme

Add a configs prop object to the Provider to configure your used processors, define a theme, helpers and all what your styles require.

Example theme and helpers

Simply add the theme and the helpers inside the configs, and these will be passed to the styles function used with the stylesInjector.

import React, {Component} from 'react'
import {InlineStylerProvider} from 'react-inline-styler'

class App extends Component {
  render() {
    const theme = {
      colors: {primary: 'blue', secondary: 'white', accent: 'orange'},
    }
    const helpers = {
      getColor(color) {
        const themeColor = theme.colors[color];
        if(!themeColor) throw Error(`no color ${color} found in theme`);
        return themeColor
      }
    }
    const configs = {
      theme,
      helpers,
    }
    return (
      <InlineStylerProvider configs={configs}>
        App Content
      </InlineStylerProvider>
    )
  }
} 

Ofcourse having each in a separate file is recommended than defining them inside the render function.

Processor Pipeline

The processor pipeline is an array of processors, each modify or add to the styles object, and feed it to the next in the line, the pipeline is super useful as it enables adding prefixes, rtl support, switching from px to em and rem or anything your app needs for your styles.

Add a pipline prop array to the Provider with your processor functions.

Processors
  • The RTL processor allows you to use the same style base for both rtl and ltr languages, it will be used here as an example.

  • The autoprefixer prefixes the styles dynamically based on the user-agent currently in used, it also works with isomorphic apps.

import React, {Component} from 'react'
import {InlineStylerProvider} from 'react-inline-styler'

import rtlProcessor from 'react-inline-styler-processor-rtl'
import autopefixerProcessor from 'react-inline-styler-processor-autoprefixer'


class App extends Component {
  render() {
    const pipeline = [rtlProcessor, autopefixerProcessor];
    const configs = {
      // rtl processor configs and options
      isRTL: false,
      helpers: {...rtlHelperes},
      // autoprefixer options
      enablePrefixing: !DEVELOPMENT,
    }
    return (
      <InlineStylerProvider pipeline={pipeline} configs={configs}>
        App Content
      </InlineStylerProvider>
    )
  }
}

Creating your own custom processor is simple, its just a function that accepts a styles object, and the configs object. check the processor boilerplate to create a processor.

List of processors
  1. rtl support: use start and end instead of right and left so they can be dynamic based on the language direction.
  2. autoprefixer: auto-prefix javascript style dynamically based on the running browser.

Please inform us if you make a processor, we'd be happy to add it to the list for people to use.

Styles File

Notice that the javascript styles can be an object instead of a function, if non of the configs are needed.

const styles = (configs) => {
  const {
    colors,
  } = configs.theme;

  const {
    onRTL,
    onlyRTL,
    onlyLTR,
  } = configs.helpers;

  return {
    containerStyle: {
      color: onRTL('red', colors.secondary),
      backgroundColor: onlyRTL('red'),
      paddingStart: 10,
    },
    buttonStyle: {
      color: 'red',
      position: 'absolute',
      start: 10,
      marginTop: 10,
      marginEnd: 15,
    },
    activeButtonStyle: {
      color: colors.primary,
    },
  }
}

export default styles

processing and merging styles in the component

The injector (HOC) function exposes two helper methods to the component, processStyle and computeStyle.

processStyles

processStyles is used to process a style dynamically created inside the component (if you dynamic attibutes based on props)

const processedStyle = processStyles({
  color: this.props.color,
  fontSize: 13,
})
computeStyle

computeStyle is used to assign multiple styles together. its inspired by the ease of classnames library, but this one is for styles instead of classes.

const computedStyle = computeStyle(alwaysHaveThisStyle, {
  conditionalStyle: this.props.withConditional,
})

here if withConditional prop is true, conditionalStyle style will be merged with in the final result otherwise, just alwaysHaveThisStyle will be outputted.

computeStyle does not merge unprocessed styles, if you have a dynamic style created inside the component, run the processor against it first.

const computedStyle = computeStyle(alwaysHaveThisStyle, {
  conditionalStyle: this.props.withConditional,
}, procesStyle({color: this.props.color}))
import React, {Component} from 'react'
import injectStyles from 'react-inline-styler'
import stylesToInject from './styles'

class MyComponent extends Component {
  render() {
    const {
      thick,
      fontSizeProp,
      styles,
      processStyle,
      computeStyle,
    } = this.props.styles;

    const {
      rootStyle,
      thickFontStyle,
    } = styles;

    const computedRootStyle = computeStyle(rootStyle, {
      thickFontStyle: thick,
    })
    const processedTextStyle = processStyle({
      fontSize: fontSizeProp,
    })
    return (
      <div style={computedRootStyle}>
        <span style={processedTextStyle} >hello world!</span>
      </div>
    )
  }
}

export default injectStyles(stylesToInject)(MyComponent)

License

MIT. Copyright (c) 2017 Ahmad Bamieh

About

A one stop shop to solve all your css issues with React

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published