Giter VIP home page Giter VIP logo

radium's Introduction

Maintenance Status Travis Status AppVeyor Status Coverage Status NPM Package Dependency Status gzipped size

Radium

yarn add radium
# or
npm install --save radium

Radium is a set of tools to manage inline styles on React elements. It gives you powerful styling capabilities without CSS.

Inspired by React: CSS in JS by vjeux.

Maintenance Status

Archived: This project is no longer maintained by Formidable. We are no longer responding to issues or pull requests unless they relate to security concerns. We encourage interested developers to fork this project and make it their own!

Overview

Eliminating CSS in favor of inline styles that are computed on the fly is a powerful approach, providing a number of benefits over traditional CSS:

  • Scoped styles without selectors
  • Avoids specificity conflicts
  • Source order independence
  • Dead code elimination
  • Highly expressive

Despite that, there are some common CSS features and techniques that inline styles don't easily accommodate: media queries, browser states (:hover, :focus, :active) and modifiers (no more .btn-primary!). Radium offers a standard interface and abstractions for dealing with these problems.

When we say expressive, we mean it: math, concatenation, regex, conditionals, functions–JavaScript is at your disposal. Modern web applications demand that the display changes when data changes, and Radium is here to help.

For a short technical explanation, see How does Radium work?.

Features

  • Conceptually simple extension of normal inline styles
  • Browser state styles to support :hover, :focus, and :active
  • Media queries
  • Automatic vendor prefixing
  • Keyframes animation helper
  • ES6 class and createClass support

Docs

Usage

Start by wrapping your component class with Radium(), like export default Radium(Component), or Component = Radium(Component), which works with classes, createClass, and stateless components (functions that take props and return a ReactElement). Then, write a style object as you normally would with inline styles, and add in styles for interactive states and media queries. Pass the style object to your component via style={...} and let Radium do the rest!

<Button kind="primary">Radium Button</Button>
import Radium from 'radium';
import React from 'react';
import color from 'color';

class Button extends React.Component {
  static propTypes = {
    kind: PropTypes.oneOf(['primary', 'warning']).isRequired
  };

  render() {
    // Radium extends the style attribute to accept an array. It will merge
    // the styles in order. We use this feature here to apply the primary
    // or warning styles depending on the value of the `kind` prop. Since its
    // all just JavaScript, you can use whatever logic you want to decide which
    // styles are applied (props, state, context, etc).
    return (
      <button style={[styles.base, styles[this.props.kind]]}>
        {this.props.children}
      </button>
    );
  }
}

Button = Radium(Button);

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
  base: {
    color: '#fff',

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': {
      background: color('#0074d9')
        .lighten(0.2)
        .hexString()
    }
  },

  primary: {
    background: '#0074D9'
  },

  warning: {
    background: '#FF4136'
  }
};

Importing Radium

As of v0.22.x, Radium is built as an ECMAScript Modules-first project. We now have a package.json:module entry pointing to our library files with import|export statements instead of CommonJS requires. We still support CommonJS requires with a special package.json:main entry pointing to root index.js to smooth over this transition. The basic takeaways are:

If you are using ESM with webpack or @std/esm with Node.js, imports like the following work fine without any gotchas:

import Radium from 'radium';
import Radium, {Style} from 'radium';

If you are using CommonJS with Node.js or webpack@1 requires work like normal:

const Radium = require('radium');
const {Style} = require('radium');

If you are using CommonJS with webpack@2+, however, you must instead add .default to the root Radium object import:

const Radium = require('radium').default; // CHANGED: Must add `.default`
const {Style} = require('radium'); // Works as per normal

If you cannot change the require statements directly (say Radium is included from a different library your project depends on) you can manually tweak the Radium import in your project's webpack configuration with the following:

resolve: {
  alias: {
    radium: require.resolve('radium/index');
  }
}

which will allow const Radium = require('radium'); to still work. The configuration effectively forces webpack to point to code from package.json:main (which points to /index.js) instead of what is in package.json:module.

Note: Radium uses Reflect which is not supported in IE11. You will need to bring in a polyfill like CoreJs in order to support <IE11.

Examples

To see the universal examples:

npm install
npm run universal

To see local client-side only examples in action, do this:

npm install
npm run examples

How does Radium work?

Following is a short technical explanation of Radium's inner workings:

  • Wrap the render function
  • Recurse into the result of the original render
  • For each element:
    • Add handlers to props if interactive styles are specified, e.g. onMouseEnter for :hover, wrapping existing handlers if necessary
    • If any of the handlers are triggered, e.g. by hovering, Radium calls setState to update a Radium-specific field on the components state object
    • On re-render, resolve any interactive styles that apply, e.g. :hover, by looking up the element's key or ref in the Radium-specific state

