@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.
@@ -0,0 +1,5 @@
1
+ 
2
+ src/index.ts → lib/index.js, es/index.js...
3
+ (!) 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`.
4
+ (!) 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
5
+ created lib/index.js, es/index.js in 1m 3.5s
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 = ((value === null || value === void 0 ? void 0 : value.match(/\d/g)) || []).join('').slice(0, length);
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
- var pin = (text.match(/\d/g) || []).join('');
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 = pin.slice(0, length);
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 = ((value === null || value === void 0 ? void 0 : value.match(/\d/g)) || []).join('').slice(0, length);
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
- var pin = (text.match(/\d/g) || []).join('');
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 = pin.slice(0, length);
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-alpha.0",
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?.match(/\d/g) || []).join('').slice(0, length);
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
- const pin = (text.match(/\d/g) || []).join('');
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 = pin.slice(0, length);
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(() => {