diff --git a/docs/storybook/demos/Calculator/Calculator.js b/docs/storybook/demos/Calculator/Calculator.js
new file mode 100644
index 00000000..a531d6be
--- /dev/null
+++ b/docs/storybook/demos/Calculator/Calculator.js
@@ -0,0 +1,441 @@
+/* eslint-disable react/jsx-no-bind, react/prop-types */
+
+// React Native version of https://codepen.io/mjijackson/pen/xOzyGX
+import React from 'react';
+import { StyleSheet, Text, TouchableHighlight, View } from 'react-native';
+
+/**
+ * KeyboardInput
+ */
+class KeyboardInput extends React.Component {
+ componentDidMount() {
+ document.addEventListener('keydown', this.handleKeyDown);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('keydown', this.handleKeyDown);
+ }
+
+ render() {
+ return null;
+ }
+
+ handleKeyDown = event => {
+ if (this.props.onKeyDown) {
+ this.props.onKeyDown(event);
+ }
+ };
+}
+
+/**
+ * CalculatorDisplay
+ */
+class CalculatorDisplay extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ scale: 1
+ };
+ }
+
+ handleTextLayout = e => {
+ const { width, x } = e.nativeEvent.layout;
+ const maxWidth = width + x;
+ const newScale = maxWidth / width;
+ if (x < 0) {
+ this.setState({ scale: newScale });
+ } else if (x > width) {
+ this.setState({ scale: 1 });
+ }
+ };
+
+ render() {
+ const { value } = this.props;
+ const { scale } = this.state;
+
+ const language = navigator.language || 'en-US';
+ let formattedValue = parseFloat(value).toLocaleString(language, {
+ useGrouping: true,
+ maximumFractionDigits: 6
+ });
+
+ const trailingZeros = value.match(/\.0*$/);
+
+ if (trailingZeros) {
+ formattedValue += trailingZeros;
+ }
+
+ return (
+
+
+
+ );
+ }
+}
+
+const calculatorDisplayStyles = StyleSheet.create({
+ root: {
+ backgroundColor: '#1c191c',
+ flex: 1,
+ justifyContent: 'center'
+ },
+ text: {
+ alignSelf: 'flex-end',
+ color: 'white',
+ //lineHeight: 130,
+ fontSize: '5.25em',
+ fontWeight: '100',
+ fontFamily: 'Roboto, sans-serif',
+ paddingHorizontal: 30,
+ //position: 'absolute',
+ right: 0,
+ transformOrigin: 'right'
+ }
+});
+
+/**
+ * CalculatorKey
+ */
+class CalculatorKey extends React.Component {
+ render() {
+ const { children, onPress, style, textStyle } = this.props;
+
+ return (
+
+
+
+ );
+ }
+}
+
+const calculatorKeyStyles = StyleSheet.create({
+ root: {
+ width: 80,
+ height: 80,
+ borderTopWidth: 1,
+ borderTopColor: '#777',
+ borderTopStyle: 'solid',
+ borderRightWidth: 1,
+ borderRightColor: '#666',
+ borderRightStyle: 'solid',
+ outline: 'none'
+ },
+ text: {
+ fontWeight: '100',
+ fontFamily: 'Roboto, sans-serif',
+ lineHeight: 80,
+ textAlign: 'center'
+ }
+});
+
+const CalculatorOperations = {
+ '/': (prevValue, nextValue) => prevValue / nextValue,
+ '*': (prevValue, nextValue) => prevValue * nextValue,
+ '+': (prevValue, nextValue) => prevValue + nextValue,
+ '-': (prevValue, nextValue) => prevValue - nextValue,
+ '=': (prevValue, nextValue) => nextValue
+};
+
+/**
+ * Calculator
+ */
+class Calculator extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ value: null,
+ displayValue: '0',
+ operator: null,
+ waitingForOperand: false
+ };
+ }
+
+ clearAll() {
+ this.setState({
+ value: null,
+ displayValue: '0',
+ operator: null,
+ waitingForOperand: false
+ });
+ }
+
+ clearDisplay() {
+ this.setState({
+ displayValue: '0'
+ });
+ }
+
+ clearLastChar() {
+ const { displayValue } = this.state;
+
+ this.setState({
+ displayValue: displayValue.substring(0, displayValue.length - 1) || '0'
+ });
+ }
+
+ toggleSign() {
+ const { displayValue } = this.state;
+ const newValue = parseFloat(displayValue) * -1;
+
+ this.setState({
+ displayValue: String(newValue)
+ });
+ }
+
+ inputPercent() {
+ const { displayValue } = this.state;
+ const currentValue = parseFloat(displayValue);
+
+ if (currentValue === 0) return;
+
+ const fixedDigits = displayValue.replace(/^-?\d*\.?/, '');
+ const newValue = parseFloat(displayValue) / 100;
+
+ this.setState({
+ displayValue: String(newValue.toFixed(fixedDigits.length + 2))
+ });
+ }
+
+ inputDot() {
+ const { displayValue } = this.state;
+
+ if (!/\./.test(displayValue)) {
+ this.setState({
+ displayValue: displayValue + '.',
+ waitingForOperand: false
+ });
+ }
+ }
+
+ inputDigit(digit) {
+ const { displayValue, waitingForOperand } = this.state;
+
+ if (waitingForOperand) {
+ this.setState({
+ displayValue: String(digit),
+ waitingForOperand: false
+ });
+ } else {
+ this.setState({
+ displayValue: displayValue === '0' ? String(digit) : displayValue + digit
+ });
+ }
+ }
+
+ performOperation(nextOperator) {
+ const { value, displayValue, operator } = this.state;
+ const inputValue = parseFloat(displayValue);
+
+ if (value == null) {
+ this.setState({
+ value: inputValue
+ });
+ } else if (operator) {
+ const currentValue = value || 0;
+ const newValue = CalculatorOperations[operator](currentValue, inputValue);
+
+ this.setState({
+ value: newValue,
+ displayValue: String(newValue)
+ });
+ }
+
+ this.setState({
+ waitingForOperand: true,
+ operator: nextOperator
+ });
+ }
+
+ handleKeyDown(event) {
+ let { key } = event;
+
+ if (key === 'Enter') key = '=';
+
+ if (/\d/.test(key)) {
+ event.preventDefault();
+ this.inputDigit(parseInt(key, 10));
+ } else if (key in CalculatorOperations) {
+ event.preventDefault();
+ this.performOperation(key);
+ } else if (key === '.') {
+ event.preventDefault();
+ this.inputDot();
+ } else if (key === '%') {
+ event.preventDefault();
+ this.inputPercent();
+ } else if (key === 'Backspace') {
+ event.preventDefault();
+ this.clearLastChar();
+ } else if (key === 'Clear') {
+ event.preventDefault();
+
+ if (this.state.displayValue !== '0') {
+ this.clearDisplay();
+ } else {
+ this.clearAll();
+ }
+ }
+ }
+
+ render() {
+ const { displayValue } = this.state;
+
+ const clearDisplay = displayValue !== '0';
+ const clearText = clearDisplay ? 'C' : 'AC';
+
+ return (
+
+ this.handleKeyDown(event)} />
+
+
+
+
+ (clearDisplay ? this.clearDisplay() : this.clearAll())}>
+ {clearText}
+
+ this.toggleSign()} style={calculatorStyles.keySign}>
+ ±
+
+ this.inputPercent()} style={calculatorStyles.keyPercent}>
+ %
+
+
+
+ this.inputDigit(0)}
+ style={calculatorStyles.key0}
+ textStyle={{ textAlign: 'left' }}
+ >
+ 0
+
+ this.inputDot()}
+ style={calculatorStyles.keyDot}
+ textStyle={calculatorStyles.keyDotText}
+ >
+ .
+
+ this.inputDigit(1)}>1
+ this.inputDigit(2)}>2
+ this.inputDigit(3)}>3
+ this.inputDigit(4)}>4
+ this.inputDigit(5)}>5
+ this.inputDigit(6)}>6
+ this.inputDigit(7)}>7
+ this.inputDigit(8)}>8
+ this.inputDigit(9)}>9
+
+
+
+ this.performOperation('/')}>÷
+ this.performOperation('*')}>×
+ this.performOperation('-')}>−
+ this.performOperation('+')}>+
+ this.performOperation('=')}>=
+
+
+
+ );
+ }
+}
+
+const DigitKey = props =>
+ ;
+
+const FunctionKey = props =>
+ ;
+
+const OperatorKey = props =>
+ ;
+
+const calculatorStyles = StyleSheet.create({
+ root: {
+ width: 320,
+ height: 520,
+ backgroundColor: 'black',
+ boxShadow: '0px 0px 20px 0px #aaa'
+ },
+ keypad: {
+ height: 400,
+ flexDirection: 'row'
+ },
+ inputKeys: {
+ width: 240
+ },
+ calculatorKeyText: {
+ fontFamily: 'Roboto, sans-serif',
+ fontSize: '1.75em',
+ fontWeight: '100'
+ },
+ functionKeys: {
+ backgroundImage: 'linear-gradient(to bottom, rgba(202,202,204,1) 0%, rgba(196,194,204,1) 100%)',
+ flexDirection: 'row'
+ },
+ functionKeyText: {
+ fontFamily: 'Roboto, sans-serif',
+ fontSize: '1.75em',
+ fontWeight: '100'
+ },
+ digitKeys: {
+ backgroundColor: '#e0e0e7',
+ flexDirection: 'row',
+ flexWrap: 'wrap-reverse'
+ },
+ digitKeyText: {
+ fontFamily: 'Roboto, sans-serif',
+ fontSize: '2em',
+ fontWeight: '100'
+ },
+ operatorKeys: {
+ backgroundImage: 'linear-gradient(to bottom, rgba(252,156,23,1) 0%, rgba(247,126,27,1) 100%)'
+ },
+ operatorKey: {
+ borderRightWidth: 0
+ },
+ operatorKeyText: {
+ color: 'white',
+ fontFamily: 'Roboto, sans-serif',
+ fontSize: '2.65em',
+ fontWeight: '100'
+ },
+ keyMultiplyText: {
+ lineHeight: 50
+ },
+ key0: {
+ paddingLeft: 32,
+ width: 160
+ },
+ keyDot: {
+ overflow: 'hidden'
+ },
+ keyDotText: {
+ fontFamily: 'Roboto, sans-serif',
+ fontSize: '4.375em',
+ fontWeight: '100',
+ marginTop: -10
+ }
+});
+
+module.exports = Calculator;
diff --git a/docs/storybook/demos/Calculator/CalculatorExample.js b/docs/storybook/demos/Calculator/CalculatorExample.js
new file mode 100644
index 00000000..95938b50
--- /dev/null
+++ b/docs/storybook/demos/Calculator/CalculatorExample.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import { storiesOf } from '@kadira/storybook';
+import Calculator from './Calculator';
+import { StyleSheet, View } from 'react-native';
+
+const styles = StyleSheet.create({
+ container: { alignItems: 'center', justifyContent: 'center', flex: 1 }
+});
+
+storiesOf('Example apps', module).add('Calculator', () =>
+
+
+
+);