Skip to content

Commit

Permalink
chore: v1.0.0 breaking changes:
Browse files Browse the repository at this point in the history
- renaming unit prop to prefix
- adding suffix prop
- removing ignoreNative prop
- adding signPosition and showPositiveSign props
  • Loading branch information
CaioQuirinoMedeiros committed Apr 18, 2021
1 parent 4c5bbbc commit 631234f
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 110 deletions.
85 changes: 47 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@

A simple currency input component for both iOS and Android.

The goal of `react-native-currency-input` is to offer a simple and effective way to handle number inputs with custom format, usually a currency input case, but it can actually be used for other purposes.
The goal of `react-native-currency-input` is to offer a simple and effective way to handle number inputs with custom format, usually a currency input, but it can be used for any number input case.

<p align="center">
<img src="https://media.giphy.com/media/q2D5lPppXYQef8YtSs/giphy.gif" />
<img src="https://media.giphy.com/media/IUoA3IbKTtkRyq7R6U/giphy.gif" />
</p>

## Features

- A simple and practical component for number inputs
- It's just a [`<TextInput/>`](https://facebook.github.io/react-native/docs/textinput.html) component, so you can use its props and it's easy to customize
- Set precision, delimiter, separator and unit so you can actually have any number format you want
- It handles negative values, in addition to having a prop to disable it
- Set minimun and maximum value
- Handle any number format with these powerful props: `precision`, `delimiter`, `separator`, `prefix` and `suffix`.
- It handles negative values and you can choose the position of the sign with the `signPosition`.
- Set minimun and maximum values with `minValue` and `maxValue`.
- Use React Native ES6 and React Hooks

**BONUS**

