@alfalab/core-components-phone-input 7.1.18 → 7.2.1

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/Component.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
6
  var React = require('react');
7
+ var mergeRefs = require('react-merge-refs');
7
8
  var textMaskCore = require('text-mask-core');
8
9
  var coreComponentsMaskedInput = require('@alfalab/core-components-masked-input');
9
10
  var utils_index = require('./utils/index.js');
@@ -11,6 +12,7 @@ var utils_index = require('./utils/index.js');
11
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
13
 
13
14
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
15
+ var mergeRefs__default = /*#__PURE__*/_interopDefaultCompat(mergeRefs);
14
16
 
15
17
  var mask = [
16
18
  '+',
@@ -34,8 +36,6 @@ var countryPrefix = '+7 ';
34
36
  var PhoneInput = React__default.default.forwardRef(function (_a, ref) {
35
37
  var _b = _a.clearableCountryCode, clearableCountryCode = _b === void 0 ? true : _b, restProps = tslib.__rest(_a, ["clearableCountryCode"]);
36
38
  var inputRef = React.useRef(null);
37
- // Оставляет возможность прокинуть ref извне
38
- React.useImperativeHandle(ref, function () { return inputRef.current; });
39
39
  var handleBeforeDisplay = React.useCallback(function (conformedValue, config) {
40
40
  var rawValue = config.rawValue, previousConformedValue = config.previousConformedValue, currentCaretPosition = config.currentCaretPosition;
41
41
  /*
@@ -92,7 +92,7 @@ var PhoneInput = React__default.default.forwardRef(function (_a, ref) {
92
92
  }
93
93
  return conformedValue;
94
94
  }, [clearableCountryCode]);
95
- return (React__default.default.createElement(coreComponentsMaskedInput.MaskedInput, tslib.__assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef })));
95
+ return (React__default.default.createElement(coreComponentsMaskedInput.MaskedInput, tslib.__assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: mergeRefs__default.default([ref, inputRef]) })));
96
96
  });
97
97
 
98
98
  exports.PhoneInput = PhoneInput;
package/cssm/Component.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
6
  var React = require('react');
7
+ var mergeRefs = require('react-merge-refs');
7
8
  var textMaskCore = require('text-mask-core');
8
9
  var coreComponentsMaskedInput = require('@alfalab/core-components-masked-input/cssm');
9
10
  var utils_index = require('./utils/index.js');
@@ -11,6 +12,7 @@ var utils_index = require('./utils/index.js');
11
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
13
 
13
14
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
15
+ var mergeRefs__default = /*#__PURE__*/_interopDefaultCompat(mergeRefs);
14
16
 
15
17
  var mask = [
16
18
  '+',
@@ -34,8 +36,6 @@ var countryPrefix = '+7 ';
34
36
  var PhoneInput = React__default.default.forwardRef(function (_a, ref) {
35
37
  var _b = _a.clearableCountryCode, clearableCountryCode = _b === void 0 ? true : _b, restProps = tslib.__rest(_a, ["clearableCountryCode"]);
36
38
  var inputRef = React.useRef(null);
37
- // Оставляет возможность прокинуть ref извне
38
- React.useImperativeHandle(ref, function () { return inputRef.current; });
39
39
  var handleBeforeDisplay = React.useCallback(function (conformedValue, config) {
40
40
  var rawValue = config.rawValue, previousConformedValue = config.previousConformedValue, currentCaretPosition = config.currentCaretPosition;
41
41
  /*
@@ -92,7 +92,7 @@ var PhoneInput = React__default.default.forwardRef(function (_a, ref) {
92
92
  }
93
93
  return conformedValue;
94
94
  }, [clearableCountryCode]);
95
- return (React__default.default.createElement(coreComponentsMaskedInput.MaskedInput, tslib.__assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef })));
95
+ return (React__default.default.createElement(coreComponentsMaskedInput.MaskedInput, tslib.__assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: mergeRefs__default.default([ref, inputRef]) })));
96
96
  });
97
97
 
98
98
  exports.PhoneInput = PhoneInput;
package/cssm/index.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var Component = require('./Component.js');
6
6
  require('tslib');
7
7
  require('react');
8
+ require('react-merge-refs');
8
9
  require('text-mask-core');
9
10
  require('@alfalab/core-components-masked-input/cssm');
10
11
  require('./utils/index.js');
package/esm/Component.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __rest, __assign } from 'tslib';
2
- import React, { useRef, useImperativeHandle, useCallback } from 'react';
2
+ import React, { useRef, useCallback } from 'react';
3
+ import mergeRefs from 'react-merge-refs';
3
4
  import { conformToMask } from 'text-mask-core';
4
5
  import { MaskedInput } from '@alfalab/core-components-masked-input/esm';
5
6
  import { deleteFormatting, setCaretPosition, getInsertedNumber } from './utils/index.js';
@@ -26,8 +27,6 @@ var countryPrefix = '+7 ';
26
27
  var PhoneInput = React.forwardRef(function (_a, ref) {
27
28
  var _b = _a.clearableCountryCode, clearableCountryCode = _b === void 0 ? true : _b, restProps = __rest(_a, ["clearableCountryCode"]);
28
29
  var inputRef = useRef(null);
29
- // Оставляет возможность прокинуть ref извне
30
- useImperativeHandle(ref, function () { return inputRef.current; });
31
30
  var handleBeforeDisplay = useCallback(function (conformedValue, config) {
32
31
  var rawValue = config.rawValue, previousConformedValue = config.previousConformedValue, currentCaretPosition = config.currentCaretPosition;
33
32
  /*
@@ -84,7 +83,7 @@ var PhoneInput = React.forwardRef(function (_a, ref) {
84
83
  }
85
84
  return conformedValue;
86
85
  }, [clearableCountryCode]);
87
- return (React.createElement(MaskedInput, __assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef })));
86
+ return (React.createElement(MaskedInput, __assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: mergeRefs([ref, inputRef]) })));
88
87
  });
89
88
 
90
89
  export { PhoneInput };
package/esm/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { PhoneInput } from './Component.js';
2
2
  import 'tslib';
3
3
  import 'react';
4
+ import 'react-merge-refs';
4
5
  import 'text-mask-core';
5
6
  import '@alfalab/core-components-masked-input/esm';
6
7
  import './utils/index.js';
package/index.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var Component = require('./Component.js');
6
6
  require('tslib');
7
7
  require('react');
8
+ require('react-merge-refs');
8
9
  require('text-mask-core');
9
10
  require('@alfalab/core-components-masked-input');
10
11
  require('./utils/index.js');
@@ -1,4 +1,5 @@
1
- import React, { useRef, useImperativeHandle, useCallback } from 'react';
1
+ import React, { useRef, useCallback } from 'react';
2
+ import mergeRefs from 'react-merge-refs';
2
3
  import { conformToMask } from 'text-mask-core';
3
4
  import { MaskedInput } from '@alfalab/core-components-masked-input/modern';
4
5
  import { deleteFormatting, setCaretPosition, getInsertedNumber } from './utils/index.js';
@@ -24,8 +25,6 @@ const mask = [
24
25
  const countryPrefix = '+7 ';
25
26
  const PhoneInput = React.forwardRef(({ clearableCountryCode = true, ...restProps }, ref) => {
26
27
  const inputRef = useRef(null);
27
- // Оставляет возможность прокинуть ref извне
28
- useImperativeHandle(ref, () => inputRef.current);
29
28
  const handleBeforeDisplay = useCallback((conformedValue, config) => {
30
29
  const { rawValue, previousConformedValue, currentCaretPosition } = config;
31
30
  /*
@@ -82,7 +81,7 @@ const PhoneInput = React.forwardRef(({ clearableCountryCode = true, ...restProps
82
81
  }
83
82
  return conformedValue;
84
83
  }, [clearableCountryCode]);
85
- return (React.createElement(MaskedInput, { ...restProps, defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef }));
84
+ return (React.createElement(MaskedInput, { ...restProps, defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: mergeRefs([ref, inputRef]) }));
86
85
  });
87
86
 
88
87
  export { PhoneInput };
package/modern/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { PhoneInput } from './Component.js';
2
2
  import 'react';
3
+ import 'react-merge-refs';
3
4
  import 'text-mask-core';
4
5
  import '@alfalab/core-components-masked-input/modern';
5
6
  import './utils/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfalab/core-components-phone-input",
3
- "version": "7.1.18",
3
+ "version": "7.2.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -14,7 +14,8 @@
14
14
  "react": "^16.9.0 || ^17.0.1 || ^18.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@alfalab/core-components-masked-input": "^6.1.18",
17
+ "@alfalab/core-components-masked-input": "^6.2.1",
18
+ "react-merge-refs": "^1.1.0",
18
19
  "text-mask-core": "^5.1.2",
19
20
  "tslib": "^2.4.0"
20
21
  }
@@ -0,0 +1,128 @@
1
+ import React, { useCallback, useRef } from 'react';
2
+ import mergeRefs from 'react-merge-refs';
3
+ import { conformToMask, TextMaskConfig } from 'text-mask-core';
4
+
5
+ import { MaskedInput, MaskedInputProps } from '@alfalab/core-components-masked-input';
6
+
7
+ import { deleteFormatting, getInsertedNumber, setCaretPosition } from './utils';
8
+
9
+ const mask = [
10
+ '+',
11
+ '7',
12
+ ' ',
13
+ /([0-6]|[8-9])/,
14
+ /\d/,
15
+ /\d/,
16
+ ' ',
17
+ /\d/,
18
+ /\d/,
19
+ /\d/,
20
+ '-',
21
+ /\d/,
22
+ /\d/,
23
+ '-',
24
+ /\d/,
25
+ /\d/,
26
+ ];
27
+
28
+ const countryPrefix = '+7 ';
29
+
30
+ export type PhoneInputProps = Omit<MaskedInputProps, 'onBeforeDisplay' | 'type' | 'mask'> & {
31
+ clearableCountryCode?: boolean;
32
+ };
33
+
34
+ export const PhoneInput = React.forwardRef<HTMLInputElement, PhoneInputProps>(
35
+ ({ clearableCountryCode = true, ...restProps }, ref) => {
36
+ const inputRef = useRef<HTMLInputElement>(null);
37
+
38
+ const handleBeforeDisplay = useCallback(
39
+ (conformedValue: string, config: TextMaskConfig) => {
40
+ const { rawValue, previousConformedValue, currentCaretPosition } = config;
41
+
42
+ /*
43
+ * код ниже нужен для фикса следующих багов библиотеки text-mask:
44
+ * 1) так как код страны указан в маске жестко как "+7",
45
+ * то при удалении цифры перед ним каретка устанавливается перед кодом страны
46
+ * 2) в номере телефона есть пробелы и дефисы,
47
+ * при редактировании цифр рядом с этими символами каретка перескакивает через них,
48
+ * а не остается на том же месте, на котором была до редактирования
49
+ */
50
+ const previousValueWithoutFormatting = previousConformedValue
51
+ ? deleteFormatting(previousConformedValue)
52
+ : '';
53
+ const currentValueWithoutFormatting = deleteFormatting(conformedValue) || '';
54
+
55
+ if (
56
+ previousConformedValue &&
57
+ (([3, 6].includes(currentCaretPosition) &&
58
+ Math.abs(
59
+ previousValueWithoutFormatting.length -
60
+ currentValueWithoutFormatting.length,
61
+ ) === 1) ||
62
+ ([7, 10, 13].includes(currentCaretPosition) &&
63
+ previousConformedValue.length > currentCaretPosition))
64
+ ) {
65
+ setCaretPosition({ position: currentCaretPosition, inputRef });
66
+ }
67
+
68
+ // Удаление цифры перед кодом страны удаляет только саму цифру, код остается ("+7 1" -> "+7 ")
69
+ if (rawValue === countryPrefix) {
70
+ return rawValue;
71
+ }
72
+
73
+ // Вставка номера с 10 цифрами без кода страны
74
+ if (rawValue.length === 10 && conformedValue.length === mask.length) {
75
+ const masked = conformToMask(`+7${rawValue}`, mask, config);
76
+
77
+ return masked.conformedValue;
78
+ }
79
+
80
+ const insertedNumber = getInsertedNumber({
81
+ rawValue,
82
+ clearableCountryCode,
83
+ countryPrefix,
84
+ previousConformedValue,
85
+ });
86
+
87
+ // Вставка номера, начинающегося с 8 или 7: 89990313131, 71112223344
88
+ if (
89
+ conformedValue.length === mask.length &&
90
+ (insertedNumber.startsWith('8') || insertedNumber.startsWith('7'))
91
+ ) {
92
+ const masked = conformToMask(`+7${insertedNumber.slice(1)}`, mask, config);
93
+
94
+ return masked.conformedValue;
95
+ }
96
+
97
+ // Если ввод начат с 7 или 8 - выводит "+7 " и дает продолжить ввод со след. цифры
98
+ if (rawValue.length === 1 && ['7', '8'].includes(rawValue[0])) {
99
+ return countryPrefix;
100
+ }
101
+
102
+ const abortCountryCodeClearing = !clearableCountryCode && !conformedValue;
103
+
104
+ if (abortCountryCodeClearing) {
105
+ setCaretPosition({ position: countryPrefix.length, inputRef });
106
+
107
+ if (!rawValue.length) return countryPrefix;
108
+
109
+ return false;
110
+ }
111
+
112
+ return conformedValue;
113
+ },
114
+ [clearableCountryCode],
115
+ );
116
+
117
+ return (
118
+ <MaskedInput
119
+ {...restProps}
120
+ defaultValue={clearableCountryCode ? restProps.defaultValue : countryPrefix}
121
+ mask={mask}
122
+ onBeforeDisplay={handleBeforeDisplay}
123
+ type='tel'
124
+ ref={mergeRefs([ref, inputRef])}
125
+ />
126
+ );
127
+ },
128
+ );
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './Component';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Удаляет форматирование номера телефона
3
+ * @param phone Номер телефона
4
+ */
5
+
6
+ export const deleteFormatting = (phone: string) =>
7
+ phone.replace('+', '').replace(/^7/, '').replace(/\s/g, '').replace(/-/g, '');
8
+
9
+ export function setCaretPosition({
10
+ position,
11
+ inputRef,
12
+ }: {
13
+ position: number;
14
+ inputRef: React.RefObject<HTMLInputElement>;
15
+ }) {
16
+ window.requestAnimationFrame(() => {
17
+ if (inputRef === null || !inputRef.current) return;
18
+
19
+ inputRef.current.setSelectionRange(position, position);
20
+ });
21
+ }
22
+
23
+ export function getInsertedNumber({
24
+ rawValue,
25
+ clearableCountryCode,
26
+ countryPrefix,
27
+ previousConformedValue,
28
+ }: {
29
+ rawValue: string;
30
+ clearableCountryCode: boolean;
31
+ countryPrefix: string;
32
+ previousConformedValue: string;
33
+ }) {
34
+ if (!clearableCountryCode && previousConformedValue === countryPrefix) {
35
+ if (rawValue.startsWith('7') || rawValue.startsWith('8')) {
36
+ return rawValue;
37
+ }
38
+
39
+ return rawValue.slice(countryPrefix.length);
40
+ }
41
+
42
+ return rawValue;
43
+ }