@hero-design/rn 8.64.7-alpha.0 → 8.64.7
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/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +6 -0
- package/es/index.js +21 -4
- package/lib/index.js +21 -4
- package/package.json +2 -3
- package/src/components/PinInput/__tests__/__snapshots__/index.spec.tsx.snap +0 -5
- package/src/components/PinInput/__tests__/index.spec.tsx +98 -1
- package/src/components/PinInput/index.tsx +23 -4
- package/stats/8.64.7/rn-stats.html +4842 -0
- package/types/components/PinInput/index.d.ts +1 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
[36m
|
|
2
|
+
[1msrc/index.ts[22m → [1mlib/index.js, es/index.js[22m...[39m
|
|
3
|
+
[1m[33m(!) Plugin replace: @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.[39m[22m
|
|
4
|
+
[1m[33m(!) Plugin node-resolve: preferring built-in module 'events' over local alternative at '/home/runner/work/hero-design/hero-design/node_modules/events/events.js', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning[39m[22m
|
|
5
|
+
[32mcreated [1mlib/index.js, es/index.js[22m in [1m1m 3.5s[22m[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @hero-design/rn
|
|
2
2
|
|
|
3
|
+
## 8.64.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#3336](https://github.com/Thinkei/hero-design/pull/3336) [`34f5cb207ed68fcb4d2882e0175c7c085963332d`](https://github.com/Thinkei/hero-design/commit/34f5cb207ed68fcb4d2882e0175c7c085963332d) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - [PinInput] Add value validation logic
|
|
8
|
+
|
|
3
9
|
## 8.64.6
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/es/index.js
CHANGED
|
@@ -15582,6 +15582,11 @@ function getState(_ref) {
|
|
|
15582
15582
|
}
|
|
15583
15583
|
return 'default';
|
|
15584
15584
|
}
|
|
15585
|
+
// Normalize the value to only contain numbers and limit the length
|
|
15586
|
+
var normalizeValue = function normalizeValue(value) {
|
|
15587
|
+
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4;
|
|
15588
|
+
return ((value === null || value === void 0 ? void 0 : value.match(/\d/g)) || []).join('').slice(0, length);
|
|
15589
|
+
};
|
|
15585
15590
|
var PinInput = /*#__PURE__*/forwardRef(function (_ref2, ref) {
|
|
15586
15591
|
var _ref2$value = _ref2.value,
|
|
15587
15592
|
value = _ref2$value === void 0 ? '' : _ref2$value,
|
|
@@ -15609,8 +15614,12 @@ var PinInput = /*#__PURE__*/forwardRef(function (_ref2, ref) {
|
|
|
15609
15614
|
disabled: disabled,
|
|
15610
15615
|
error: error
|
|
15611
15616
|
});
|
|
15612
|
-
var trimmedValue = (
|
|
15617
|
+
var trimmedValue = normalizeValue(value, length);
|
|
15613
15618
|
var maskedValueWithExtraSpace = Platform.OS === 'android' && !trimmedValue ? '*' : trimmedValue;
|
|
15619
|
+
var _useState3 = useState(false),
|
|
15620
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
15621
|
+
hasFulfilled = _useState4[0],
|
|
15622
|
+
setHasFulfilled = _useState4[1];
|
|
15614
15623
|
var focus = useCallback(function () {
|
|
15615
15624
|
if (inputRef !== null && inputRef !== void 0 && inputRef.current) {
|
|
15616
15625
|
inputRef.current.focus();
|
|
@@ -15624,14 +15633,22 @@ var PinInput = /*#__PURE__*/forwardRef(function (_ref2, ref) {
|
|
|
15624
15633
|
}
|
|
15625
15634
|
}, []);
|
|
15626
15635
|
var changeText = useCallback(function (text) {
|
|
15627
|
-
|
|
15636
|
+
// If the input is already fulfilled and the user tries to remove characters
|
|
15637
|
+
if (hasFulfilled && text.length < length) {
|
|
15638
|
+
setHasFulfilled(false);
|
|
15639
|
+
}
|
|
15640
|
+
// If the input is already fulfilled and the user tries to add more characters
|
|
15641
|
+
if (hasFulfilled && ((text === null || text === void 0 ? void 0 : text.match(/\d/g)) || []).join('').length > length) {
|
|
15642
|
+
return;
|
|
15643
|
+
}
|
|
15628
15644
|
// Prevent user from entering more than the length
|
|
15629
|
-
var trimmedPin =
|
|
15645
|
+
var trimmedPin = normalizeValue(text, length);
|
|
15630
15646
|
onChangeText === null || onChangeText === void 0 || onChangeText(trimmedPin);
|
|
15631
15647
|
if (trimmedPin.length === length) {
|
|
15632
15648
|
onFulfill === null || onFulfill === void 0 || onFulfill(trimmedPin);
|
|
15649
|
+
setHasFulfilled(true);
|
|
15633
15650
|
}
|
|
15634
|
-
}, [length, onChangeText, onFulfill]);
|
|
15651
|
+
}, [length, onChangeText, onFulfill, hasFulfilled]);
|
|
15635
15652
|
useEffect(function () {
|
|
15636
15653
|
// Must run after animations for keyboard to automatically open
|
|
15637
15654
|
if (autoFocus) {
|
package/lib/index.js
CHANGED
|
@@ -15612,6 +15612,11 @@ function getState(_ref) {
|
|
|
15612
15612
|
}
|
|
15613
15613
|
return 'default';
|
|
15614
15614
|
}
|
|
15615
|
+
// Normalize the value to only contain numbers and limit the length
|
|
15616
|
+
var normalizeValue = function normalizeValue(value) {
|
|
15617
|
+
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4;
|
|
15618
|
+
return ((value === null || value === void 0 ? void 0 : value.match(/\d/g)) || []).join('').slice(0, length);
|
|
15619
|
+
};
|
|
15615
15620
|
var PinInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
15616
15621
|
var _ref2$value = _ref2.value,
|
|
15617
15622
|
value = _ref2$value === void 0 ? '' : _ref2$value,
|
|
@@ -15639,8 +15644,12 @@ var PinInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
15639
15644
|
disabled: disabled,
|
|
15640
15645
|
error: error
|
|
15641
15646
|
});
|
|
15642
|
-
var trimmedValue = (
|
|
15647
|
+
var trimmedValue = normalizeValue(value, length);
|
|
15643
15648
|
var maskedValueWithExtraSpace = reactNative.Platform.OS === 'android' && !trimmedValue ? '*' : trimmedValue;
|
|
15649
|
+
var _useState3 = React.useState(false),
|
|
15650
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
15651
|
+
hasFulfilled = _useState4[0],
|
|
15652
|
+
setHasFulfilled = _useState4[1];
|
|
15644
15653
|
var focus = React.useCallback(function () {
|
|
15645
15654
|
if (inputRef !== null && inputRef !== void 0 && inputRef.current) {
|
|
15646
15655
|
inputRef.current.focus();
|
|
@@ -15654,14 +15663,22 @@ var PinInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
15654
15663
|
}
|
|
15655
15664
|
}, []);
|
|
15656
15665
|
var changeText = React.useCallback(function (text) {
|
|
15657
|
-
|
|
15666
|
+
// If the input is already fulfilled and the user tries to remove characters
|
|
15667
|
+
if (hasFulfilled && text.length < length) {
|
|
15668
|
+
setHasFulfilled(false);
|
|
15669
|
+
}
|
|
15670
|
+
// If the input is already fulfilled and the user tries to add more characters
|
|
15671
|
+
if (hasFulfilled && ((text === null || text === void 0 ? void 0 : text.match(/\d/g)) || []).join('').length > length) {
|
|
15672
|
+
return;
|
|
15673
|
+
}
|
|
15658
15674
|
// Prevent user from entering more than the length
|
|
15659
|
-
var trimmedPin =
|
|
15675
|
+
var trimmedPin = normalizeValue(text, length);
|
|
15660
15676
|
onChangeText === null || onChangeText === void 0 || onChangeText(trimmedPin);
|
|
15661
15677
|
if (trimmedPin.length === length) {
|
|
15662
15678
|
onFulfill === null || onFulfill === void 0 || onFulfill(trimmedPin);
|
|
15679
|
+
setHasFulfilled(true);
|
|
15663
15680
|
}
|
|
15664
|
-
}, [length, onChangeText, onFulfill]);
|
|
15681
|
+
}, [length, onChangeText, onFulfill, hasFulfilled]);
|
|
15665
15682
|
React.useEffect(function () {
|
|
15666
15683
|
// Must run after animations for keyboard to automatically open
|
|
15667
15684
|
if (autoFocus) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/rn",
|
|
3
|
-
"version": "8.64.7
|
|
3
|
+
"version": "8.64.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -93,6 +93,5 @@
|
|
|
93
93
|
"ts-jest": "^29.1.1",
|
|
94
94
|
"typescript": "4.8.4"
|
|
95
95
|
},
|
|
96
|
-
"prettier": "prettier-config-hd"
|
|
97
|
-
"react-native": "src/index.ts"
|
|
96
|
+
"prettier": "prettier-config-hd"
|
|
98
97
|
}
|
|
@@ -205,7 +205,6 @@ exports[`rendering renders correctly 1`] = `
|
|
|
205
205
|
autoFocus={false}
|
|
206
206
|
editable={true}
|
|
207
207
|
keyboardType="numeric"
|
|
208
|
-
maxLength={4}
|
|
209
208
|
onBlur={[Function]}
|
|
210
209
|
onChangeText={[Function]}
|
|
211
210
|
onFocus={[Function]}
|
|
@@ -462,7 +461,6 @@ exports[`rendering renders correctly when disabled 1`] = `
|
|
|
462
461
|
autoFocus={false}
|
|
463
462
|
editable={false}
|
|
464
463
|
keyboardType="numeric"
|
|
465
|
-
maxLength={4}
|
|
466
464
|
onBlur={[Function]}
|
|
467
465
|
onChangeText={[Function]}
|
|
468
466
|
onFocus={[Function]}
|
|
@@ -837,7 +835,6 @@ exports[`rendering renders correctly when length is 6 and secure is false 1`] =
|
|
|
837
835
|
autoFocus={false}
|
|
838
836
|
editable={true}
|
|
839
837
|
keyboardType="numeric"
|
|
840
|
-
maxLength={6}
|
|
841
838
|
onBlur={[Function]}
|
|
842
839
|
onChangeText={[Function]}
|
|
843
840
|
onFocus={[Function]}
|
|
@@ -1147,7 +1144,6 @@ exports[`rendering renders correctly when there is error 1`] = `
|
|
|
1147
1144
|
autoFocus={false}
|
|
1148
1145
|
editable={true}
|
|
1149
1146
|
keyboardType="numeric"
|
|
1150
|
-
maxLength={4}
|
|
1151
1147
|
onBlur={[Function]}
|
|
1152
1148
|
onChangeText={[Function]}
|
|
1153
1149
|
onFocus={[Function]}
|
|
@@ -1405,7 +1401,6 @@ exports[`rendering renders correctly with textContentType and autoComplete 1`] =
|
|
|
1405
1401
|
autoFocus={false}
|
|
1406
1402
|
editable={true}
|
|
1407
1403
|
keyboardType="numeric"
|
|
1408
|
-
maxLength={4}
|
|
1409
1404
|
onBlur={[Function]}
|
|
1410
1405
|
onChangeText={[Function]}
|
|
1411
1406
|
onFocus={[Function]}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { fireEvent } from '@testing-library/react-native';
|
|
3
3
|
import { Platform } from 'react-native';
|
|
4
4
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
5
|
-
import PinInput, { getState } from '..';
|
|
5
|
+
import PinInput, { getState, normalizeValue } from '..';
|
|
6
6
|
|
|
7
7
|
describe('rendering', () => {
|
|
8
8
|
it('renders correctly', () => {
|
|
@@ -94,6 +94,76 @@ describe('behaviors', () => {
|
|
|
94
94
|
expect(onChangeText).toHaveBeenCalledWith('1234');
|
|
95
95
|
expect(onFulfill).toHaveBeenCalledWith('1234');
|
|
96
96
|
});
|
|
97
|
+
|
|
98
|
+
it.each`
|
|
99
|
+
value | expected
|
|
100
|
+
${'12 34'} | ${'1234'}
|
|
101
|
+
${'1 2 3 4'} | ${'1234'}
|
|
102
|
+
${' 1 2 3 4 '} | ${'1234'}
|
|
103
|
+
`(
|
|
104
|
+
'automatically trims whitespace characters when value is $value',
|
|
105
|
+
({ value, expected }) => {
|
|
106
|
+
const onChangeText = jest.fn();
|
|
107
|
+
const onFulfill = jest.fn();
|
|
108
|
+
const { getByTestId } = renderWithTheme(
|
|
109
|
+
<PinInput
|
|
110
|
+
secure={false}
|
|
111
|
+
value=""
|
|
112
|
+
onChangeText={onChangeText}
|
|
113
|
+
onFulfill={onFulfill}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const pinInput = getByTestId('pin-hidden-input');
|
|
118
|
+
fireEvent.changeText(pinInput, value);
|
|
119
|
+
|
|
120
|
+
expect(onChangeText).toHaveBeenCalledWith(expected);
|
|
121
|
+
expect(onFulfill).toHaveBeenCalledWith(expected);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
it.each`
|
|
126
|
+
value | length | expected
|
|
127
|
+
${'1234'} | ${4} | ${'1234'}
|
|
128
|
+
${'12345'} | ${4} | ${'1234'}
|
|
129
|
+
${'1234'} | ${6} | ${'1234'}
|
|
130
|
+
`(
|
|
131
|
+
'limits the value when value is $value and length is $length',
|
|
132
|
+
({ value, length, expected }) => {
|
|
133
|
+
const onChangeText = jest.fn();
|
|
134
|
+
const onFulfill = jest.fn();
|
|
135
|
+
const { getByTestId } = renderWithTheme(
|
|
136
|
+
<PinInput
|
|
137
|
+
value=""
|
|
138
|
+
length={length}
|
|
139
|
+
onChangeText={onChangeText}
|
|
140
|
+
onFulfill={onFulfill}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const pinInput = getByTestId('pin-hidden-input');
|
|
145
|
+
fireEvent.changeText(pinInput, value);
|
|
146
|
+
|
|
147
|
+
expect(onChangeText).toHaveBeenCalledWith(expected);
|
|
148
|
+
if (length === expected.legth) {
|
|
149
|
+
expect(onFulfill).toHaveBeenCalledWith(expected);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
it('does not allow typing when the max length is reached', () => {
|
|
154
|
+
const onChangeText = jest.fn();
|
|
155
|
+
const onFulfill = jest.fn();
|
|
156
|
+
const { getByTestId } = renderWithTheme(
|
|
157
|
+
<PinInput value="" onChangeText={onChangeText} onFulfill={onFulfill} />
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const pinInput = getByTestId('pin-hidden-input');
|
|
161
|
+
fireEvent.changeText(pinInput, '1234');
|
|
162
|
+
fireEvent.changeText(pinInput, '56789');
|
|
163
|
+
|
|
164
|
+
expect(onChangeText).toHaveBeenCalledTimes(1);
|
|
165
|
+
expect(onFulfill).toHaveBeenCalledTimes(1);
|
|
166
|
+
});
|
|
97
167
|
});
|
|
98
168
|
|
|
99
169
|
describe('getState', () => {
|
|
@@ -115,3 +185,30 @@ describe('getState', () => {
|
|
|
115
185
|
}
|
|
116
186
|
);
|
|
117
187
|
});
|
|
188
|
+
|
|
189
|
+
describe('normalizeValue', () => {
|
|
190
|
+
it.each`
|
|
191
|
+
value | expected
|
|
192
|
+
${''} | ${''}
|
|
193
|
+
${'1'} | ${'1'}
|
|
194
|
+
${'1234 '} | ${'1234'}
|
|
195
|
+
${' 1234'} | ${'1234'}
|
|
196
|
+
${'1 2 3 4'} | ${'1234'}
|
|
197
|
+
`('returns correct value without any whitespace', ({ value, expected }) => {
|
|
198
|
+
expect(normalizeValue(value)).toBe(expected);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it.each`
|
|
202
|
+
value | length | expected
|
|
203
|
+
${'1234'} | ${undefined} | ${'1234'}
|
|
204
|
+
${'1234'} | ${4} | ${'1234'}
|
|
205
|
+
${'12345'} | ${4} | ${'1234'}
|
|
206
|
+
${'1234'} | ${6} | ${'1234'}
|
|
207
|
+
${'12345'} | ${6} | ${'12345'}
|
|
208
|
+
`(
|
|
209
|
+
'returns correct value when length is $length',
|
|
210
|
+
({ value, length, expected }) => {
|
|
211
|
+
expect(normalizeValue(value, length)).toBe(expected);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
});
|
|
@@ -99,6 +99,10 @@ export interface PinInputHandler {
|
|
|
99
99
|
*/
|
|
100
100
|
blur: () => void;
|
|
101
101
|
}
|
|
102
|
+
// Normalize the value to only contain numbers and limit the length
|
|
103
|
+
export const normalizeValue = (value?: string, length = 4) => {
|
|
104
|
+
return (value?.match(/\d/g) || []).join('').slice(0, length);
|
|
105
|
+
};
|
|
102
106
|
|
|
103
107
|
const PinInput = forwardRef<PinInputHandler, PinInputProps>(
|
|
104
108
|
(
|
|
@@ -121,11 +125,13 @@ const PinInput = forwardRef<PinInputHandler, PinInputProps>(
|
|
|
121
125
|
const inputRef = useRef<TextInput>(null);
|
|
122
126
|
const [focused, setFocused] = useState(autoFocus);
|
|
123
127
|
const state = getState({ disabled, error });
|
|
124
|
-
const trimmedValue = (value
|
|
128
|
+
const trimmedValue = normalizeValue(value, length);
|
|
125
129
|
|
|
126
130
|
const maskedValueWithExtraSpace =
|
|
127
131
|
Platform.OS === 'android' && !trimmedValue ? '*' : trimmedValue;
|
|
128
132
|
|
|
133
|
+
const [hasFulfilled, setHasFulfilled] = useState(false);
|
|
134
|
+
|
|
129
135
|
const focus = useCallback(() => {
|
|
130
136
|
if (inputRef?.current) {
|
|
131
137
|
inputRef.current.focus();
|
|
@@ -142,17 +148,30 @@ const PinInput = forwardRef<PinInputHandler, PinInputProps>(
|
|
|
142
148
|
|
|
143
149
|
const changeText = useCallback(
|
|
144
150
|
(text: string) => {
|
|
145
|
-
|
|
151
|
+
// If the input is already fulfilled and the user tries to remove characters
|
|
152
|
+
if (hasFulfilled && text.length < length) {
|
|
153
|
+
setHasFulfilled(false);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// If the input is already fulfilled and the user tries to add more characters
|
|
157
|
+
if (
|
|
158
|
+
hasFulfilled &&
|
|
159
|
+
(text?.match(/\d/g) || []).join('').length > length
|
|
160
|
+
) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
146
164
|
// Prevent user from entering more than the length
|
|
147
|
-
const trimmedPin =
|
|
165
|
+
const trimmedPin = normalizeValue(text, length);
|
|
148
166
|
|
|
149
167
|
onChangeText?.(trimmedPin);
|
|
150
168
|
|
|
151
169
|
if (trimmedPin.length === length) {
|
|
152
170
|
onFulfill?.(trimmedPin);
|
|
171
|
+
setHasFulfilled(true);
|
|
153
172
|
}
|
|
154
173
|
},
|
|
155
|
-
[length, onChangeText, onFulfill]
|
|
174
|
+
[length, onChangeText, onFulfill, hasFulfilled]
|
|
156
175
|
);
|
|
157
176
|
|
|
158
177
|
useEffect(() => {
|