- [`<FakeCurrencyInput />`](#fakecurrencyinput): A fake input that hides the real TextInput in order to terminate the [flickering issue](https://reactnative.dev/docs/textinput#value)
- [`<FakeCurrencyInput />`](#fakecurrencyinput): A fake input that hides the real TextInput in order to get rid of the [flickering issue](https://reactnative.dev/docs/textinput#value)
- [`formatNumber()`](#formatnumbervalue-options): A function that formats number

## Installation
Expand Down Expand Up @@ -70,20 +70,25 @@ function MyComponent() {

## Props

This component uses the same props as [`<TextInput/>`](https://facebook.github.io/react-native/docs/textinput.html). Below are the additional props for this component:

| Prop | Type | Default | Description |
| -------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **`value`** | number | | The value for controlled input. **REQUIRED** |
| **`onChangeValue`** | function | | Callback that is called when the input's value changes. **REQUIRED** |
| **`unit`** | string | | Character to be prefixed on the value. |
| **`delimiter`** | string | , | Character for thousands delimiter. |
| **`separator`** | string | . | Decimal separator character. |
| **`precision`** | number | 2 | Decimal precision. |
| **`ignoreNegative`** | boolean | false | Set this to true to disable negative values. |
| **`maxValue`** | number | | Max value allowed. This might cause unexpected behavior if you pass a value higher than this direct to the input. |
| **`minValue`** | number | | Min value allowed. This might cause unexpected behavior if you pass a value lower than this direct to the input. |
| **`onChangeText`** | function | | Callback that is called when the input's text changes. **IMPORTANT**: This does not control the input value, you should use `onChangeValue`. |
| Prop | Type | Default | Description |
| ---------------------- | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **...TextInputProps** | | | Inherit all [props of `TextInput`](https://reactnative.dev/docs/textinput#props). |
| **`value`** | number | | The value for controlled input. **REQUIRED** |
| **`onChangeValue`** | function | | Callback that is called when the input's value changes. **REQUIRED** |
| **`prefix`** | string | | Character to be prefixed on the value. |
| **`suffix`\*** | string | | Character to be suffixed on the value. |
| **`delimiter`** | string | , | Character for thousands delimiter. |
| **`separator`** | string | . | Decimal separator character. |
| **`precision`** | number | 2 | Decimal precision. |
| **`maxValue`** | number | | Max value allowed. Might cause unexpected behavior if you pass a `value` higher than the one defined here. |
| **`minValue`** | number | | Min value allowed. Might cause unexpected behavior if you pass a `value` lower than the one defined here. |
| **`signPosition`** | string | "afterPrefix" | Where the negative/positive sign (+/-) should be placed. |
| **`showPositiveSign`** | boolean | false | Set this to `true` to show the `+` character on positive values. |
| **`onChangeText`** | function | | Callback that is called when the input's text changes. **IMPORTANT**: This does not control the input value, you must use `onChangeValue`. |

**_\* IMPORTANT:_** Be aware that using the `suffix` implies setting the `selection` property of the `TextInput` internally. You can override the `selection`, but that will cause behavior problems on the component

**_Tip:_** If you don't want negative values, just use `minValue={0}`.

## Example

Expand All @@ -100,22 +105,22 @@ yarn android / yarn ios

## `FakeCurrencyInput`

This component hides the real currency input and use a Text to imitate the input, so you won't get the flickering issue but will lost the selection functionality. The cursor is not a real cursor, but a pipe character (|) that will be always at the end of the text. It also have a wrapper View with position 'relative' on which the Text Input is stretched over.
This component hides the `TextInput` and use a `Text` on its place, so you'll lost the cursor, but will get rid of the [flickering issue](https://reactnative.dev/docs/textinput#value). To replace the cursor it's used a pipe character (|) that will be always at the end of the text. It also have a wrapper `View` with position "relative" on which the `TextInput` is stretched over.

- Pros
- No [flickering issue](https://reactnative.dev/docs/textinput#value) as a controlled input component
- The cursor is locked at the end, avoiding the user to mess up with the mask
- Cons
- Lost of selection functionality... The user will still be able to copy/paste, but with a bad experience
- The cursor is locked at the end... You may have users who won't like that
- Lost of selection functionality. The user will still be able to copy/paste, but with a bad experience
- The cursor is locked at the end...

### `FakeCurrencyInput` Usage

```javascript
import { FakeCurrencyInput } from 'react-native-currency-input';

function MyComponent() {
const [value, setValue] = ReactuseState(0); // can also be null
const [value, setValue] = React.useState(0); // can also be null

return (
<FakeCurrencyInput
Expand All @@ -137,10 +142,11 @@ function MyComponent() {

It includes the same props of the CurrencyInput with the additional of the following:

| Prop | Type | Default | Description |
| -------------------- | ---------- | ------- | ------------------------------------------------- |
| **`containerStyle`** | style prop | | Style for the container View that wraps the Text. |
| **`caretColor`** | string | #6495ed | Color of the caret. |
| Prop | Type | Default | Description |
| ------------------------- | ---------- | ------- | ------------------------------------------------- |
| **...CurrencuInputProps** | | | Inherit all [props of `CurrencyInput`](#props). |
| **`containerStyle`** | style prop | | Style for the container View that wraps the Text. |
| **`caretColor`** | string | #6495ed | Color of the caret. |

<br>

Expand All @@ -153,24 +159,27 @@ const value = -2375923.3;

const formattedValue = formatNumber(value, {
separator: ',',
unit: 'R$ ',
prefix: 'R$ ',
precision: 2,
delimiter: '.',
ignoreNegative: true,
signPosition: 'beforePrefix',
});

console.log(formattedValue); // R$ 2.375.923,30
console.log(formattedValue); // -R$ 2.375.923,30
```

### `options` (optional)

| Name | Type | Default | Description |
| -------------------- | ------- | ------- | -------------------------------------------- |
| **`unit`** | string | | Character to be prefixed on the value. |
| **`delimiter`** | string | , | Character for thousands delimiter. |
| **`separator`** | string | . | Decimal separator character. |
| **`precision`** | number | 2 | Decimal precision. |
| **`ignoreNegative`** | boolean | false | Set this to true to disable negative values. |
| Name | Type | Default | Description |
| ---------------------- | ------- | ------------- | ---------------------------------------------------------------- |
| **`prefix`** | string | | Character to be prefixed on the value. |
| **`suffix`** | string | | Character to be suffixed on the value. |
| **`delimiter`** | string | , | Character for thousands delimiter. |
| **`separator`** | string | . | Decimal separator character. |
| **`precision`** | number | 2 | Decimal precision. |
| **`ignoreNegative`** | boolean | false | Set this to true to disable negative values. |
| **`signPosition`** | string | "afterPrefix" | Where the negative/positive sign (+/-) should be placed. |
| **`showPositiveSign`** | boolean | false | Set this to `true` to show the `+` character on positive values. |

## Contributing

Expand Down
3 changes: 1 addition & 2 deletions example/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ module.exports = {
resolver: {
blacklistRE: blacklist(
modules.map(
(m) =>
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
(m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
)
),

Expand Down
37 changes: 19 additions & 18 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@ import {
import CurrencyInput, { FakeCurrencyInput } from 'react-native-currency-input';

export default function App() {
const [valor, setValor] = React.useState<number | null>(null);
const [valor, setValor] = React.useState<number | null>(0);

return (
<KeyboardAvoidingView style={styles.screenContainer}>
<ScrollView
contentContainerStyle={styles.container}
keyboardShouldPersistTaps="handled"
>
<Text style={styles.label}>CurrencyInput</Text>
<Text style={styles.label}>CurrencyInput Examples</Text>
<CurrencyInput
value={valor}
style={styles.inputBasic}
onChangeValue={setValor}
delimiter=""
separator="."
precision={3}
minValue={0}
prefix="R$ "
precision={2}
/>
<CurrencyInput
value={valor}
style={styles.inputBasic}
onChangeValue={setValor}
unit="US$ "
ignoreNegative
prefix={'U$ '}
signPosition="beforePrefix"
delimiter=","
precision={2}
separator="."
Expand All @@ -41,31 +41,30 @@ export default function App() {
value={valor}
style={styles.inputBasic}
onChangeValue={setValor}
precision={7}
delimiter=","
separator="."
unit={'LAT: '}
precision={0}
delimiter=""
suffix={' meters'}
/>
<Text style={styles.label}>FakeCurrencyInput</Text>
<FakeCurrencyInput
value={valor}
style={styles.inputMask}
containerStyle={styles.inputMaskContainer}
onChangeValue={setValor}
precision={7}
showPositiveSign
delimiter=","
separator="."
unit={'LAT: '}
prefix={'LAT: '}
/>

<View style={styles.buttonsWrapper}>
<TouchableOpacity
style={styles.button}
onPress={() => {
setValor(238551.23);
setValor(123456.78);
}}
>
<Text>238551.23</Text>
<Text>123456.78</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
Expand All @@ -86,10 +85,10 @@ export default function App() {
<TouchableOpacity
style={styles.button}
onPress={() => {
setValor(-927.863942);
setValor(-9257.863942);
}}
>
<Text>-927.863942</Text>
<Text>-9257.863942</Text>
</TouchableOpacity>
</View>
</ScrollView>
Expand Down Expand Up @@ -138,9 +137,11 @@ const styles = StyleSheet.create({
borderWidth: 1,
},
label: {
fontSize: 18,
fontSize: 20,
marginBottom: 16,
fontWeight: 'bold',
marginTop: 24,
textAlign: 'center',
},
screenContainer: {
flex: 1,
Expand Down
14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-currency-input",
"version": "0.1.3",
"version": "1.0.0",
"description": "A simple currency input component for both iOS and Android",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down Expand Up @@ -124,17 +124,25 @@
]
}
},
"eslintIgnore": ["node_modules/", "lib/"],
"eslintIgnore": [
"node_modules/",
"lib/"
],
"prettier": {
"quoteProps": "consistent",
"singleQuote": true,
"printWidth": 88,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false
},
"@react-native-community/bob": {
"source": "src",
"output": "lib",
"targets": ["commonjs", "module", "typescript"]
"targets": [
"commonjs",
"module",
"typescript"
]
}
}
Loading

0 comments on commit 631234f

Please sign in to comment.