diff --git a/src/component/field.js b/src/component/field.js
index 21b92f158..974c8380c 100644
--- a/src/component/field.js
+++ b/src/component/field.js
@@ -1,32 +1,36 @@
import React from 'react';
-import { Text as RNText, StyleSheet, View } from 'react-native';
+import { Text as RNText, StyleSheet, View, Platform } from 'react-native';
import PropTypes from 'prop-types';
import Text from './text';
-import { TextInput, HorizontalExpandingTextInput } from './input';
-import { color, font } from './style';
+import { TextInput, AdjustingTextInput } from './input';
+import { color, font, fontFamily } from './style';
//
// Amount Input Field
//
+const amountFont = fontFamily.WorkSansExtraLight;
+
const amountStyles = StyleSheet.create({
input: {
textAlign: 'right',
- fontFamily: 'WorkSans ExtraLight',
- fontSize: font.sizeXXXL,
+ fontFamily: amountFont.name,
+ height: 105,
},
});
-export const AmountInputField = ({ style, ...props }) => (
-
-);
+export const AmountInputField = ({ style, ...props }) => {
+ const nonWebProps = Platform.OS === 'web' ? {} : { keyboardType: 'numeric' };
+ return (
+
+ );
+};
AmountInputField.propTypes = {
style: RNText.propTypes.style,
diff --git a/src/component/input.js b/src/component/input.js
index 388aaed02..20e50d108 100644
--- a/src/component/input.js
+++ b/src/component/input.js
@@ -36,43 +36,150 @@ TextInput.propTypes = {
};
//
-// Horizontal Expanding Text Input
+// Adjusting Text Input
//
-export class HorizontalExpandingTextInput extends Component {
+const getCharWidthHeightRatio = (fontWidthHeightRatio, char) =>
+ fontWidthHeightRatio[char] || fontWidthHeightRatio['default'];
+
+const calculateWidthAndFontSize = (
+ text,
+ maxWidth,
+ defaultFontSize,
+ fontWidthHeightRatio,
+ placeholderFirstChar
+) => {
+ const predictedTextLength = text.length || 1;
+ const predictedTextCharArray = text.split('') || [placeholderFirstChar];
+ const predictedTextWidth = predictedTextCharArray.reduce(
+ (accumulator, currentValue) =>
+ getCharWidthHeightRatio(fontWidthHeightRatio, currentValue) *
+ defaultFontSize +
+ accumulator,
+ 0
+ );
+ const calculatedWidth = Math.min(
+ maxWidth,
+ Math.max(
+ predictedTextWidth,
+ getCharWidthHeightRatio(fontWidthHeightRatio, placeholderFirstChar) *
+ defaultFontSize
+ )
+ );
+
+ const averageFontWidthHeightRatio =
+ predictedTextCharArray.reduce(
+ (accumulator, currentValue) =>
+ getCharWidthHeightRatio(fontWidthHeightRatio, currentValue) +
+ accumulator,
+ 0
+ ) / predictedTextLength;
+ const calculatedFontSize =
+ calculatedWidth >= maxWidth
+ ? Math.min(
+ defaultFontSize,
+ calculatedWidth / predictedTextLength / averageFontWidthHeightRatio
+ )
+ : defaultFontSize;
+
+ return { calculatedWidth, calculatedFontSize };
+};
+
+export class AdjustingTextInput extends Component {
constructor(props) {
super(props);
- this.state = { text: '', width: 0 };
+ const { defaultFontSize, fontWidthHeightRatio, placeholder } = props;
+ const placeholderFirstChar = placeholder.length
+ ? placeholder.charAt(0)
+ : '0';
+
+ this.state = {
+ text: '',
+ width: defaultFontSize * fontWidthHeightRatio[placeholderFirstChar],
+ fontSize: defaultFontSize,
+ placeholderFirstChar,
+ };
+
+ this.onChangeTextHandler = this.onChangeTextHandler.bind(this);
}
+
+ onChangeTextHandler(
+ changedText,
+ maxWidth,
+ defaultFontSize,
+ fontWidthHeightRatio,
+ onChangeText,
+ placeholderFirstChar
+ ) {
+ const { calculatedWidth, calculatedFontSize } = calculateWidthAndFontSize(
+ changedText,
+ maxWidth,
+ defaultFontSize,
+ fontWidthHeightRatio,
+ placeholderFirstChar
+ );
+
+ if (changedText.match(/^(?:[1-9]\d*|0)?(?:\.\d*)?$/)) {
+ this.setState({
+ text: changedText,
+ width: calculatedWidth,
+ fontSize: calculatedFontSize,
+ });
+ onChangeText && onChangeText(changedText);
+ }
+ }
+
render() {
- const { value, charWidth, onChangeText, style, ...props } = this.props;
+ const {
+ value,
+ style,
+ fontWidthHeightRatio,
+ defaultFontSize,
+ maxWidth,
+ onChangeText,
+ ...props
+ } = this.props;
+ const { text, width, fontSize, placeholderFirstChar } = this.state;
+ const calculatedStyle = [
+ style,
+ {
+ width,
+ fontSize,
+ },
+ ];
+
return (
{
- this.setState({ text, width: charWidth * (text.length + 1) });
- onChangeText && onChangeText(text);
- }}
- style={[
- style,
- {
- width: Math.max(
- charWidth * 2,
- value ? charWidth * (value.length + 1) : this.state.width
- ),
- },
- ]}
+ value={value || text}
+ onChangeText={changedText =>
+ this.onChangeTextHandler(
+ changedText,
+ maxWidth,
+ defaultFontSize,
+ fontWidthHeightRatio,
+ onChangeText,
+ placeholderFirstChar
+ )
+ }
+ style={calculatedStyle}
{...props}
/>
);
}
}
-HorizontalExpandingTextInput.propTypes = {
+AdjustingTextInput.propTypes = {
value: PropTypes.string,
- charWidth: PropTypes.number.isRequired,
+ fontWidthHeightRatio: PropTypes.object.isRequired,
+ defaultFontSize: PropTypes.number.isRequired,
+ maxWidth: PropTypes.number.isRequired,
onChangeText: PropTypes.func,
style: RNText.propTypes.style,
+ placeholder: PropTypes.string,
+};
+
+AdjustingTextInput.defaultProps = {
+ placeholder: '0',
};
export default TextInput;
diff --git a/src/component/layout/AdjustingLayout/AdjustingLayout.jsx b/src/component/layout/AdjustingLayout/AdjustingLayout.jsx
new file mode 100644
index 000000000..d064078e9
--- /dev/null
+++ b/src/component/layout/AdjustingLayout/AdjustingLayout.jsx
@@ -0,0 +1,56 @@
+import React, { Component } from 'react';
+import { StyleSheet, View } from 'react-native';
+import PropTypes from 'prop-types';
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ alignSelf: 'stretch',
+ justifyContent: 'center',
+ },
+});
+
+export class AdjustingLayout extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ containerWidth: 0,
+ elementWidth: 0,
+ };
+ this.onLayoutHandler = this.onLayoutHandler.bind(this);
+ }
+
+ onLayoutHandler(event, key) {
+ const { width } = event.nativeEvent.layout;
+ this.setState({ [key]: width });
+ }
+
+ render() {
+ const { children, style, ...rest } = this.props;
+ const { containerWidth, elementWidth } = this.state;
+ const maxWidth = containerWidth - elementWidth;
+
+ return (
+ this.onLayoutHandler(event, 'containerWidth')}
+ {...rest}
+ >
+ {React.cloneElement(children[0], {
+ maxWidth,
+ })}
+ this.onLayoutHandler(event, 'elementWidth')}>
+ {children[1]}
+
+
+ );
+ }
+}
+
+AdjustingLayout.propTypes = {
+ children: PropTypes.node.isRequired,
+ style: View.propTypes.style,
+};
+
+export default AdjustingLayout;
diff --git a/src/component/layout/AdjustingLayout/index.js b/src/component/layout/AdjustingLayout/index.js
new file mode 100644
index 000000000..537c8c3bb
--- /dev/null
+++ b/src/component/layout/AdjustingLayout/index.js
@@ -0,0 +1,3 @@
+import AdjustingLayout from './AdjustingLayout';
+
+export default AdjustingLayout;
diff --git a/src/component/style.js b/src/component/style.js
index 9a956e8e0..67a5f1105 100644
--- a/src/component/style.js
+++ b/src/component/style.js
@@ -51,3 +51,23 @@ export const font = {
lineHeightXXL: 60,
lineHeightXXXL: 100,
};
+
+export const fontFamily = {
+ WorkSansExtraLight: {
+ name: 'WorkSans ExtraLight',
+ widthHeightRatio: {
+ '0': 0.596,
+ '1': 0.333,
+ '2': 0.543,
+ '3': 0.533,
+ '4': 0.561,
+ '5': 0.544,
+ '6': 0.555,
+ '7': 0.507,
+ '8': 0.572,
+ '9': 0.577,
+ '.': 0.186,
+ default: 0.793,
+ },
+ },
+};
diff --git a/src/view/invoice.js b/src/view/invoice.js
index 507245b23..e85463ae9 100644
--- a/src/view/invoice.js
+++ b/src/view/invoice.js
@@ -7,11 +7,12 @@ import MainContent from '../component/main-content';
import { InputField, AmountInputField } from '../component/field';
import { Header, Title } from '../component/header';
import { CancelButton, PillButton, Button } from '../component/button';
-import { BalanceLabel, BalanceLabelUnit } from '../component/label';
+import { BalanceLabelUnit } from '../component/label';
import Card from '../component/card';
import LightningBoltIcon from '../asset/icon/lightning-bolt';
import { FormStretcher, FormSubText } from '../component/form';
import { color } from '../component/style';
+import AdjustingLayout from '../component/layout/AdjustingLayout';
const styles = StyleSheet.create({
balance: {
@@ -37,7 +38,7 @@ const InvoiceView = ({ store, nav, invoice }) => (
-
+
(
{store.unitFiatLabel}
-
+