More with Radium

You can find a list of other tools, components, and frameworks to help you build with Radium on our wiki. Contributions welcome!

Contributing

Please see CONTRIBUTING

radium's People

Contributors

alexlande avatar almost avatar azazdeaz avatar blainekasten avatar bobbyrenwick avatar boygirl avatar bsbeeks avatar catamphetamine avatar chrisbolin avatar colinmegill avatar david-davidson avatar dependabot[bot] avatar exogen avatar greenkeeperio-bot avatar ianobermiller avatar iclanzan avatar jeffrifwald avatar jfschwarz avatar kenwheeler avatar maringerov avatar mhink avatar nathanmarks avatar ryan-roemer avatar spacenick avatar stefvhuynh avatar stevenmusumeche avatar tmarshall avatar tptee avatar vincentriemer avatar williamboman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radium's Issues

Replace lodash with ES5 methods where possible

We should keep our dependencies as slim as possible. To that end, we should favor ES5 array and object methods (that React shims anyway) to their lodash equivalents where possible. This means you, forEach, map, and reduce!

Create component for `<style>` tags.

We need to use <style> tags nested in components for cases where we don't have control over markup. There are two main use cases here, that will require two behaviors for the <style> tag component.

Unscoped style tags

We need unscoped style tags for high level page styles. The main use case here is to drop a style tag at the root of the app that applies global styles (like browser resets, font-family on body, etc). This can also be done by just adding a base stylesheet or style tag to your template, but wouldn't it be nice to have it all live in React?

Style Objects as Model Injects

Style Objects look like simple JSON documents. This means that there must be a way to define and store them outside a components render function then fetch and inject them, right?

This way a component could use whatever exchangeable Style Object (JSON document) might be activated. So, if Firebase is used a Firebase ref in the component could be set to a given Style Object.

Love Radium just hope the inject approach works so I do not need to hardwire styles directly into a component. Having injectable Style Objects and good performance that does not re-render styles if not needed would be fantastic!

Active state should not be lost on mouseout if the mouse is held

In Chrome, if I click a button, hold the mouse, and then move the pointer outside the button, the button remains in the active state. However, using Radium, this behaviour is not respected, and I lose active state when the mouse leaves the button - regardless of the state of the mouse.

Media query behavior

Need a mixin or component to enable media query behavior in inline styles.

The current plan for responsive behaviors as I see it:

  • Responsive styles work similarly to modifiers (except that instead of choosing one value for a modifier, like size="large", they stack on top of eachother.

We use matchMedia in a mixin (potentially very high up in the app), and pass down applicable responsive modifiers as props.

Style Objects for other targets

Style Objects seem close to a design pattern I found many things in my app segmenting into, so I quite like the concept. React does not just target the DOM, it is also targeting iOS and Android via React Native. I assume Radium is meant to work with these targets as well?

In addition, I am interested in targeting the 2D Canvas element. In my flow of model data to a view component I'd hope to render some data to the DOM and most of it to a 2D Canvas via a custom filter function. To route to a Canvas element I match IDs on specific datums and fetch glyphs from a OTF or TTF font. Then I'd like to style those glyphs JIT before rendering them to the Canvas.

Would there be any issue with using the Style Object in such a way? Can the Style Object be extended with new style categories?

Radium Bootstrap Components

This is a loose ranking of Bootstrap components we should include for MVP. I left out most of the Bootstrap JS components because the effort to implement them well is probably not even with the amount of value they would provide as Radium examples. Maybe I'm totally wrong about that?

  • Buttons
  • Form groups / form controls / labels
  • Grid system
  • Dropdown
  • Table
  • Navbar
  • Pagination
  • Breadcrumbs
  • Alerts
  • Tabs (JS component)

/cc @eastridge

Allow modifiers to take precedence over other rules

Use Case: Responsive Left Nav
Given a nav list on the left side
And a media query to set the nav width to '0px' on small devices
When the 'expanded' prop is set to true
Then the 'expanded' modifier should set the width to '250px'

This 'expanded' prop would be set on the nav list when a menu trigger is activated

Server side media queries

Once the React media query situation has stabilized, we need to integrate a module that will scrape media query styles, apply classes to components that use them, and place those styles in a style tag in the head so that server-side rendering works correctly for responsive apps.

Tests?

Just that really. What is the testing story? We are more than a little reticent to really use something with no tests (no critique on the quality of the product tho!). But some amount of assurance against regressions and bugs across releases would be appreciated, along with just the additional implicit documentation tests provide about expected behavior.

Thanks for the great library we have really been enjoying it :)

