): number {
141 | const mergedSettings = super.mergeSettings(DOLLAR_MONEY_MASK_SETTINGS, settings) as MoneyMaskSettings;
142 | let normalized = super.removeNotNumbers(maskedValue);
143 |
144 | const dotPosition = normalized.length - mergedSettings.precision;
145 | normalized = this._insert(normalized, dotPosition, '.');
146 |
147 | return Number(normalized);
148 | }
149 |
150 | validate(): boolean {
151 | return true;
152 | }
153 |
154 | private _insert(text: string, index: number, stringToInsert: string): string {
155 | if (index > 0) {
156 | return text.substring(0, index) + stringToInsert + text.substring(index, text.length);
157 | } else {
158 | return stringToInsert + text;
159 | }
160 | }
161 | }
162 |
163 | export const dollarMoneyMask = () => new DollarMoneyMask();
164 |
165 | // dollar-money -> U$ 9,475.28
166 | ```
167 |
--------------------------------------------------------------------------------
/__tests__/__snapshots__/text-input-mask.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`TextInputMask renders controlled component 1`] = `
4 |
8 | `;
9 |
10 | exports[`TextInputMask renders controlled component 2`] = `
11 |
15 | `;
16 |
17 | exports[`TextInputMask renders controlled component with initial value 1`] = `
18 | {
19 | "asFragment": [Function],
20 | "baseElement":
21 |
22 |
26 |
27 | ,
28 | "container":
29 |
33 |
,
34 | "debug": [Function],
35 | "findAllByAltText": [Function],
36 | "findAllByDisplayValue": [Function],
37 | "findAllByLabelText": [Function],
38 | "findAllByPlaceholderText": [Function],
39 | "findAllByRole": [Function],
40 | "findAllByTestId": [Function],
41 | "findAllByText": [Function],
42 | "findAllByTitle": [Function],
43 | "findByAltText": [Function],
44 | "findByDisplayValue": [Function],
45 | "findByLabelText": [Function],
46 | "findByPlaceholderText": [Function],
47 | "findByRole": [Function],
48 | "findByTestId": [Function],
49 | "findByText": [Function],
50 | "findByTitle": [Function],
51 | "getAllByAltText": [Function],
52 | "getAllByDisplayValue": [Function],
53 | "getAllByLabelText": [Function],
54 | "getAllByPlaceholderText": [Function],
55 | "getAllByRole": [Function],
56 | "getAllByTestId": [Function],
57 | "getAllByText": [Function],
58 | "getAllByTitle": [Function],
59 | "getByAltText": [Function],
60 | "getByDisplayValue": [Function],
61 | "getByLabelText": [Function],
62 | "getByPlaceholderText": [Function],
63 | "getByRole": [Function],
64 | "getByTestId": [Function],
65 | "getByText": [Function],
66 | "getByTitle": [Function],
67 | "queryAllByAltText": [Function],
68 | "queryAllByDisplayValue": [Function],
69 | "queryAllByLabelText": [Function],
70 | "queryAllByPlaceholderText": [Function],
71 | "queryAllByRole": [Function],
72 | "queryAllByTestId": [Function],
73 | "queryAllByText": [Function],
74 | "queryAllByTitle": [Function],
75 | "queryByAltText": [Function],
76 | "queryByDisplayValue": [Function],
77 | "queryByLabelText": [Function],
78 | "queryByPlaceholderText": [Function],
79 | "queryByRole": [Function],
80 | "queryByTestId": [Function],
81 | "queryByText": [Function],
82 | "queryByTitle": [Function],
83 | "rerender": [Function],
84 | "unmount": [Function],
85 | }
86 | `;
87 |
88 | exports[`TextInputMask renders uncontrolled component 1`] = `
89 | {
90 | "asFragment": [Function],
91 | "baseElement":
92 |
93 |
97 |
98 | ,
99 | "container":
100 |
104 |
,
105 | "debug": [Function],
106 | "findAllByAltText": [Function],
107 | "findAllByDisplayValue": [Function],
108 | "findAllByLabelText": [Function],
109 | "findAllByPlaceholderText": [Function],
110 | "findAllByRole": [Function],
111 | "findAllByTestId": [Function],
112 | "findAllByText": [Function],
113 | "findAllByTitle": [Function],
114 | "findByAltText": [Function],
115 | "findByDisplayValue": [Function],
116 | "findByLabelText": [Function],
117 | "findByPlaceholderText": [Function],
118 | "findByRole": [Function],
119 | "findByTestId": [Function],
120 | "findByText": [Function],
121 | "findByTitle": [Function],
122 | "getAllByAltText": [Function],
123 | "getAllByDisplayValue": [Function],
124 | "getAllByLabelText": [Function],
125 | "getAllByPlaceholderText": [Function],
126 | "getAllByRole": [Function],
127 | "getAllByTestId": [Function],
128 | "getAllByText": [Function],
129 | "getAllByTitle": [Function],
130 | "getByAltText": [Function],
131 | "getByDisplayValue": [Function],
132 | "getByLabelText": [Function],
133 | "getByPlaceholderText": [Function],
134 | "getByRole": [Function],
135 | "getByTestId": [Function],
136 | "getByText": [Function],
137 | "getByTitle": [Function],
138 | "queryAllByAltText": [Function],
139 | "queryAllByDisplayValue": [Function],
140 | "queryAllByLabelText": [Function],
141 | "queryAllByPlaceholderText": [Function],
142 | "queryAllByRole": [Function],
143 | "queryAllByTestId": [Function],
144 | "queryAllByText": [Function],
145 | "queryAllByTitle": [Function],
146 | "queryByAltText": [Function],
147 | "queryByDisplayValue": [Function],
148 | "queryByLabelText": [Function],
149 | "queryByPlaceholderText": [Function],
150 | "queryByRole": [Function],
151 | "queryByTestId": [Function],
152 | "queryByText": [Function],
153 | "queryByTitle": [Function],
154 | "rerender": [Function],
155 | "unmount": [Function],
156 | }
157 | `;
158 |
--------------------------------------------------------------------------------
/__tests__/cel-phone.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { CelPhoneMask } from './../src/masks/cel-phone.mask';
2 |
3 | test('getType results cel-phone', () => {
4 | var expected = 'cel-phone';
5 | var received = CelPhoneMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('5188888888 results (51) 8888-8888', () => {
11 | var mask = new CelPhoneMask();
12 | var expected = '(51) 8888-8888';
13 | var received = mask.getValue('5188888888');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('51888888888 results (51) 88888-8888', () => {
19 | var mask = new CelPhoneMask();
20 | var expected = '(51) 88888-8888';
21 | var received = mask.getValue('51888888888');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('88888888 withDDD=false results 8888-8888', () => {
27 | var mask = new CelPhoneMask();
28 | var expected = '8888-8888';
29 | var received = mask.getValue('88888888', {
30 | withDDD: false
31 | });
32 |
33 | expect(received).toBe(expected);
34 | });
35 |
36 | test('888888888 withDDD=false results 88888-8888', () => {
37 | var mask = new CelPhoneMask();
38 | var expected = '88888-8888';
39 | var received = mask.getValue('888888888', {
40 | withDDD: false
41 | });
42 |
43 | expect(received).toBe(expected);
44 | });
45 |
46 | test('12377777777 dddMask=999 results 123 7777-7777', () => {
47 | var mask = new CelPhoneMask();
48 | var expected = '123 7777-7777';
49 | var received = mask.getValue('12377777777', {
50 | dddMask: '999 '
51 | });
52 |
53 | expect(received).toBe(expected);
54 | });
55 |
56 | test('123777777777 dddMask=999 results 123 77777-7777', () => {
57 | var mask = new CelPhoneMask();
58 | var expected = '123 77777-7777';
59 | var received = mask.getValue('123777777777', {
60 | dddMask: '999 '
61 | });
62 |
63 | expect(received).toBe(expected);
64 | });
65 |
66 | test('123123 is not valid', () => {
67 | var mask = new CelPhoneMask();
68 | var expected = false;
69 | var received = mask.validate('123123');
70 |
71 | expect(received).toBe(expected);
72 | });
73 |
74 | test('5188888888 is valid', () => {
75 | var mask = new CelPhoneMask();
76 | var isValid = mask.validate('5188888888');
77 |
78 | expect(isValid).toBe(true);
79 | });
80 |
81 | test('123777777777 dddMask=999 is valid', () => {
82 | var mask = new CelPhoneMask();
83 | var isValid = mask.validate('123777777777', {
84 | dddMask: '999 '
85 | });
86 |
87 | expect(isValid).toBe(true);
88 | });
89 |
90 | test('1237777777 dddMask=999 is not valid', () => {
91 | var mask = new CelPhoneMask();
92 | var isValid = mask.validate('1237777777', {
93 | dddMask: '999 '
94 | });
95 |
96 | expect(isValid).toBe(false);
97 | });
98 |
99 | test('5188888888 results (51) 8888-8888 and raw value 5188888888', () => {
100 | var mask = new CelPhoneMask();
101 | var expected = '(51) 8888-8888';
102 | var received = mask.getValue('5188888888');
103 |
104 | var expectedRawValue = '5188888888';
105 | var receivedRawValue = mask.getRawValue(received);
106 |
107 | expect(received).toBe(expected);
108 | expect(receivedRawValue).toBe(expectedRawValue);
109 | });
110 |
111 | test('123777777777 dddMask=999 results 123 77777-7777 and raw value 123777777777', () => {
112 | var mask = new CelPhoneMask();
113 | var expected = '123 77777-7777';
114 | var received = mask.getValue('123777777777', {
115 | dddMask: '999 '
116 | });
117 |
118 | var expectedRawValue = '123777777777';
119 | var receivedRawValue = mask.getRawValue(received);
120 |
121 | expect(received).toBe(expected);
122 | expect(receivedRawValue).toBe(expectedRawValue);
123 | });
--------------------------------------------------------------------------------
/__tests__/cnpj.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { CnpjMask } from './../src/masks/cnpj.mask';
2 |
3 | test('getType results cnpj', () => {
4 | var expected = 'cnpj';
5 | var received = CnpjMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('79885262000130 results 79.885.262/0001-30', () => {
11 | var mask = new CnpjMask();
12 | var expected = '79.885.262/0001-30';
13 | var received = mask.getValue('79885262000130');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('798852 results 79.885.2', () => {
19 | var mask = new CnpjMask();
20 | var expected = '79.885.2';
21 | var received = mask.getValue('798852');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('79885262000130 results 79.885.262/0001-30 and is valid', () => {
27 | var mask = new CnpjMask();
28 | var expected = '79.885.262/0001-30';
29 | var received = mask.getValue('79885262000130');
30 | var isValid = mask.validate(received);
31 |
32 | expect(received).toBe(expected);
33 | expect(isValid).toBe(true);
34 | });
35 |
36 | test('79885262000140 results 79.885.262/0001-40 and is not valid', () => {
37 | var mask = new CnpjMask();
38 | var expected = '79.885.262/0001-40';
39 | var received = mask.getValue('79885262000140');
40 | var isValid = mask.validate(received);
41 |
42 | expect(received).toBe(expected);
43 | expect(isValid).toBe(false);
44 | });
45 |
46 | test('7988526200013 results 79.885.262/0001-3 and is not valid', () => {
47 | var mask = new CnpjMask();
48 | var expected = '79.885.262/0001-3';
49 | var received = mask.getValue('7988526200013');
50 | var isValid = mask.validate(received);
51 |
52 | expect(received).toBe(expected);
53 | expect(isValid).toBe(false);
54 | });
55 |
56 | test('79885262000130 results 79.885.262/0001-30 and raw value 79885262000130', () => {
57 | var mask = new CnpjMask();
58 | var expected = '79.885.262/0001-30';
59 | var received = mask.getValue('79885262000130');
60 |
61 | var expectedRawValue = '79885262000130';
62 | var receivedRawValue = mask.getRawValue(received);
63 |
64 | expect(received).toBe(expected);
65 | expect(receivedRawValue).toBe(expectedRawValue);
66 | });
--------------------------------------------------------------------------------
/__tests__/cpf.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { CpfMask } from './../src/masks/cpf.mask';
2 |
3 | test('getType results cpf', () => {
4 | var expected = 'cpf';
5 | var received = CpfMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('12312312356 results 123.123.123-56', () => {
11 | var mask = new CpfMask();
12 | var expected = '123.123.123-56';
13 | var received = mask.getValue('12312312356');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('123123 results 123.123', () => {
19 | var mask = new CpfMask();
20 | var expected = '123.123';
21 | var received = mask.getValue('123123');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('07833823678 results 078.338.236-78 and is valid', () => {
27 | var mask = new CpfMask();
28 | var expected = '078.338.236-78';
29 | var received = mask.getValue('07833823678');
30 | var isValid = mask.validate(received);
31 |
32 | expect(received).toBe(expected);
33 | expect(isValid).toBe(true);
34 | });
35 |
36 | test('11111111111 results 111.111.111-11 and is not valid', () => {
37 | var mask = new CpfMask();
38 | var expected = '111.111.111-11';
39 | var received = mask.getValue('11111111111');
40 | var isValid = mask.validate(received);
41 |
42 | expect(received).toBe(expected);
43 | expect(isValid).toBe(false);
44 | });
45 |
46 | test('1234567890 results 123.456.789-0 and is not valid', () => {
47 | var mask = new CpfMask();
48 | var expected = '123.456.789-0';
49 | var received = mask.getValue('1234567890');
50 | var isValid = mask.validate(received);
51 |
52 | expect(received).toBe(expected);
53 | expect(isValid).toBe(false);
54 | });
55 |
56 | test('12312312356 results 123.123.123-56 and raw value 12312312356', () => {
57 | var mask = new CpfMask();
58 | var expected = '123.123.123-56';
59 | var received = mask.getValue('12312312356');
60 |
61 | var expectedRawValue = '12312312356';
62 | var receivedRawValue = mask.getRawValue(received);
63 |
64 | expect(received).toBe(expected);
65 | expect(receivedRawValue).toBe(expectedRawValue);
66 | });
--------------------------------------------------------------------------------
/__tests__/credit-card.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { CreditCardMask } from './../src/masks/credit-card.mask';
2 |
3 | test('getType results credit-card', () => {
4 | var expected = 'credit-card';
5 | var received = CreditCardMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('1234123412341234 results 1234 1234 1234 1234', () => {
11 | var mask = new CreditCardMask();
12 | var expected = '1234 1234 1234 1234';
13 | var received = mask.getValue('1234123412341234');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('1234123412341234 obfuscated true results 1234 **** **** 1234', () => {
19 | var mask = new CreditCardMask();
20 | var expected = '1234 **** **** 1234';
21 | var received = mask.getValue('1234123412341234', {
22 | obfuscated: true
23 | });
24 |
25 | expect(received).toBe(expected);
26 | });
27 |
28 | test('1234123412341234 obfuscated false results 1234 1234 1234 1234', () => {
29 | var mask = new CreditCardMask();
30 | var expected = '1234 1234 1234 1234';
31 | var received = mask.getValue('1234123412341234', {
32 | obfuscated: false
33 | });
34 |
35 | expect(received).toBe(expected);
36 | });
37 |
38 | test('1234123412341234 obfuscated false results 1234 1234 1234 1234 and raw value [1234, 1234, 1234, 1234]', () => {
39 | var mask = new CreditCardMask();
40 | var options = {
41 | obfuscated: false
42 | };
43 |
44 | var expected = '1234 1234 1234 1234';
45 | var received = mask.getValue('1234123412341234', options);
46 |
47 | var expectedRawValue = ['1234', '1234', '1234', '1234'];
48 | var receivedRawValue = mask.getRawValue(received);
49 |
50 | expect(received).toBe(expected);
51 |
52 | expectedRawValue.forEach((val, index) => {
53 | expect(val).toBe(receivedRawValue[index]);
54 | });
55 | });
56 |
57 | test('1234123412341234 obfuscated true results 1234 **** **** 1234 and raw value [1234, ****, ****, 1234]', () => {
58 | var mask = new CreditCardMask();
59 | var options = {
60 | obfuscated: true
61 | };
62 |
63 | var expected = '1234 **** **** 1234';
64 | var received = mask.getValue('1234123412341234', options);
65 |
66 | var expectedRawValue = ['1234', '****', '****', '1234'];
67 | var receivedRawValue = mask.getRawValue(received);
68 |
69 | expect(received).toBe(expected);
70 |
71 | expectedRawValue.forEach((val, index) => {
72 | expect(val).toBe(receivedRawValue[index]);
73 | });
74 | });
--------------------------------------------------------------------------------
/__tests__/custom.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { CustomMask } from './../src/masks/custom.mask';
2 |
3 | test('getType results custom', () => {
4 | var expected = 'custom';
5 | var received = CustomMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('123 with mask AAA9 results ', () => {
11 | var mask = new CustomMask('AAA9');
12 | var expected = '';
13 | var received = mask.getValue('123');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('TA3 with mask AAA9 results TA', () => {
19 | var mask = new CustomMask('AAA9');
20 | var expected = 'TA';
21 | var received = mask.getValue('TA3');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('TABC with mask AAA9 results TAB', () => {
27 | var mask = new CustomMask('AAA9');
28 | var expected = 'TAB';
29 | var received = mask.getValue('TABC');
30 |
31 | expect(received).toBe(expected);
32 | });
33 |
34 | test('1111111 with mask 999-9999 results 111-1111', () => {
35 | var mask = new CustomMask('999-9999');
36 | var expected = '111-1111';
37 | var received = mask.getValue('1111111');
38 |
39 | expect(received).toBe(expected);
40 | });
41 |
42 | test('B45 with mask A#99 results B#45', () => {
43 | var mask = new CustomMask('A#99');
44 | var expected = 'B#45';
45 | var received = mask.getValue('B45');
46 |
47 | expect(received).toBe(expected);
48 | });
49 |
50 | test('BC45 with mask AS#99 results BC#45', () => {
51 | var mask = new CustomMask('AS#99');
52 | var expected = 'BC#45';
53 | var received = mask.getValue('BC45');
54 |
55 | expect(received).toBe(expected);
56 | });
57 |
58 | test('B345 with mask AS#99 results B3#45', () => {
59 | var mask = new CustomMask('AS#99');
60 | var expected = 'B3#45';
61 | var received = mask.getValue('B345');
62 |
63 | expect(received).toBe(expected);
64 | });
65 |
66 | test('DWARF with mask AAAAA and custom validator results DWARF and is valid', () => {
67 | var mask = new CustomMask('AAAAA');
68 | var input = 'DWARF';
69 |
70 | var validator = (value) => {
71 | return value === 'DWARF';
72 | };
73 |
74 | var expected = 'DWARF';
75 | var received = mask.getValue(input);
76 | var isValid = mask.validate(input, { validator });
77 |
78 | expect(expected).toBe(received);
79 | expect(isValid).toBe(true);
80 | });
81 |
82 | test('ELF with mask AAAAA and custom validator results DWARF and is invalid', () => {
83 | var mask = new CustomMask('AAAAA');
84 | var input = 'ELF';
85 |
86 | var validator = (value) => {
87 | return value === 'DWARF';
88 | };
89 |
90 | var expected = 'ELF';
91 | var received = mask.getValue(input);
92 | var isValid = mask.validate(input, { validator });
93 |
94 | expect(expected).toBe(received);
95 | expect(isValid).toBe(false);
96 | });
97 |
98 | test('123 with mask 999 results 123 and raw value 123(type Number)', () => {
99 | var mask = new CustomMask('999');
100 | var options = {
101 | getRawValue: function (maskedValue) {
102 | return Number(maskedValue);
103 | }
104 | };
105 |
106 | var expected = '123';
107 | var received = mask.getValue('123');
108 |
109 | var expectedRawValue = 123;
110 | var receivedRawValue = mask.getRawValue(received, options);
111 |
112 | expect(received).toBe(expected);
113 | expect(receivedRawValue).toBe(expectedRawValue);
114 | });
115 |
116 | test('mask with custom translation and match', () => {
117 | var mask = new CustomMask('999&AAA');
118 | var options = {
119 | translation: {
120 | '&': function (val) {
121 | return ['#', '.', ':'].indexOf(val) >= 0 ? val : null;
122 | }
123 | }
124 | }
125 |
126 | var expected = '123#ABC';
127 | var received = mask.getValue('123#ABC', options);
128 |
129 | expect(received).toBe(expected);
130 | });
131 |
132 | test('mask with custom translation and not match', () => {
133 | var mask = new CustomMask('999&AAA');
134 | var options = {
135 | translation: {
136 | '&': function (val) {
137 | return ['#', '.', ':'].indexOf(val) >= 0 ? val : null;
138 | }
139 | }
140 | }
141 |
142 | var expected = '123';
143 | var received = mask.getValue('123|ABC', options);
144 |
145 | expect(received).toBe(expected);
146 | });
147 |
148 | test('mask with custom translation and optionals and matching', () => {
149 | var mask = new CustomMask('999***AAA&');
150 | var options = {
151 | translation: {
152 | '&': function (val) {
153 | return ['#', '.', ':'].indexOf(val) >= 0 ? val : null;
154 | }
155 | }
156 | }
157 |
158 | var expected = '123|% ABC.';
159 | var received = mask.getValue('123|% ABC.', options);
160 |
161 | expect(received).toBe(expected);
162 | });
163 |
--------------------------------------------------------------------------------
/__tests__/date-parser.test.ts:
--------------------------------------------------------------------------------
1 | import { parseStringDate } from '../src/masks/internal-dependencies/date-parser';
2 |
3 | var input1 = '01/01/1990 17:40:30';
4 | const format1 = `DD/MM/YYYY HH:mm:ss`;
5 | test(`format ${format1} parses ${input1}`, () => {
6 | const date = parseStringDate(input1, format1);
7 |
8 | expect(date.getFullYear()).toBe(1990);
9 | expect(date.getMonth()).toBe(0);
10 | expect(date.getDay()).toBe(1);
11 | expect(date.getHours()).toBe(17);
12 | expect(date.getMinutes()).toBe(40);
13 | expect(date.getSeconds()).toBe(30);
14 | });
15 |
16 | var input2 = '01-01-1990';
17 | const format2 = `DD-MM-YYYY`;
18 | test(`format ${format2} parses ${input2}`, () => {
19 | const date = parseStringDate(input2, format2);
20 |
21 | expect(date.getFullYear()).toBe(1990);
22 | expect(date.getMonth()).toBe(0);
23 | expect(date.getDay()).toBe(1);
24 | });
25 |
26 | var input3 = '99.99.9999';
27 | const format3 = `DD.MM.YYYY`;
28 | test(`format ${format3} doesnt parse ${input3}`, () => {
29 | const date = parseStringDate(input3, format3);
30 |
31 | expect(date).toBe(null);
32 | });
33 |
34 | var input4 = '14/a1/2018';
35 | const format4 = `DD/MM/YYYY`;
36 | test(`format ${format4} parses ${input4}`, () => {
37 | const date = parseStringDate(input4, format4);
38 |
39 | expect(date).toBe(null);
40 | });
41 |
42 | var input5 = '17:40:30';
43 | const format5 = `HH:mm:ss`;
44 | test(`format ${format5} parses ${input5}`, () => {
45 | const date = parseStringDate(input5, format5);
46 |
47 | expect(date.getHours()).toBe(17);
48 | expect(date.getMinutes()).toBe(40);
49 | expect(date.getSeconds()).toBe(30);
50 | });
51 |
52 | var input6 = '09:40 PM';
53 | const format6 = `hh:mm aa`;
54 | test(`format ${format6} parses ${input6}`, () => {
55 | const date = parseStringDate(input6, format6);
56 |
57 | expect(date.getHours()).toBe(21);
58 | expect(date.getMinutes()).toBe(40);
59 | });
60 |
61 | var input7 = '17';
62 | const format7 = `HH`;
63 | test(`format ${format7} parses ${input7}`, () => {
64 | const date = parseStringDate(input7, format7);
65 |
66 | expect(date.getHours()).toBe(17);
67 | });
68 |
--------------------------------------------------------------------------------
/__tests__/datetime.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { DatetimeMask } from './../src/masks/datetime.mask';
2 | var moment = require('moment');
3 | const { parseStringDate } = require('../src/masks/internal-dependencies/date-parser.ts');
4 |
5 | function compareMomentObj(dateTimeA, dateTimeB) {
6 | var momentA = moment(dateTimeA, "DD/MM/YYYY");
7 | var momentB = moment(dateTimeB, "DD/MM/YYYY");
8 | if (momentA > momentB) return 1;
9 | else if (momentA < momentB) return -1;
10 | else return 0;
11 | }
12 |
13 | test('getType results datetime', () => {
14 | var expected = 'datetime';
15 | var received = DatetimeMask.getType();
16 |
17 | expect(received).toBe(expected);
18 | });
19 |
20 | test('01011990174030 with format DD/MM/YYYY HH:mm:ss results 01/01/1990 17:40:30', () => {
21 | var mask = new DatetimeMask();
22 | var expected = '01/01/1990 17:40:30';
23 | var received = mask.getValue('01011990174030');
24 |
25 | expect(received).toBe(expected);
26 | });
27 |
28 | test('01011990174030 with format DD-MM-YYYY HH:mm:ss results 01-01-1990 17:40:30', () => {
29 | var mask = new DatetimeMask();
30 | var expected = '01-01-1990 17:40:30';
31 | var received = mask.getValue('01011990174030', {
32 | format: 'DD-MM-YYYY HH:mm:ss'
33 | });
34 |
35 | expect(received).toBe(expected);
36 | });
37 |
38 |
39 | test('01011990 with format DD-MM-YYYY results 01-01-1990', () => {
40 | var mask = new DatetimeMask();
41 | var expected = '01-01-1990';
42 | var received = mask.getValue('01011990', {
43 | format: 'DD-MM-YYYY HH:mm:ss',
44 | });
45 |
46 | expect(received).toBe(expected);
47 | });
48 |
49 | test('191050 with format HH:mm:ss results 19:10:50 and is valid', () => {
50 | var mask = new DatetimeMask();
51 | var input = '191050';
52 | var settings = {
53 | format: 'HH:mm:ss',
54 | };
55 |
56 | var expected = '19:10:50';
57 | var received = mask.getValue(input, settings);
58 | var isValid = mask.validate(input, settings);
59 |
60 | expect(received).toBe(expected);
61 | expect(isValid).toBe(true);
62 | });
63 |
64 | test('99999999 with format DD/MM/YYYY results 99/99/9999 and is invalid', () => {
65 | var mask = new DatetimeMask();
66 | var input = '99999999';
67 | var settings = {
68 | format: 'DD/MM/YYYY',
69 | };
70 |
71 | var expected = '99/99/9999';
72 | var received = mask.getValue(input, settings);
73 | var isValid = mask.validate(input, settings);
74 |
75 | expect(received).toBe(expected);
76 | expect(isValid).toBe(false);
77 | });
78 |
79 | test('01011990174030 with format DD/MM/YYYY HH:mm:ss results 01/01/1990 17:40:30 and is valid', () => {
80 | var mask = new DatetimeMask();
81 | var input = '01011990174030';
82 | var settings = {
83 | format: 'DD/MM/YYYY HH:mm:ss',
84 | };
85 |
86 | var expected = '01/01/1990 17:40:30';
87 | var received = mask.getValue(input, settings);
88 | var isValid = mask.validate(input, settings);
89 |
90 | expect(received).toBe(expected);
91 | expect(isValid).toBe(true);
92 | });
93 |
94 | test('01011990174030 with format DD/MM/YYYY HH:mm:ss results 01/01/1990 17:40:30 and raw value Date', () => {
95 | var mask = new DatetimeMask();
96 | var expected = '01/01/1990 17:40:30';
97 | var settings = {
98 | format: 'DD/MM/YYYY HH:mm:ss',
99 | };
100 | var received = mask.getValue('01011990174030');
101 |
102 | var expectedRawValue = parseStringDate(received, settings.format);
103 | var receivedRawValue = mask.getRawValue(received, settings);
104 |
105 | expect(received).toBe(expected);
106 | expect(compareMomentObj(receivedRawValue, expectedRawValue)).toBe(0);
107 | });
--------------------------------------------------------------------------------
/__tests__/money.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { MoneyMask } from './../src/masks/money.mask';
2 |
3 | test('getType results money', () => {
4 | var expected = 'money';
5 | var received = MoneyMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('1 results R$0,01', () => {
11 | var mask = new MoneyMask();
12 | var expected = 'R$0,01';
13 | var received = mask.getValue('1');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('111 results R$1,11', () => {
19 | var mask = new MoneyMask();
20 | var expected = 'R$1,11';
21 | var received = mask.getValue('111');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('1111 results R$11,11', () => {
27 | var mask = new MoneyMask();
28 | var expected = 'R$11,11';
29 | var received = mask.getValue('1111');
30 |
31 | expect(received).toBe(expected);
32 | });
33 |
34 | test('11111 results R$111,11', () => {
35 | var mask = new MoneyMask();
36 | var expected = 'R$111,11';
37 | var received = mask.getValue('11111');
38 |
39 | expect(received).toBe(expected);
40 | });
41 |
42 | test('111111 results R$1.111,11', () => {
43 | var mask = new MoneyMask();
44 | var expected = 'R$1.111,11';
45 | var received = mask.getValue('111111');
46 |
47 | expect(received).toBe(expected);
48 | });
49 |
50 | test('111111111 results R$1.111.111,11', () => {
51 | var mask = new MoneyMask();
52 | var expected = 'R$1.111.111,11';
53 | var received = mask.getValue('111111111');
54 |
55 | expect(received).toBe(expected);
56 | });
57 |
58 | test(' results R$0,00', () => {
59 | var mask = new MoneyMask();
60 | var expected = 'R$0,00';
61 | var received = mask.getValue('');
62 |
63 | expect(received).toBe(expected);
64 | });
65 |
66 | test('11111 precision 3 results R$11,111', () => {
67 | var mask = new MoneyMask();
68 | var expected = 'R$11,111';
69 | var received = mask.getValue('11111', {
70 | precision: 3
71 | });
72 |
73 | expect(received).toBe(expected);
74 | });
75 |
76 | test('111 separator . results R$1.11', () => {
77 | var mask = new MoneyMask();
78 | var expected = 'R$1.11';
79 | var received = mask.getValue('111', {
80 | separator: '.'
81 | });
82 |
83 | expect(received).toBe(expected);
84 | });
85 |
86 | test('111111 delimiter , results R$1,111,11', () => {
87 | var mask = new MoneyMask();
88 | var expected = 'R$1,111,11';
89 | var received = mask.getValue('111111', {
90 | delimiter: ','
91 | });
92 |
93 | expect(received).toBe(expected);
94 | });
95 |
96 | test('1 unit US$ results US$0,01', () => {
97 | var mask = new MoneyMask();
98 | var expected = 'US$0,01';
99 | var received = mask.getValue('1', {
100 | unit: 'US$'
101 | });
102 |
103 | expect(received).toBe(expected);
104 | });
105 |
106 | test('1 suffixUnit $$$ results R$0,01', () => {
107 | var mask = new MoneyMask();
108 | var expected = 'R$0,01 $$$';
109 | var received = mask.getValue('1', {
110 | suffixUnit: '$$$'
111 | });
112 |
113 | expect(received).toBe(expected);
114 | });
115 |
116 | test('1 zeroCents results R$1,00', () => {
117 | var mask = new MoneyMask();
118 | var expected = 'R$1,00';
119 | var received = mask.getValue('1', {
120 | zeroCents: true
121 | });
122 |
123 | expect(received).toBe(expected);
124 | });
125 |
126 | test('US$ config with value 1234567 results US$12,345.67', () => {
127 | var mask = new MoneyMask();
128 | var expected = 'US$12,345.67';
129 | var received = mask.getValue('1234567', {
130 | unit: 'US$',
131 | delimiter: ',',
132 | separator: '.'
133 | });
134 |
135 | expect(received).toBe(expected);
136 | });
137 |
138 | test('1 results R$0,01 and raw value 0.01', () => {
139 | var mask = new MoneyMask();
140 | var expected = 'R$0,01';
141 | var received = mask.getValue('1');
142 |
143 | var expectedRawValue = 0.01;
144 | var receivedRawValue = mask.getRawValue(received);
145 |
146 | expect(received).toBe(expected);
147 | expect(receivedRawValue).toBe(expectedRawValue);
148 | });
149 |
150 | test('111111 results R$1.111,11 and raw value 1111.11', () => {
151 | var mask = new MoneyMask();
152 | var expected = 'R$1.111,11';
153 | var received = mask.getValue('111111');
154 |
155 | var expectedRawValue = 1111.11;
156 | var receivedRawValue = mask.getRawValue(received);
157 |
158 | expect(received).toBe(expected);
159 | expect(receivedRawValue).toBe(expectedRawValue);
160 | });
161 |
162 | test('1 zeroCents results R$1,00 and raw value 1', () => {
163 | var mask = new MoneyMask();
164 | var expected = 'R$1,00';
165 | var received = mask.getValue('1', {
166 | zeroCents: true
167 | });
168 |
169 | var expectedRawValue = 1;
170 | var receivedRawValue = mask.getRawValue(received);
171 |
172 | expect(received).toBe(expected);
173 | expect(receivedRawValue).toBe(expectedRawValue);
174 | });
175 |
176 | test('111111 delimiter , results R$1,111,11 and raw value 1111.11', () => {
177 | var mask = new MoneyMask();
178 | var expected = 'R$1,111,11';
179 | var received = mask.getValue('111111', {
180 | delimiter: ','
181 | });
182 |
183 | var expectedRawValue = 1111.11;
184 | var receivedRawValue = mask.getRawValue(received);
185 |
186 | expect(received).toBe(expected);
187 | expect(receivedRawValue).toBe(expectedRawValue);
188 | });
189 |
190 | test('1 unit US$ results US$ 0,01', () => {
191 | var mask = new MoneyMask();
192 | var expected = 'US$ 0,01';
193 | var received = mask.getValue('1', {
194 | unit: 'US$ '
195 | });
196 |
197 | expect(received).toBe(expected);
198 | });
--------------------------------------------------------------------------------
/__tests__/only-numbers.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { OnlyNumbersMask } from './../src/masks/only-numbers.mask';
2 |
3 | test('getType results only-numbers', () => {
4 | var expected = 'only-numbers';
5 | var received = OnlyNumbersMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('abc123 results 123', () => {
11 | var mask = new OnlyNumbersMask();
12 | var expected = '123';
13 | var received = mask.getValue('abc123');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('1 results 1', () => {
19 | var mask = new OnlyNumbersMask();
20 | var expected = '1';
21 | var received = mask.getValue('1');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('abc results ', () => {
27 | var mask = new OnlyNumbersMask();
28 | var expected = '';
29 | var received = mask.getValue('abc');
30 |
31 | expect(received).toBe(expected);
32 | });
33 |
34 | test('1 results 1 and raw value 1', () => {
35 | var mask = new OnlyNumbersMask();
36 | var expected = '1';
37 | var received = mask.getValue('1');
38 |
39 | var expectedRawValue = '1';
40 | var receivedRawValue = mask.getRawValue(received);
41 |
42 | expect(received).toBe(expected);
43 | expect(receivedRawValue).toBe(expectedRawValue);
44 | });
45 |
--------------------------------------------------------------------------------
/__tests__/text-input-mask.test.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import { render, screen } from "@testing-library/react";
3 | import "@testing-library/jest-dom";
4 | import TextInputMask, { cpfMask } from "../src/text-input-mask";
5 | import * as React from "react";
6 |
7 | beforeAll(() => {
8 | // Create a spy on console (console.error in this case) and provide some mocked implementation
9 | jest.spyOn(console, "error").mockImplementation(() => {});
10 | });
11 | afterAll(() => {
12 | // Restore mock after all tests are done, so it won't affect other test suites
13 | console.error.mockRestore();
14 | });
15 | afterEach(() => {
16 | // Clear mock (all calls etc) after each test.
17 | // It's needed when you're using console somewhere in the tests so you have clean mock each time
18 | console.error.mockClear();
19 | });
20 |
21 | test("TextInputMask renders uncontrolled component", () => {
22 | const result = render();
23 | expect(result).toMatchSnapshot();
24 | });
25 |
26 | test("TextInputMask renders controlled component", () => {
27 | const { rerender } = render();
28 | expect(screen.getByDisplayValue("")).toMatchSnapshot();
29 |
30 | rerender();
31 | expect(screen.getByDisplayValue("123.123")).toMatchSnapshot();
32 | });
33 |
34 | test("TextInputMask renders hybrid component (controlled and uncontrolled). This is not recommended and will throw an error on the console.", () => {
35 | expect(() =>
36 | render()
37 | ).toThrow(
38 | "Use either the defaultValue prop, or the value prop, but not both"
39 | );
40 | });
41 |
42 | test("TextInputMask renders controlled component with initial value", () => {
43 | let value = "223";
44 | const onChange = (val) => (value = val);
45 | const result = render(
46 |
47 | );
48 | expect(result).toMatchSnapshot();
49 | });
50 |
--------------------------------------------------------------------------------
/__tests__/zip-code.mask.test.ts:
--------------------------------------------------------------------------------
1 | import { ZipCodeMask } from './../src/masks/zip-code.mask';
2 |
3 | test('getType results zip-code', () => {
4 | var expected = 'zip-code';
5 | var received = ZipCodeMask.getType();
6 |
7 | expect(received).toBe(expected);
8 | });
9 |
10 | test('11111111 results 11111-111', () => {
11 | var mask = new ZipCodeMask();
12 | var expected = '11111-111';
13 | var received = mask.getValue('11111111');
14 |
15 | expect(received).toBe(expected);
16 | });
17 |
18 | test('1111111 results 11111-11', () => {
19 | var mask = new ZipCodeMask();
20 | var expected = '11111-11';
21 | var received = mask.getValue('1111111');
22 |
23 | expect(received).toBe(expected);
24 | });
25 |
26 | test('1111111 results 11111-11 and is not valid', () => {
27 | var mask = new ZipCodeMask();
28 | var expected = '11111-11';
29 | var received = mask.getValue('1111111');
30 | var isValid = mask.validate(received);
31 |
32 | expect(isValid).toBe(false);
33 | });
34 |
35 | test('11111111 results 11111-111 and is not valid', () => {
36 | var mask = new ZipCodeMask();
37 | var expected = '11111-111';
38 | var received = mask.getValue('11111111');
39 | var isValid = mask.validate(received);
40 |
41 | expect(isValid).toBe(true);
42 | });
43 |
44 | test('11111111 results 11111-111 and raw value 11111111', () => {
45 | var mask = new ZipCodeMask();
46 | var expected = '11111-111';
47 | var received = mask.getValue('11111111');
48 |
49 | var expectedRawValue = '11111111';
50 | var receivedRawValue = mask.getRawValue(received);
51 |
52 | expect(received).toBe(expected);
53 | expect(receivedRawValue).toBe(expectedRawValue);
54 | });
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import TextInputMask from "./dist/text-input-mask";
2 |
3 | module.exports.TextInputMask = TextInputMask;
4 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('ts-jest').JestConfigWithTsJest} */
2 | module.exports = {
3 | preset: 'ts-jest',
4 | testEnvironment: 'jsdom',
5 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-masked-text",
3 | "version": "1.0.5",
4 | "description": "Text and TextInput with mask for React applications, based on benhurott/react-native-masked-text.",
5 | "licenses": [
6 | {
7 | "type": "MIT",
8 | "url": "https://www.opensource.org/licenses/mit-license.php"
9 | }
10 | ],
11 | "main": "dist/index.js",
12 | "types": "dist/types/index.d.ts",
13 | "scripts": {
14 | "test": "BABEL_ENV=test jest",
15 | "build": "BABEL_ENV=build rollup -c --bundleConfigAsCjs"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/emiyake/react-masked-text"
20 | },
21 | "keywords": [
22 | "mask",
23 | "text",
24 | "textinput",
25 | "react",
26 | "vanilla-masker"
27 | ],
28 | "author": "Edmar Miyake",
29 | "license": "ISC",
30 | "bugs": {
31 | "url": "https://github.com/benhurott/react-masked-text/issues"
32 | },
33 | "homepage": "https://github.com/benhurott/react-masked-text#readme",
34 | "resolutions": {
35 | "babel-core": "7.0.0-bridge.0"
36 | },
37 | "devDependencies": {
38 | "@babel/core": "7.0.0",
39 | "@babel/plugin-proposal-object-rest-spread": "7.0.0",
40 | "@babel/plugin-transform-destructuring": "7.0.0",
41 | "@babel/plugin-transform-parameters": "7.0.0",
42 | "@babel/preset-env": "7.0.0",
43 | "@babel/preset-react": "7.0.0",
44 | "@rollup/plugin-terser": "0.4.4",
45 | "@testing-library/jest-dom": "6.1.3",
46 | "@testing-library/react": "12.1.2",
47 | "@types/jest": "29.5.4",
48 | "@types/react": "18.2.22",
49 | "babel-core": "^7.0.0-bridge.0",
50 | "babel-jest": "23.6.0",
51 | "jest": "29.7.0",
52 | "jest-environment-jsdom": "29.7.0",
53 | "moment": "2.22.2",
54 | "react": "18.2.0",
55 | "react-dom": "18.2.0",
56 | "rollup": "3.29.2",
57 | "rollup-plugin-babel": "4.4.0",
58 | "rollup-plugin-copy": "3.5.0",
59 | "rollup-plugin-node-resolve": "5.2.0",
60 | "rollup-plugin-ts": "3.4.5",
61 | "ts-jest": "29.1.1",
62 | "typescript": "5.2.2"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | // rollup.config.mjs
2 | const ts = require('rollup-plugin-ts');
3 | const babel = require("rollup-plugin-babel");
4 | const resolve = require("rollup-plugin-node-resolve");
5 | const copy = require("rollup-plugin-copy");
6 | const terser = require("@rollup/plugin-terser");
7 |
8 | let includePathOptions = {
9 | paths: ['src'],
10 | extensions: ['.js', '.ts', '.tsx']
11 | };
12 |
13 |
14 | export default {
15 | input: "src/index.ts",
16 | output: {
17 | file: "dist/index.js",
18 | name: 'My Bundle',
19 | format: "umd",
20 | globals: {
21 | react: 'react',
22 | },
23 | },
24 | external: ['react'],
25 | plugins: [
26 | copy({ 'src/masks/internal-dependencies': 'dist/internal-dependencies' }),
27 | resolve({ jsnext: true }),
28 | babel(),
29 | ts(),
30 | terser(),
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from "./masks/base.mask";
2 | import { celPhoneMask } from "./masks/cel-phone.mask";
3 | import { cnpjMask } from "./masks/cnpj.mask";
4 | import { customMask } from "./masks/custom.mask";
5 | import { cpfMask } from "./masks/cpf.mask";
6 | import { creditCardMask } from "./masks/credit-card.mask";
7 | import { datetimeMask } from "./masks/datetime.mask";
8 | import { moneyMask } from "./masks/money.mask";
9 | import { onlyNumbersMask } from "./masks/only-numbers.mask";
10 | import { zipCodeMask } from "./masks/zip-code.mask";
11 | import TextInputMask from "./text-input-mask";
12 |
13 | export {
14 | BaseMask,
15 | celPhoneMask,
16 | customMask,
17 | cnpjMask,
18 | cpfMask,
19 | creditCardMask,
20 | datetimeMask,
21 | moneyMask,
22 | onlyNumbersMask,
23 | zipCodeMask,
24 | TextInputMask,
25 | };
26 |
--------------------------------------------------------------------------------
/src/masks/base.mask.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2 | import VMasker from './internal-dependencies/vanilla-masker';
3 |
4 | export default class BaseMask {
5 | getVMasker(): typeof VMasker {
6 | return VMasker;
7 | }
8 |
9 | getValue(value: string): string {
10 | return value;
11 | }
12 |
13 | mergeSettings>(obj1: P, obj2: P): P {
14 | const obj3: Record = {};
15 | for (const attrname in obj1) {
16 | if (Object.prototype.hasOwnProperty.call(obj1, attrname)) {
17 | obj3[attrname] = obj1[attrname];
18 | }
19 | }
20 | for (const attrname in obj2) {
21 | if (Object.prototype.hasOwnProperty.call(obj2, attrname)) {
22 | obj3[attrname] = obj2[attrname];
23 | }
24 | }
25 | return obj3 as P;
26 | }
27 |
28 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
29 | getRawValue(maskedValue: string, settings?: any): any {
30 | return maskedValue;
31 | }
32 |
33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
34 | getDefaultValue(value: any, settings?: any): string {
35 | if (value === undefined || value === null) {
36 | return '';
37 | }
38 |
39 | return String(value);
40 | }
41 |
42 | removeNotNumbers(text: string): string {
43 | return text.replace(/[^0-9]+/g, '');
44 | }
45 |
46 | removeWhiteSpaces(text: string): string {
47 | return (text || '').replace(/\s/g, '');
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/masks/cel-phone.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | const PHONE_8_MASK = '9999-9999';
4 | const PHONE_9_MASK = '99999-9999';
5 |
6 | interface CellPhoneSettings {
7 | withDDD?: boolean;
8 | dddMask?: string;
9 | }
10 |
11 | const CEL_PHONE_SETTINGS: CellPhoneSettings = {
12 | withDDD: true,
13 | dddMask: '(99) ',
14 | };
15 |
16 | class CelPhoneMask extends BaseMask {
17 | static getType(): string {
18 | return 'cel-phone';
19 | }
20 |
21 | getValue(value: string, settings?: CellPhoneSettings): string {
22 | const mask: string = this._getMask(value, settings);
23 | return this.getVMasker().toPattern(value, mask);
24 | }
25 |
26 | getRawValue(maskedValue: string): string {
27 | return super.removeNotNumbers(maskedValue);
28 | }
29 |
30 | validate(value: string, settings?: CellPhoneSettings): boolean {
31 | let valueToValidate: string = super.getDefaultValue(value);
32 | valueToValidate = this.getValue(value, settings);
33 |
34 | const mask: string = this._getMask(value, settings);
35 |
36 | return valueToValidate.length === mask.length;
37 | }
38 |
39 | _getMask(value: string, settings: CellPhoneSettings): string {
40 | const mergedSettings: any = super.mergeSettings(CEL_PHONE_SETTINGS, settings);
41 |
42 | const numbers: string = super.removeNotNumbers(value);
43 | let mask: string = PHONE_8_MASK;
44 |
45 | const use9DigitMask: boolean = (() => {
46 | if (mergedSettings.withDDD) {
47 | const numbersDDD: string = super.removeNotNumbers(mergedSettings.dddMask);
48 | const remainingValueNumbers: string = numbers.substring(numbersDDD.length);
49 | return remainingValueNumbers.length >= 9;
50 | } else {
51 | return numbers.length >= 9;
52 | }
53 | })();
54 |
55 | if (use9DigitMask) {
56 | mask = PHONE_9_MASK;
57 | }
58 |
59 | if (mergedSettings.withDDD) {
60 | mask = `${mergedSettings.dddMask}${mask}`;
61 | }
62 |
63 | return mask;
64 | }
65 | }
66 |
67 | export const celPhoneMask = () => new CelPhoneMask();
--------------------------------------------------------------------------------
/src/masks/cnpj.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | const CNPJ_MASK = '99.999.999/9999-99';
4 |
5 | const validateCnpj = (cnpj: string): boolean => {
6 | const valida: number[] = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
7 | let dig1 = 0;
8 | let dig2 = 0;
9 |
10 | const exp = /\.|\-|\//g;
11 | cnpj = cnpj.toString().replace(exp, '');
12 | const digito = Number(cnpj.charAt(12) + cnpj.charAt(13));
13 |
14 | for (let i = 0; i < valida.length; i++) {
15 | dig1 += i > 0 ? Number(cnpj.charAt(i - 1)) * valida[i] : 0;
16 | dig2 += Number(cnpj.charAt(i)) * valida[i];
17 | }
18 | dig1 = dig1 % 11 < 2 ? 0 : 11 - (dig1 % 11);
19 | dig2 = dig2 % 11 < 2 ? 0 : 11 - (dig2 % 11);
20 |
21 | return dig1 * 10 + dig2 === digito;
22 | };
23 |
24 | class CnpjMask extends BaseMask {
25 | static getType(): string {
26 | return 'cnpj';
27 | }
28 |
29 | getValue(value: string): string {
30 | return this.getVMasker().toPattern(value, CNPJ_MASK);
31 | }
32 |
33 | getRawValue(maskedValue: string): string {
34 | return super.removeNotNumbers(maskedValue);
35 | }
36 |
37 | validate(value: string): boolean {
38 | return validateCnpj(value);
39 | }
40 | }
41 |
42 | export const cnpjMask = () => new CnpjMask();
43 |
--------------------------------------------------------------------------------
/src/masks/cpf.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | const CPF_MASK = '999.999.999-99';
4 |
5 | const validateCPF = (cpf: string): boolean => {
6 | if (cpf == '') {
7 | return true;
8 | }
9 |
10 | cpf = cpf.replace(/\./gi, '').replace(/-/gi, '');
11 | let isValid = true;
12 | let sum: number;
13 | let rest: number;
14 | let i: number;
15 | i = 0;
16 | sum = 0;
17 |
18 | if (
19 | cpf.length != 11 ||
20 | cpf == '00000000000' ||
21 | cpf == '11111111111' ||
22 | cpf == '22222222222' ||
23 | cpf == '33333333333' ||
24 | cpf == '44444444444' ||
25 | cpf == '55555555555' ||
26 | cpf == '66666666666' ||
27 | cpf == '77777777777' ||
28 | cpf == '88888888888' ||
29 | cpf == '99999999999'
30 | ) {
31 | isValid = false;
32 | }
33 |
34 | for (i = 1; i <= 9; i++) {
35 | sum = sum + parseInt(cpf.substring(i - 1, i)) * (11 - i);
36 | }
37 |
38 | rest = (sum * 10) % 11;
39 |
40 | if (rest == 10 || rest == 11) {
41 | rest = 0;
42 | }
43 |
44 | if (rest != parseInt(cpf.substring(9, 10))) {
45 | isValid = false;
46 | }
47 |
48 | sum = 0;
49 |
50 | for (i = 1; i <= 10; i++) {
51 | sum = sum + parseInt(cpf.substring(i - 1, i)) * (12 - i);
52 | }
53 |
54 | rest = (sum * 10) % 11;
55 |
56 | if (rest == 10 || rest == 11) {
57 | rest = 0;
58 | }
59 | if (rest != parseInt(cpf.substring(10, 11))) {
60 | isValid = false;
61 | }
62 |
63 | return isValid;
64 | };
65 |
66 | class CpfMask extends BaseMask {
67 | static getType(): string {
68 | return 'cpf';
69 | }
70 |
71 | getValue(value: string): string {
72 | return this.getVMasker().toPattern(value, CPF_MASK);
73 | }
74 |
75 | getRawValue(maskedValue: string): string {
76 | return super.removeNotNumbers(maskedValue);
77 | }
78 |
79 | validate(value: string): boolean {
80 | return validateCPF(value);
81 | }
82 | }
83 |
84 | export const cpfMask = () => new CpfMask();
85 |
--------------------------------------------------------------------------------
/src/masks/credit-card.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | interface ICreditCardSettings {
4 | obfuscated?: boolean;
5 | }
6 |
7 | const CREDIT_CARD_MASK = '9999 9999 9999 9999';
8 | const CREDIT_CARD_OBFUSCATED_MASK = '9999 **** **** 9999';
9 |
10 | const CREDIT_CARD_SETTINGS: ICreditCardSettings = {
11 | obfuscated: false,
12 | };
13 |
14 | class CreditCardMask extends BaseMask {
15 | static getType(): string {
16 | return 'credit-card';
17 | }
18 |
19 | getValue(value: string, settings?: ICreditCardSettings): string {
20 | const selectedMask = this._getMask(settings);
21 | return this.getVMasker().toPattern(value, selectedMask);
22 | }
23 |
24 | validate(value: string, settings: ICreditCardSettings): boolean {
25 | if (!!value) {
26 | const selectedMask = this._getMask(settings);
27 | return value.length === selectedMask.length;
28 | }
29 |
30 | return true;
31 | }
32 |
33 | getRawValue(maskedValue: string): string[] {
34 | if (!maskedValue) return [];
35 |
36 | return maskedValue.split(' ').map((val: string) => {
37 | if (!val) return '';
38 |
39 | return val.trim();
40 | });
41 | }
42 |
43 | private _getMask(settings: ICreditCardSettings): string {
44 | const mergedSettings = super.mergeSettings(CREDIT_CARD_SETTINGS, settings);
45 | const selectedMask = mergedSettings.obfuscated ? CREDIT_CARD_OBFUSCATED_MASK : CREDIT_CARD_MASK;
46 | return selectedMask;
47 | }
48 | }
49 |
50 | export const creditCardMask = () => new CreditCardMask();
51 |
--------------------------------------------------------------------------------
/src/masks/custom.mask.ts:
--------------------------------------------------------------------------------
1 | import TinyMask from '../../tiny-mask/tinyMask';
2 |
3 | import BaseMask from './base.mask';
4 |
5 | interface Settings {
6 | mask?: string;
7 | translation?: any;
8 | getRawValue?: (maskedValue: any, settings: Settings) => any;
9 | validator?: (value: any, settings: Settings) => boolean;
10 | }
11 |
12 | const DEFAULT_TRANSLATION: { [key: string]: (val: string) => string } = {
13 | '9': function (val: string) {
14 | return val.replace(/[^0-9]+/g, '');
15 | },
16 | A: function (val: string) {
17 | return val.replace(/[^a-zA-Z]+/g, '');
18 | },
19 | S: function (val: string) {
20 | return val.replace(/[^a-zA-Z0-9]+/g, '');
21 | },
22 | '*': function (val: string) {
23 | return val;
24 | },
25 | };
26 |
27 | class CustomMask extends BaseMask {
28 | private _mask: string;
29 | constructor(customMask: string = '') {
30 | super();
31 | this._mask = customMask;
32 | }
33 |
34 | static getType(): string {
35 | return 'custom';
36 | }
37 |
38 | getValue(value: string, settings?: Settings): string {
39 | if (value === '') {
40 | return value;
41 | }
42 | const translation = this.mergeSettings(DEFAULT_TRANSLATION, settings?.translation);
43 |
44 | const masked = new TinyMask(this._mask, { translation }).mask(value);
45 | return masked;
46 | }
47 |
48 | getRawValue(maskedValue: string, settings: Settings): string {
49 | if (!!settings && settings?.getRawValue) {
50 | return settings?.getRawValue(maskedValue, settings);
51 | }
52 |
53 | return maskedValue;
54 | }
55 |
56 | validate(value: string, settings: Settings): boolean {
57 | if (!!settings && settings?.validator) {
58 | return settings?.validator(value, settings);
59 | }
60 |
61 | return true;
62 | }
63 | }
64 |
65 | export const customMask = (customMask: string) => new CustomMask(customMask);
66 |
--------------------------------------------------------------------------------
/src/masks/datetime.mask.ts:
--------------------------------------------------------------------------------
1 | // TypeScript
2 | import BaseMask from './base.mask';
3 | import { parseStringDate } from './internal-dependencies/date-parser';
4 |
5 | interface Settings {
6 | format: string;
7 | }
8 |
9 | const DATETIME_MASK_SETTINGS: Settings = {
10 | format: 'DD/MM/YYYY HH:mm:ss',
11 | };
12 |
13 | class DatetimeMask extends BaseMask {
14 | static getType(): string {
15 | return 'datetime';
16 | }
17 |
18 | getValue(value: string, settings?: Settings): string {
19 | const mergedSettings = this._getMergedSettings(settings);
20 | let mask = '';
21 |
22 | for (let i = 0; i < mergedSettings.format.length; i++) {
23 | mask += mergedSettings.format[i].replace(/[a-zA-Z]+/g, '9');
24 | }
25 |
26 | return this.getVMasker().toPattern(value, mask);
27 | }
28 |
29 | getRawValue(maskedValue: string, settings: Settings): Date {
30 | const mergedSettings = this._getMergedSettings(settings);
31 | return parseStringDate(maskedValue, mergedSettings.format) as unknown as Date;
32 | }
33 |
34 | validate(value: string, settings: Settings): boolean {
35 | const maskedValue = this.getValue(value, settings);
36 | const mergedSettings = this._getMergedSettings(settings);
37 | const date = parseStringDate(maskedValue, mergedSettings.format);
38 | const isValid = this._isValidDate(date);
39 | return isValid;
40 | }
41 |
42 | _getMergedSettings(settings: Settings): Settings {
43 | return super.mergeSettings(DATETIME_MASK_SETTINGS, settings);
44 | }
45 |
46 | /** https://stackoverflow.com/a/1353711/3670829 */
47 | _isValidDate(d: Date): boolean {
48 | return d instanceof Date && !isNaN(d.getTime());
49 | }
50 | }
51 |
52 | export const datetimeMask = () => new DatetimeMask();
53 |
--------------------------------------------------------------------------------
/src/masks/internal-dependencies/date-parser.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Parses a datetime (ex: 01/01/1990 17:40:30) given a format (ex: DD/MM/YYYY HH:mm:ss)
3 | * Nowadays, this parsers supports:
4 | * - MM = 01..12 Month number
5 | * - DD = 01..31 Day of month
6 | * - YYYY = 4 or 2 digit year (ex= 2018)
7 | * - YY = 2 digit year (ex= 18)
8 | * - HH = 0..23 Hours (24 hour time)
9 | * - hh = 1..12 Hours (12 hour time used with a A.)
10 | * - kk = 1..24 Hours (24 hour time from 1 to 24)
11 | * - aa = m pm Post or ante meridiem (Note the one character a p are also considered valid)
12 | * - mm = 0..59 Minutes
13 | * - ss = 0..59 Seconds
14 | */
15 | type DateKeys = 'Y' | 'M' | 'D' | 'H' | 'h' | 'a' | 'm' | 's';
16 |
17 | type DateComponents = {
18 | [k in DateKeys]: number;
19 | };
20 |
21 | interface FormatComponents {
22 | [key: string]: string;
23 | }
24 |
25 | export const parseStringDate = (input: string, format: string): Date => {
26 | if (input.length !== format.length) {
27 | return null;
28 | }
29 |
30 | const componentsOfFormatFromInput: FormatComponents = format
31 | .split('')
32 | .reduce((acc: FormatComponents, curr: string, index: number) => {
33 | acc[curr] = `${acc[curr] || ''}${input[index]}`;
34 | return acc;
35 | }, {});
36 |
37 | const dateComponents: DateComponents = validChars.reduce((acc: DateComponents, curr: string) => {
38 | acc[curr as DateKeys] = strToDateComponent[curr](componentsOfFormatFromInput[curr]);
39 | return acc;
40 | }, {} as DateComponents);
41 |
42 | if (Object.values(dateComponents).some((component) => component === null)) {
43 | return null;
44 | }
45 |
46 | const year = dateComponents['Y'];
47 | const monthIndex = dateComponents['M'];
48 | const day = dateComponents['D'];
49 | const hours =
50 | dateComponents['h'] && dateComponents['a']
51 | ? dateComponents['h'] + (dateComponents['a'] === AMPM.PM ? 12 : 0)
52 | : dateComponents['H'];
53 | const minutes = dateComponents['m'];
54 | const seconds = dateComponents['s'];
55 |
56 | const date = new Date(year, monthIndex, day, hours, minutes, seconds);
57 | return date;
58 | };
59 |
60 | const validChars: string[] = ['Y', 'M', 'D', 'H', 'h', 'a', 'm', 's'];
61 |
62 | const AMPM: { [key: string]: number } = {
63 | AM: 0,
64 | PM: 1,
65 | };
66 | const now: Date = new Date();
67 | const strToDateComponent: { [key: string]: (str: string) => number | null | undefined } = {
68 | Y: (str: string): number => {
69 | return str ? Number(str) : now.getFullYear();
70 | },
71 | M: (str: string): number | null => {
72 | const month = str ? Number(str) - 1 : now.getMonth();
73 | return month >= 0 && month <= 11 ? month : null;
74 | },
75 | D: (str: string): number => {
76 | return str ? Number(str) : now.getDate();
77 | },
78 | H: (str: string): number | null => {
79 | const hour = str ? Number(str) : now.getHours();
80 | return hour >= 0 && hour <= 23 ? hour : null;
81 | },
82 | h: (str: string): number | null => {
83 | const hour = str ? Number(str) : now.getHours() % 12;
84 | return hour >= 0 && hour <= 12 ? hour : null;
85 | },
86 | a: (str: string): number | undefined => {
87 | if (!str) return undefined;
88 | if (str.toLowerCase() === 'am') {
89 | return AMPM.AM;
90 | } else if (str.toLowerCase() === 'pm') {
91 | return AMPM.PM;
92 | } else {
93 | return null;
94 | }
95 | },
96 | m: (str: string): number | null => {
97 | const minute = str ? Number(str) : now.getMinutes();
98 | return minute >= 1 && minute <= 59 ? minute : null;
99 | },
100 | s: (str: string): number | null => {
101 | const second = str ? Number(str) : now.getSeconds();
102 | return second >= 1 && second <= 59 ? second : null;
103 | },
104 | };
105 |
--------------------------------------------------------------------------------
/src/masks/internal-dependencies/vanilla-masker.ts:
--------------------------------------------------------------------------------
1 | //@ts-nocheck
2 | class VanillaMasker {
3 | constructor(elements) {
4 | this.elements = elements;
5 | }
6 |
7 | unbindElementToMask() {
8 | for (let i = 0, len = this.elements.length; i < len; i++) {
9 | this.elements[i].lastOutput = '';
10 | this.elements[i].onkeyup = false;
11 | this.elements[i].onkeydown = false;
12 |
13 | if (this.elements[i].value.length) {
14 | this.elements[i].value = this.elements[i].value.replace(/\D/g, '');
15 | }
16 | }
17 | }
18 |
19 | bindElementToMask(maskFunction) {
20 | const that = this;
21 | const onType = function (e) {
22 | const source = e.target || e.srcElement;
23 |
24 | if (isAllowedKeyCode(e.keyCode)) {
25 | setTimeout(function () {
26 | that.opts.lastOutput = source.lastOutput;
27 | source.value = VMasker[maskFunction](source.value, that.opts);
28 | source.lastOutput = source.value;
29 | if (source.setSelectionRange && that.opts.suffixUnit) {
30 | source.setSelectionRange(
31 | source.value.length,
32 | source.value.length - that.opts.suffixUnit.length
33 | );
34 | }
35 | }, 0);
36 | }
37 | };
38 | for (let i = 0, len = this.elements.length; i < len; i++) {
39 | this.elements[i].lastOutput = '';
40 | this.elements[i].onkeyup = onType;
41 | if (this.elements[i].value.length) {
42 | this.elements[i].value = VMasker[maskFunction](this.elements[i].value, this.opts);
43 | }
44 | }
45 | }
46 |
47 | maskMoney(opts) {
48 | this.opts = mergeMoneyOptions(opts);
49 | this.bindElementToMask('toMoney');
50 | }
51 |
52 | maskNumber() {
53 | this.opts = {};
54 | this.bindElementToMask('toNumber');
55 | }
56 |
57 | maskAlphaNum() {
58 | this.opts = {};
59 | this.bindElementToMask('toAlphaNumeric');
60 | }
61 |
62 | maskPattern(pattern) {
63 | this.opts = { pattern: pattern };
64 | this.bindElementToMask('toPattern');
65 | }
66 |
67 | unMask() {
68 | this.unbindElementToMask();
69 | }
70 | }
71 |
72 | const VMasker = function (el) {
73 | if (!el) {
74 | throw new Error('VanillaMasker: There is no element to bind.');
75 | }
76 | const elements = 'length' in el ? (el.length ? el : []) : [el];
77 | return new VanillaMasker(elements);
78 | };
79 |
80 | VMasker.toMoney = function (value, opts) {
81 | opts = mergeMoneyOptions(opts);
82 | if (opts.zeroCents) {
83 | opts.lastOutput = opts.lastOutput || '';
84 | const zeroMatcher = '(' + opts.separator + '[0]{0,' + opts.precision + '})';
85 | const zeroRegExp = new RegExp(zeroMatcher, 'g');
86 | const digitsLength = value.toString().replace(/[\D]/g, '').length || 0;
87 | const lastDigitLength = opts.lastOutput.toString().replace(/[\D]/g, '').length || 0;
88 | value = value.toString().replace(zeroRegExp, '');
89 | if (digitsLength < lastDigitLength) {
90 | value = value.slice(0, value.length - 1);
91 | }
92 | }
93 | const number = value.toString().replace(/[\D]/g, '');
94 | const clearDelimiter = new RegExp('^(0|\\' + opts.delimiter + ')');
95 | const clearSeparator = new RegExp('(\\' + opts.separator + ')$');
96 | let money = number.substr(0, number.length - opts.moneyPrecision);
97 | let masked = money.substr(0, money.length % 3);
98 | let cents = new Array(opts.precision + 1).join('0');
99 | money = money.substr(money.length % 3, money.length);
100 | for (let i = 0, len = money.length; i < len; i++) {
101 | if (i % 3 === 0) {
102 | masked += opts.delimiter;
103 | }
104 | masked += money[i];
105 | }
106 | masked = masked.replace(clearDelimiter, '');
107 | masked = masked.length ? masked : '0';
108 | if (!opts.zeroCents) {
109 | const beginCents = number.length - opts.precision;
110 | const centsValue = number.substr(beginCents, opts.precision);
111 | const centsLength = centsValue.length;
112 | const centsSliced = opts.precision > centsLength ? opts.precision : centsLength;
113 | cents = (cents + centsValue).slice(-centsSliced);
114 | }
115 |
116 | const unitToApply =
117 | opts.unit[opts.unit.length - 1] === ' ' ? opts.unit.substring(0, opts.unit.length - 1) : opts.unit;
118 | const output = unitToApply + masked + opts.separator + cents + opts.suffixUnit;
119 | return output.replace(clearSeparator, '');
120 | };
121 |
122 | VMasker.toPattern = function (value, opts) {
123 | const pattern = typeof opts === 'object' ? opts.pattern : opts;
124 | const patternChars = pattern.replace(/\W/g, '');
125 | const output = pattern.split('');
126 | const values = value.toString().replace(/\W/g, '');
127 | const charsValues = values.replace(/\W/g, '');
128 | let index = 0;
129 | let i;
130 | const outputLength = output.length;
131 | const placeholder = typeof opts === 'object' ? opts.placeholder : undefined;
132 | for (i = 0; i < outputLength; i++) {
133 | if (index >= values.length) {
134 | if (patternChars.length == charsValues.length) {
135 | return output.join('');
136 | } else if (placeholder !== undefined && patternChars.length > charsValues.length) {
137 | return addPlaceholdersToOutput(output, i, placeholder).join('');
138 | } else {
139 | break;
140 | }
141 | } else {
142 | if (
143 | (output[i] === DIGIT && values[index].match(/[0-9]/)) ||
144 | (output[i] === ALPHA && values[index].match(/[a-zA-Z]/)) ||
145 | (output[i] === ALPHANUM && values[index].match(/[0-9a-zA-Z]/))
146 | ) {
147 | output[i] = values[index++];
148 | } else if (output[i] === DIGIT || output[i] === ALPHA || output[i] === ALPHANUM) {
149 | if (placeholder !== undefined) {
150 | return addPlaceholdersToOutput(output, i, placeholder).join('');
151 | } else {
152 | return output.slice(0, i).join('');
153 | }
154 | }
155 | }
156 | }
157 | return output.join('').substr(0, i);
158 | };
159 |
160 | VMasker.toNumber = function (value) {
161 | return value.toString().replace(/(?!^-)[^0-9]/g, '');
162 | };
163 |
164 | VMasker.toAlphaNumeric = function (value) {
165 | return value.toString().replace(/[^a-z0-9 ]+/i, '');
166 | };
167 |
168 | function isAllowedKeyCode(keyCode) {
169 | for (let i = 0, len = BY_PASS_KEYS.length; i < len; i++) {
170 | if (keyCode == BY_PASS_KEYS[i]) {
171 | return false;
172 | }
173 | }
174 | return true;
175 | }
176 |
177 | function mergeMoneyOptions(opts) {
178 | opts = opts || {};
179 | opts = {
180 | precision: opts.hasOwnProperty('precision') ? opts.precision : 2,
181 | separator: opts.separator || ',',
182 | delimiter: opts.delimiter || '.',
183 | unit: opts.unit ? opts.unit + ' ' : '',
184 | suffixUnit: (opts.suffixUnit && ' ' + opts.suffixUnit.replace(/[\s]/g, '')) || '',
185 | zeroCents: opts.zeroCents,
186 | lastOutput: opts.lastOutput,
187 | };
188 | opts.moneyPrecision = opts.zeroCents ? 0 : opts.precision;
189 | return opts;
190 | }
191 |
192 | function addPlaceholdersToOutput(output, index, placeholder) {
193 | for (; index < output.length; index++) {
194 | if (output[index] === DIGIT || output[index] === ALPHA || output[index] === ALPHANUM) {
195 | output[index] = placeholder;
196 | }
197 | }
198 | return output;
199 | }
200 |
201 | const DIGIT = '9';
202 | const ALPHA = 'A';
203 | const ALPHANUM = 'S';
204 | const BY_PASS_KEYS = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91, 92, 93];
205 |
206 | export default VMasker;
207 |
--------------------------------------------------------------------------------
/src/masks/money.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | interface MoneyMaskSettings {
4 | precision: number;
5 | separator: string;
6 | delimiter: string;
7 | unit: string;
8 | suffixUnit: string;
9 | zeroCents: boolean;
10 | }
11 |
12 | const MONEY_MASK_SETTINGS: MoneyMaskSettings = {
13 | precision: 2,
14 | separator: ',',
15 | delimiter: '.',
16 | unit: 'R$',
17 | suffixUnit: '',
18 | zeroCents: false,
19 | };
20 |
21 | class MoneyMask extends BaseMask {
22 | static getType(): string {
23 | return 'money';
24 | }
25 |
26 | getValue(value: string, settings?: Partial, oldValue?: string): string {
27 | const mergedSettings = super.mergeSettings(MONEY_MASK_SETTINGS, settings) as MoneyMaskSettings;
28 |
29 | if (mergedSettings.suffixUnit && oldValue && value) {
30 | if (value.length === oldValue.length - 1) {
31 | const cleared = this.removeNotNumbers(value);
32 | value = cleared.substring(0, cleared.length - 1);
33 | }
34 | }
35 |
36 | const masked = this.getVMasker().toMoney(value, mergedSettings);
37 | return masked;
38 | }
39 |
40 | getRawValue(maskedValue: string, settings?: Partial): number {
41 | const mergedSettings = super.mergeSettings(MONEY_MASK_SETTINGS, settings) as MoneyMaskSettings;
42 | let normalized = super.removeNotNumbers(maskedValue);
43 |
44 | const dotPosition = normalized.length - mergedSettings.precision;
45 | normalized = this._insert(normalized, dotPosition, '.');
46 |
47 | return Number(normalized);
48 | }
49 |
50 | validate(): boolean {
51 | return true;
52 | }
53 |
54 | private _insert(text: string, index: number, stringToInsert: string): string {
55 | if (index > 0) {
56 | return text.substring(0, index) + stringToInsert + text.substring(index, text.length);
57 | } else {
58 | return stringToInsert + text;
59 | }
60 | }
61 | }
62 |
63 | export const moneyMask = () => new MoneyMask();
64 |
--------------------------------------------------------------------------------
/src/masks/only-numbers.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | class OnlyNumbersMask extends BaseMask {
4 | static getType(): string {
5 | return 'only-numbers';
6 | }
7 |
8 | getValue(value: string): string {
9 | return this.getVMasker().toNumber(value);
10 | }
11 |
12 | getRawValue(maskedValue: string): string {
13 | return super.removeNotNumbers(maskedValue);
14 | }
15 |
16 | validate(): boolean {
17 | return true;
18 | }
19 | }
20 |
21 | export const onlyNumbersMask = () => new OnlyNumbersMask();
22 |
--------------------------------------------------------------------------------
/src/masks/zip-code.mask.ts:
--------------------------------------------------------------------------------
1 | import BaseMask from './base.mask';
2 |
3 | const ZIP_CODE_MASK = '99999-999';
4 |
5 | class ZipCodeMask extends BaseMask {
6 | static getType(): string {
7 | return 'zip-code';
8 | }
9 |
10 | getValue(value: string): string {
11 | return this.getVMasker().toPattern(value, ZIP_CODE_MASK);
12 | }
13 |
14 | getRawValue(maskedValue: string): string {
15 | return super.removeNotNumbers(maskedValue);
16 | }
17 |
18 | validate(value: string): boolean {
19 | if (!!value) {
20 | return value.length === ZIP_CODE_MASK.length;
21 | }
22 |
23 | return true;
24 | }
25 | }
26 |
27 | export const zipCodeMask = () => new ZipCodeMask();
28 |
--------------------------------------------------------------------------------
/src/text-input-mask.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | ForwardRefRenderFunction,
3 | InputHTMLAttributes,
4 | useEffect,
5 | useRef,
6 | } from "react";
7 |
8 | import BaseMask from "./masks/base.mask";
9 |
10 | export interface BaseTextComponentProps
11 | extends InputHTMLAttributes {
12 | mask?: BaseMask;
13 | }
14 |
15 | const BaseTextComponent: ForwardRefRenderFunction<
16 | HTMLInputElement,
17 | BaseTextComponentProps
18 | > = (props, ref) => {
19 | const { defaultValue, value, mask, type, onChange, ...otherProps } = props;
20 |
21 | const maskHandler = mask as any; // Adjust the type according to MaskResolver
22 |
23 | const inputRef = useRef();
24 |
25 | const isControlled = React.useCallback((): boolean => {
26 | return value !== undefined;
27 | }, [value]);
28 |
29 | useEffect(() => {
30 | if (defaultValue !== undefined && value !== undefined) {
31 | throw new Error(
32 | "Use either the defaultValue prop, or the value prop, but not both"
33 | );
34 | }
35 |
36 | let masked = maskHandler?.getValue(defaultValue || "");
37 |
38 | if (isControlled()) {
39 | masked = maskHandler?.getValue(value || "") || value;
40 | }
41 |
42 | inputRef.current.value = masked;
43 | }, [mask, defaultValue, value, isControlled]);
44 |
45 | const handleChangeText = async (text: string) => {
46 | const maskedText = mask?.getValue(text || "") || text;
47 | onChange?.(maskedText as any);
48 |
49 | if (!isControlled()) {
50 | inputRef.current.value = maskedText;
51 | }
52 | };
53 | return (
54 | {
56 | inputRef.current = elementRef;
57 | if (typeof ref === "function") {
58 | ref(elementRef);
59 | } else if (!!ref) {
60 | ref.current = elementRef;
61 | }
62 | }}
63 | type={type ?? "text"}
64 | {...otherProps}
65 | onChange={(event) => handleChangeText(event.currentTarget.value)}
66 | />
67 | );
68 | };
69 |
70 | export default React.forwardRef(BaseTextComponent);
71 |
--------------------------------------------------------------------------------
/tiny-mask/tinyMask.ts:
--------------------------------------------------------------------------------
1 | type TranslationOptions = {
2 | [key: string]: (val: string) => string;
3 | };
4 |
5 | interface TinyMaskOptions {
6 | translation?: TranslationOptions;
7 | invalidValues?: any[];
8 | }
9 |
10 | class TinyMask {
11 | private _options: {
12 | translation: TranslationOptions;
13 | invalidValues: any[];
14 | pattern: string;
15 | };
16 | private _handlers: (string | ((val: string) => string))[];
17 |
18 | constructor(pattern: string, options?: TinyMaskOptions) {
19 | const defaultOptions = {
20 | translation: {
21 | '9': (val: string) => val.replace(/[^0-9]+/g, ''),
22 | 'A': (val: string) => val.replace(/[^a-zA-Z]+/g, ''),
23 | 'S': (val: string) => val.replace(/[^a-zA-Z0-9]+/g, ''),
24 | '*': (val: string) => val
25 | },
26 | invalidValues: [null, undefined, '']
27 | };
28 |
29 | const opt = options || {};
30 | this._options = {
31 | translation: { ...defaultOptions.translation, ...opt.translation },
32 | invalidValues: [...defaultOptions.invalidValues, ...opt.invalidValues || []],
33 | pattern: pattern
34 | };
35 |
36 | this._handlers = [];
37 |
38 | for (let i = 0; i < pattern.length; i++) {
39 | const element = pattern[i];
40 | const result = this._options.translation[element] || element;
41 | this._handlers.push(result);
42 | }
43 | }
44 |
45 | private _isString(value: any): value is string {
46 | return typeof value === "string";
47 | }
48 |
49 | public mask(value: any): string {
50 | let result = '';
51 | const val = String(value);
52 |
53 |
54 | if (val.length === 0) return '';
55 |
56 | let maskSize = this._handlers.length;
57 | let maskResolved = 0;
58 |
59 | let valueSize = val.length;
60 | let valueResolved = 0;
61 |
62 | while (maskResolved < maskSize) {
63 | const hand = this._handlers[maskResolved];
64 | const char = val[valueResolved];
65 |
66 | if (char === undefined) {
67 | break;
68 | }
69 |
70 | if (char === hand) {
71 | result += char;
72 | maskResolved++;
73 | valueResolved++
74 | continue;
75 | }
76 |
77 | if (this._isString(hand)) {
78 | result += hand;
79 | maskResolved++;
80 | continue;
81 | }
82 |
83 | const parsed = hand(char);
84 |
85 |
86 | if (this._options.invalidValues.indexOf(parsed) < 0) {
87 | result += parsed;
88 | valueResolved++;
89 | }
90 | else {
91 | break;
92 | }
93 |
94 | maskResolved++;
95 | }
96 |
97 | return result;
98 | }
99 | }
100 |
101 | export default TinyMask;
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "module": "ESNext",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "outDir": "dist",
8 | "lib": ["dom", "dom.iterable", "ES2020"],
9 | "target": "ES5",
10 | "declaration": true,
11 | "sourceMap": true,
12 | "moduleResolution": "Node",
13 | "allowSyntheticDefaultImports": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "skipLibCheck": true,
16 | "declarationDir": "dist/types"
17 | },
18 | "include": ["src"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------