@jobber/components-native 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/AtlantisContext/AtlantisContext.js +2 -0
- package/dist/src/Flex/Flex.js +1 -1
- package/dist/src/InputCurrency/InputCurrency.js +93 -0
- package/dist/src/InputCurrency/constants.js +1 -0
- package/dist/src/InputCurrency/index.js +3 -0
- package/dist/src/InputCurrency/messages.js +8 -0
- package/dist/src/InputCurrency/utils.js +58 -0
- package/dist/src/InputSearch/InputSearch.js +1 -1
- package/dist/src/InputText/InputText.js +1 -1
- package/dist/src/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/AtlantisContext/AtlantisContext.d.ts +4 -0
- package/dist/types/src/InputCurrency/InputCurrency.d.ts +32 -0
- package/dist/types/src/InputCurrency/constants.d.ts +1 -0
- package/dist/types/src/InputCurrency/index.d.ts +3 -0
- package/dist/types/src/InputCurrency/messages.d.ts +7 -0
- package/dist/types/src/InputCurrency/utils.d.ts +9 -0
- package/dist/types/src/index.d.ts +1 -0
- package/package.json +2 -5
- package/src/AtlantisContext/AtlantisContext.test.tsx +1 -0
- package/src/AtlantisContext/AtlantisContext.tsx +7 -0
- package/src/Flex/Flex.tsx +1 -1
- package/src/InputCurrency/InputCurrency.test.tsx +158 -0
- package/src/InputCurrency/InputCurrency.tsx +206 -0
- package/src/InputCurrency/constants.ts +1 -0
- package/src/InputCurrency/index.ts +3 -0
- package/src/InputCurrency/messages.ts +10 -0
- package/src/InputCurrency/utils.ts +92 -0
- package/src/InputSearch/InputSearch.tsx +1 -1
- package/src/InputText/InputText.tsx +1 -1
- package/src/index.ts +1 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
3
|
import RNLocalize from "react-native-localize";
|
|
4
|
+
import { DEFAULT_CURRENCY_SYMBOL } from "../InputCurrency/constants";
|
|
4
5
|
export const defaultValues = {
|
|
5
6
|
// The system time is "p"
|
|
6
7
|
timeFormat: "p",
|
|
@@ -10,6 +11,7 @@ export const defaultValues = {
|
|
|
10
11
|
return;
|
|
11
12
|
},
|
|
12
13
|
floatSeparators: { group: ",", decimal: "." },
|
|
14
|
+
currencySymbol: DEFAULT_CURRENCY_SYMBOL,
|
|
13
15
|
};
|
|
14
16
|
export const AtlantisContext = createContext(defaultValues);
|
|
15
17
|
export function useAtlantisContext() {
|
package/dist/src/Flex/Flex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { Children } from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import chunk from "lodash
|
|
3
|
+
import chunk from "lodash/chunk";
|
|
4
4
|
import { columnStyles, gapStyles, styles } from "./Flex.styles";
|
|
5
5
|
import { Content } from "../Content";
|
|
6
6
|
export function Flex({ template = [], align = "center", gap = "base", children, }) {
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { Platform } from "react-native";
|
|
4
|
+
import { NUMBER_VALIDATION_REGEX, checkLastChar, configureDecimal, convertToNumber, isValidNumber, limitInputWholeDigits, parseGivenInput, } from "./utils";
|
|
5
|
+
import { messages } from "./messages";
|
|
6
|
+
import { useAtlantisContext } from "../AtlantisContext";
|
|
7
|
+
import { InputText } from "../InputText";
|
|
8
|
+
import { useFormController } from "../hooks/useFormController";
|
|
9
|
+
export const getInternalValue = (props, field, formatNumber) => {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
if (!props.value && !field.value)
|
|
12
|
+
return "";
|
|
13
|
+
return ((_b = (_a = props.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : formatNumber(field.value, {
|
|
14
|
+
maximumFractionDigits: props.maxDecimalPlaces,
|
|
15
|
+
}));
|
|
16
|
+
};
|
|
17
|
+
const getKeyboard = (props) => {
|
|
18
|
+
var _a;
|
|
19
|
+
if (Platform.OS === "ios") {
|
|
20
|
+
//since we are checking for which keyboard to use here, just implement default keyboard here instead of in params
|
|
21
|
+
return (_a = props.keyboard) !== null && _a !== void 0 ? _a : "numbers-and-punctuation";
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return "numeric";
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export function InputCurrency(props) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const { showCurrencySymbol = true, maxDecimalPlaces = 5, decimalPlaces = 2, maxLength = 10, } = props;
|
|
30
|
+
const intl = useIntl();
|
|
31
|
+
const { floatSeparators, currencySymbol } = useAtlantisContext();
|
|
32
|
+
const { field } = useFormController({
|
|
33
|
+
name: props.name,
|
|
34
|
+
value: props.value,
|
|
35
|
+
});
|
|
36
|
+
const internalValue = getInternalValue(props, field, intl.formatNumber);
|
|
37
|
+
const [displayValue, setDisplayValue] = useState(internalValue);
|
|
38
|
+
const setOnChangeAndDisplayValues = (onChangeValue, valueToDisplay) => {
|
|
39
|
+
var _a;
|
|
40
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, onChangeValue);
|
|
41
|
+
setDisplayValue(valueToDisplay);
|
|
42
|
+
};
|
|
43
|
+
const checkDecimalAndI18nOfDisplayValue = (numberedValue, decimalNumbers, decimalCount) => {
|
|
44
|
+
const transformedValue = limitInputWholeDigits(numberedValue, maxLength);
|
|
45
|
+
const stringValue = decimalNumbers !== ""
|
|
46
|
+
? transformedValue.toString() + "." + decimalNumbers.slice(1)
|
|
47
|
+
: transformedValue.toString();
|
|
48
|
+
if (checkLastChar(stringValue)) {
|
|
49
|
+
const roundedDecimal = configureDecimal(decimalCount, maxDecimalPlaces, stringValue, decimalPlaces);
|
|
50
|
+
const internationalizedValueToDisplay = intl.formatNumber(roundedDecimal, {
|
|
51
|
+
maximumFractionDigits: maxDecimalPlaces,
|
|
52
|
+
});
|
|
53
|
+
setOnChangeAndDisplayValues(roundedDecimal, internationalizedValueToDisplay);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const internationalizedValueToDisplay = intl.formatNumber(transformedValue, {
|
|
57
|
+
maximumFractionDigits: maxDecimalPlaces,
|
|
58
|
+
}) + decimalNumbers;
|
|
59
|
+
setOnChangeAndDisplayValues(transformedValue.toString() + "." + decimalNumbers.slice(1), internationalizedValueToDisplay);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const handleChange = (newValue) => {
|
|
63
|
+
const [decimalCount, wholeIntegerValue, decimalNumbers] = parseGivenInput(newValue, floatSeparators.decimal);
|
|
64
|
+
const numberedValue = wholeIntegerValue
|
|
65
|
+
? convertToNumber(wholeIntegerValue)
|
|
66
|
+
: wholeIntegerValue;
|
|
67
|
+
if (isValidNumber(numberedValue) && typeof numberedValue === "number") {
|
|
68
|
+
checkDecimalAndI18nOfDisplayValue(numberedValue, decimalNumbers, decimalCount);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const value = (numberedValue === null || numberedValue === void 0 ? void 0 : numberedValue.toString()) + decimalNumbers;
|
|
72
|
+
setOnChangeAndDisplayValues(value, value);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const { formatMessage } = useIntl();
|
|
76
|
+
return (React.createElement(React.Fragment, null,
|
|
77
|
+
React.createElement(InputText, Object.assign({}, props, { prefix: showCurrencySymbol ? { label: currencySymbol } : undefined, keyboard: getKeyboard(props), value: ((_a = props.value) === null || _a === void 0 ? void 0 : _a.toString()) || displayValue, defaultValue: (_b = props.defaultValue) === null || _b === void 0 ? void 0 : _b.toString(), onChangeText: handleChange, transform: {
|
|
78
|
+
output: val => {
|
|
79
|
+
return val === null || val === void 0 ? void 0 : val.split(floatSeparators.group).join("").replace(floatSeparators.decimal, ".");
|
|
80
|
+
},
|
|
81
|
+
}, validations: Object.assign({ pattern: {
|
|
82
|
+
value: NUMBER_VALIDATION_REGEX,
|
|
83
|
+
message: formatMessage(messages.notANumberError),
|
|
84
|
+
} }, props.validations), onBlur: () => {
|
|
85
|
+
var _a;
|
|
86
|
+
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props);
|
|
87
|
+
if (field.value === 0 ||
|
|
88
|
+
field.value === "" ||
|
|
89
|
+
field.value === undefined) {
|
|
90
|
+
setDisplayValue("0");
|
|
91
|
+
}
|
|
92
|
+
} }))));
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DEFAULT_CURRENCY_SYMBOL = "$";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { defineMessages } from "react-intl";
|
|
2
|
+
export const messages = defineMessages({
|
|
3
|
+
notANumberError: {
|
|
4
|
+
id: "notANumberError",
|
|
5
|
+
defaultMessage: "Enter a number",
|
|
6
|
+
description: "Error message shown when a non-numeric value is typed in number input",
|
|
7
|
+
},
|
|
8
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export function countDecimal(value) {
|
|
2
|
+
const convertedValue = value.toString();
|
|
3
|
+
if (convertedValue.includes(".")) {
|
|
4
|
+
return convertedValue.split(".")[1].length;
|
|
5
|
+
}
|
|
6
|
+
return 0;
|
|
7
|
+
}
|
|
8
|
+
export function limitInputWholeDigits(value, maxInputLength) {
|
|
9
|
+
let convertedValue = value.toString();
|
|
10
|
+
if (convertedValue.length > maxInputLength) {
|
|
11
|
+
convertedValue = convertedValue.slice(0, maxInputLength);
|
|
12
|
+
return parseFloat(convertedValue);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function configureDecimal(decimalCount, maxDecimalPlaces, transformedValue, decimalPlaces) {
|
|
17
|
+
const targetDecimalPlaces = Math.min(Math.max(decimalCount, decimalPlaces), maxDecimalPlaces);
|
|
18
|
+
const precision = Math.pow(10, targetDecimalPlaces);
|
|
19
|
+
const convertedValue = Math.round(parseFloat(transformedValue) * precision) / precision;
|
|
20
|
+
return convertedValue;
|
|
21
|
+
}
|
|
22
|
+
export function convertToNumber(value) {
|
|
23
|
+
var _a;
|
|
24
|
+
const regexValidation = /^[0-9]*$/;
|
|
25
|
+
if ((_a = value === null || value === void 0 ? void 0 : value.match) === null || _a === void 0 ? void 0 : _a.call(value, regexValidation)) {
|
|
26
|
+
return parseFloat(value);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
export const checkLastChar = (stringValue) => {
|
|
31
|
+
const lastChar = stringValue[stringValue.length - 1];
|
|
32
|
+
return Boolean(Number(stringValue)) && lastChar !== "0" && lastChar !== ".";
|
|
33
|
+
};
|
|
34
|
+
export const isValidNumber = (numberedValue) => {
|
|
35
|
+
return (typeof numberedValue === "number" &&
|
|
36
|
+
!isNaN(numberedValue) &&
|
|
37
|
+
numberedValue !== 0);
|
|
38
|
+
};
|
|
39
|
+
export const getDecimalNumbers = (value, decimalSeparator) => {
|
|
40
|
+
const decimalValue = value.split(".")[1];
|
|
41
|
+
if (!decimalValue) {
|
|
42
|
+
return decimalSeparator;
|
|
43
|
+
}
|
|
44
|
+
return `${decimalSeparator}${decimalValue}`;
|
|
45
|
+
};
|
|
46
|
+
export const parseGivenInput = (value, decimalSeparator) => {
|
|
47
|
+
let decimalCount = 0;
|
|
48
|
+
let decimalNumbers = "";
|
|
49
|
+
let wholeIntegerValue = value;
|
|
50
|
+
if (value === null || value === void 0 ? void 0 : value.includes(".")) {
|
|
51
|
+
const splittedValue = value === null || value === void 0 ? void 0 : value.split(".");
|
|
52
|
+
decimalCount = splittedValue[1].length;
|
|
53
|
+
wholeIntegerValue = splittedValue[0];
|
|
54
|
+
decimalNumbers = getDecimalNumbers(value, decimalSeparator);
|
|
55
|
+
}
|
|
56
|
+
return [decimalCount, wholeIntegerValue, decimalNumbers];
|
|
57
|
+
};
|
|
58
|
+
export const NUMBER_VALIDATION_REGEX = /^[-+]?(([0-9]*\.[0-9]+)|([0-9]+)|([0-9]+(\.?[0-9]+)?e[-+]?[0-9]+))$/;
|
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import React, { forwardRef, useEffect } from "react";
|
|
13
13
|
import { View } from "react-native";
|
|
14
|
-
import debounce from "lodash
|
|
14
|
+
import debounce from "lodash/debounce";
|
|
15
15
|
import { styles } from "./InputSearch.style";
|
|
16
16
|
import { InputText } from "../InputText";
|
|
17
17
|
export const InputSearch = forwardRef(SearchInputInternal);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
2
2
|
import { Platform, TextInput, } from "react-native";
|
|
3
|
-
import identity from "lodash
|
|
3
|
+
import identity from "lodash/identity";
|
|
4
4
|
import { styles } from "./InputText.style";
|
|
5
5
|
import { useInputAccessoriesContext } from "./context";
|
|
6
6
|
import { useFormController } from "../hooks";
|
package/dist/src/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export * from "./Heading";
|
|
|
18
18
|
export * from "./Icon";
|
|
19
19
|
export * from "./IconButton";
|
|
20
20
|
export * from "./InputFieldWrapper";
|
|
21
|
+
export * from "./InputCurrency";
|
|
21
22
|
export * from "./InputNumber";
|
|
22
23
|
export * from "./InputPassword";
|
|
23
24
|
export * from "./InputPressable";
|