react-input-mask-format 1.0.5 → 2.1.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,935 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ default: () => src_default,
34
+ defaultFormatChars: () => defaultFormatChars,
35
+ extendedFormatChars: () => extendedFormatChars
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+ var import_react2 = __toESM(require("react"), 1);
39
+
40
+ // src/hooks.ts
41
+ var import_react = require("react");
42
+
43
+ // src/utils/defer.ts
44
+ function defer(fn) {
45
+ return requestAnimationFrame(fn);
46
+ }
47
+ function cancelDefer(deferId) {
48
+ if (deferId !== null) {
49
+ cancelAnimationFrame(deferId);
50
+ }
51
+ }
52
+
53
+ // src/utils/input.ts
54
+ function setInputSelection(input, start, end) {
55
+ if (end === void 0) {
56
+ end = start;
57
+ }
58
+ input.setSelectionRange(start, end);
59
+ }
60
+ function getInputSelection(input) {
61
+ const start = input.selectionStart;
62
+ const end = input.selectionEnd;
63
+ return {
64
+ start,
65
+ end,
66
+ length: (end != null ? end : 0) - (start != null ? start : 0)
67
+ };
68
+ }
69
+ function isInputFocused(input) {
70
+ const inputDocument = input.ownerDocument;
71
+ return inputDocument.hasFocus() && inputDocument.activeElement === input;
72
+ }
73
+
74
+ // src/utils/helpers.ts
75
+ function getElementDocument(element) {
76
+ return element == null ? void 0 : element.ownerDocument;
77
+ }
78
+ function getElementWindow(element) {
79
+ var _a;
80
+ return (_a = getElementDocument(element)) == null ? void 0 : _a.defaultView;
81
+ }
82
+ function isDOMElement(element) {
83
+ const elementWindow = getElementWindow(element);
84
+ return !!elementWindow && element instanceof elementWindow.HTMLElement;
85
+ }
86
+ function isFunction(value) {
87
+ return typeof value === "function";
88
+ }
89
+ function findLastIndex(array, predicate) {
90
+ for (let i = array.length - 1; i >= 0; i--) {
91
+ const x = array[i];
92
+ if (predicate(x, i)) {
93
+ return i;
94
+ }
95
+ }
96
+ return -1;
97
+ }
98
+ function repeat(string, n = 1) {
99
+ let result = "";
100
+ for (let i = 0; i < n; i++) {
101
+ result += string;
102
+ }
103
+ return result;
104
+ }
105
+ function toString(value) {
106
+ return `${value}`;
107
+ }
108
+
109
+ // src/hooks.ts
110
+ function useInputElement(inputRef) {
111
+ return (0, import_react.useCallback)(() => {
112
+ let input = inputRef.current;
113
+ const isDOMNode = typeof window !== "undefined" && isDOMElement(input);
114
+ if (!input || !isDOMNode) {
115
+ return null;
116
+ }
117
+ if (input.nodeName !== "INPUT") {
118
+ input = input.querySelector("input");
119
+ }
120
+ if (!input) {
121
+ throw new Error("react-input-mask: inputComponent doesn't contain input node");
122
+ }
123
+ return input;
124
+ }, [inputRef]);
125
+ }
126
+ function useDeferLoop(callback) {
127
+ const deferIdRef = (0, import_react.useRef)(null);
128
+ const runLoop = (0, import_react.useCallback)(() => {
129
+ if (deferIdRef.current !== null) {
130
+ return;
131
+ }
132
+ function loop() {
133
+ callback();
134
+ deferIdRef.current = defer(loop);
135
+ }
136
+ loop();
137
+ }, [callback]);
138
+ const stopLoop = (0, import_react.useCallback)(() => {
139
+ cancelDefer(deferIdRef.current);
140
+ deferIdRef.current = null;
141
+ }, []);
142
+ (0, import_react.useEffect)(() => {
143
+ if (deferIdRef.current) {
144
+ stopLoop();
145
+ runLoop();
146
+ }
147
+ }, [runLoop, stopLoop]);
148
+ (0, import_react.useEffect)(() => cancelDefer(deferIdRef.current), []);
149
+ return [runLoop, stopLoop];
150
+ }
151
+ function useSelection(inputRef, isMasked) {
152
+ const selectionRef = (0, import_react.useRef)({ start: null, end: null });
153
+ const getInputElement = useInputElement(inputRef);
154
+ const getSelection = (0, import_react.useCallback)(() => {
155
+ const input = getInputElement();
156
+ return getInputSelection(input);
157
+ }, [getInputElement]);
158
+ const getLastSelection = (0, import_react.useCallback)(() => {
159
+ return selectionRef.current;
160
+ }, []);
161
+ const setSelection = (0, import_react.useCallback)(
162
+ (selection) => {
163
+ const input = getInputElement();
164
+ if (!input || !isInputFocused(input)) {
165
+ return;
166
+ }
167
+ setInputSelection(input, selection.start, selection.end);
168
+ selectionRef.current = getSelection();
169
+ },
170
+ [getInputElement, getSelection]
171
+ );
172
+ const selectionLoop = (0, import_react.useCallback)(() => {
173
+ selectionRef.current = getSelection();
174
+ }, [getSelection]);
175
+ const [runSelectionLoop, stopSelectionLoop] = useDeferLoop(selectionLoop);
176
+ (0, import_react.useLayoutEffect)(() => {
177
+ if (!isMasked) {
178
+ return;
179
+ }
180
+ const input = getInputElement();
181
+ if (!input) return;
182
+ input.addEventListener("focus", runSelectionLoop);
183
+ input.addEventListener("blur", stopSelectionLoop);
184
+ if (isInputFocused(input)) {
185
+ runSelectionLoop();
186
+ }
187
+ return () => {
188
+ input.removeEventListener("focus", runSelectionLoop);
189
+ input.removeEventListener("blur", stopSelectionLoop);
190
+ stopSelectionLoop();
191
+ };
192
+ });
193
+ return { getSelection, getLastSelection, setSelection };
194
+ }
195
+ function useValue(inputRef, initialValue) {
196
+ const getInputElement = useInputElement(inputRef);
197
+ const valueRef = (0, import_react.useRef)(initialValue);
198
+ const getValue = (0, import_react.useCallback)(() => {
199
+ return getInputElement().value;
200
+ }, [getInputElement]);
201
+ const getLastValue = (0, import_react.useCallback)(() => {
202
+ return valueRef.current;
203
+ }, []);
204
+ const setValue = (0, import_react.useCallback)(
205
+ (newValue) => {
206
+ valueRef.current = newValue;
207
+ const input = getInputElement();
208
+ if (input) {
209
+ input.value = newValue;
210
+ }
211
+ },
212
+ [getInputElement]
213
+ );
214
+ return {
215
+ getValue,
216
+ getLastValue,
217
+ setValue
218
+ };
219
+ }
220
+ function useInputState(initialValue, isMasked) {
221
+ const inputRef = (0, import_react.useRef)(null);
222
+ const { getSelection, getLastSelection, setSelection } = useSelection(inputRef, isMasked);
223
+ const { getValue, getLastValue, setValue } = useValue(inputRef, initialValue);
224
+ function getLastInputState() {
225
+ return {
226
+ value: getLastValue(),
227
+ selection: getLastSelection()
228
+ };
229
+ }
230
+ function getInputState() {
231
+ return {
232
+ value: getValue(),
233
+ selection: getSelection()
234
+ };
235
+ }
236
+ function setInputState({ value, selection }) {
237
+ setValue(value);
238
+ setSelection(selection);
239
+ }
240
+ return {
241
+ inputRef,
242
+ getInputState,
243
+ getLastInputState,
244
+ setInputState
245
+ };
246
+ }
247
+ function usePrevious(value) {
248
+ const ref = (0, import_react.useRef)(void 0);
249
+ (0, import_react.useEffect)(() => {
250
+ ref.current = value;
251
+ });
252
+ return ref.current;
253
+ }
254
+
255
+ // src/constants.ts
256
+ var CONTROLLED_PROPS = [
257
+ "disabled",
258
+ "onBlur",
259
+ "onChange",
260
+ "onFocus",
261
+ "onMouseDown",
262
+ "readOnly",
263
+ "value"
264
+ ];
265
+ var defaultFormatChars = {
266
+ "9": /[0-9]/,
267
+ a: /[A-Za-z]/,
268
+ "*": /[A-Za-z0-9]/
269
+ };
270
+ var extendedFormatChars = {
271
+ ...defaultFormatChars,
272
+ A: /[A-Z]/,
273
+ "\u042F": /[А-Яа-яЁёӘәҒғҚқҢңӨөҰұҮүҺһІі]/,
274
+ "#": /[0-9A-Fa-f]/
275
+ };
276
+
277
+ // src/validate-props.ts
278
+ function warnDev(condition, message) {
279
+ if (process.env.NODE_ENV !== "production" && !condition) {
280
+ console.error(`react-input-mask-format: ${message}`);
281
+ }
282
+ }
283
+ function invariant(condition, message) {
284
+ if (!condition) {
285
+ throw new Error(`react-input-mask-format: ${message}`);
286
+ }
287
+ }
288
+ function validateMaxLength(props) {
289
+ warnDev(
290
+ !props.maxLength || !props.mask,
291
+ "maxLength property shouldn't be passed to the masked input. It breaks masking and unnecessary because length is limited by the mask length."
292
+ );
293
+ }
294
+ function validateMaskPlaceholder(props) {
295
+ const { mask, maskPlaceholder } = props;
296
+ invariant(
297
+ !mask || !maskPlaceholder || maskPlaceholder.length === 1 || maskPlaceholder.length === mask.length,
298
+ `maskPlaceholder should either be a single character or have the same length as the mask:
299
+ mask: ${mask}
300
+ maskPlaceholder: ${maskPlaceholder}`
301
+ );
302
+ }
303
+ function validateChildren(props, inputElement) {
304
+ const conflictProps = CONTROLLED_PROPS.filter(
305
+ (propId) => inputElement.props[propId] != null && inputElement.props[propId] !== props[propId]
306
+ );
307
+ invariant(
308
+ !conflictProps.length,
309
+ `the following props should be passed to the InputMask component, not to children: ${conflictProps.join(",")}`
310
+ );
311
+ }
312
+
313
+ // src/utils/parse-mask.ts
314
+ function parseMask({
315
+ mask,
316
+ maskPlaceholder,
317
+ formatChars = defaultFormatChars
318
+ }) {
319
+ const permanents = [];
320
+ if (!mask) {
321
+ return {
322
+ maskPlaceholder: null,
323
+ mask: null,
324
+ prefix: null,
325
+ lastEditablePosition: null,
326
+ permanents: []
327
+ };
328
+ }
329
+ let parsedMask;
330
+ if (typeof mask === "string") {
331
+ let isPermanent = false;
332
+ let parsedMaskString = "";
333
+ mask.split("").forEach((character) => {
334
+ if (!isPermanent && character === "\\") {
335
+ isPermanent = true;
336
+ } else {
337
+ if (isPermanent || !formatChars[character]) {
338
+ permanents.push(parsedMaskString.length);
339
+ }
340
+ parsedMaskString += character;
341
+ isPermanent = false;
342
+ }
343
+ });
344
+ parsedMask = parsedMaskString.split("").map((character, index) => {
345
+ if (permanents.indexOf(index) === -1) {
346
+ return formatChars[character];
347
+ }
348
+ return character;
349
+ });
350
+ } else {
351
+ mask.forEach((character, index) => {
352
+ if (typeof character === "string") {
353
+ permanents.push(index);
354
+ }
355
+ });
356
+ parsedMask = mask;
357
+ }
358
+ let parsedPlaceholder = maskPlaceholder != null ? maskPlaceholder : null;
359
+ if (parsedPlaceholder) {
360
+ let placeholderChars;
361
+ if (parsedPlaceholder.length === 1) {
362
+ placeholderChars = parsedMask.map((character, index) => {
363
+ if (permanents.indexOf(index) !== -1) {
364
+ return character;
365
+ }
366
+ return parsedPlaceholder;
367
+ });
368
+ } else {
369
+ placeholderChars = parsedPlaceholder.split("");
370
+ }
371
+ permanents.forEach((position) => {
372
+ placeholderChars[position] = parsedMask[position];
373
+ });
374
+ parsedPlaceholder = placeholderChars.join("");
375
+ }
376
+ const prefix = permanents.filter((position, index) => position === index).map((position) => parsedMask[position]).join("");
377
+ let lastEditablePosition = parsedMask.length - 1;
378
+ while (permanents.indexOf(lastEditablePosition) !== -1) {
379
+ lastEditablePosition--;
380
+ }
381
+ return {
382
+ maskPlaceholder: parsedPlaceholder,
383
+ prefix,
384
+ mask: parsedMask,
385
+ lastEditablePosition,
386
+ permanents
387
+ };
388
+ }
389
+
390
+ // src/utils/mask.ts
391
+ var MaskUtils = class {
392
+ constructor(options) {
393
+ this.isCharacterAllowedAtPosition = (character, position) => {
394
+ const { maskPlaceholder } = this.maskOptions;
395
+ if (this.isCharacterFillingPosition(character, position)) {
396
+ return true;
397
+ }
398
+ if (!maskPlaceholder) {
399
+ return false;
400
+ }
401
+ return maskPlaceholder[position] === character;
402
+ };
403
+ this.isCharacterFillingPosition = (character, position) => {
404
+ const { mask } = this.maskOptions;
405
+ if (!character || position >= mask.length) {
406
+ return false;
407
+ }
408
+ if (!this.isPositionEditable(position)) {
409
+ return mask[position] === character;
410
+ }
411
+ const charRule = mask[position];
412
+ return new RegExp(charRule).test(character);
413
+ };
414
+ this.isPositionEditable = (position) => {
415
+ const { mask, permanents } = this.maskOptions;
416
+ return position < mask.length && permanents.indexOf(position) === -1;
417
+ };
418
+ this.isValueEmpty = (value) => {
419
+ return value.split("").every((character, position) => {
420
+ return !this.isPositionEditable(position) || !this.isCharacterFillingPosition(character, position);
421
+ });
422
+ };
423
+ this.isValueFilled = (value) => {
424
+ return this.getFilledLength(value) === this.maskOptions.lastEditablePosition + 1;
425
+ };
426
+ this.getDefaultSelectionForValue = (value) => {
427
+ const filledLength = this.getFilledLength(value);
428
+ const cursorPosition = this.getRightEditablePosition(filledLength);
429
+ return { start: cursorPosition, end: cursorPosition };
430
+ };
431
+ this.getFilledLength = (value) => {
432
+ const characters = value.split("");
433
+ const lastFilledIndex = findLastIndex(characters, (character, position) => {
434
+ return this.isPositionEditable(position) && this.isCharacterFillingPosition(character, position);
435
+ });
436
+ return lastFilledIndex + 1;
437
+ };
438
+ this.getStringFillingLengthAtPosition = (string, position) => {
439
+ const characters = string.split("");
440
+ const insertedValue = characters.reduce((value, character) => {
441
+ return this.insertCharacterAtPosition(value, character, value.length);
442
+ }, repeat(" ", position));
443
+ return insertedValue.length - position;
444
+ };
445
+ this.getLeftEditablePosition = (position) => {
446
+ for (let i = position; i >= 0; i--) {
447
+ if (this.isPositionEditable(i)) {
448
+ return i;
449
+ }
450
+ }
451
+ return null;
452
+ };
453
+ this.getRightEditablePosition = (position) => {
454
+ const { mask } = this.maskOptions;
455
+ for (let i = position; i < mask.length; i++) {
456
+ if (this.isPositionEditable(i)) {
457
+ return i;
458
+ }
459
+ }
460
+ return null;
461
+ };
462
+ this.formatValue = (value) => {
463
+ const { maskPlaceholder, mask } = this.maskOptions;
464
+ if (!maskPlaceholder) {
465
+ value = this.insertStringAtPosition("", value, 0);
466
+ while (value.length < mask.length && !this.isPositionEditable(value.length)) {
467
+ value += mask[value.length];
468
+ }
469
+ return value;
470
+ }
471
+ return this.insertStringAtPosition(maskPlaceholder, value, 0);
472
+ };
473
+ this.clearRange = (value, start, len) => {
474
+ if (!len) {
475
+ return value;
476
+ }
477
+ const end = start + len;
478
+ const { maskPlaceholder, mask } = this.maskOptions;
479
+ const clearedValue = value.split("").map((character, i) => {
480
+ const isEditable = this.isPositionEditable(i);
481
+ if (!maskPlaceholder && i >= end && !isEditable) {
482
+ return "";
483
+ }
484
+ if (i < start || i >= end) {
485
+ return character;
486
+ }
487
+ if (!isEditable) {
488
+ return mask[i];
489
+ }
490
+ if (maskPlaceholder) {
491
+ return maskPlaceholder[i];
492
+ }
493
+ return "";
494
+ }).join("");
495
+ return this.formatValue(clearedValue);
496
+ };
497
+ this.insertCharacterAtPosition = (value, character, position) => {
498
+ const { mask, maskPlaceholder } = this.maskOptions;
499
+ if (position >= mask.length) {
500
+ return value;
501
+ }
502
+ const transformedCharacter = this.transform && this.isPositionEditable(position) ? this.transform(character, position) : character;
503
+ const isAllowed = this.isCharacterAllowedAtPosition(transformedCharacter, position);
504
+ const isEditable = this.isPositionEditable(position);
505
+ const nextEditablePosition = this.getRightEditablePosition(position);
506
+ const isNextPlaceholder = maskPlaceholder && nextEditablePosition ? transformedCharacter === maskPlaceholder[nextEditablePosition] : null;
507
+ const valueBefore = value.slice(0, position);
508
+ if (isAllowed || !isEditable) {
509
+ const insertedCharacter = isAllowed ? transformedCharacter : mask[position];
510
+ value = valueBefore + insertedCharacter;
511
+ }
512
+ if (!isAllowed && !isEditable && !isNextPlaceholder) {
513
+ value = this.insertCharacterAtPosition(value, character, position + 1);
514
+ }
515
+ return value;
516
+ };
517
+ this.insertStringAtPosition = (value, string, position) => {
518
+ const { mask, maskPlaceholder } = this.maskOptions;
519
+ if (!string || position >= mask.length) {
520
+ return value;
521
+ }
522
+ const characters = string.split("");
523
+ const isFixedLength = this.isValueFilled(value) || !!maskPlaceholder;
524
+ const valueAfter = value.slice(position);
525
+ value = characters.reduce((value2, character) => {
526
+ return this.insertCharacterAtPosition(value2, character, value2.length);
527
+ }, value.slice(0, position));
528
+ if (isFixedLength) {
529
+ value += valueAfter.slice(value.length - position);
530
+ } else if (this.isValueFilled(value)) {
531
+ value += mask.slice(value.length).join("");
532
+ } else {
533
+ const editableCharactersAfter = valueAfter.split("").filter((character, i) => {
534
+ return this.isPositionEditable(position + i);
535
+ });
536
+ value = editableCharactersAfter.reduce((value2, character) => {
537
+ const nextEditablePosition = this.getRightEditablePosition(
538
+ value2.length
539
+ );
540
+ if (nextEditablePosition === null) {
541
+ return value2;
542
+ }
543
+ if (!this.isPositionEditable(value2.length)) {
544
+ value2 += mask.slice(value2.length, nextEditablePosition).join("");
545
+ }
546
+ return this.insertCharacterAtPosition(value2, character, value2.length);
547
+ }, value);
548
+ }
549
+ return value;
550
+ };
551
+ this.processChange = (currentState, previousState) => {
552
+ const { mask, prefix, lastEditablePosition } = this.maskOptions;
553
+ const { value, selection } = currentState;
554
+ const previousValue = previousState.value;
555
+ const previousSelection = previousState.selection;
556
+ let newValue = value;
557
+ let enteredString = "";
558
+ let formattedEnteredStringLength = 0;
559
+ let removedLength = 0;
560
+ let cursorPosition = Math.min(previousSelection.start, selection.start);
561
+ if (selection.end > previousSelection.start) {
562
+ enteredString = newValue.slice(previousSelection.start, selection.end);
563
+ formattedEnteredStringLength = this.getStringFillingLengthAtPosition(
564
+ enteredString,
565
+ cursorPosition
566
+ );
567
+ if (!formattedEnteredStringLength) {
568
+ removedLength = 0;
569
+ } else {
570
+ removedLength = previousSelection.length;
571
+ }
572
+ } else if (newValue.length < previousValue.length) {
573
+ removedLength = previousValue.length - newValue.length;
574
+ }
575
+ newValue = previousValue;
576
+ if (removedLength) {
577
+ if (removedLength === 1 && !previousSelection.length) {
578
+ const deleteFromRight = previousSelection.start === selection.start;
579
+ cursorPosition = deleteFromRight ? this.getRightEditablePosition(selection.start) : this.getLeftEditablePosition(selection.start);
580
+ }
581
+ newValue = this.clearRange(newValue, cursorPosition, removedLength);
582
+ }
583
+ newValue = this.insertStringAtPosition(
584
+ newValue,
585
+ enteredString,
586
+ cursorPosition
587
+ );
588
+ cursorPosition += formattedEnteredStringLength;
589
+ if (cursorPosition >= mask.length) {
590
+ cursorPosition = mask.length;
591
+ } else if (cursorPosition < prefix.length && !formattedEnteredStringLength) {
592
+ cursorPosition = prefix.length;
593
+ } else if (cursorPosition >= prefix.length && cursorPosition < lastEditablePosition && formattedEnteredStringLength) {
594
+ cursorPosition = this.getRightEditablePosition(cursorPosition);
595
+ }
596
+ newValue = this.formatValue(newValue);
597
+ return {
598
+ value: newValue,
599
+ enteredString,
600
+ selection: { start: cursorPosition, end: cursorPosition }
601
+ };
602
+ };
603
+ this.maskOptions = parseMask(options);
604
+ this.transform = options.transform;
605
+ }
606
+ };
607
+
608
+ // src/v2-compat.ts
609
+ var warned = /* @__PURE__ */ new Set();
610
+ function warnDeprecatedOnce(prop, message) {
611
+ if (process.env.NODE_ENV !== "production" && !warned.has(prop)) {
612
+ warned.add(prop);
613
+ console.warn(`react-input-mask-format: ${message}`);
614
+ }
615
+ }
616
+ function resolveMaskPlaceholder(maskPlaceholder, maskChar) {
617
+ if (maskPlaceholder !== void 0) {
618
+ return maskPlaceholder;
619
+ }
620
+ return maskChar;
621
+ }
622
+ function normalizeFormatChars(formatChars) {
623
+ if (!formatChars) {
624
+ return { formatChars: void 0, hasLegacyString: false };
625
+ }
626
+ const result = {};
627
+ let hasLegacyString = false;
628
+ for (const key of Object.keys(formatChars)) {
629
+ const value = formatChars[key];
630
+ if (typeof value === "string") {
631
+ hasLegacyString = true;
632
+ result[key] = new RegExp(value);
633
+ } else {
634
+ result[key] = value;
635
+ }
636
+ }
637
+ return { formatChars: result, hasLegacyString };
638
+ }
639
+ function createBeforeMaskedStateChangeAdapter(beforeMaskedValueChange, maskOptions) {
640
+ return ({ previousState, currentState, nextState }) => {
641
+ var _a, _b;
642
+ return beforeMaskedValueChange(
643
+ nextState,
644
+ (_a = previousState != null ? previousState : currentState) != null ? _a : null,
645
+ (_b = nextState.enteredString) != null ? _b : null,
646
+ maskOptions
647
+ );
648
+ };
649
+ }
650
+
651
+ // src/utils/transform.ts
652
+ function resolveTransform(transform) {
653
+ if (!transform) {
654
+ return void 0;
655
+ }
656
+ if (transform === "uppercase") {
657
+ return (char) => char.toUpperCase();
658
+ }
659
+ if (transform === "lowercase") {
660
+ return (char) => char.toLowerCase();
661
+ }
662
+ if (typeof transform === "function") {
663
+ return transform;
664
+ }
665
+ if (process.env.NODE_ENV !== "production") {
666
+ console.error(
667
+ `react-input-mask-format: invalid transform "${String(
668
+ transform
669
+ )}", expected "uppercase" | "lowercase" | (char, position) => char`
670
+ );
671
+ }
672
+ return void 0;
673
+ }
674
+
675
+ // src/index.tsx
676
+ var InputMask = (0, import_react2.forwardRef)(function InputMask2(props, forwardedRef) {
677
+ const {
678
+ alwaysShowMask = false,
679
+ children,
680
+ mask,
681
+ maskPlaceholder: maskPlaceholderProp,
682
+ beforeMaskedStateChange: beforeMaskedStateChangeProp,
683
+ transform,
684
+ maskChar,
685
+ formatChars,
686
+ beforeMaskedValueChange,
687
+ ...restProps
688
+ } = props;
689
+ if (maskChar !== void 0) {
690
+ warnDeprecatedOnce("maskChar", "maskChar is deprecated, use maskPlaceholder instead. See migration guide: https://github.com/Temirtator/react-input-mask-format#migrating-from-react-input-mask");
691
+ }
692
+ if (beforeMaskedValueChange !== void 0) {
693
+ warnDeprecatedOnce("beforeMaskedValueChange", "beforeMaskedValueChange is deprecated, use beforeMaskedStateChange. See migration guide: https://github.com/Temirtator/react-input-mask-format#migrating-from-react-input-mask");
694
+ }
695
+ const resolvedPlaceholder = resolveMaskPlaceholder(maskPlaceholderProp, maskChar);
696
+ const maskPlaceholder = resolvedPlaceholder === void 0 ? "_" : resolvedPlaceholder;
697
+ validateMaxLength(props);
698
+ validateMaskPlaceholder({ ...props, maskPlaceholder });
699
+ const { formatChars: normalizedFormatChars, hasLegacyString } = normalizeFormatChars(formatChars);
700
+ if (hasLegacyString) {
701
+ warnDeprecatedOnce(
702
+ "formatChars",
703
+ 'string values in formatChars are deprecated, pass RegExp values instead (e.g. { "#": /[0-9]/ }). See migration guide: https://github.com/Temirtator/react-input-mask-format#migrating-from-react-input-mask'
704
+ );
705
+ }
706
+ const maskUtils = new MaskUtils({
707
+ mask,
708
+ maskPlaceholder,
709
+ formatChars: normalizedFormatChars,
710
+ transform: resolveTransform(transform)
711
+ });
712
+ let beforeMaskedStateChange = beforeMaskedStateChangeProp;
713
+ if (!beforeMaskedStateChange && beforeMaskedValueChange) {
714
+ const v2MaskOptions = {
715
+ mask,
716
+ maskChar: maskPlaceholder,
717
+ alwaysShowMask,
718
+ formatChars: formatChars != null ? formatChars : { "9": "[0-9]", a: "[A-Za-z]", "*": "[A-Za-z0-9]" },
719
+ permanents: maskUtils.maskOptions.permanents
720
+ };
721
+ beforeMaskedStateChange = createBeforeMaskedStateChangeAdapter(
722
+ beforeMaskedValueChange,
723
+ v2MaskOptions
724
+ );
725
+ }
726
+ const isMasked = !!mask;
727
+ const isEditable = !restProps.disabled && !restProps.readOnly;
728
+ const isControlled = props.value !== null && props.value !== void 0;
729
+ const previousIsMasked = usePrevious(isMasked);
730
+ const initialValue = toString(
731
+ (isControlled ? props.value : props.defaultValue) || ""
732
+ );
733
+ const {
734
+ inputRef,
735
+ getInputState,
736
+ setInputState,
737
+ getLastInputState
738
+ } = useInputState(initialValue, isMasked);
739
+ const getInputElement = useInputElement(inputRef);
740
+ function onChange(event) {
741
+ const currentState = getInputState();
742
+ const previousState = getLastInputState();
743
+ let newInputState = maskUtils.processChange(currentState, previousState);
744
+ if (beforeMaskedStateChange) {
745
+ newInputState = beforeMaskedStateChange({
746
+ currentState,
747
+ previousState,
748
+ nextState: newInputState
749
+ });
750
+ }
751
+ setInputState(newInputState);
752
+ if (props.onChange) {
753
+ props.onChange(event);
754
+ }
755
+ }
756
+ function onFocus(event) {
757
+ inputRef.current = event.target;
758
+ const currentValue = getInputState().value;
759
+ if (isMasked && !maskUtils.isValueFilled(currentValue)) {
760
+ let newValue = maskUtils.formatValue(currentValue);
761
+ let newSelection = maskUtils.getDefaultSelectionForValue(newValue);
762
+ let newInputState = {
763
+ value: newValue,
764
+ selection: newSelection
765
+ };
766
+ if (beforeMaskedStateChange) {
767
+ newInputState = beforeMaskedStateChange({
768
+ currentState: getInputState(),
769
+ nextState: newInputState
770
+ });
771
+ newValue = newInputState.value;
772
+ newSelection = newInputState.selection;
773
+ }
774
+ setInputState(newInputState);
775
+ if (newValue !== currentValue && props.onChange) {
776
+ props.onChange(event);
777
+ }
778
+ defer(() => {
779
+ setInputState(getLastInputState());
780
+ });
781
+ }
782
+ if (props.onFocus) {
783
+ props.onFocus(event);
784
+ }
785
+ }
786
+ function onBlur(event) {
787
+ const currentValue = getInputState().value;
788
+ const lastValue = getLastInputState().value;
789
+ if (isMasked && !alwaysShowMask && maskUtils.isValueEmpty(lastValue)) {
790
+ let newValue = "";
791
+ let newInputState = {
792
+ value: newValue,
793
+ selection: { start: null, end: null }
794
+ };
795
+ if (beforeMaskedStateChange) {
796
+ newInputState = beforeMaskedStateChange({
797
+ currentState: getInputState(),
798
+ nextState: newInputState
799
+ });
800
+ newValue = newInputState.value;
801
+ }
802
+ setInputState(newInputState);
803
+ if (newValue !== currentValue && props.onChange) {
804
+ props.onChange(event);
805
+ }
806
+ }
807
+ if (props.onBlur) {
808
+ props.onBlur(event);
809
+ }
810
+ }
811
+ function onMouseDown(event) {
812
+ const input = getInputElement();
813
+ const { value } = getInputState();
814
+ const inputDocument = getElementDocument(input);
815
+ if (!isInputFocused(input) && !maskUtils.isValueFilled(value)) {
816
+ const mouseDownX = event.clientX;
817
+ const mouseDownY = event.clientY;
818
+ const mouseDownTime = (/* @__PURE__ */ new Date()).getTime();
819
+ const mouseUpHandler = (mouseUpEvent) => {
820
+ inputDocument.removeEventListener("mouseup", mouseUpHandler);
821
+ if (!isInputFocused(input)) {
822
+ return;
823
+ }
824
+ const deltaX = Math.abs(mouseUpEvent.clientX - mouseDownX);
825
+ const deltaY = Math.abs(mouseUpEvent.clientY - mouseDownY);
826
+ const axisDelta = Math.max(deltaX, deltaY);
827
+ const timeDelta = (/* @__PURE__ */ new Date()).getTime() - mouseDownTime;
828
+ if (axisDelta <= 10 && timeDelta <= 200 || axisDelta <= 5 && timeDelta <= 300) {
829
+ const lastState = getLastInputState();
830
+ const newSelection = maskUtils.getDefaultSelectionForValue(
831
+ lastState.value
832
+ );
833
+ const newState = {
834
+ ...lastState,
835
+ selection: newSelection
836
+ };
837
+ setInputState(newState);
838
+ }
839
+ };
840
+ inputDocument.addEventListener("mouseup", mouseUpHandler);
841
+ }
842
+ if (props.onMouseDown) {
843
+ props.onMouseDown(event);
844
+ }
845
+ }
846
+ let renderValue = props.value;
847
+ if (isMasked && isControlled) {
848
+ const input = getInputElement();
849
+ const isFocused = !!input && isInputFocused(input);
850
+ let newValue = isFocused || alwaysShowMask || props.value ? maskUtils.formatValue(props.value) : props.value;
851
+ if (beforeMaskedStateChange) {
852
+ newValue = beforeMaskedStateChange({
853
+ nextState: { value: newValue, selection: { start: null, end: null } }
854
+ }).value;
855
+ }
856
+ renderValue = newValue;
857
+ }
858
+ const lastSelection = getLastInputState().selection;
859
+ (0, import_react2.useLayoutEffect)(() => {
860
+ if (isMasked && isControlled) {
861
+ setInputState({
862
+ ...getLastInputState(),
863
+ value: renderValue
864
+ });
865
+ }
866
+ });
867
+ (0, import_react2.useLayoutEffect)(() => {
868
+ if (!isMasked) {
869
+ return;
870
+ }
871
+ const input = getInputElement();
872
+ const isFocused = isInputFocused(input);
873
+ const previousSelection = lastSelection;
874
+ const currentState = getInputState();
875
+ let newInputState = { ...currentState };
876
+ if (!isControlled) {
877
+ const currentValue = currentState.value;
878
+ const formattedValue = maskUtils.formatValue(currentValue);
879
+ const isValueEmpty = maskUtils.isValueEmpty(formattedValue);
880
+ const shouldFormatValue = !isValueEmpty || isFocused || alwaysShowMask;
881
+ if (shouldFormatValue) {
882
+ newInputState.value = formattedValue;
883
+ } else if (isValueEmpty && !isFocused) {
884
+ newInputState.value = "";
885
+ }
886
+ }
887
+ if (isFocused && !previousIsMasked) {
888
+ newInputState.selection = maskUtils.getDefaultSelectionForValue(
889
+ newInputState.value
890
+ );
891
+ } else if (isControlled && isFocused && previousSelection) {
892
+ if (previousSelection.start !== null && previousSelection.end !== null) {
893
+ newInputState.selection = previousSelection;
894
+ }
895
+ }
896
+ if (beforeMaskedStateChange) {
897
+ newInputState = beforeMaskedStateChange({
898
+ currentState,
899
+ nextState: newInputState
900
+ });
901
+ }
902
+ setInputState(newInputState);
903
+ });
904
+ const inputProps = {
905
+ ...restProps,
906
+ onFocus,
907
+ onBlur,
908
+ onChange: isMasked && isEditable ? onChange : props.onChange,
909
+ onMouseDown: isMasked && isEditable ? onMouseDown : props.onMouseDown,
910
+ // `ref` may target either the plain <input> DOM node or, when custom
911
+ // children are used, whatever node the child's own ref forwards to.
912
+ ref: (ref) => {
913
+ inputRef.current = ref;
914
+ if (isFunction(forwardedRef)) {
915
+ forwardedRef(ref);
916
+ } else if (forwardedRef !== null && typeof forwardedRef === "object") {
917
+ forwardedRef.current = ref;
918
+ }
919
+ },
920
+ value: isMasked && isControlled ? renderValue : props.value
921
+ };
922
+ if (children) {
923
+ validateChildren(props, children);
924
+ return import_react2.default.cloneElement(children, inputProps);
925
+ }
926
+ return /* @__PURE__ */ import_react2.default.createElement("input", { ...inputProps });
927
+ });
928
+ InputMask.displayName = "InputMask";
929
+ var src_default = InputMask;
930
+ // Annotate the CommonJS export names for ESM import in node:
931
+ 0 && (module.exports = {
932
+ defaultFormatChars,
933
+ extendedFormatChars
934
+ });
935
+ //# sourceMappingURL=index.cjs.map