Build global variable module

We need to provide an interface to let people use variables + components out of the box or configure them with their own styles.

Pseudo-selector support

:hover, :focus, and :active styles all need to be handled with component state. We need a clean interface for adding these styles.

For common states, you’ll need these listeners for most components:

  • onMouseEnter + onMouseLeave (:hover)
  • onFocus + onBlur (:focus)
  • onMouseDown + onMouseUp (:active)

Mixins vs. composition?

I was wondering if there are any plans for making this library work with ES6 classes without requiring the use of mixins? It isn't a huge deal since the React team has been pretty explicit that React.createClass isn't going anywhere, but it would be nice not to have to find a way to use mixins just to use radium.

This thread discusses the possible evolution of React apart from mixins: facebook/react#1380

Here's an example from @sebmarkbage of one way to accomplish a similar effect compositionally: https://gist.github.com/sebmarkbage/fac0830dbb13ccbff596

Seems like maybe something like this could work for radium, or possibly be exposed as an alternative to standard mixins? Anyone have thoughts?

Migration helper

I am currently in the process of converting parts of an app to use Radium. The most tedious part of this is changing spinal-case to camelCase, wrapping string values in quotes, removing px, etc. as this is the paradigm shift from CSS syntax to JS style syntax:

width: 100px;  →  width: 100
background-color: #abcdef;  →  backgroundColor: '#abcdef'
-webkit-overflow-scrolling: touch;  →  webkitOverflowScrolling: 'touch'

Doing this manually takes hours for even a small app, but I’d imagine parsing would take seconds. Would it be appropriate for Radium to include a helper to parse a compiled CSS file since this would reduce the friction of adopting the framework? Or should this be a separate project / addon?

Autogenerated classes and debugging?

This library seems neat so far! But, I had a few questions, particularly on why there is an emphasis on inline styles and not autogenerated classes.

I noticed the scopable style tag feature, but unfortunately placing style tags in <body> does not scope, and the scoped property isn't fully supported. And you still have to worry about class collision. Creating those style tags individually per mounted component instance instead of globally managing it also seems problematic (unless I misread it).

Also, how has debugging been working with this? Do inline styles ever collapse in the inspector? Are they easy to ignore? This is the case where autogenerated + debuggable classnames seem helpful; less inspector noise.

Is there any performance/accessibility impact using event handlers vs pseudo attributes?

I'm asking these questions after looking at JSS and react-styles. Just trying to find a good medium for all these ideas. Maybe I'm missing something regarding inline styles as the answer!

Looking forward to this!

Scoped style component

Splitting this into it's own issue from #18.

Scoped style tags

For things like user-generated content, or places where we need to use pseudo-elements, nth-child, etc, we need style tags that are scoped to the component they're included in. This is another case where you can use regular CSS in the meantime. I think this would look like this:

    <div>
      <Style local={true} style={scopedStyles} />
      {this.getUserGeneratedContent()}
    </div>
}

This would return a style tag where any rules would be scoped to the parent component. Given that the parent div would have some unique identifier ("we'll say #react-radium-id-foo-123):

<style>
#react-radium-id-foo-123 a {
  color: blue;
}

#react-radium-id-foo-123 a:hover {
  text-decoration: underline;
}
</style>

Create interface to map modifiers into adjoining modifiers

Title is probably a very bad way to describe this. In CSS, you sometimes have situations where styles should differ based on two modifiers used at the same time. This would traditionally be handled with adjoining classes or !important

.btn.active {
  background: black;
}

.btn-link,
.btn-link.active {
  background: transparent;
}

In this example, .btn-link.active is used in addition to .btn-link to prevent .btn-link elements with that class from using the background: black rule.

In Radium, we could handle this with a custom prop for this edge case

<Button
  kind='link'
  active={true}
  activeLink={true}>

This is not a good API. Instead, a component should be able to do things like set modifiers based on multiple props, or states, or whatever. Might look something like this:

if (this.props.kind === 'link' && this.props.active) {
  this.setModifier('activeLink', true);
}

Use React logic to serialize styles for style component.

To generate the innerHTML for each rule of the <Style> component, you could do something like this:

require('react/lib/CSSPropertyOperations').createMarkupForStyles({
  width: 10,
  margin: 'auto'
});
// => 'width:10px;margin:auto'

Create config file

