@player-ui/common-types-plugin 0.8.0--canary.307.9621 → 0.8.0--canary.410.15865
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/CommonTypesPlugin.native.js +8292 -0
- package/dist/CommonTypesPlugin.native.js.map +1 -0
- package/dist/{index.cjs.js → cjs/index.cjs} +273 -233
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/{index.esm.js → index.legacy-esm.js} +246 -220
- package/dist/index.mjs +782 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +26 -58
- package/src/__tests__/index.test.ts +198 -0
- package/src/data-types/types.ts +27 -37
- package/src/formats/__tests__/formats.test.ts +264 -0
- package/src/formats/__tests__/utils.test.ts +44 -0
- package/src/formats/index.ts +71 -69
- package/src/formats/utils.ts +16 -16
- package/src/index.ts +12 -12
- package/src/validators/__tests__/index.test.ts +472 -0
- package/src/validators/index.ts +67 -68
- package/types/data-types/types.d.ts +10 -0
- package/types/formats/index.d.ts +24 -0
- package/types/formats/utils.d.ts +41 -0
- package/types/index.d.ts +27 -0
- package/types/validators/index.d.ts +68 -0
- package/dist/common-types-plugin.dev.js +0 -11388
- package/dist/common-types-plugin.prod.js +0 -2
- package/dist/index.d.ts +0 -260
- package/dist/xlr/BooleanType.json +0 -72
- package/dist/xlr/CollectionType.json +0 -39
- package/dist/xlr/DateType.json +0 -55
- package/dist/xlr/IntegerNNType.json +0 -75
- package/dist/xlr/IntegerPosType.json +0 -75
- package/dist/xlr/IntegerType.json +0 -55
- package/dist/xlr/PhoneType.json +0 -55
- package/dist/xlr/StringType.json +0 -62
- package/dist/xlr/manifest.js +0 -21
- package/dist/xlr/manifest.json +0 -26
- package/src/data-types/refs.ts +0 -33
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-loss-of-precision */
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { commaNumber, integer, date, currency, phone } from "..";
|
|
4
|
+
|
|
5
|
+
describe("integer", () => {
|
|
6
|
+
describe("formatting", () => {
|
|
7
|
+
it("stringifies numbers", () => {
|
|
8
|
+
expect(integer.format?.("45")).toBe("45");
|
|
9
|
+
expect(integer.format?.("4.000")).toBe("4");
|
|
10
|
+
expect(integer.format?.(4.5)).toBe("4");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("ignores non-numeric things", () => {
|
|
14
|
+
expect(integer.format?.(undefined as any)).toBe("");
|
|
15
|
+
expect(integer.format?.(null as any)).toBe("");
|
|
16
|
+
expect(integer.format?.("blah")).toBe("");
|
|
17
|
+
expect(integer.format?.("foo33bar")).toBe("33");
|
|
18
|
+
expect(integer.format?.("foo4.00bar")).toBe("4");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("leaves the negative sign alone", () => {
|
|
22
|
+
expect(integer.format?.("-")).toBe("-");
|
|
23
|
+
expect(integer.format?.("-0")).toBe("0");
|
|
24
|
+
expect(integer.format?.("-4.0")).toBe("-4");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("deformatting", () => {
|
|
29
|
+
it("always returns +0", () => {
|
|
30
|
+
expect(Object.is(integer.deformat?.(-0), 0)).toBe(true);
|
|
31
|
+
expect(Object.is(integer.deformat?.(+0), 0)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("removes decimal points", () => {
|
|
35
|
+
expect(integer.deformat?.("4.00")).toBe(4);
|
|
36
|
+
expect(integer.deformat?.("-0.000000")).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("handles bad values", () => {
|
|
40
|
+
expect(integer.deformat?.(null as any)).toBeUndefined();
|
|
41
|
+
expect(integer.deformat?.(undefined as any)).toBeUndefined();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("removes ascii chars", () => {
|
|
45
|
+
expect(integer.deformat?.("333dsfdfsd")).toBe(333);
|
|
46
|
+
expect(integer.deformat?.("blah4.00foo")).toBe(4);
|
|
47
|
+
expect(integer.deformat?.("-")).toBeUndefined();
|
|
48
|
+
expect(integer.deformat?.("4.0.0")).toBe(4);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("commaNumber", () => {
|
|
54
|
+
describe("formatting", () => {
|
|
55
|
+
it("leaves things alone", () => {
|
|
56
|
+
expect(commaNumber.format?.("")).toBe("");
|
|
57
|
+
expect(commaNumber.format?.(undefined as any)).toBe(undefined);
|
|
58
|
+
expect(commaNumber.format?.({} as any)).toBe("");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("adds commas to things", () => {
|
|
62
|
+
expect(commaNumber.format?.(1000)).toBe("1,000");
|
|
63
|
+
expect(commaNumber.format?.(-1000)).toBe("-1,000");
|
|
64
|
+
expect(commaNumber.format?.(1000000000.999)).toBe("1,000,000,000.999");
|
|
65
|
+
expect(commaNumber.format?.(".99")).toBe("0.99");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("works with precision", () => {
|
|
69
|
+
expect(commaNumber.format?.(1000.999, { precision: 2 })).toBe("1,000.99");
|
|
70
|
+
expect(commaNumber.format?.(1000, { precision: 2 })).toBe("1,000.00");
|
|
71
|
+
expect(commaNumber.format?.(1000.1, { precision: 2 })).toBe("1,000.10");
|
|
72
|
+
expect(commaNumber.format?.(123456789, { precision: 0 })).toBe(
|
|
73
|
+
"123,456,789",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("handles out of bounds", () => {
|
|
78
|
+
expect(commaNumber.format?.(123456789123456789, { precision: 2 })).toBe(
|
|
79
|
+
"1,234,567,891,234,567.00",
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(commaNumber.format?.(123456789123456789.0, { precision: 2 })).toBe(
|
|
83
|
+
"1,234,567,891,234,567.00",
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("deformatting", () => {
|
|
89
|
+
it("does nothing with null values", () => {
|
|
90
|
+
expect(commaNumber.deformat?.(null as any)).toBe(null);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("does nothing with integer values", () => {
|
|
94
|
+
expect(commaNumber.deformat?.(1 as any)).toBe(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("strips commas from the string", () => {
|
|
98
|
+
expect(commaNumber.deformat?.("111,111")).toBe(111111);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("treats non-numbers as undef", () => {
|
|
102
|
+
expect(commaNumber.deformat?.("")).toBe(undefined);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("treats out of bound numbers as undef", () => {
|
|
106
|
+
expect(commaNumber.deformat?.("9,999,999,999,999,999.00")).toBe(
|
|
107
|
+
undefined,
|
|
108
|
+
);
|
|
109
|
+
expect(commaNumber.deformat?.("-9,999,999,999,999,999.00")).toBe(
|
|
110
|
+
undefined,
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("date", () => {
|
|
117
|
+
describe("formatting", () => {
|
|
118
|
+
it("leaves things alone", () => {
|
|
119
|
+
expect(date.format?.("")).toBe("");
|
|
120
|
+
expect(date.format?.(undefined as any)).toBe(undefined);
|
|
121
|
+
expect(date.format?.({} as any)).toBe("");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("add slashes as long as theyre not trailing", () => {
|
|
125
|
+
expect(date.format?.("11")).toBe("11");
|
|
126
|
+
expect(date.format?.("112")).toBe("11/2");
|
|
127
|
+
expect(date.format?.("1122")).toBe("11/22");
|
|
128
|
+
expect(date.format?.("112233")).toBe("11/22/1933");
|
|
129
|
+
expect(date.format?.("11223333")).toBe("11/22/3333");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("doesnt recognize 00 as valid month or day", () => {
|
|
133
|
+
expect(date.format?.("00")).toBe("0");
|
|
134
|
+
expect(date.format?.("00/01")).toBe("00/01");
|
|
135
|
+
expect(date.format?.("05/00")).toBe("05/0");
|
|
136
|
+
expect(date.format?.("05/00/1999")).toBe("05/00/1999");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("cuts off after mask is full", () => {
|
|
140
|
+
expect(date.format?.("112233334444")).toBe("11/22/3333");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("uses mask option for custom date mask", () => {
|
|
144
|
+
expect(date.format?.("112233334444", { mask: "MM/DD/YY" })).toBe(
|
|
145
|
+
"11/22/33",
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("converts YYYY-MM-DD to MM/DD/YYYY", () => {
|
|
150
|
+
expect(date.format?.("2021-4-1")).toBe("04/01/2021");
|
|
151
|
+
expect(date.format?.("2021-04-20")).toBe("04/20/2021");
|
|
152
|
+
expect(date.format?.("1111-22-33")).toBe("22/33/1111");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("does not attempt to convert - delimited date format other than specifically YYYY-MM-DD", () => {
|
|
156
|
+
expect(date.format?.("2021-")).toBe("20/21");
|
|
157
|
+
expect(date.format?.("202-0")).toBe("20/20");
|
|
158
|
+
expect(date.format?.("2021-0420")).toBe("20/21/0420");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("currency", () => {
|
|
164
|
+
const currencyOptions = { currencySymbol: "$" };
|
|
165
|
+
|
|
166
|
+
describe("formatting", () => {
|
|
167
|
+
it("leaves things alone", () => {
|
|
168
|
+
expect(currency.format?.("")).toBe("");
|
|
169
|
+
expect(currency.format?.(undefined as any)).toBe(undefined);
|
|
170
|
+
expect(currency.format?.(null as any)).toBe(null);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("adds commas to things", () => {
|
|
174
|
+
expect(currency.format?.(1000, currencyOptions)).toBe("$1,000.00");
|
|
175
|
+
expect(currency.format?.(-1000, currencyOptions)).toBe("-$1,000.00");
|
|
176
|
+
|
|
177
|
+
// Forces precision of 2
|
|
178
|
+
expect(currency.format?.(1000000000.999, currencyOptions)).toBe(
|
|
179
|
+
"$1,000,000,001.00",
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("optionally uses parens", () => {
|
|
184
|
+
expect(
|
|
185
|
+
currency.format?.(-100, {
|
|
186
|
+
...currencyOptions,
|
|
187
|
+
useParensForNeg: true,
|
|
188
|
+
precision: 1,
|
|
189
|
+
}),
|
|
190
|
+
).toBe("($100.0)");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("uses custom currency symbols", () => {
|
|
194
|
+
expect(
|
|
195
|
+
currency.format?.(-100100, { currencySymbol: "ADAM", precision: 0 }),
|
|
196
|
+
).toBe("-ADAM100,100");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe("deformatting", () => {
|
|
201
|
+
it("does nothing with integer values", () => {
|
|
202
|
+
expect(currency.deformat?.(1 as any, currencyOptions)).toBe(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("strips commas from the string", () => {
|
|
206
|
+
expect(currency.deformat?.("111,111", currencyOptions)).toBe(111111);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("treats non-numbers as undef", () => {
|
|
210
|
+
expect(currency.deformat?.("", currencyOptions)).toBe(undefined);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("strips out currency symbols", () => {
|
|
214
|
+
expect(currency.deformat?.("-$111,111", currencyOptions)).toBe(-111111);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("phone", () => {
|
|
220
|
+
describe("formatting", () => {
|
|
221
|
+
it("adds formatting when one character entered", () => {
|
|
222
|
+
expect(phone.format?.("1")).toBe("(1");
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("removes formatting when open paren given", () => {
|
|
226
|
+
expect(phone.format?.("(")).toBe("");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("adds formatting when partial number given", () => {
|
|
230
|
+
expect(phone.format?.("123456")).toBe("(123) 456-");
|
|
231
|
+
expect(phone.format?.("12345678")).toBe("(123) 456-78");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("fixes formatting when missing prefix digit", () => {
|
|
235
|
+
expect(phone.format?.("(858) 53-6789")).toBe("(858) 536-789");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("fixes formatting when missing area code digit", () => {
|
|
239
|
+
expect(phone.format?.("(88) 531-6789")).toBe("(885) 316-789");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("preserves formatting when value is well formatted", () => {
|
|
243
|
+
expect(phone.format?.("(123) 123-1231")).toBe("(123) 123-1231");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it(`doesn't add extra characters beyond mask value`, () => {
|
|
247
|
+
expect(phone.format?.("(123) 123-123145")).toBe("(123) 123-1231");
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe("deformatting", () => {
|
|
252
|
+
it("removes masking chars", () => {
|
|
253
|
+
expect(phone.deformat?.("(123) 123-1231")).toBe("1231231231");
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it(`doesn't remove characters when deformatting a deformatted value`, () => {
|
|
257
|
+
expect(phone.deformat?.("1231231231")).toBe("1231231231");
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("ignores improper formatting of the input string", () => {
|
|
261
|
+
expect(phone.deformat?.("123-123-1231")).toBe("1231231231");
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { removeFormatCharactersFromMaskedString, PLACEHOLDER } from "../utils";
|
|
3
|
+
|
|
4
|
+
describe("removeFormatCharactersFromMaskedString", () => {
|
|
5
|
+
it("removes formatted characters correctly", () => {
|
|
6
|
+
const result = removeFormatCharactersFromMaskedString(
|
|
7
|
+
"123-456_789",
|
|
8
|
+
"###-###_###",
|
|
9
|
+
);
|
|
10
|
+
expect(result).toBe("123456789");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("removes formatted characters with multiple reserved keys", () => {
|
|
14
|
+
const result = removeFormatCharactersFromMaskedString(
|
|
15
|
+
"123-456",
|
|
16
|
+
"###-$$$",
|
|
17
|
+
[PLACEHOLDER, "$"],
|
|
18
|
+
);
|
|
19
|
+
expect(result).toBe("123456");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it(`doesn't remove characters when value doesn't align with mask`, () => {
|
|
23
|
+
const result = removeFormatCharactersFromMaskedString("123456", "###-###");
|
|
24
|
+
expect(result).toBe("123456");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it(`doesn't add characters that extend beyond the length of the mask`, () => {
|
|
28
|
+
expect(removeFormatCharactersFromMaskedString("123456", "#####")).toBe(
|
|
29
|
+
"12345",
|
|
30
|
+
);
|
|
31
|
+
expect(
|
|
32
|
+
removeFormatCharactersFromMaskedString("123456", "#$#-##", [
|
|
33
|
+
PLACEHOLDER,
|
|
34
|
+
"$",
|
|
35
|
+
]),
|
|
36
|
+
).toBe("12345");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it(`doesn't add characters beyond possible characters that can be replaced`, () => {
|
|
40
|
+
expect(removeFormatCharactersFromMaskedString("123456", "###-##")).toBe(
|
|
41
|
+
"12345",
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/formats/index.ts
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import type { FormatType } from
|
|
2
|
-
import { createMaskedNumericFormatter } from
|
|
1
|
+
import type { FormatType } from "@player-ui/player";
|
|
2
|
+
import { createMaskedNumericFormatter } from "./utils";
|
|
3
3
|
|
|
4
|
-
const LENGTH_OF_MAX_INT = String(Number.MAX_SAFE_INTEGER).split(
|
|
4
|
+
const LENGTH_OF_MAX_INT = String(Number.MAX_SAFE_INTEGER).split("").length;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Converts an integer to and from a string for display
|
|
8
8
|
*/
|
|
9
9
|
export const integer: FormatType<number, string> = {
|
|
10
|
-
name:
|
|
10
|
+
name: "integer",
|
|
11
11
|
|
|
12
12
|
/** Converts any integer to a string */
|
|
13
13
|
format: (value) => {
|
|
14
|
-
if (value ===
|
|
14
|
+
if (value === "-") {
|
|
15
15
|
return value;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const formatted = integer.deformat?.(value) ?? value;
|
|
19
19
|
|
|
20
|
-
if (typeof formatted ===
|
|
20
|
+
if (typeof formatted === "number") {
|
|
21
21
|
return String(formatted);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
return
|
|
24
|
+
return "";
|
|
25
25
|
},
|
|
26
26
|
|
|
27
27
|
/** Converts any string or number to an integer */
|
|
28
28
|
deformat: (value) => {
|
|
29
|
-
if (typeof value ===
|
|
29
|
+
if (typeof value === "number") {
|
|
30
30
|
// Handle different zeros. Math.floor(-0) is still -0
|
|
31
31
|
return Math.floor(value) + 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
if (typeof value !==
|
|
34
|
+
if (typeof value !== "string") {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const isNeg = value.replace(/[^0-9.-]/g,
|
|
38
|
+
const isNeg = value.replace(/[^0-9.-]/g, "").charAt(0) === "-";
|
|
39
39
|
|
|
40
40
|
// Remove everything but digits and decimal
|
|
41
|
-
let digits = value.replace(/[^0-9.]/g,
|
|
42
|
-
const decimalPlace = digits.indexOf(
|
|
41
|
+
let digits = value.replace(/[^0-9.]/g, "");
|
|
42
|
+
const decimalPlace = digits.indexOf(".");
|
|
43
43
|
|
|
44
44
|
if (decimalPlace > -1) {
|
|
45
45
|
digits = digits.substring(0, decimalPlace);
|
|
@@ -52,7 +52,7 @@ export const integer: FormatType<number, string> = {
|
|
|
52
52
|
// Can't be longer than the biggest int
|
|
53
53
|
digits = digits.substr(0, LENGTH_OF_MAX_INT);
|
|
54
54
|
|
|
55
|
-
const num = Number(`${isNeg ?
|
|
55
|
+
const num = Number(`${isNeg ? "-" : ""}${digits}`);
|
|
56
56
|
|
|
57
57
|
// Handle different zeros. Math.floor(-0) is still -0
|
|
58
58
|
return Math.floor(num) + 0;
|
|
@@ -68,35 +68,35 @@ export const commaNumber: FormatType<
|
|
|
68
68
|
precision?: number;
|
|
69
69
|
}
|
|
70
70
|
> = {
|
|
71
|
-
name:
|
|
71
|
+
name: "commaNumber",
|
|
72
72
|
|
|
73
73
|
/** Go from number to number w/ commas */
|
|
74
74
|
format: (_value, options) => {
|
|
75
|
-
if (_value === undefined || _value ===
|
|
75
|
+
if (_value === undefined || _value === "") {
|
|
76
76
|
return _value;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (typeof _value !==
|
|
80
|
-
return
|
|
79
|
+
if (typeof _value !== "string" && typeof _value !== "number") {
|
|
80
|
+
return "";
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
const value = String(_value);
|
|
84
84
|
|
|
85
85
|
// Check to see if first valid char is a negative
|
|
86
|
-
const isNeg = value.replace(/[^0-9.-]/g,
|
|
86
|
+
const isNeg = value.replace(/[^0-9.-]/g, "").charAt(0) === "-";
|
|
87
87
|
// Remove everything but digits and decimal
|
|
88
|
-
let digitAndDecimal = value.replace(/[^0-9.]/g,
|
|
88
|
+
let digitAndDecimal = value.replace(/[^0-9.]/g, "");
|
|
89
89
|
// Remove extra leading zeros
|
|
90
|
-
digitAndDecimal = digitAndDecimal.replace(/^(0*)((0.)?\d)/g,
|
|
90
|
+
digitAndDecimal = digitAndDecimal.replace(/^(0*)((0.)?\d)/g, "$2");
|
|
91
91
|
|
|
92
92
|
// Find index of first decimal point, for insertion later
|
|
93
|
-
const firstDecimal = digitAndDecimal.indexOf(
|
|
93
|
+
const firstDecimal = digitAndDecimal.indexOf(".");
|
|
94
94
|
|
|
95
95
|
// Remove all non-digits i.e. extra decimal points
|
|
96
|
-
const digitsOnly = digitAndDecimal.replace(/[^0-9]/g,
|
|
96
|
+
const digitsOnly = digitAndDecimal.replace(/[^0-9]/g, "");
|
|
97
97
|
|
|
98
98
|
let preDecDigits = digitsOnly;
|
|
99
|
-
let postDecDigits =
|
|
99
|
+
let postDecDigits = "";
|
|
100
100
|
|
|
101
101
|
if (firstDecimal >= 0) {
|
|
102
102
|
preDecDigits = digitsOnly
|
|
@@ -110,14 +110,13 @@ export const commaNumber: FormatType<
|
|
|
110
110
|
if (options?.precision !== undefined) {
|
|
111
111
|
postDecDigits = postDecDigits
|
|
112
112
|
.substring(0, options.precision)
|
|
113
|
-
.padEnd(options.precision,
|
|
113
|
+
.padEnd(options.precision, "0");
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
// Beautify
|
|
117
|
-
preDecDigits = preDecDigits.replace(/\B(?=(\d{3})+(?!\d))/g,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
preDecDigits = '0';
|
|
117
|
+
preDecDigits = preDecDigits.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
118
|
+
if (preDecDigits === "" && firstDecimal === 0) {
|
|
119
|
+
preDecDigits = "0";
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
// Put pieces together
|
|
@@ -127,7 +126,10 @@ export const commaNumber: FormatType<
|
|
|
127
126
|
retVal = `-${retVal}`;
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
if (
|
|
129
|
+
if (
|
|
130
|
+
(firstDecimal >= 0 || options?.precision !== undefined) &&
|
|
131
|
+
postDecDigits !== ""
|
|
132
|
+
) {
|
|
131
133
|
retVal += `.${postDecDigits}`;
|
|
132
134
|
}
|
|
133
135
|
|
|
@@ -136,13 +138,13 @@ export const commaNumber: FormatType<
|
|
|
136
138
|
|
|
137
139
|
/** Go from string with comma's to numbers */
|
|
138
140
|
deformat: (value) => {
|
|
139
|
-
if (typeof value !==
|
|
141
|
+
if (typeof value !== "string") {
|
|
140
142
|
return value;
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
const strValue = value.replace(/,/g,
|
|
145
|
+
const strValue = value.replace(/,/g, "");
|
|
144
146
|
|
|
145
|
-
if (strValue ===
|
|
147
|
+
if (strValue === "") {
|
|
146
148
|
return undefined;
|
|
147
149
|
}
|
|
148
150
|
|
|
@@ -164,27 +166,27 @@ export const date: FormatType<
|
|
|
164
166
|
mask?: string;
|
|
165
167
|
}
|
|
166
168
|
> = {
|
|
167
|
-
name:
|
|
169
|
+
name: "date",
|
|
168
170
|
|
|
169
171
|
format: (_value, options) => {
|
|
170
|
-
let value = typeof _value ===
|
|
172
|
+
let value = typeof _value === "number" ? String(_value) : _value;
|
|
171
173
|
if (_value === undefined) {
|
|
172
174
|
return undefined;
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
if (typeof value !==
|
|
176
|
-
return
|
|
177
|
+
if (typeof value !== "string" || value === "") {
|
|
178
|
+
return "";
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
// matching anything in DDDD-DD-DD format, including invalid date like 1111-99-99
|
|
180
182
|
if (value.match(/^\d{4}[-]\d{1,2}[-]\d{1,2}$/)) {
|
|
181
|
-
const tempVal = value.split(
|
|
183
|
+
const tempVal = value.split("-");
|
|
182
184
|
value = `${tempVal[1]}/${tempVal[2]}/${tempVal[0]}`;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
const dateFormat = options?.mask?.toUpperCase() ??
|
|
187
|
+
const dateFormat = options?.mask?.toUpperCase() ?? "MM/DD/YYYY";
|
|
186
188
|
|
|
187
|
-
const delimiter = dateFormat.replace(/[^/.-]/g,
|
|
189
|
+
const delimiter = dateFormat.replace(/[^/.-]/g, "").charAt(0);
|
|
188
190
|
const formatParts = dateFormat.split(delimiter);
|
|
189
191
|
const valueParts = value.split(delimiter);
|
|
190
192
|
const processedValueParts = [];
|
|
@@ -195,18 +197,18 @@ export const date: FormatType<
|
|
|
195
197
|
|
|
196
198
|
if (lastMatchIsFull && index < formatParts.length) {
|
|
197
199
|
// Remove all non-digits
|
|
198
|
-
part = part.replace(/[^0-9]/g,
|
|
200
|
+
part = part.replace(/[^0-9]/g, "");
|
|
199
201
|
const isLastExpectedField = formatParts.length - 1 === index;
|
|
200
202
|
const hasDelimiterAfter = valueParts.length - 1 > index;
|
|
201
203
|
const curFormat = formatParts[index];
|
|
202
204
|
|
|
203
|
-
if (curFormat ===
|
|
205
|
+
if (curFormat === "YYYY") {
|
|
204
206
|
if (part.length > 4) {
|
|
205
207
|
valueParts[index + 1] = [
|
|
206
|
-
|
|
208
|
+
"*",
|
|
207
209
|
part.substring(4),
|
|
208
210
|
valueParts[index + 1],
|
|
209
|
-
].join(
|
|
211
|
+
].join("");
|
|
210
212
|
part = part.substring(0, 4);
|
|
211
213
|
}
|
|
212
214
|
|
|
@@ -239,7 +241,7 @@ export const date: FormatType<
|
|
|
239
241
|
if (
|
|
240
242
|
part.length === 2 &&
|
|
241
243
|
(hasDelimiterAfter ||
|
|
242
|
-
(isLastExpectedField && part !==
|
|
244
|
+
(isLastExpectedField && part !== "19" && part !== "20"))
|
|
243
245
|
) {
|
|
244
246
|
autocomplete = `20${part}`;
|
|
245
247
|
|
|
@@ -263,13 +265,13 @@ export const date: FormatType<
|
|
|
263
265
|
lastMatchIsFull = false;
|
|
264
266
|
processedValueParts.push(part);
|
|
265
267
|
}
|
|
266
|
-
} else if (curFormat ===
|
|
268
|
+
} else if (curFormat === "YY") {
|
|
267
269
|
if (part.length > 2) {
|
|
268
270
|
valueParts[index + 1] = [
|
|
269
|
-
|
|
271
|
+
"*",
|
|
270
272
|
part.substring(2),
|
|
271
273
|
valueParts[index + 1],
|
|
272
|
-
].join(
|
|
274
|
+
].join("");
|
|
273
275
|
part = part.substring(0, 2);
|
|
274
276
|
}
|
|
275
277
|
|
|
@@ -286,10 +288,10 @@ export const date: FormatType<
|
|
|
286
288
|
// Only MM and DD left
|
|
287
289
|
if (part.length > 2) {
|
|
288
290
|
valueParts[index + 1] = [
|
|
289
|
-
|
|
291
|
+
"*",
|
|
290
292
|
part.substring(2),
|
|
291
293
|
valueParts[index + 1],
|
|
292
|
-
].join(
|
|
294
|
+
].join("");
|
|
293
295
|
part = part.substring(0, 2);
|
|
294
296
|
}
|
|
295
297
|
|
|
@@ -297,9 +299,9 @@ export const date: FormatType<
|
|
|
297
299
|
// 00 isn't a valid month or day,
|
|
298
300
|
// but if they typed in a delimiter,
|
|
299
301
|
// let them deal with it being wrong
|
|
300
|
-
if (part ===
|
|
302
|
+
if (part === "00" && !hasDelimiterAfter) {
|
|
301
303
|
lastMatchIsFull = false;
|
|
302
|
-
processedValueParts.push(
|
|
304
|
+
processedValueParts.push("0");
|
|
303
305
|
} else {
|
|
304
306
|
lastMatchIsFull = true;
|
|
305
307
|
processedValueParts.push(part);
|
|
@@ -342,25 +344,25 @@ export const currency: FormatType<
|
|
|
342
344
|
precision?: number;
|
|
343
345
|
}
|
|
344
346
|
> = {
|
|
345
|
-
name:
|
|
347
|
+
name: "currency",
|
|
346
348
|
format: (_value, options) => {
|
|
347
|
-
const value = typeof _value ===
|
|
349
|
+
const value = typeof _value === "number" ? String(_value) : _value;
|
|
348
350
|
const {
|
|
349
|
-
currencySymbol =
|
|
351
|
+
currencySymbol = "",
|
|
350
352
|
useParensForNeg = false,
|
|
351
353
|
precision = 2,
|
|
352
354
|
} = options ?? {};
|
|
353
355
|
|
|
354
|
-
if (value === undefined || value ===
|
|
356
|
+
if (value === undefined || value === "") {
|
|
355
357
|
return value;
|
|
356
358
|
}
|
|
357
359
|
|
|
358
|
-
if (typeof value !==
|
|
360
|
+
if (typeof value !== "string") {
|
|
359
361
|
return value;
|
|
360
362
|
}
|
|
361
363
|
|
|
362
364
|
const sign = /^\s*-/.test(value) ? -1 : 1;
|
|
363
|
-
const dotIndex = value.indexOf(
|
|
365
|
+
const dotIndex = value.indexOf(".");
|
|
364
366
|
|
|
365
367
|
let preDecimal: string;
|
|
366
368
|
let postDecimal: string;
|
|
@@ -368,11 +370,11 @@ export const currency: FormatType<
|
|
|
368
370
|
// Strip out non-digits
|
|
369
371
|
// Check if first non-empty character is a minus sign
|
|
370
372
|
if (dotIndex >= 0) {
|
|
371
|
-
preDecimal = value.substr(0, dotIndex).replace(/\D+/g,
|
|
372
|
-
postDecimal = value.substr(dotIndex + 1).replace(/\D+/g,
|
|
373
|
+
preDecimal = value.substr(0, dotIndex).replace(/\D+/g, "");
|
|
374
|
+
postDecimal = value.substr(dotIndex + 1).replace(/\D+/g, "");
|
|
373
375
|
} else {
|
|
374
|
-
preDecimal = value.replace(/\D+/g,
|
|
375
|
-
postDecimal =
|
|
376
|
+
preDecimal = value.replace(/\D+/g, "");
|
|
377
|
+
postDecimal = "0";
|
|
376
378
|
}
|
|
377
379
|
|
|
378
380
|
const numericalValue = sign * Number(`${preDecimal}.${postDecimal}`);
|
|
@@ -381,9 +383,9 @@ export const currency: FormatType<
|
|
|
381
383
|
|
|
382
384
|
// Beautify - add commas between groups of 3 digits
|
|
383
385
|
// Would need to split the string first if we had more than 3 decimal places
|
|
384
|
-
const prettyString = fixedString.replace(/\B(?=(\d{3})+(?!\d))/g,
|
|
386
|
+
const prettyString = fixedString.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
385
387
|
|
|
386
|
-
if (prettyString.charAt(0) ===
|
|
388
|
+
if (prettyString.charAt(0) === "-") {
|
|
387
389
|
if (useParensForNeg) {
|
|
388
390
|
return `(${currencySymbol}${prettyString.substring(1)})`;
|
|
389
391
|
}
|
|
@@ -394,18 +396,18 @@ export const currency: FormatType<
|
|
|
394
396
|
return currencySymbol + prettyString;
|
|
395
397
|
},
|
|
396
398
|
deformat: (value, options) => {
|
|
397
|
-
if (typeof value ===
|
|
399
|
+
if (typeof value === "number") {
|
|
398
400
|
return value;
|
|
399
401
|
}
|
|
400
402
|
|
|
401
|
-
if (typeof value !==
|
|
403
|
+
if (typeof value !== "string") {
|
|
402
404
|
return undefined;
|
|
403
405
|
}
|
|
404
406
|
|
|
405
407
|
let deformatted = value;
|
|
406
408
|
|
|
407
409
|
if (options?.currencySymbol) {
|
|
408
|
-
deformatted = value.replace(options.currencySymbol,
|
|
410
|
+
deformatted = value.replace(options.currencySymbol, "");
|
|
409
411
|
}
|
|
410
412
|
|
|
411
413
|
return commaNumber.deformat?.(deformatted);
|
|
@@ -413,13 +415,13 @@ export const currency: FormatType<
|
|
|
413
415
|
};
|
|
414
416
|
|
|
415
417
|
const basePhoneFormatter = createMaskedNumericFormatter(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
+
"phone",
|
|
419
|
+
"(###) ###-####",
|
|
418
420
|
);
|
|
419
421
|
|
|
420
422
|
export const phone: FormatType<string> = {
|
|
421
423
|
...basePhoneFormatter,
|
|
422
424
|
deformat: (value) => basePhoneFormatter.deformat?.(value),
|
|
423
425
|
format: (value) =>
|
|
424
|
-
basePhoneFormatter.format?.(value ===
|
|
426
|
+
basePhoneFormatter.format?.(value === "(" ? "" : value) ?? value,
|
|
425
427
|
};
|