@hh.ru/magritte-ui-phone-input 4.3.41 → 4.3.43
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/CallingCodeInput-CccAVXGJ.js +139 -0
- package/{CallingCodeInput-Dgx-XDoR.js.map → CallingCodeInput-CccAVXGJ.js.map} +1 -1
- package/CallingCodeInput.d.ts +1 -1
- package/CallingCodeInput.js +1 -1
- package/PhoneInput.js +162 -80
- package/PhoneInput.js.map +1 -1
- package/RegionSelect.d.ts +2 -2
- package/RegionSelect.js +95 -28
- package/RegionSelect.js.map +1 -1
- package/basicMetadata.js +246 -246
- package/basicMetadata.js.map +1 -1
- package/index.css +86 -86
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.mock.d.ts +1 -1
- package/index.mock.js +2 -2
- package/index.mock.js.map +1 -1
- package/{metadata.max-DSNgy9A6.js → metadata.max-BtLm3_Jz.js} +1 -1
- package/{metadata.max-DSNgy9A6.js.map → metadata.max-BtLm3_Jz.js.map} +1 -1
- package/{metadata.mobile-6_mnHNh9.js → metadata.mobile-PgGgMG2t.js} +1 -1
- package/{metadata.mobile-6_mnHNh9.js.map → metadata.mobile-PgGgMG2t.js.map} +1 -1
- package/{metadata.ru_by_kz_uz.max-CcLl17V4.js → metadata.ru_by_kz_uz.max-DOkjzVfi.js} +1 -1
- package/{metadata.ru_by_kz_uz.max-CcLl17V4.js.map → metadata.ru_by_kz_uz.max-DOkjzVfi.js.map} +1 -1
- package/{metadata.ru_by_kz_uz.mobile-CJDhJXrq.js → metadata.ru_by_kz_uz.mobile-BjjwTeqx.js} +1 -1
- package/{metadata.ru_by_kz_uz.mobile-CJDhJXrq.js.map → metadata.ru_by_kz_uz.mobile-BjjwTeqx.js.map} +1 -1
- package/package.json +9 -9
- package/phoneFormatter.d.ts +1 -1
- package/phoneFormatter.js +59 -83
- package/phoneFormatter.js.map +1 -1
- package/useCountrySelectDataProvider.d.ts +1 -1
- package/useCountrySelectDataProvider.js +116 -136
- package/useCountrySelectDataProvider.js.map +1 -1
- package/useLibPhoneNumber.js +65 -65
- package/useLibPhoneNumber.js.map +1 -1
- package/CallingCodeInput-Dgx-XDoR.js +0 -95
package/phoneFormatter.js
CHANGED
|
@@ -4,92 +4,68 @@ const prohibitedSymbolsRegExp = /[^0-9+()-]/g;
|
|
|
4
4
|
const digitRegexp = /\d/;
|
|
5
5
|
const notSpaceRegExp = /[^\s]/;
|
|
6
6
|
const buildRegExpFromNumber = (number, inTheMiddle = false, optionalDigits = true) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
return acc;
|
|
17
|
-
}, [])
|
|
18
|
-
.join('');
|
|
19
|
-
return new RegExp(inTheMiddle ? `.*(${regExp}).*` : regExp, 'u');
|
|
7
|
+
const regExp = number.split("").reduce((acc, char, index) => {
|
|
8
|
+
acc.push(`\\u{${char.charCodeAt(0).toString(16)}}${optionalDigits ? "?" : ""}`);
|
|
9
|
+
if (index !== number.length - 1) {
|
|
10
|
+
acc.push("\\s?-?\\(?\\)?\\s?");
|
|
11
|
+
}
|
|
12
|
+
return acc;
|
|
13
|
+
}, []).join("");
|
|
14
|
+
return new RegExp(inTheMiddle ? `.*(${regExp}).*` : regExp, "u");
|
|
20
15
|
};
|
|
21
16
|
const phoneFormatterFactory = (params) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// кроме того делаем все символы опциональными, т.к. после форматирования может удалиться часть
|
|
73
|
-
// символов в начале номера относящаяся к коду страны
|
|
74
|
-
const caretPositionRegExp = buildRegExpFromNumber(digitsBeforeCaret);
|
|
75
|
-
// применяем регулярку к отформатированной строке и сдвигаем каретку на длину найденного совпадения
|
|
76
|
-
const match = formattedValue.match(caretPositionRegExp)?.[0];
|
|
77
|
-
if (match) {
|
|
78
|
-
const positionOfFirstDigitToTheRightOfCaret = formattedValue
|
|
79
|
-
.substring(match.length)
|
|
80
|
-
.search(digitRegexp);
|
|
81
|
-
caret =
|
|
82
|
-
positionOfFirstDigitToTheRightOfCaret === -1
|
|
83
|
-
? formattedValue.length
|
|
84
|
-
: positionOfFirstDigitToTheRightOfCaret + match.length;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
formattedValue,
|
|
89
|
-
outputValue: formattedValue,
|
|
90
|
-
caretPosition: caret,
|
|
91
|
-
};
|
|
17
|
+
const {
|
|
18
|
+
setCountry,
|
|
19
|
+
currentCountryRef,
|
|
20
|
+
libPhoneNumberAPI: { formatIncompletePhoneNumber, parsePhoneNumber, getCountryCallingCode },
|
|
21
|
+
availableCountriesRef,
|
|
22
|
+
countryLocked
|
|
23
|
+
} = params;
|
|
24
|
+
return (prevValue, value, caretPosition) => {
|
|
25
|
+
let sanitizedValue = value.replace(prohibitedSymbolsRegExp, "");
|
|
26
|
+
let formattedValue = sanitizedValue;
|
|
27
|
+
let caret = caretPosition;
|
|
28
|
+
let digitsBeforeCaret = value.substring(0, caret).replace(notDigitsOrPlusRegExp, "");
|
|
29
|
+
if (prevValue.length - value.length === 1 && notDigitsOrPlusRegExp.test(prevValue[caretPosition])) {
|
|
30
|
+
digitsBeforeCaret = digitsBeforeCaret.slice(0, -1);
|
|
31
|
+
formattedValue = `${digitsBeforeCaret}${value.substring(caret)}`;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const phoneNumber = parsePhoneNumber(formattedValue, currentCountryRef.current || "RU");
|
|
35
|
+
const allowedCountry = (!availableCountriesRef?.current || !phoneNumber.country || availableCountriesRef.current.includes(phoneNumber.country)) && (!countryLocked || currentCountryRef.current === phoneNumber.country);
|
|
36
|
+
const country = (allowedCountry ? phoneNumber.country : false) || currentCountryRef.current || "RU";
|
|
37
|
+
formattedValue = phoneNumber.isValid() && allowedCountry ? phoneNumber.format("NATIONAL", { nationalPrefix: false }) : formatIncompletePhoneNumber(phoneNumber.nationalNumber, country);
|
|
38
|
+
const code = getCountryCallingCode(country);
|
|
39
|
+
if (sanitizedValue.startsWith(`+${code}`)) {
|
|
40
|
+
sanitizedValue = sanitizedValue.slice(code.length + 1);
|
|
41
|
+
}
|
|
42
|
+
if (country !== currentCountryRef.current) {
|
|
43
|
+
setCountry(country);
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
const currentValueRegExp = buildRegExpFromNumber(
|
|
48
|
+
sanitizedValue.replace(notDigitsOrPlusRegExp, ""),
|
|
49
|
+
true,
|
|
50
|
+
false
|
|
51
|
+
);
|
|
52
|
+
formattedValue = formattedValue.match(currentValueRegExp)?.[1] || formattedValue;
|
|
53
|
+
if (digitsBeforeCaret.length === 0) {
|
|
54
|
+
caret = formattedValue.substring(0, caret).match(notSpaceRegExp)?.[0].length || 0;
|
|
55
|
+
} else {
|
|
56
|
+
const caretPositionRegExp = buildRegExpFromNumber(digitsBeforeCaret);
|
|
57
|
+
const match = formattedValue.match(caretPositionRegExp)?.[0];
|
|
58
|
+
if (match) {
|
|
59
|
+
const positionOfFirstDigitToTheRightOfCaret = formattedValue.substring(match.length).search(digitRegexp);
|
|
60
|
+
caret = positionOfFirstDigitToTheRightOfCaret === -1 ? formattedValue.length : positionOfFirstDigitToTheRightOfCaret + match.length;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
formattedValue,
|
|
65
|
+
outputValue: formattedValue,
|
|
66
|
+
caretPosition: caret
|
|
92
67
|
};
|
|
68
|
+
};
|
|
93
69
|
};
|
|
94
70
|
|
|
95
71
|
export { phoneFormatterFactory };
|
package/phoneFormatter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phoneFormatter.js","sources":["src/phoneFormatter.ts"],"sourcesContent":["import { type RefObject } from 'react';\nimport { type CountryCode } from 'libphonenumber-js';\n\nimport { type InputFormatter } from '@hh.ru/magritte-ui-input';\nimport { type LibPhoneNumberAPI } from '@hh.ru/magritte-ui-phone-input/useLibPhoneNumber';\n\nconst notDigitsOrPlusRegExp = /[\\D+]/g;\nconst prohibitedSymbolsRegExp = /[^0-9+()-]/g;\nconst digitRegexp = /\\d/;\nconst notSpaceRegExp = /[^\\s]/;\n\nconst buildRegExpFromNumber = (number: string, inTheMiddle = false, optionalDigits = true) => {\n const regExp = number\n .split('')\n .reduce<string[]>((acc, char, index) => {\n // символы из строки нужно экранировать т.к. там могут оказаться символы имеющие специальное\n // значение в регулярных выражениях, например +\n acc.push(`\\\\u{${char.charCodeAt(0).toString(16)}}${optionalDigits ? '?' : ''}`);\n if (index !== number.length - 1) {\n acc.push('\\\\s?-?\\\\(?\\\\)?\\\\s?');\n }\n return acc;\n }, [])\n .join('');\n return new RegExp(inTheMiddle ? `.*(${regExp}).*` : regExp, 'u');\n};\n\nexport const phoneFormatterFactory = (params: {\n setCountry: (country: CountryCode) => void;\n currentCountryRef: RefObject<CountryCode>;\n availableCountriesRef?: RefObject<CountryCode[] | undefined>;\n libPhoneNumberAPI: LibPhoneNumberAPI;\n countryLocked: boolean;\n}): InputFormatter => {\n const {\n setCountry,\n currentCountryRef,\n libPhoneNumberAPI: { formatIncompletePhoneNumber, parsePhoneNumber, getCountryCallingCode },\n availableCountriesRef,\n countryLocked,\n } = params;\n\n return (prevValue: string, value: string, caretPosition: number) => {\n let sanitizedValue = value.replace(prohibitedSymbolsRegExp, '');\n let formattedValue = sanitizedValue;\n let caret = caretPosition;\n\n let digitsBeforeCaret = value.substring(0, caret).replace(notDigitsOrPlusRegExp, '');\n\n // удалили один символ и этот символ не цифра, надо удалить ближайшую цифру слева от каретки\n if (prevValue.length - value.length === 1 && notDigitsOrPlusRegExp.test(prevValue[caretPosition])) {\n digitsBeforeCaret = digitsBeforeCaret.slice(0, -1);\n formattedValue = `${digitsBeforeCaret}${value.substring(caret)}`;\n }\n\n try {\n const phoneNumber = parsePhoneNumber(formattedValue, currentCountryRef.current || 'RU');\n const allowedCountry =\n (!availableCountriesRef?.current ||\n !phoneNumber.country ||\n availableCountriesRef.current.includes(phoneNumber.country)) &&\n (!countryLocked || currentCountryRef.current === phoneNumber.country);\n\n const country = (allowedCountry ? phoneNumber.country : false) || currentCountryRef.current || 'RU';\n\n formattedValue =\n phoneNumber.isValid() && allowedCountry\n ? phoneNumber.format('NATIONAL', { nationalPrefix: false })\n : formatIncompletePhoneNumber(phoneNumber.nationalNumber, country);\n\n const code = getCountryCallingCode(country);\n if (sanitizedValue.startsWith(`+${code}`)) {\n sanitizedValue = sanitizedValue.slice(code.length + 1);\n }\n if (country !== currentCountryRef.current) {\n setCountry(country);\n }\n } catch {\n // do nothing\n }\n\n // В процессе форматирования libphonenumber может дописать в national number префикс, который не используется\n // в международном номере (для Беларуси например 80), при этом требование дизайна в остальном форматировать\n // часть номера после кода по национальным стандартам. Поэтому находим цифры которые пользователь не вводил\n // и удаляем их.\n const currentValueRegExp = buildRegExpFromNumber(\n sanitizedValue.replace(notDigitsOrPlusRegExp, ''),\n true,\n false\n );\n formattedValue = formattedValue.match(currentValueRegExp)?.[1] || formattedValue;\n\n if (digitsBeforeCaret.length === 0) {\n caret = formattedValue.substring(0, caret).match(notSpaceRegExp)?.[0].length || 0;\n } else {\n // в результате форматирования в строке с номером могут появляться дополнительные символы\n // при этом каретка должна сохранить свое положение относительно цифр в номере\n // для этого находим позицию каретки в строке до форматирования, извлекаем из неё только цифры находящиеся\n // перед кареткой, находим длину строки после форматирования которая содержит те же цифры что и в строке до\n // форматирования перед кареткой и сдвигаем каретку на эту длину\n // для этого используем регулярку в которую добавляем все символы перед кареткой и возможные символы между\n // ними которые могут появиться после форматирования\n // кроме того делаем все символы опциональными, т.к. после форматирования может удалиться часть\n // символов в начале номера относящаяся к коду страны\n const caretPositionRegExp = buildRegExpFromNumber(digitsBeforeCaret);\n\n // применяем регулярку к отформатированной строке и сдвигаем каретку на длину найденного совпадения\n const match = formattedValue.match(caretPositionRegExp)?.[0];\n\n if (match) {\n const positionOfFirstDigitToTheRightOfCaret = formattedValue\n .substring(match.length)\n .search(digitRegexp);\n\n caret =\n positionOfFirstDigitToTheRightOfCaret === -1\n ? formattedValue.length\n : positionOfFirstDigitToTheRightOfCaret + match.length;\n }\n }\n\n return {\n formattedValue,\n outputValue: formattedValue,\n caretPosition: caret,\n };\n };\n};\n"],"names":[],"mappings":"AAMA,MAAM,
|
|
1
|
+
{"version":3,"file":"phoneFormatter.js","sources":["src/phoneFormatter.ts"],"sourcesContent":["import { type RefObject } from 'react';\nimport { type CountryCode } from 'libphonenumber-js';\n\nimport { type InputFormatter } from '@hh.ru/magritte-ui-input';\nimport { type LibPhoneNumberAPI } from '@hh.ru/magritte-ui-phone-input/useLibPhoneNumber';\n\nconst notDigitsOrPlusRegExp = /[\\D+]/g;\nconst prohibitedSymbolsRegExp = /[^0-9+()-]/g;\nconst digitRegexp = /\\d/;\nconst notSpaceRegExp = /[^\\s]/;\n\nconst buildRegExpFromNumber = (number: string, inTheMiddle = false, optionalDigits = true) => {\n const regExp = number\n .split('')\n .reduce<string[]>((acc, char, index) => {\n // символы из строки нужно экранировать т.к. там могут оказаться символы имеющие специальное\n // значение в регулярных выражениях, например +\n acc.push(`\\\\u{${char.charCodeAt(0).toString(16)}}${optionalDigits ? '?' : ''}`);\n if (index !== number.length - 1) {\n acc.push('\\\\s?-?\\\\(?\\\\)?\\\\s?');\n }\n return acc;\n }, [])\n .join('');\n return new RegExp(inTheMiddle ? `.*(${regExp}).*` : regExp, 'u');\n};\n\nexport const phoneFormatterFactory = (params: {\n setCountry: (country: CountryCode) => void;\n currentCountryRef: RefObject<CountryCode>;\n availableCountriesRef?: RefObject<CountryCode[] | undefined>;\n libPhoneNumberAPI: LibPhoneNumberAPI;\n countryLocked: boolean;\n}): InputFormatter => {\n const {\n setCountry,\n currentCountryRef,\n libPhoneNumberAPI: { formatIncompletePhoneNumber, parsePhoneNumber, getCountryCallingCode },\n availableCountriesRef,\n countryLocked,\n } = params;\n\n return (prevValue: string, value: string, caretPosition: number) => {\n let sanitizedValue = value.replace(prohibitedSymbolsRegExp, '');\n let formattedValue = sanitizedValue;\n let caret = caretPosition;\n\n let digitsBeforeCaret = value.substring(0, caret).replace(notDigitsOrPlusRegExp, '');\n\n // удалили один символ и этот символ не цифра, надо удалить ближайшую цифру слева от каретки\n if (prevValue.length - value.length === 1 && notDigitsOrPlusRegExp.test(prevValue[caretPosition])) {\n digitsBeforeCaret = digitsBeforeCaret.slice(0, -1);\n formattedValue = `${digitsBeforeCaret}${value.substring(caret)}`;\n }\n\n try {\n const phoneNumber = parsePhoneNumber(formattedValue, currentCountryRef.current || 'RU');\n const allowedCountry =\n (!availableCountriesRef?.current ||\n !phoneNumber.country ||\n availableCountriesRef.current.includes(phoneNumber.country)) &&\n (!countryLocked || currentCountryRef.current === phoneNumber.country);\n\n const country = (allowedCountry ? phoneNumber.country : false) || currentCountryRef.current || 'RU';\n\n formattedValue =\n phoneNumber.isValid() && allowedCountry\n ? phoneNumber.format('NATIONAL', { nationalPrefix: false })\n : formatIncompletePhoneNumber(phoneNumber.nationalNumber, country);\n\n const code = getCountryCallingCode(country);\n if (sanitizedValue.startsWith(`+${code}`)) {\n sanitizedValue = sanitizedValue.slice(code.length + 1);\n }\n if (country !== currentCountryRef.current) {\n setCountry(country);\n }\n } catch {\n // do nothing\n }\n\n // В процессе форматирования libphonenumber может дописать в national number префикс, который не используется\n // в международном номере (для Беларуси например 80), при этом требование дизайна в остальном форматировать\n // часть номера после кода по национальным стандартам. Поэтому находим цифры которые пользователь не вводил\n // и удаляем их.\n const currentValueRegExp = buildRegExpFromNumber(\n sanitizedValue.replace(notDigitsOrPlusRegExp, ''),\n true,\n false\n );\n formattedValue = formattedValue.match(currentValueRegExp)?.[1] || formattedValue;\n\n if (digitsBeforeCaret.length === 0) {\n caret = formattedValue.substring(0, caret).match(notSpaceRegExp)?.[0].length || 0;\n } else {\n // в результате форматирования в строке с номером могут появляться дополнительные символы\n // при этом каретка должна сохранить свое положение относительно цифр в номере\n // для этого находим позицию каретки в строке до форматирования, извлекаем из неё только цифры находящиеся\n // перед кареткой, находим длину строки после форматирования которая содержит те же цифры что и в строке до\n // форматирования перед кареткой и сдвигаем каретку на эту длину\n // для этого используем регулярку в которую добавляем все символы перед кареткой и возможные символы между\n // ними которые могут появиться после форматирования\n // кроме того делаем все символы опциональными, т.к. после форматирования может удалиться часть\n // символов в начале номера относящаяся к коду страны\n const caretPositionRegExp = buildRegExpFromNumber(digitsBeforeCaret);\n\n // применяем регулярку к отформатированной строке и сдвигаем каретку на длину найденного совпадения\n const match = formattedValue.match(caretPositionRegExp)?.[0];\n\n if (match) {\n const positionOfFirstDigitToTheRightOfCaret = formattedValue\n .substring(match.length)\n .search(digitRegexp);\n\n caret =\n positionOfFirstDigitToTheRightOfCaret === -1\n ? formattedValue.length\n : positionOfFirstDigitToTheRightOfCaret + match.length;\n }\n }\n\n return {\n formattedValue,\n outputValue: formattedValue,\n caretPosition: caret,\n };\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CountryCode, type CountryCallingCode } from 'libphonenumber-js';
|
|
2
2
|
import { DataProvider, StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';
|
|
3
|
-
import { type LibPhoneNumberAPI } from '
|
|
3
|
+
import { type LibPhoneNumberAPI } from './useLibPhoneNumber';
|
|
4
4
|
export interface PhoneCodeOption extends StaticDataFetcherItem {
|
|
5
5
|
value: CountryCode;
|
|
6
6
|
callingCode: CountryCallingCode;
|
|
@@ -3,148 +3,128 @@ import { useRef } from 'react';
|
|
|
3
3
|
import { createDataProvider, decorateWithResultProducer, createStaticDataFetcher } from '@hh.ru/magritte-common-data-provider';
|
|
4
4
|
|
|
5
5
|
const compareArrays = (a, b) => {
|
|
6
|
-
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
9
|
-
if (a.length !== b.length) {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
for (let i = 0, j = a.length; i < j; i++) {
|
|
13
|
-
if (a[i] !== b[i]) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
6
|
+
if (a === b) {
|
|
17
7
|
return true;
|
|
8
|
+
}
|
|
9
|
+
if (a.length !== b.length) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
for (let i = 0, j = a.length; i < j; i++) {
|
|
13
|
+
if (a[i] !== b[i]) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
18
|
};
|
|
19
|
-
// нужен чтобы ссылка оставалась постоянной
|
|
20
19
|
const EMPTY_COUNTRIES_LIST = [];
|
|
21
|
-
const useCountrySelectDataProvider = ({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return { dataProvider: dataProviderRef.current, options: optionsRef.current };
|
|
43
|
-
}
|
|
20
|
+
const useCountrySelectDataProvider = ({
|
|
21
|
+
availableCountries,
|
|
22
|
+
countryNames,
|
|
23
|
+
priorityCountriesTitle,
|
|
24
|
+
priorityCountries,
|
|
25
|
+
libPhoneNumberAPI
|
|
26
|
+
}) => {
|
|
27
|
+
const { getCountryCallingCode, getCountries } = libPhoneNumberAPI;
|
|
28
|
+
const dataProviderRef = useRef(null);
|
|
29
|
+
const optionsRef = useRef([]);
|
|
30
|
+
const prevAvailableCountries = useRef(availableCountries || EMPTY_COUNTRIES_LIST);
|
|
31
|
+
const prevPriorityCountries = useRef(priorityCountries || EMPTY_COUNTRIES_LIST);
|
|
32
|
+
const prevApi = useRef(libPhoneNumberAPI);
|
|
33
|
+
const priority = priorityCountries || EMPTY_COUNTRIES_LIST;
|
|
34
|
+
if (dataProviderRef.current) {
|
|
35
|
+
const propsHasChanged = !compareArrays(availableCountries || EMPTY_COUNTRIES_LIST, prevAvailableCountries.current) || !compareArrays(priority, prevPriorityCountries.current) || prevApi.current !== libPhoneNumberAPI;
|
|
36
|
+
prevAvailableCountries.current = availableCountries || EMPTY_COUNTRIES_LIST;
|
|
37
|
+
prevPriorityCountries.current = priority;
|
|
38
|
+
prevApi.current = libPhoneNumberAPI;
|
|
39
|
+
if (!propsHasChanged) {
|
|
40
|
+
return { dataProvider: dataProviderRef.current, options: optionsRef.current };
|
|
44
41
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.sort((a, b) => {
|
|
58
|
-
const aIndex = priority.indexOf(a.value);
|
|
59
|
-
const bIndex = priority.indexOf(b.value);
|
|
60
|
-
if (aIndex === -1 && bIndex === -1) {
|
|
61
|
-
return a.text.localeCompare(b.text);
|
|
62
|
-
}
|
|
63
|
-
return ((aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) - (bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex));
|
|
64
|
-
});
|
|
65
|
-
optionsRef.current = options;
|
|
66
|
-
const optionsWithDelimiter = [...options];
|
|
67
|
-
// если опций больше 10, то добавляем разделители в виде букв
|
|
68
|
-
if (optionsWithDelimiter.length > 10) {
|
|
69
|
-
let offset = 0;
|
|
70
|
-
// если есть список приоритетных стран, то считаем их количество, добавляем перед ними разделитель Популярные
|
|
71
|
-
// добавляем к количеству 1, т.к. добавился еще разделитель
|
|
72
|
-
if (priority.length > 0) {
|
|
73
|
-
offset =
|
|
74
|
-
priority.reduce((acc, country) => (countries.includes(country) ? acc + 1 : acc), 0) +
|
|
75
|
-
(priorityCountriesTitle ? 1 : 0);
|
|
76
|
-
if (priorityCountriesTitle) {
|
|
77
|
-
optionsWithDelimiter.unshift({
|
|
78
|
-
text: priorityCountriesTitle,
|
|
79
|
-
searchKey: `delimiter`,
|
|
80
|
-
value: 'delimiter-popular',
|
|
81
|
-
type: 'delimiter',
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
let previousLetter = '';
|
|
86
|
-
// проходимся по списку и добавляем разделители
|
|
87
|
-
// для этого сравниваем первую букву названия страны с предыдущей
|
|
88
|
-
// если она изменилась, значит нужно добавить разделитель в виде буквы
|
|
89
|
-
for (let i = offset; i < optionsWithDelimiter.length; i++) {
|
|
90
|
-
const letter = optionsWithDelimiter[i].text[0].toUpperCase();
|
|
91
|
-
if (letter !== previousLetter) {
|
|
92
|
-
optionsWithDelimiter.splice(i, 0, {
|
|
93
|
-
text: letter,
|
|
94
|
-
value: `delimiter-${letter}`,
|
|
95
|
-
type: 'delimiter',
|
|
96
|
-
searchKey: 'delimiter',
|
|
97
|
-
});
|
|
98
|
-
previousLetter = letter;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
42
|
+
}
|
|
43
|
+
const countries = availableCountries ?? getCountries();
|
|
44
|
+
const options = countries.filter((country) => !!countryNames[country]).map((country) => ({
|
|
45
|
+
text: countryNames[country],
|
|
46
|
+
value: country,
|
|
47
|
+
searchKey: `+${getCountryCallingCode(country)}`,
|
|
48
|
+
callingCode: getCountryCallingCode(country)
|
|
49
|
+
})).sort((a, b) => {
|
|
50
|
+
const aIndex = priority.indexOf(a.value);
|
|
51
|
+
const bIndex = priority.indexOf(b.value);
|
|
52
|
+
if (aIndex === -1 && bIndex === -1) {
|
|
53
|
+
return a.text.localeCompare(b.text);
|
|
101
54
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
55
|
+
return (aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) - (bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex);
|
|
56
|
+
});
|
|
57
|
+
optionsRef.current = options;
|
|
58
|
+
const optionsWithDelimiter = [...options];
|
|
59
|
+
if (optionsWithDelimiter.length > 10) {
|
|
60
|
+
let offset = 0;
|
|
61
|
+
if (priority.length > 0) {
|
|
62
|
+
offset = priority.reduce((acc, country) => countries.includes(country) ? acc + 1 : acc, 0) + (priorityCountriesTitle ? 1 : 0);
|
|
63
|
+
if (priorityCountriesTitle) {
|
|
64
|
+
optionsWithDelimiter.unshift({
|
|
65
|
+
text: priorityCountriesTitle,
|
|
66
|
+
searchKey: `delimiter`,
|
|
67
|
+
value: "delimiter-popular",
|
|
68
|
+
type: "delimiter"
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let previousLetter = "";
|
|
73
|
+
for (let i = offset; i < optionsWithDelimiter.length; i++) {
|
|
74
|
+
const letter = optionsWithDelimiter[i].text[0].toUpperCase();
|
|
75
|
+
if (letter !== previousLetter) {
|
|
76
|
+
optionsWithDelimiter.splice(i, 0, {
|
|
77
|
+
text: letter,
|
|
78
|
+
value: `delimiter-${letter}`,
|
|
79
|
+
type: "delimiter",
|
|
80
|
+
searchKey: "delimiter"
|
|
81
|
+
});
|
|
82
|
+
previousLetter = letter;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
dataProviderRef.current = createDataProvider({
|
|
87
|
+
minCharsCount: 0,
|
|
88
|
+
debounceTimeout: 0,
|
|
89
|
+
fetcher: decorateWithResultProducer(createStaticDataFetcher(optionsWithDelimiter, "searchKey"), (data) => {
|
|
90
|
+
const sections = [];
|
|
91
|
+
let currentSection = null;
|
|
92
|
+
data?.forEach((option) => {
|
|
93
|
+
const optionType = option.type ?? "cells";
|
|
94
|
+
if (!currentSection || optionType !== currentSection?.type || optionType === "delimiter") {
|
|
95
|
+
if (optionType === "delimiter") {
|
|
96
|
+
currentSection = { type: optionType, text: option.text };
|
|
97
|
+
} else {
|
|
98
|
+
currentSection = {
|
|
99
|
+
type: "cells",
|
|
100
|
+
items: [
|
|
101
|
+
{
|
|
102
|
+
value: option.value,
|
|
103
|
+
data: {
|
|
104
|
+
...option,
|
|
105
|
+
value: option.value,
|
|
106
|
+
callingCode: option.callingCode
|
|
107
|
+
}
|
|
142
108
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
109
|
+
]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
sections.push(currentSection);
|
|
113
|
+
} else {
|
|
114
|
+
currentSection.items.push({
|
|
115
|
+
value: option.value,
|
|
116
|
+
data: {
|
|
117
|
+
...option,
|
|
118
|
+
value: option.value,
|
|
119
|
+
callingCode: option.callingCode
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return sections;
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
return { dataProvider: dataProviderRef.current, options };
|
|
148
128
|
};
|
|
149
129
|
|
|
150
130
|
export { useCountrySelectDataProvider };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCountrySelectDataProvider.js","sources":["src/useCountrySelectDataProvider.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { type CountryCode, type CountryCallingCode } from 'libphonenumber-js';\n\nimport {\n createDataProvider,\n createStaticDataFetcher,\n DataProvider,\n DataSection,\n DataSectionOfType,\n decorateWithResultProducer,\n StaticDataFetcherItem,\n} from '@hh.ru/magritte-common-data-provider';\nimport { type LibPhoneNumberAPI } from '@hh.ru/magritte-ui-phone-input/useLibPhoneNumber';\n\nconst compareArrays = <T>(a: T[], b: T[]) => {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0, j = a.length; i < j; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n};\n\nexport interface PhoneCodeOption extends StaticDataFetcherItem {\n value: CountryCode;\n callingCode: CountryCallingCode;\n}\ntype PrepareOptionsArgs = {\n availableCountries?: CountryCode[];\n countryNames: Partial<Record<CountryCode, string>>;\n priorityCountriesTitle?: string;\n priorityCountries: CountryCode[];\n libPhoneNumberAPI: LibPhoneNumberAPI;\n};\n\n// нужен чтобы ссылка оставалась постоянной\nconst EMPTY_COUNTRIES_LIST: CountryCode[] = [] as const;\ninterface CountryOption extends StaticDataFetcherItem {\n text: string;\n searchKey: string;\n value: CountryCode;\n callingCode: CountryCallingCode;\n}\ninterface CountryOptionWithDelimiter extends StaticDataFetcherItem {\n text: string;\n searchKey: string;\n value: CountryCode | string;\n callingCode?: CountryCallingCode;\n type?: 'delimiter';\n}\nexport const useCountrySelectDataProvider = ({\n availableCountries,\n countryNames,\n priorityCountriesTitle,\n priorityCountries,\n libPhoneNumberAPI,\n}: PrepareOptionsArgs): { dataProvider: DataProvider<PhoneCodeOption>; options: PhoneCodeOption[] } => {\n const { getCountryCallingCode, getCountries } = libPhoneNumberAPI;\n const dataProviderRef = useRef<DataProvider<PhoneCodeOption> | null>(null);\n const optionsRef = useRef<CountryOption[]>([]);\n const prevAvailableCountries = useRef<CountryCode[]>(availableCountries || EMPTY_COUNTRIES_LIST);\n const prevPriorityCountries = useRef<CountryCode[]>(priorityCountries || EMPTY_COUNTRIES_LIST);\n const prevApi = useRef<LibPhoneNumberAPI>(libPhoneNumberAPI);\n const priority = priorityCountries || EMPTY_COUNTRIES_LIST;\n\n // Мемоизация для бедных\n // Сравниваем непосредственно элементы массивов, потому что ссылка будет меняться при каждом ререндере\n // если в пропы передадут array literal\n // Ожидается что если эти пропы передаются, то содержащиеся в них массивы не должны\n // быть большого размера (до 10 элементов)\n if (dataProviderRef.current) {\n const propsHasChanged =\n !compareArrays(availableCountries || EMPTY_COUNTRIES_LIST, prevAvailableCountries.current) ||\n !compareArrays(priority, prevPriorityCountries.current) ||\n prevApi.current !== libPhoneNumberAPI;\n prevAvailableCountries.current = availableCountries || EMPTY_COUNTRIES_LIST;\n prevPriorityCountries.current = priority;\n prevApi.current = libPhoneNumberAPI;\n\n if (!propsHasChanged) {\n return { dataProvider: dataProviderRef.current, options: optionsRef.current };\n }\n }\n\n const countries = availableCountries ?? getCountries();\n const options = countries\n // убираем из списка страны для которых не передано название в переводах\n .filter((country) => !!countryNames[country])\n .map<CountryOption>((country) => ({\n text: countryNames[country] as string,\n value: country,\n searchKey: `+${getCountryCallingCode(country)}`,\n callingCode: getCountryCallingCode(country),\n }))\n // сортируем опции, если страна есть в приоритетном списке, то используем её индекс в этом списке\n // если нет, то сортируем по алфавиту\n .sort((a, b) => {\n const aIndex = priority.indexOf(a.value);\n const bIndex = priority.indexOf(b.value);\n if (aIndex === -1 && bIndex === -1) {\n return a.text.localeCompare(b.text);\n }\n\n return (\n (aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) - (bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex)\n );\n });\n\n optionsRef.current = options;\n\n const optionsWithDelimiter: CountryOptionWithDelimiter[] = [...options];\n\n // если опций больше 10, то добавляем разделители в виде букв\n if (optionsWithDelimiter.length > 10) {\n let offset = 0;\n // если есть список приоритетных стран, то считаем их количество, добавляем перед ними разделитель Популярные\n // добавляем к количеству 1, т.к. добавился еще разделитель\n if (priority.length > 0) {\n offset =\n priority.reduce((acc, country) => (countries.includes(country) ? acc + 1 : acc), 0) +\n (priorityCountriesTitle ? 1 : 0);\n if (priorityCountriesTitle) {\n optionsWithDelimiter.unshift({\n text: priorityCountriesTitle,\n searchKey: `delimiter`,\n value: 'delimiter-popular',\n type: 'delimiter',\n });\n }\n }\n let previousLetter = '';\n // проходимся по списку и добавляем разделители\n // для этого сравниваем первую букву названия страны с предыдущей\n // если она изменилась, значит нужно добавить разделитель в виде буквы\n for (let i = offset; i < optionsWithDelimiter.length; i++) {\n const letter = optionsWithDelimiter[i].text[0].toUpperCase();\n if (letter !== previousLetter) {\n optionsWithDelimiter.splice(i, 0, {\n text: letter,\n value: `delimiter-${letter}`,\n type: 'delimiter',\n searchKey: 'delimiter',\n });\n previousLetter = letter;\n }\n }\n }\n\n dataProviderRef.current = createDataProvider({\n minCharsCount: 0,\n debounceTimeout: 0,\n fetcher: decorateWithResultProducer(createStaticDataFetcher(optionsWithDelimiter, 'searchKey'), (data) => {\n const sections: DataSection<PhoneCodeOption>[] = [];\n let currentSection: DataSection<PhoneCodeOption> | null = null;\n data?.forEach((option) => {\n const optionType = option.type ?? 'cells';\n if (\n !currentSection ||\n optionType !== (currentSection as DataSection)?.type ||\n optionType === 'delimiter'\n ) {\n if (optionType === 'delimiter') {\n currentSection = { type: optionType, text: option.text };\n } else {\n currentSection = {\n type: 'cells',\n items: [\n {\n value: option.value,\n data: {\n ...option,\n value: option.value as CountryCode,\n callingCode: option.callingCode as CountryCallingCode,\n },\n },\n ],\n };\n }\n sections.push(currentSection);\n } else {\n (currentSection as DataSectionOfType<'cells', PhoneCodeOption>).items.push({\n value: option.value,\n data: {\n ...option,\n value: option.value as CountryCode,\n callingCode: option.callingCode as CountryCallingCode,\n },\n });\n }\n });\n return sections;\n }),\n });\n\n return { dataProvider: dataProviderRef.current, options };\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCountrySelectDataProvider.js","sources":["src/useCountrySelectDataProvider.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { type CountryCode, type CountryCallingCode } from 'libphonenumber-js';\n\nimport {\n createDataProvider,\n createStaticDataFetcher,\n DataProvider,\n DataSection,\n DataSectionOfType,\n decorateWithResultProducer,\n StaticDataFetcherItem,\n} from '@hh.ru/magritte-common-data-provider';\nimport { type LibPhoneNumberAPI } from '@hh.ru/magritte-ui-phone-input/useLibPhoneNumber';\n\nconst compareArrays = <T>(a: T[], b: T[]) => {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0, j = a.length; i < j; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n};\n\nexport interface PhoneCodeOption extends StaticDataFetcherItem {\n value: CountryCode;\n callingCode: CountryCallingCode;\n}\ntype PrepareOptionsArgs = {\n availableCountries?: CountryCode[];\n countryNames: Partial<Record<CountryCode, string>>;\n priorityCountriesTitle?: string;\n priorityCountries: CountryCode[];\n libPhoneNumberAPI: LibPhoneNumberAPI;\n};\n\n// нужен чтобы ссылка оставалась постоянной\nconst EMPTY_COUNTRIES_LIST: CountryCode[] = [] as const;\ninterface CountryOption extends StaticDataFetcherItem {\n text: string;\n searchKey: string;\n value: CountryCode;\n callingCode: CountryCallingCode;\n}\ninterface CountryOptionWithDelimiter extends StaticDataFetcherItem {\n text: string;\n searchKey: string;\n value: CountryCode | string;\n callingCode?: CountryCallingCode;\n type?: 'delimiter';\n}\nexport const useCountrySelectDataProvider = ({\n availableCountries,\n countryNames,\n priorityCountriesTitle,\n priorityCountries,\n libPhoneNumberAPI,\n}: PrepareOptionsArgs): { dataProvider: DataProvider<PhoneCodeOption>; options: PhoneCodeOption[] } => {\n const { getCountryCallingCode, getCountries } = libPhoneNumberAPI;\n const dataProviderRef = useRef<DataProvider<PhoneCodeOption> | null>(null);\n const optionsRef = useRef<CountryOption[]>([]);\n const prevAvailableCountries = useRef<CountryCode[]>(availableCountries || EMPTY_COUNTRIES_LIST);\n const prevPriorityCountries = useRef<CountryCode[]>(priorityCountries || EMPTY_COUNTRIES_LIST);\n const prevApi = useRef<LibPhoneNumberAPI>(libPhoneNumberAPI);\n const priority = priorityCountries || EMPTY_COUNTRIES_LIST;\n\n // Мемоизация для бедных\n // Сравниваем непосредственно элементы массивов, потому что ссылка будет меняться при каждом ререндере\n // если в пропы передадут array literal\n // Ожидается что если эти пропы передаются, то содержащиеся в них массивы не должны\n // быть большого размера (до 10 элементов)\n if (dataProviderRef.current) {\n const propsHasChanged =\n !compareArrays(availableCountries || EMPTY_COUNTRIES_LIST, prevAvailableCountries.current) ||\n !compareArrays(priority, prevPriorityCountries.current) ||\n prevApi.current !== libPhoneNumberAPI;\n prevAvailableCountries.current = availableCountries || EMPTY_COUNTRIES_LIST;\n prevPriorityCountries.current = priority;\n prevApi.current = libPhoneNumberAPI;\n\n if (!propsHasChanged) {\n return { dataProvider: dataProviderRef.current, options: optionsRef.current };\n }\n }\n\n const countries = availableCountries ?? getCountries();\n const options = countries\n // убираем из списка страны для которых не передано название в переводах\n .filter((country) => !!countryNames[country])\n .map<CountryOption>((country) => ({\n text: countryNames[country] as string,\n value: country,\n searchKey: `+${getCountryCallingCode(country)}`,\n callingCode: getCountryCallingCode(country),\n }))\n // сортируем опции, если страна есть в приоритетном списке, то используем её индекс в этом списке\n // если нет, то сортируем по алфавиту\n .sort((a, b) => {\n const aIndex = priority.indexOf(a.value);\n const bIndex = priority.indexOf(b.value);\n if (aIndex === -1 && bIndex === -1) {\n return a.text.localeCompare(b.text);\n }\n\n return (\n (aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) - (bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex)\n );\n });\n\n optionsRef.current = options;\n\n const optionsWithDelimiter: CountryOptionWithDelimiter[] = [...options];\n\n // если опций больше 10, то добавляем разделители в виде букв\n if (optionsWithDelimiter.length > 10) {\n let offset = 0;\n // если есть список приоритетных стран, то считаем их количество, добавляем перед ними разделитель Популярные\n // добавляем к количеству 1, т.к. добавился еще разделитель\n if (priority.length > 0) {\n offset =\n priority.reduce((acc, country) => (countries.includes(country) ? acc + 1 : acc), 0) +\n (priorityCountriesTitle ? 1 : 0);\n if (priorityCountriesTitle) {\n optionsWithDelimiter.unshift({\n text: priorityCountriesTitle,\n searchKey: `delimiter`,\n value: 'delimiter-popular',\n type: 'delimiter',\n });\n }\n }\n let previousLetter = '';\n // проходимся по списку и добавляем разделители\n // для этого сравниваем первую букву названия страны с предыдущей\n // если она изменилась, значит нужно добавить разделитель в виде буквы\n for (let i = offset; i < optionsWithDelimiter.length; i++) {\n const letter = optionsWithDelimiter[i].text[0].toUpperCase();\n if (letter !== previousLetter) {\n optionsWithDelimiter.splice(i, 0, {\n text: letter,\n value: `delimiter-${letter}`,\n type: 'delimiter',\n searchKey: 'delimiter',\n });\n previousLetter = letter;\n }\n }\n }\n\n dataProviderRef.current = createDataProvider({\n minCharsCount: 0,\n debounceTimeout: 0,\n fetcher: decorateWithResultProducer(createStaticDataFetcher(optionsWithDelimiter, 'searchKey'), (data) => {\n const sections: DataSection<PhoneCodeOption>[] = [];\n let currentSection: DataSection<PhoneCodeOption> | null = null;\n data?.forEach((option) => {\n const optionType = option.type ?? 'cells';\n if (\n !currentSection ||\n optionType !== (currentSection as DataSection)?.type ||\n optionType === 'delimiter'\n ) {\n if (optionType === 'delimiter') {\n currentSection = { type: optionType, text: option.text };\n } else {\n currentSection = {\n type: 'cells',\n items: [\n {\n value: option.value,\n data: {\n ...option,\n value: option.value as CountryCode,\n callingCode: option.callingCode as CountryCallingCode,\n },\n },\n ],\n };\n }\n sections.push(currentSection);\n } else {\n (currentSection as DataSectionOfType<'cells', PhoneCodeOption>).items.push({\n value: option.value,\n data: {\n ...option,\n value: option.value as CountryCode,\n callingCode: option.callingCode as CountryCallingCode,\n },\n });\n }\n });\n return sections;\n }),\n });\n\n return { dataProvider: dataProviderRef.current, options };\n};\n"],"names":[],"mappings":"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"}
|