I think we need a place to store configuration like default included mixins/modules and variables. I'm not sure if there's an npm convention we want to follow or pave our own path or something else.

/cc @alexlande @colinmegill @aykayen

Don't directly tie modifiers to props and states to state

Attempting to tie modifiers and states directly to their "corresponding" React data types (props and states) is probably not flexible enough.

As it currently stands, states maps directly to simulated browser states (:hover, :focus, etc), which doesn't cover the use case where a component needs different modifier styles based on it's own state. A good use case is the Bootstrap .active modifier on buttons, which is a modifier that matches :active styles. It's used for things like buttons that can be toggled on and off.

computed variables value proposition

Regarding variables - maybe you want them darker or lighter on different media, so you could take in user agent string and then return different variables in the store for colors, things like that, if we use a store for styles and put the variables there, rather than just using a module and returning an object.

Convert separate lodash packages to lodash path includes

Currently we're installing and importing separate lodash packages. It's easier to just add lodash as a dependency then require specific lodash modules by path. Instead of:

var merge = require('lodash.merge');

We can do:

var merge = require('lodash/object/merge');

Replace computed style callback with inline computed prop methods

Currently, if you want computed styles, you create a function that will create any computed styles you want based on the state of the style object after Radium has evaluated which modifiers and states should apply.

This tends to looks something like this:

getStyles: function () {
  return {
    $dynamicWidth: true
  }
}
createComputedStyles: function (styles) {
  var computedStyles = {};

  if (styles.$dynamicWidth) {
    computedStyles.width = exampleFunctionToGetWidth();
  }

  return computedStyles;
}

This isn't the absolute worst thing in the world, but ideally we would define computed styles as methods on the initial style object so that no callback is necessary, then Radium would evaluate the methods at the correct time and return the style object with the return values of those methods.

Testing Styles

@ryan-roemer Someone at the last FB meetup brought up that testing styles with Radium is now more feasible "because testing CSS was hell". Any ideas here?

Aggregate style component for server-side rendering

Problem

Radium media queries and browser states don't work with server-side rendering. This hurts initial render speed (we lose some of the benefits of server-side rendering because the initial render is incorrect), and means that apps using Radium won't display correctly until/if the app is hydrated on the client.

Aside from looking bad, this is an accessibility concern, particularly for browser state events.

Solution?

@rgerstenberger spent some time testing out variations of the Style component to handle this use case. In his tests, he handled :hover, :focus, and :active with style tags in each component, scoped to the parent component's react-id. The performance there was terrible, because the browser had to re-evaluate everything every time it hit a style tag.

The only good solution I can think of is to implement an aggregate style tag (code name: StyleCatcher) at the top of Radium apps. On server-side renders, we would take any media query + browser state styles and drop them there in a way similar to the existing Style component. I'm assuming this will have enough overhead that we won't want to do it on repeated renders on the client-side. If that's not the case, we could replace our existing media query + browser state behavior with the StyleCatcher.

Challenges

  • How do we now if it's a server side render or not (if we need to tell the difference)?
  • How does the interaction between components and StyleCatcher work? When a component calls buildStyles it updates state on StyleCatcher? Probably.
  • More things I'm forgetting?

Issue with well in example

The example of a dynamic background color in computed-well.jsx appears to be broken. It looks like it's trying to pass a styles object in as the additionalModifiers parameter to buildStyles(), which doesn't work. A simple fix for me was removing buildComputedStyles() all together and instead just checking for this.state.dynamicBg and updating accordingly in getStyles(), but I'm not sure if that's a best practice.

Performance concerns

Computing styles can be quite expensive with all the merging and mapping of objects and is made worse by the fact that they are recomputed on every render, even if they don’t change.

Any thoughts on how the situation can be improved?

peerDependency prevents using radium with react 0.13.0-rc1

Currently, if you have a project using react 0.13.0-rc1 the npm install radium will fail because it expects react 0.12.x on the peerDependencies attribute of package.json.

npm ERR! Linux 3.16.0-28-generic
npm ERR! argv "/home/fabricio/.nvm/versions/io.js/v1.0.3/bin/iojs" "/home/fabricio/.nvm/versions/io.js/v1.0.3/bin/npm" "install" "-D" "radium"
npm ERR! node v1.0.3
npm ERR! npm  v2.2.0
npm ERR! code EPEERINVALID

npm ERR! peerinvalid The package react does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer [email protected] wants [email protected]

npm ERR! Please include the following file with any support request:
npm ERR!     /home/fabricio/work/tcnet-login/npm-debug.log

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.