From d110ae76594ccbf7f6d8a5764d3c2a72b1ae9a26 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 19 Jul 2021 18:03:03 +0300 Subject: [PATCH] feat(phone-input): add 'clearableCountyCode' prop (#749) * feat(phone-input): add 'clearableCountyCode' prop * fix(phone-input): typo * fix(phone-input): number insertions to unclearable country input * fix(phone-input): insertion to selected input --- packages/phone-input/src/Component.tsx | 47 +++++++++++++------ .../src/docs/Component.stories.mdx | 1 + packages/phone-input/src/utils/index.ts | 36 ++++++++++++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/phone-input/src/Component.tsx b/packages/phone-input/src/Component.tsx index 05e7da85b5..904cf25c76 100644 --- a/packages/phone-input/src/Component.tsx +++ b/packages/phone-input/src/Component.tsx @@ -2,7 +2,7 @@ import React, { useImperativeHandle, useCallback, useRef } from 'react'; import { conformToMask, TextMaskConfig } from 'text-mask-core'; import { MaskedInput, MaskedInputProps } from '@alfalab/core-components-masked-input'; -import { deleteFormatting } from './utils'; +import { deleteFormatting, setCaretPosition, getInsertedNumber } from './utils'; const mask = [ '+', @@ -23,10 +23,14 @@ const mask = [ /\d/, ]; -export type PhoneInputProps = Omit; +const countryPrefix = '+7 '; + +export type PhoneInputProps = Omit & { + clearableCountryCode?: boolean; +}; export const PhoneInput = React.forwardRef( - ({ ...restProps }, ref) => { + ({ clearableCountryCode = true, ...restProps }, ref) => { const inputRef = useRef(null); // Оставляет возможность прокинуть ref извне @@ -59,17 +63,11 @@ export const PhoneInput = React.forwardRef( ([7, 10, 13].includes(currentCaretPosition) && previousConformedValue.length > currentCaretPosition)) ) { - const caret = currentCaretPosition; - window.requestAnimationFrame(() => { - if (inputRef !== null && inputRef.current) { - inputRef.current.selectionStart = caret; - inputRef.current.selectionEnd = caret; - } - }); + setCaretPosition({ position: currentCaretPosition, inputRef }); } // Удаление цифры перед кодом страны удаляет только саму цифру, код остается ("+7 1" -> "+7 ") - if (rawValue === '+7 ') { + if (rawValue === countryPrefix) { return rawValue; } @@ -79,28 +77,47 @@ export const PhoneInput = React.forwardRef( return masked.conformedValue; } + const insertedNumber = getInsertedNumber({ + rawValue, + clearableCountryCode, + countryPrefix, + previousConformedValue, + }); + // Вставка номера, начинающегося с 8 или 7: 89990313131, 71112223344 if ( conformedValue.length === mask.length && - (rawValue.startsWith('8') || rawValue.startsWith('7')) + (insertedNumber.startsWith('8') || insertedNumber.startsWith('7')) ) { - const masked = conformToMask(`+7${rawValue.slice(1)}`, mask, config); + const masked = conformToMask(`+7${insertedNumber.slice(1)}`, mask, config); return masked.conformedValue; } // Если ввод начат с 7 или 8 - выводит "+7 " и дает продолжить ввод со след. цифры if (rawValue.length === 1 && ['7', '8'].includes(rawValue[0])) { - return '+7 '; + return countryPrefix; + } + + const abortCountryCodeClearing = + !clearableCountryCode && !rawValue.startsWith(countryPrefix); + + if (abortCountryCodeClearing) { + setCaretPosition({ position: countryPrefix.length, inputRef }); + + if (!rawValue.length) return countryPrefix; + + return false; } return conformedValue; }, - [], + [clearableCountryCode], ); return ( } rightAddons={boolean('rightAddons', false) && } bottomAddons={boolean('bottomAddons', false) && bottom text} diff --git a/packages/phone-input/src/utils/index.ts b/packages/phone-input/src/utils/index.ts index 0b2f719ff3..6e18e61e7a 100644 --- a/packages/phone-input/src/utils/index.ts +++ b/packages/phone-input/src/utils/index.ts @@ -9,3 +9,39 @@ export const deleteFormatting = (phone: string) => .replace(/^7/, '') .replace(/\s/g, '') .replace(/-/g, ''); + +export function setCaretPosition({ + position, + inputRef, +}: { + position: number; + inputRef: React.RefObject; +}) { + window.requestAnimationFrame(() => { + if (inputRef === null || !inputRef.current) return; + + inputRef.current.setSelectionRange(position, position); + }); +} + +export function getInsertedNumber({ + rawValue, + clearableCountryCode, + countryPrefix, + previousConformedValue, +}: { + rawValue: string; + clearableCountryCode: boolean; + countryPrefix: string; + previousConformedValue: string; +}) { + if (!clearableCountryCode && previousConformedValue === countryPrefix) { + if (rawValue.startsWith('7') || rawValue.startsWith('8')) { + return rawValue; + } + + return rawValue.slice(countryPrefix.length); + } + + return rawValue; +}