@alfalab/core-components-phone-input 5.2.0

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<Pick<MaskedInputProps, "className" | "dataTestId" | "form" | "label" | "slot" | "style" | "title" | "pattern" | "children" | "leftAddons" | "rightAddons" | "size" | "block" | "colors" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "placeholder" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "list" | "step" | "autoFocus" | "disabled" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "name" | "value" | "fieldClassName" | "labelClassName" | "addonsClassName" | "error" | "hint" | "bottomAddons" | "accept" | "alt" | "autoComplete" | "capture" | "checked" | "crossOrigin" | "height" | "max" | "maxLength" | "min" | "minLength" | "multiple" | "readOnly" | "required" | "src" | "width" | "clear" | "success" | "inputClassName" | "focusedClassName" | "filledClassName" | "onClear" | "wrapperRef" | "keepCharPositions"> & {
8
+ clearableCountryCode?: boolean | undefined;
9
+ } & React.RefAttributes<HTMLInputElement>>;
10
+ export { PhoneInputProps, PhoneInput };
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var textMaskCore = require('text-mask-core');
7
+ var coreComponentsMaskedInput = require('@alfalab/core-components-masked-input/dist/cssm');
8
+ var utils_index = require('./utils/index.js');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
13
+
14
+ /*! *****************************************************************************
15
+ Copyright (c) Microsoft Corporation.
16
+
17
+ Permission to use, copy, modify, and/or distribute this software for any
18
+ purpose with or without fee is hereby granted.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
21
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
22
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
23
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
24
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26
+ PERFORMANCE OF THIS SOFTWARE.
27
+ ***************************************************************************** */
28
+ var __assign = function () {
29
+ __assign = Object.assign || function __assign(t) {
30
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
31
+ s = arguments[i];
32
+ for (var p in s)
33
+ if (Object.prototype.hasOwnProperty.call(s, p))
34
+ t[p] = s[p];
35
+ }
36
+ return t;
37
+ };
38
+ return __assign.apply(this, arguments);
39
+ };
40
+ function __rest(s, e) {
41
+ var t = {};
42
+ for (var p in s)
43
+ if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
44
+ t[p] = s[p];
45
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
46
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
47
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
48
+ t[p[i]] = s[p[i]];
49
+ }
50
+ return t;
51
+ }
52
+
53
+ var mask = [
54
+ '+',
55
+ '7',
56
+ ' ',
57
+ /([0-6]|[8-9])/,
58
+ /\d/,
59
+ /\d/,
60
+ ' ',
61
+ /\d/,
62
+ /\d/,
63
+ /\d/,
64
+ '-',
65
+ /\d/,
66
+ /\d/,
67
+ '-',
68
+ /\d/,
69
+ /\d/,
70
+ ];
71
+ var countryPrefix = '+7 ';
72
+ var PhoneInput = React__default['default'].forwardRef(function (_a, ref) {
73
+ var _b = _a.clearableCountryCode, clearableCountryCode = _b === void 0 ? true : _b, restProps = __rest(_a, ["clearableCountryCode"]);
74
+ var inputRef = React.useRef(null);
75
+ // Оставляет возможность прокинуть ref извне
76
+ React.useImperativeHandle(ref, function () { return inputRef.current; });
77
+ var handleBeforeDisplay = React.useCallback(function (conformedValue, config) {
78
+ var rawValue = config.rawValue, previousConformedValue = config.previousConformedValue, currentCaretPosition = config.currentCaretPosition;
79
+ /*
80
+ * код ниже нужен для фикса следующих багов библиотеки text-mask:
81
+ * 1) так как код страны указан в маске жестко как "+7",
82
+ * то при удалении цифры перед ним каретка устанавливается перед кодом страны
83
+ * 2) в номере телефона есть пробелы и дефисы,
84
+ * при редактировании цифр рядом с этими символами каретка перескакивает через них,
85
+ * а не остается на том же месте, на котором была до редактирования
86
+ */
87
+ var previousValueWithoutFormatting = previousConformedValue
88
+ ? utils_index.deleteFormatting(previousConformedValue)
89
+ : '';
90
+ var currentValueWithoutFormatting = utils_index.deleteFormatting(conformedValue) || '';
91
+ if (previousConformedValue &&
92
+ (([3, 6].includes(currentCaretPosition) &&
93
+ Math.abs(previousValueWithoutFormatting.length -
94
+ currentValueWithoutFormatting.length) === 1) ||
95
+ ([7, 10, 13].includes(currentCaretPosition) &&
96
+ previousConformedValue.length > currentCaretPosition))) {
97
+ utils_index.setCaretPosition({ position: currentCaretPosition, inputRef: inputRef });
98
+ }
99
+ // Удаление цифры перед кодом страны удаляет только саму цифру, код остается ("+7 1" -> "+7 ")
100
+ if (rawValue === countryPrefix) {
101
+ return rawValue;
102
+ }
103
+ // Вставка номера с 10 цифрами без кода страны
104
+ if (rawValue.length === 10 && conformedValue.length === mask.length) {
105
+ var masked = textMaskCore.conformToMask("+7" + rawValue, mask, config);
106
+ return masked.conformedValue;
107
+ }
108
+ var insertedNumber = utils_index.getInsertedNumber({
109
+ rawValue: rawValue,
110
+ clearableCountryCode: clearableCountryCode,
111
+ countryPrefix: countryPrefix,
112
+ previousConformedValue: previousConformedValue,
113
+ });
114
+ // Вставка номера, начинающегося с 8 или 7: 89990313131, 71112223344
115
+ if (conformedValue.length === mask.length &&
116
+ (insertedNumber.startsWith('8') || insertedNumber.startsWith('7'))) {
117
+ var masked = textMaskCore.conformToMask("+7" + insertedNumber.slice(1), mask, config);
118
+ return masked.conformedValue;
119
+ }
120
+ // Если ввод начат с 7 или 8 - выводит "+7 " и дает продолжить ввод со след. цифры
121
+ if (rawValue.length === 1 && ['7', '8'].includes(rawValue[0])) {
122
+ return countryPrefix;
123
+ }
124
+ var abortCountryCodeClearing = !clearableCountryCode && !conformedValue;
125
+ if (abortCountryCodeClearing) {
126
+ utils_index.setCaretPosition({ position: countryPrefix.length, inputRef: inputRef });
127
+ if (!rawValue.length)
128
+ return countryPrefix;
129
+ return false;
130
+ }
131
+ return conformedValue;
132
+ }, [clearableCountryCode]);
133
+ return (React__default['default'].createElement(coreComponentsMaskedInput.MaskedInput, __assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef })));
134
+ });
135
+
136
+ exports.PhoneInput = PhoneInput;
@@ -0,0 +1 @@
1
+ export * from "./Component";
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var Component = require('./Component.js');
6
+ require('react');
7
+ require('text-mask-core');
8
+ require('@alfalab/core-components-masked-input/dist/cssm');
9
+ require('./utils/index.js');
10
+
11
+
12
+
13
+ exports.PhoneInput = Component.PhoneInput;
@@ -0,0 +1,17 @@
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
+ export { deleteFormatting, setCaretPosition, getInsertedNumber };
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * Удаляет форматирование номера телефона
7
+ * @param phone Номер телефона
8
+ */
9
+ var deleteFormatting = function (phone) {
10
+ return phone
11
+ .replace('+', '')
12
+ .replace(/^7/, '')
13
+ .replace(/\s/g, '')
14
+ .replace(/-/g, '');
15
+ };
16
+ function setCaretPosition(_a) {
17
+ var position = _a.position, inputRef = _a.inputRef;
18
+ window.requestAnimationFrame(function () {
19
+ if (inputRef === null || !inputRef.current)
20
+ return;
21
+ inputRef.current.setSelectionRange(position, position);
22
+ });
23
+ }
24
+ function getInsertedNumber(_a) {
25
+ var rawValue = _a.rawValue, clearableCountryCode = _a.clearableCountryCode, countryPrefix = _a.countryPrefix, previousConformedValue = _a.previousConformedValue;
26
+ if (!clearableCountryCode && previousConformedValue === countryPrefix) {
27
+ if (rawValue.startsWith('7') || rawValue.startsWith('8')) {
28
+ return rawValue;
29
+ }
30
+ return rawValue.slice(countryPrefix.length);
31
+ }
32
+ return rawValue;
33
+ }
34
+
35
+ exports.deleteFormatting = deleteFormatting;
36
+ exports.getInsertedNumber = getInsertedNumber;
37
+ exports.setCaretPosition = setCaretPosition;
@@ -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<Pick<MaskedInputProps, "className" | "dataTestId" | "form" | "label" | "slot" | "style" | "title" | "pattern" | "children" | "leftAddons" | "rightAddons" | "size" | "block" | "colors" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "placeholder" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "list" | "step" | "autoFocus" | "disabled" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "name" | "value" | "fieldClassName" | "labelClassName" | "addonsClassName" | "error" | "hint" | "bottomAddons" | "accept" | "alt" | "autoComplete" | "capture" | "checked" | "crossOrigin" | "height" | "max" | "maxLength" | "min" | "minLength" | "multiple" | "readOnly" | "required" | "src" | "width" | "clear" | "success" | "inputClassName" | "focusedClassName" | "filledClassName" | "onClear" | "wrapperRef" | "keepCharPositions"> & {
8
+ clearableCountryCode?: boolean | undefined;
9
+ } & React.RefAttributes<HTMLInputElement>>;
10
+ export { PhoneInputProps, PhoneInput };
@@ -0,0 +1,128 @@
1
+ import React, { useRef, useImperativeHandle, useCallback } from 'react';
2
+ import { conformToMask } from 'text-mask-core';
3
+ import { MaskedInput } from '@alfalab/core-components-masked-input/dist/esm';
4
+ import { deleteFormatting, setCaretPosition, getInsertedNumber } from './utils/index.js';
5
+
6
+ /*! *****************************************************************************
7
+ Copyright (c) Microsoft Corporation.
8
+
9
+ Permission to use, copy, modify, and/or distribute this software for any
10
+ purpose with or without fee is hereby granted.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
13
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
15
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
17
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18
+ PERFORMANCE OF THIS SOFTWARE.
19
+ ***************************************************************************** */
20
+ var __assign = function () {
21
+ __assign = Object.assign || function __assign(t) {
22
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
23
+ s = arguments[i];
24
+ for (var p in s)
25
+ if (Object.prototype.hasOwnProperty.call(s, p))
26
+ t[p] = s[p];
27
+ }
28
+ return t;
29
+ };
30
+ return __assign.apply(this, arguments);
31
+ };
32
+ function __rest(s, e) {
33
+ var t = {};
34
+ for (var p in s)
35
+ if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
36
+ t[p] = s[p];
37
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
38
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
39
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
40
+ t[p[i]] = s[p[i]];
41
+ }
42
+ return t;
43
+ }
44
+
45
+ var mask = [
46
+ '+',
47
+ '7',
48
+ ' ',
49
+ /([0-6]|[8-9])/,
50
+ /\d/,
51
+ /\d/,
52
+ ' ',
53
+ /\d/,
54
+ /\d/,
55
+ /\d/,
56
+ '-',
57
+ /\d/,
58
+ /\d/,
59
+ '-',
60
+ /\d/,
61
+ /\d/,
62
+ ];
63
+ var countryPrefix = '+7 ';
64
+ var PhoneInput = React.forwardRef(function (_a, ref) {
65
+ var _b = _a.clearableCountryCode, clearableCountryCode = _b === void 0 ? true : _b, restProps = __rest(_a, ["clearableCountryCode"]);
66
+ var inputRef = useRef(null);
67
+ // Оставляет возможность прокинуть ref извне
68
+ useImperativeHandle(ref, function () { return inputRef.current; });
69
+ var handleBeforeDisplay = useCallback(function (conformedValue, config) {
70
+ var rawValue = config.rawValue, previousConformedValue = config.previousConformedValue, currentCaretPosition = config.currentCaretPosition;
71
+ /*
72
+ * код ниже нужен для фикса следующих багов библиотеки text-mask:
73
+ * 1) так как код страны указан в маске жестко как "+7",
74
+ * то при удалении цифры перед ним каретка устанавливается перед кодом страны
75
+ * 2) в номере телефона есть пробелы и дефисы,
76
+ * при редактировании цифр рядом с этими символами каретка перескакивает через них,
77
+ * а не остается на том же месте, на котором была до редактирования
78
+ */
79
+ var previousValueWithoutFormatting = previousConformedValue
80
+ ? deleteFormatting(previousConformedValue)
81
+ : '';
82
+ var currentValueWithoutFormatting = deleteFormatting(conformedValue) || '';
83
+ if (previousConformedValue &&
84
+ (([3, 6].includes(currentCaretPosition) &&
85
+ Math.abs(previousValueWithoutFormatting.length -
86
+ currentValueWithoutFormatting.length) === 1) ||
87
+ ([7, 10, 13].includes(currentCaretPosition) &&
88
+ previousConformedValue.length > currentCaretPosition))) {
89
+ setCaretPosition({ position: currentCaretPosition, inputRef: inputRef });
90
+ }
91
+ // Удаление цифры перед кодом страны удаляет только саму цифру, код остается ("+7 1" -> "+7 ")
92
+ if (rawValue === countryPrefix) {
93
+ return rawValue;
94
+ }
95
+ // Вставка номера с 10 цифрами без кода страны
96
+ if (rawValue.length === 10 && conformedValue.length === mask.length) {
97
+ var masked = conformToMask("+7" + rawValue, mask, config);
98
+ return masked.conformedValue;
99
+ }
100
+ var insertedNumber = getInsertedNumber({
101
+ rawValue: rawValue,
102
+ clearableCountryCode: clearableCountryCode,
103
+ countryPrefix: countryPrefix,
104
+ previousConformedValue: previousConformedValue,
105
+ });
106
+ // Вставка номера, начинающегося с 8 или 7: 89990313131, 71112223344
107
+ if (conformedValue.length === mask.length &&
108
+ (insertedNumber.startsWith('8') || insertedNumber.startsWith('7'))) {
109
+ var masked = conformToMask("+7" + insertedNumber.slice(1), mask, config);
110
+ return masked.conformedValue;
111
+ }
112
+ // Если ввод начат с 7 или 8 - выводит "+7 " и дает продолжить ввод со след. цифры
113
+ if (rawValue.length === 1 && ['7', '8'].includes(rawValue[0])) {
114
+ return countryPrefix;
115
+ }
116
+ var abortCountryCodeClearing = !clearableCountryCode && !conformedValue;
117
+ if (abortCountryCodeClearing) {
118
+ setCaretPosition({ position: countryPrefix.length, inputRef: inputRef });
119
+ if (!rawValue.length)
120
+ return countryPrefix;
121
+ return false;
122
+ }
123
+ return conformedValue;
124
+ }, [clearableCountryCode]);
125
+ return (React.createElement(MaskedInput, __assign({}, restProps, { defaultValue: clearableCountryCode ? restProps.defaultValue : countryPrefix, mask: mask, onBeforeDisplay: handleBeforeDisplay, type: 'tel', ref: inputRef })));
126
+ });
127
+
128
+ export { PhoneInput };
@@ -0,0 +1 @@
1
+ export * from "./Component";
@@ -0,0 +1,5 @@
1
+ export { PhoneInput } from './Component.js';
2
+ import 'react';
3
+ import 'text-mask-core';
4
+ import '@alfalab/core-components-masked-input/dist/esm';
5
+ import './utils/index.js';
@@ -0,0 +1,17 @@
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
+ export { deleteFormatting, setCaretPosition, getInsertedNumber };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Удаляет форматирование номера телефона
3
+ * @param phone Номер телефона
4
+ */
5
+ var deleteFormatting = function (phone) {
6
+ return phone
7
+ .replace('+', '')
8
+ .replace(/^7/, '')
9
+ .replace(/\s/g, '')
10
+ .replace(/-/g, '');
11
+ };
12
+ function setCaretPosition(_a) {
13
+ var position = _a.position, inputRef = _a.inputRef;
14
+ window.requestAnimationFrame(function () {
15
+ if (inputRef === null || !inputRef.current)
16
+ return;
17
+ inputRef.current.setSelectionRange(position, position);
18
+ });
19
+ }
20
+ function getInsertedNumber(_a) {
21
+ var rawValue = _a.rawValue, clearableCountryCode = _a.clearableCountryCode, countryPrefix = _a.countryPrefix, previousConformedValue = _a.previousConformedValue;
22
+ if (!clearableCountryCode && previousConformedValue === countryPrefix) {
23
+ if (rawValue.startsWith('7') || rawValue.startsWith('8')) {
24
+ return rawValue;
25
+ }
26
+ return rawValue.slice(countryPrefix.length);
27
+ }
28
+ return rawValue;
29
+ }
30
+
31
+ export { deleteFormatting, getInsertedNumber, setCaretPosition };
@@ -0,0 +1 @@
1
+ export * from "./Component";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var Component = require('./Component.js');
6
+ require('react');
7
+ require('text-mask-core');
8
+ require('@alfalab/core-components-masked-input');
9
+ require('./utils/index.js');
10
+
11
+
12
+
13
+ exports.PhoneInput = Component.PhoneInput;
@@ -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<Pick<MaskedInputProps, "className" | "dataTestId" | "form" | "label" | "slot" | "style" | "title" | "pattern" | "children" | "leftAddons" | "rightAddons" | "size" | "block" | "colors" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "placeholder" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "list" | "step" | "autoFocus" | "disabled" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "name" | "value" | "fieldClassName" | "labelClassName" | "addonsClassName" | "error" | "hint" | "bottomAddons" | "accept" | "alt" | "autoComplete" | "capture" | "checked" | "crossOrigin" | "height" | "max" | "maxLength" | "min" | "minLength" | "multiple" | "readOnly" | "required" | "src" | "width" | "clear" | "success" | "inputClassName" | "focusedClassName" | "filledClassName" | "onClear" | "wrapperRef" | "keepCharPositions"> & {
8
+ clearableCountryCode?: boolean | undefined;
9
+ } & React.RefAttributes<HTMLInputElement>>;
10
+ export { PhoneInputProps, PhoneInput };