React Money Component

by Jon Beebe

HTML

<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
<script src="http://fb.me/react-with-addons-0.10.0.js"></script>
<script src="http://fb.me/react-js-fiddle-integration.js"></script>
<div id="for-currenty"></div>

SCSS

// Supporting Styles
// -----------------

$text-color: #6c6c6b;
$danger-color: #e33c20;
$success-color: #00d1be;

.text--danger {
  color: $danger-color;
}
.text--success {
  color: $success-color;
}

.text--inline-block {
  display: inline-block;
}

.text--right {
  text-align: right;
}

// Money Module
// ------------

$money-symbol-offset: 0.6em;
$money-symbol-font-size: 0.6em;

.money {
  position: relative;
  line-height: inherit;
  @extend .text--inline-block;
  margin-left: $money-symbol-offset / 2;
}

// If you don't want the money symbol to affect positioning, e.g.
// ignore the symbol when centering, use this class.
.money--ignoreSymbol {
  margin-left: 0;
}

.money-symbol {
  display: block;
  position: absolute;
  -webkit-transform: translate(-$money-symbol-offset, -0.3em);
  -moz-transform: translate(-$money-symbol-offset, -0.3em);
  transform: translate(-$money-symbol-offset, -0.3em);
  font-size: $money-symbol-font-size;
}

.money-integer {
  @extend .text--inline-block;
}

.money-decimal {
  @extend .text--inline-block;
}

.money-fractional {
  @extend .text--inline-block;
}

.money--normal {
  color: $text-color;
}

.money--danger {
  @extend .text--danger;
}

.money--success {
  @extend .text--success;
}

.money--right {
  @extend .text--right;
}

.money--right input {
  @extend .text--right;
  width: 100%;
}

JavaScript 1.7

/** @jsx React.DOM */
'use strict';

function integerWithThousandsSeparator (x, sep) {
  sep = sep || ',';
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, sep);
}

var Money = React.createClass({

  getDefaultProps: function () {
    return {
      className: '',
      symbol: '$',
      decimalSep: '.',
      thousandsSep: ',',
      amount: 0,
      integer: 0,
      fractional: 0,
      showDecimals: true
    };
  },

  getInitialState: function () {
    return this.transformAmount(this.props.amount);
  },

  componentWillReceiveProps: function (nextProps) {
    if(nextProps.amount) {
      this.setState(this.transformAmount(nextProps.amount));
    }
  },

  transformAmount: function (amt) {
    var fixedFloat = parseFloat(amt).toFixed(2);
    var parts = fixedFloat.split('.');
    return {
      integer: integerWithThousandsSeparator(parts[0], this.props.thousandsSep),
      fractional: parts[1]
    };
  },

  renderSymbol: function () {
    return <span className="money-symbol">{this.props.symbol}</span>;
  },

  renderInteger: function () {
    return <span className="money-integer">{this.state.integer}</span>;
  },

  renderDecimal: function () {
    if(this.props.showDecimals) {
      return <span className="money-decimal">{this.props.decimalSep}</span>;
    }
  },

  renderFractional: function () {
    if(this.props.showDecimals) {
      return <span className="money-fractional">{this.state.fractional}</span>;
    }
  },

  render: function () {
    var classes = 'money';
    if(this.props.className !== '') {
        classes += ' ' + this.props.className;
    }
    return <span className={classes}>
      {this.renderSymbol()}
      {this.renderInteger()}
      {this.renderDecimal()}
      {this.renderFractional()}
    </span>;
  },

});

React.renderComponent(
  <div>
      <Money amount={100.54} />
      <br />
      <Money amount={3520.54} showDecimals={false} className="money--success" />
      <br />
      <Money amount={8.54} symbol={false}...