@alfalab/core-components-phone-input 7.3.18 → 7.3.20

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,10 @@
1
+ /// <reference types="react" />
2
+ import React from 'react';
3
+ import { MaskedInputProps } from "@alfalab/core-components-masked-input";
4
+ type PhoneInputProps = Omit<MaskedInputProps, 'onBeforeDisplay' | 'type' | 'mask'> & {
5
+ clearableCountryCode?: boolean;
6
+ };
7
+ declare const PhoneInput: React.ForwardRefExoticComponent<Omit<MaskedInputProps, "mask" | "type" | "onBeforeDisplay"> & {
8
+ clearableCountryCode?: boolean | undefined;
9
+ } & React.RefAttributes<HTMLInputElement>>;
10
+ export { PhoneInputProps, PhoneInput };
@@ -0,0 +1,104 @@
1
+ import React, { useRef, useCallback } from 'react';
2
+ import mergeRefs from 'react-merge-refs';
3
+ import { conformToMask } from 'text-mask-core';
4
+ import { MaskedInput } from '@alfalab/core-components-masked-input/moderncssm';
5
+ import { deleteFormatting, deleteMaskChar, setCaretPosition, getInsertedNumber } from './utils/index.js';
6
+
7
+ /* eslint-disable complexity, no-param-reassign */
8
+ const mask = [
9
+ '+',
10
+ '7',
11
+ ' ',
12
+ /([0-6]|[8-9])/,
13
+ /\d/,
14
+ /\d/,
15
+ ' ',
16
+ /\d/,
17
+ /\d/,
18
+ /\d/,
19
+ ' ',
20
+ /\d/,
21
+ /\d/,
22
+ ' ',
23
+ /\d/,
24
+ /\d/,
25
+ ];
26
+ const countryPrefix = '+7 ';
27
+ const PhoneInput = React.forwardRef(({ clearableCountryCode = true, ...restProps }, ref) => {
28
+ const inputRef = useRef(null);
29
+ const handleBeforeDisplay = useCallback((conformedValue, config) => {
30
+ const { rawValue, previousConformedValue, currentCaretPosition } = config;
31
+ const previousValueWithoutFormatting = previousConformedValue
32
+ ? deleteFormatting(previousConformedValue)
33
+ : '';
34
+ /*
35
+ * Удаляем лишний символ маски при вводе или вставке значений перед знаком + или после него.
36
+ */
37
+ if (previousConformedValue && rawValue.indexOf('+7') !== 0) {
38
+ const newRaw = deleteMaskChar(previousValueWithoutFormatting, rawValue);
39
+ conformedValue = conformToMask(newRaw, mask, config).conformedValue;
40
+ }
41
+ const currentValueWithoutFormatting = deleteFormatting(conformedValue) || '';
42
+ /*
43
+ * код ниже нужен для фикса следующих багов библиотеки text-mask:
44
+ * 1) так как код страны указан в маске жестко как "+7",
45
+ * то при удалении цифры перед ним каретка устанавливается перед кодом страны
46
+ * 2) в номере телефона есть пробелы и дефисы,
47
+ * при редактировании цифр рядом с этими символами каретка перескакивает через них,
48
+ * а не остается на том же месте, на котором была до редактирования
49
+ */
50
+ if (previousConformedValue &&
51
+ (([3, 6].includes(currentCaretPosition) &&
52
+ Math.abs(previousValueWithoutFormatting.length -
53
+ currentValueWithoutFormatting.length) === 1) ||
54
+ ([7, 10, 13].includes(currentCaretPosition) &&
55
+ previousConformedValue.length > currentCaretPosition))) {
56
+ setCaretPosition({ position: currentCaretPosition, inputRef });
57
+ }
58
+ // Удаление цифры перед кодом страны удаляет только саму цифру, код остается ("+7 1" -> "+7 ")
59
+ if (rawValue === countryPrefix) {
60
+ return rawValue;
61
+ }
62
+ // Вставка номера с 10 цифрами без кода страны
63
+ if (rawValue.length === 10 && conformedValue.length === mask.length) {
64
+ const masked = conformToMask(`+7${rawValue}`, mask, config);
65
+ return masked.conformedValue;
66
+ }
67
+ /*
68
+ * Код нужен для исправления ошибки в библиотеке text-mask: если цифра 7 находится на второй позиции при вставке, то она удаляется
69
+ * Это происходит потому что цифра 7 есть уже в маске
70
+ */
71
+ if (rawValue[1] === '7') {
72
+ const masked = conformToMask(`+7${rawValue}`, mask, config);
73
+ return masked.conformedValue;
74
+ }
75
+ const insertedNumber = getInsertedNumber({
76
+ rawValue,
77
+ clearableCountryCode,
78
+ countryPrefix,
79
+ previousConformedValue,
80
+ });
81
+ // Вставка номера, начинающегося с 8 или 7: 89990313131, 71112223344
82
+ if (conformedValue.length === mask.length &&
83
+ (insertedNumber.startsWith('8') || insertedNumber.startsWith('7'))) {
84
+ const masked = conformToMask(`+7${insertedNumber.slice(1)}`, mask, config);
85
+ return masked.conformedValue;
86
+ }
87
+ // Если ввод начат с 7 или 8 - выводит "+7 " и дает продолжить ввод со след. цифры
88
+ if (rawValue.length === 1 && ['7', '8'].includes(rawValue[0])) {
89
+ return countryPrefix;
90
+ }
91
+ const abortCountryCodeClearing = !clearableCountryCode && !conformedValue;
92
+ if (abortCountryCodeClearing) {
93
+ setCaretPosition({ position: countryPrefix.length, inputRef });
94
+ if (!rawValue.length)
95
+ return countryPrefix;
96
+ return false;
97
+ }
98
+ return conformedValue;
99
+ }, [clearableCountryCode]);
100
+ return (React.createElement(MaskedInput, { ...restProps, defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: mergeRefs([ref, inputRef]) }));
101
+ });
102
+ PhoneInput.displayName = 'PhoneInputs';
103
+
104
+ export { PhoneInput };
@@ -0,0 +1 @@
1
+ export * from "./Component";
@@ -0,0 +1 @@
1
+ export { PhoneInput } from './Component.js';
@@ -0,0 +1,18 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * Удаляет форматирование номера телефона
4
+ * @param phone Номер телефона
5
+ */
6
+ declare const deleteFormatting: (phone: string) => string;
7
+ declare function setCaretPosition({ position, inputRef, }: {
8
+ position: number;
9
+ inputRef: React.RefObject<HTMLInputElement>;
10
+ }): void;
11
+ declare function getInsertedNumber({ rawValue, clearableCountryCode, countryPrefix, previousConformedValue, }: {
12
+ rawValue: string;
13
+ clearableCountryCode: boolean;
14
+ countryPrefix: string;
15
+ previousConformedValue: string;
16
+ }): string;
17
+ declare function deleteMaskChar(previousValue: string, rawValue: string): string;
18
+ export { deleteFormatting, setCaretPosition, getInsertedNumber, deleteMaskChar };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Удаляет форматирование номера телефона
3
+ * @param phone Номер телефона
4
+ */
5
+ const deleteFormatting = (phone) => phone.replace('+', '').replace(/^7/, '').replace(/\s/g, '');
6
+ function setCaretPosition({ position, inputRef, }) {
7
+ window.requestAnimationFrame(() => {
8
+ if (inputRef === null || !inputRef.current)
9
+ return;
10
+ inputRef.current.setSelectionRange(position, position);
11
+ });
12
+ }
13
+ function getInsertedNumber({ rawValue, clearableCountryCode, countryPrefix, previousConformedValue, }) {
14
+ if (!clearableCountryCode && previousConformedValue === countryPrefix) {
15
+ if (rawValue.startsWith('7') || rawValue.startsWith('8')) {
16
+ return rawValue;
17
+ }
18
+ return rawValue.slice(countryPrefix.length);
19
+ }
20
+ return rawValue;
21
+ }
22
+ function deleteMaskChar(previousValue, rawValue) {
23
+ const prevRawValueAsArr = deleteFormatting(rawValue).split('').reverse();
24
+ let prevConformedCharIdx = previousValue.length - 1;
25
+ let isMaskRemoved = false;
26
+ const newRaw = [];
27
+ prevRawValueAsArr.forEach((char) => {
28
+ if (isMaskRemoved || char === previousValue[prevConformedCharIdx]) {
29
+ newRaw.push(char);
30
+ prevConformedCharIdx -= 1;
31
+ }
32
+ else if (char === '7') {
33
+ isMaskRemoved = true;
34
+ }
35
+ });
36
+ return newRaw.reverse().join('');
37
+ }
38
+
39
+ export { deleteFormatting, deleteMaskChar, getInsertedNumber, setCaretPosition };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfalab/core-components-phone-input",
3
- "version": "7.3.18",
3
+ "version": "7.3.20",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -14,11 +14,11 @@
14
14
  "react": "^16.9.0 || ^17.0.1 || ^18.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@alfalab/core-components-masked-input": "^6.3.17",
17
+ "@alfalab/core-components-masked-input": "^6.3.19",
18
18
  "react-merge-refs": "^1.1.0",
19
19
  "text-mask-core": "^5.1.2",
20
20
  "tslib": "^2.4.0"
21
21
  },
22
- "themesVersion": "13.0.1",
23
- "varsVersion": "9.11.1"
22
+ "themesVersion": "13.1.0",
23
+ "varsVersion": "9.12.0"
24
24
  }