npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

flourish

v0.0.2

Published

Magical JS styles

Readme

flourish

Inline JS styles mixin for React components which work like magic. Component state and props are accessible to your styles, and media queries work too. You can even easily pass styles down from parents as props and choose where to apply them.

This is a mixin, not a decorator or a higher order component, because mixins are simple, inherently useful, play nice together, and don't break other functionality like refs.

Usage is simple.

import flourish from 'flourish'

export default React.createClass({
  mixins: [flourish], // attach the mixin
  ...
  render() {
    let { wrapper, title } = this.style // all styles are on this.style
    return (
      <div style={ wrapper }>
        <h1 style={ title }>This is the title</h1>   
      </div>
    )
  },

  statics: {
    style: require('./style') // import your component styles in statics
  }
})

... and in your style.js:

let wrapper: {
  backgroundColor: '#666',
  padding: 30
}

let title: {
  color: 'white',
  fontSize: 30
}

export default { wrapper, title }

That's it. No bullshit. Just write your styles, attach the mixin, then style any number of elements in your component.

If you want your styles to adapt to component state/props/media queries, all that is handled when you write up your styles. Nothing changes in your component.

Here's an example of a complex input taken from a real live application:

// style.js

import v from '../../styleHelpers/all' // custom SASS-like helpers and app-wide variables

let _greyedOut = {
  borderBottomColor: v.grey,
  color: v.grey
}

let Wrapper = { // base styles
  inherit: true, // append this.props.style here (inherit from parent)
  float: 'left',
  position: 'relative',
  zIndex: 1,
  textAlign: 'left',
  fontFamily: v.font,

  'props:width': { // example of string props
    full: { width: '100%' },
    wide: { width: '66%' },
    half: { width: '50%' },
    narrow: { width: '34%' },
    quarter: { width: '25%' }
  },

  'props:spacing': { // example of string props
    compact: { padding: 0 },
    tight: { padding: v.sh(0, v.xs, v.s) },
    loose: { padding: v.sh(0, v.m, v.xl) }
  }
}

let Label = { // base styles
  position: 'relative',
  transition: v.transitionFast,
  display: 'block',
  width: '100%',
  borderRadius: 2,
  backgroundColor: v.white,
  border: v.sh(1, 'solid', v.greyLight),
  borderBottom: v.sh(1, 'solid', v.greyDark),
  padding: v.sh(v.xs, v.s, 0),
  textTransform: 'uppercase',
  letterSpacing: v.spacedWidest,
  fontSize: 9,
  lineHeight: '9px',
  color: v.greyDark,

  'state:error': { // example of boolean state
    borderBottomColor: v.error,
    color: v.error
  },

  'state:focus': { // example of boolean state
    borderBottomColor: v.greenLight,
    color: v.greenLight
  },

  'state:hasValue': _greyedOut, // example of boolean state
  'props:disabled': _greyedOut, // example of boolean props
  'props:readOnly': _greyedOut // example of boolean props
}

let Input = { // base styles
  fontFamily: v.font,
  display: 'block',
  width: '100%',
  border: 'none',
  outline: 'none',
  background: 'transparent',
  fontSize: 15,
  color: v.greyDark,
  textTransform: 'none',
  letterSpacing: v.spaced,
  lineHeight: '27px',
  height: '27px',

  'props:disabled': { color: v.grey } // example of boolean props
}

let Icon = { // base styles
  position: 'absolute',
  right: v.s,
  top: '50%',
  marginTop: -12,
  lineHeight: '24px',
  fontSize: 14,

  'state:error': { color: v.error }, // example of boolean state
  'state:valid': { color: v.greenLight } // example of boolean state
}

let Message = { // base styles
  transition: v.transitionSlowDelay,
  position: 'relative',
  zIndex: -1,
  top: -56,
  borderRadius: '0 0 2px 2px',
  color: v.greyDark,
  fontSize: 12,
  lineHeight: 1,
  letterSpacing: v.spaced,
  padding: v.sh(v.xs, v.s),
  opacity: 0,

  'state:error': { // example of boolean state
    opacity: 1,
    top: 0,
    margin: v.sh(0, v.s),
    backgroundColor: v.error,
    color: v.white
  },

  'state:focus': { // example of boolean state
    opacity: 1,
    top: 0
  }
}

export default { Wrapper, Label, Input, Icon, Message }

As you can see, styling a component based on props/state is as simple as 'props:KEY': { VALUE: { ...styles }} or 'state:KEY': { VALUE: { ...styles }}.

Media queries follow the same pattern: 'media:phone': { ...styles }.

Out of the box, these are the default breakpoints used for media queries:

{
  tiny: '(min-width: 200px)',
  small: '(min-width: 350px)',
  phone: '(min-width: 450px)',
  medium: '(min-width: 500px)',
  large: '(min-width: 650px)',
  tablet: '(min-width: 700px)',
  huge: '(min-width: 800px)',
  laptop: '(min-width: 950px)',
  desktop: '(min-width: 1200px)',
  tv: '(min-width: 1450px)',
  tinyMax: '(max-width: 199px)',
  smallMax: '(max-width: 349px)',
  phoneMax: '(max-width: 449px)',
  mediumMax: '(max-width: 499px)',
  largeMax: '(max-width: 649px)',
  tabletMax: '(max-width: 699px)',
  hugeMax: '(max-width: 799px)',
  laptopMax: '(max-width: 949px)',
  desktopMax: '(max-width: 1199px)',
  tvMax: '(max-width: 1449px)'
}

But you can use your own instead:

import flourish from 'flourish'

let newBreakpoints = { ... }
flourish.setBreakpoints(newBreakpoints)