@sproutsocial/seeds-react-numeral 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,452 @@
1
+ import testNumeral from "./testNumeral";
2
+
3
+ describe("When using the default precision...", () => {
4
+ describe("... with decimals use up to 2 decimal places", () => {
5
+ // positive values
6
+ testNumeral(
7
+ 1.0,
8
+ {},
9
+ {
10
+ text: "1",
11
+ }
12
+ );
13
+ testNumeral(
14
+ 1.2,
15
+ {},
16
+ {
17
+ text: "1.2",
18
+ }
19
+ );
20
+ testNumeral(
21
+ 0.23,
22
+ {},
23
+ {
24
+ text: "0.23",
25
+ }
26
+ );
27
+ testNumeral(
28
+ 1.235,
29
+ {},
30
+ {
31
+ text: "1.24",
32
+ }
33
+ );
34
+ // negative values
35
+ testNumeral(
36
+ -1.0,
37
+ {},
38
+ {
39
+ text: "-1",
40
+ }
41
+ );
42
+ testNumeral(
43
+ -1.2,
44
+ {},
45
+ {
46
+ text: "-1.2",
47
+ }
48
+ );
49
+ testNumeral(
50
+ -0.23,
51
+ {},
52
+ {
53
+ text: "-0.23",
54
+ }
55
+ );
56
+ testNumeral(
57
+ -1.235,
58
+ {},
59
+ {
60
+ text: "-1.24",
61
+ }
62
+ );
63
+ });
64
+
65
+ describe("... abbreviated decimals always use 2 decimal places", () => {
66
+ // positive values
67
+ testNumeral(
68
+ 10000,
69
+ {},
70
+ {
71
+ text: "10.00K",
72
+ tip: "10,000",
73
+ }
74
+ );
75
+ testNumeral(
76
+ 10109,
77
+ {},
78
+ {
79
+ text: "10.11K",
80
+ tip: "10,109",
81
+ }
82
+ );
83
+ testNumeral(
84
+ 10000.909999,
85
+ {},
86
+ {
87
+ text: "10.00K",
88
+ tip: "10,000.91",
89
+ }
90
+ );
91
+ // negative values
92
+ testNumeral(
93
+ -10000,
94
+ {},
95
+ {
96
+ text: "-10.00K",
97
+ tip: "-10,000",
98
+ }
99
+ );
100
+ testNumeral(
101
+ -10109,
102
+ {},
103
+ {
104
+ text: "-10.11K",
105
+ tip: "-10,109",
106
+ }
107
+ );
108
+ testNumeral(
109
+ -10000.909999,
110
+ {},
111
+ {
112
+ text: "-10.00K",
113
+ tip: "-10,000.91",
114
+ }
115
+ );
116
+ });
117
+
118
+ describe("... with percent use up to 1 decimal places", () => {
119
+ const options = {
120
+ format: "percent",
121
+ };
122
+ // positive values
123
+ testNumeral(1.0, options, {
124
+ text: "1%",
125
+ });
126
+ testNumeral(9.99, options, {
127
+ text: "10%",
128
+ });
129
+ testNumeral(100, options, {
130
+ text: "100%",
131
+ });
132
+ testNumeral(1.2, options, {
133
+ text: "1.2%",
134
+ });
135
+ testNumeral(0.23, options, {
136
+ text: "0.2%",
137
+ });
138
+ testNumeral(1.26789, options, {
139
+ text: "1.3%",
140
+ });
141
+ // negative values
142
+ testNumeral(-1.0, options, {
143
+ text: "-1%",
144
+ });
145
+ testNumeral(-9.99, options, {
146
+ text: "-10%",
147
+ });
148
+ testNumeral(-100, options, {
149
+ text: "-100%",
150
+ });
151
+ testNumeral(-1.2, options, {
152
+ text: "-1.2%",
153
+ });
154
+ testNumeral(-0.23, options, {
155
+ text: "-0.2%",
156
+ });
157
+ testNumeral(-1.26789, options, {
158
+ text: "-1.3%",
159
+ });
160
+ xdescribe("NOTE: This test misbehaves in node/jest!!!", () => {
161
+ // It improperly answers "11.11K", "11,111%"
162
+ testNumeral(11111, options, {
163
+ text: "11.11K%",
164
+ tip: "11,111%",
165
+ });
166
+ });
167
+ });
168
+
169
+ describe("... with current always use 2 decimal places", () => {
170
+ const options = {
171
+ currency: "USD",
172
+ };
173
+ // positive values
174
+ testNumeral(1.0, options, {
175
+ text: "$1.00",
176
+ });
177
+ testNumeral(1234.0, options, {
178
+ text: "$1,234.00",
179
+ });
180
+ testNumeral(123456.98765432, options, {
181
+ text: "$123.46K",
182
+ tip: "$123,456.99",
183
+ });
184
+ // negative values
185
+ testNumeral(-1.0, options, {
186
+ text: "-$1.00",
187
+ });
188
+ testNumeral(-1234.0, options, {
189
+ text: "-$1,234.00",
190
+ });
191
+ testNumeral(-123456.98765432, options, {
192
+ text: "-$123.46K",
193
+ tip: "-$123,456.99",
194
+ });
195
+ });
196
+ });
197
+
198
+ describe("When using a set precision...", () => {
199
+ const options = {
200
+ precision: 4,
201
+ };
202
+
203
+ describe("... with small numbers it should not abbreviate the text", () => {
204
+ // positive values
205
+ testNumeral(1, options, {
206
+ text: "1.0000",
207
+ });
208
+ testNumeral(12, options, {
209
+ text: "12.0000",
210
+ });
211
+ testNumeral(123, options, {
212
+ text: "123.0000",
213
+ });
214
+ testNumeral(1234, options, {
215
+ text: "1,234.0000",
216
+ });
217
+ testNumeral(1234.1, options, {
218
+ text: "1,234.1000",
219
+ });
220
+ testNumeral(1234.0000987, options, {
221
+ text: "1,234.0001",
222
+ });
223
+ // negative values
224
+ testNumeral(-1, options, {
225
+ text: "-1.0000",
226
+ });
227
+ testNumeral(-12, options, {
228
+ text: "-12.0000",
229
+ });
230
+ testNumeral(-123, options, {
231
+ text: "-123.0000",
232
+ });
233
+ testNumeral(-1234, options, {
234
+ text: "-1,234.0000",
235
+ });
236
+ testNumeral(-1234.1, options, {
237
+ text: "-1,234.1000",
238
+ });
239
+ testNumeral(-1234.0000987, options, {
240
+ text: "-1,234.0001",
241
+ });
242
+ });
243
+
244
+ describe("... with big numbers it should round and abbreviate the text", () => {
245
+ // positive values
246
+ testNumeral(12345, options, {
247
+ text: "12.3450K",
248
+ tip: "12,345.0000",
249
+ });
250
+ testNumeral(123456, options, {
251
+ text: "123.4560K",
252
+ tip: "123,456.0000",
253
+ });
254
+ testNumeral(1225000, options, {
255
+ text: "1.2250M",
256
+ tip: "1,225,000.0000",
257
+ });
258
+ testNumeral(1225000000, options, {
259
+ text: "1.2250B",
260
+ tip: "1,225,000,000.0000",
261
+ });
262
+ testNumeral(1225000000000, options, {
263
+ text: "1.2250T",
264
+ tip: "1,225,000,000,000.0000",
265
+ });
266
+ testNumeral(12250000000000000, options, {
267
+ text: "12,250.0000T",
268
+ tip: "12,250,000,000,000,000.0000",
269
+ });
270
+ // negative values
271
+ testNumeral(-12345, options, {
272
+ text: "-12.3450K",
273
+ tip: "-12,345.0000",
274
+ });
275
+ testNumeral(-123456, options, {
276
+ text: "-123.4560K",
277
+ tip: "-123,456.0000",
278
+ });
279
+ testNumeral(-1225000, options, {
280
+ text: "-1.2250M",
281
+ tip: "-1,225,000.0000",
282
+ });
283
+ testNumeral(-1225000000, options, {
284
+ text: "-1.2250B",
285
+ tip: "-1,225,000,000.0000",
286
+ });
287
+ testNumeral(-1225000000000, options, {
288
+ text: "-1.2250T",
289
+ tip: "-1,225,000,000,000.0000",
290
+ });
291
+ testNumeral(-12250000000000000, options, {
292
+ text: "-12,250.0000T",
293
+ tip: "-12,250,000,000,000,000.0000",
294
+ });
295
+ });
296
+
297
+ describe("... with percent", () => {
298
+ const options = {
299
+ precision: 4,
300
+ format: "percent",
301
+ };
302
+ // positive values
303
+ testNumeral(1.0, options, {
304
+ text: "1.0000%",
305
+ });
306
+ testNumeral(1.2, options, {
307
+ text: "1.2000%",
308
+ });
309
+ testNumeral(0.23, options, {
310
+ text: "0.2300%",
311
+ });
312
+ testNumeral(1.26789, options, {
313
+ text: "1.2679%",
314
+ });
315
+ // negative values
316
+ testNumeral(-1.0, options, {
317
+ text: "-1.0000%",
318
+ });
319
+ testNumeral(-1.2, options, {
320
+ text: "-1.2000%",
321
+ });
322
+ testNumeral(-0.23, options, {
323
+ text: "-0.2300%",
324
+ });
325
+ testNumeral(-1.26789, options, {
326
+ text: "-1.2679%",
327
+ });
328
+ });
329
+
330
+ describe("... with currency", () => {
331
+ const options = {
332
+ precision: 4,
333
+ currency: "USD",
334
+ };
335
+ // positive values
336
+ testNumeral(1234.0000987, options, {
337
+ text: "$1,234.0001",
338
+ });
339
+ testNumeral(123456, options, {
340
+ text: "$123.4560K",
341
+ tip: "$123,456.0000",
342
+ });
343
+ // negative values
344
+ testNumeral(-1234.0000987, options, {
345
+ text: "-$1,234.0001",
346
+ });
347
+ testNumeral(-123456, options, {
348
+ text: "-$123.4560K",
349
+ tip: "-$123,456.0000",
350
+ });
351
+ });
352
+ });
353
+
354
+ describe("When using precision 'none' ...", () => {
355
+ const options = {
356
+ precision: "none",
357
+ };
358
+
359
+ describe("... with small numbers it should not abbreviate the text", () => {
360
+ // positive values
361
+ testNumeral(12, options, {
362
+ text: "12",
363
+ });
364
+ testNumeral(1234.0000987, options, {
365
+ text: "1,234.0000987",
366
+ });
367
+ // negative values
368
+ testNumeral(-12, options, {
369
+ text: "-12",
370
+ });
371
+ testNumeral(-1234.0000987, options, {
372
+ text: "-1,234.0000987",
373
+ });
374
+ });
375
+
376
+ describe("... with big numbers it should round and abbreviate the text", () => {
377
+ // positive values
378
+ testNumeral(12345, options, {
379
+ text: "12.35K",
380
+ tip: "12,345",
381
+ });
382
+ testNumeral(123456.98765432, options, {
383
+ text: "123.46K",
384
+ tip: "123,456.98765432",
385
+ });
386
+ // negative values
387
+ testNumeral(-12345, options, {
388
+ text: "-12.35K",
389
+ tip: "-12,345",
390
+ });
391
+ testNumeral(-123456.98765432, options, {
392
+ text: "-123.46K",
393
+ tip: "-123,456.98765432",
394
+ });
395
+ });
396
+
397
+ describe("... with percent", () => {
398
+ const options = {
399
+ precision: "none",
400
+ format: "percent",
401
+ };
402
+ // positive values
403
+ testNumeral(1.0, options, {
404
+ text: "1%",
405
+ });
406
+ testNumeral(1.2, options, {
407
+ text: "1.2%",
408
+ });
409
+ testNumeral(0.23, options, {
410
+ text: "0.23%",
411
+ });
412
+ testNumeral(1.26789, options, {
413
+ text: "1.26789%",
414
+ });
415
+ // negative values
416
+ testNumeral(-1.0, options, {
417
+ text: "-1%",
418
+ });
419
+ testNumeral(-1.2, options, {
420
+ text: "-1.2%",
421
+ });
422
+ testNumeral(-0.23, options, {
423
+ text: "-0.23%",
424
+ });
425
+ testNumeral(-1.26789, options, {
426
+ text: "-1.26789%",
427
+ });
428
+ });
429
+
430
+ describe("... with currency", () => {
431
+ const options = {
432
+ precision: "none",
433
+ currency: "USD",
434
+ };
435
+ // positive values
436
+ testNumeral(1234.0, options, {
437
+ text: "$1,234",
438
+ });
439
+ testNumeral(123456.98765432, options, {
440
+ text: "$123.46K",
441
+ tip: "$123,456.98765432",
442
+ });
443
+ // negative values
444
+ testNumeral(-1234.0, options, {
445
+ text: "-$1,234",
446
+ });
447
+ testNumeral(-123456.98765432, options, {
448
+ text: "-$123.46K",
449
+ tip: "-$123,456.98765432",
450
+ });
451
+ });
452
+ });
@@ -0,0 +1,82 @@
1
+ /* eslint-env jest, node */
2
+ import React from "react";
3
+ import {
4
+ render,
5
+ fireEvent,
6
+ screen,
7
+ } from "@sproutsocial/seeds-react-testing-library";
8
+ import Numeral, { formatNumeral } from "../../Numeral";
9
+
10
+ jest.mock("../../constants.ts", () => ({
11
+ ...jest.requireActual("../../constants.ts"),
12
+ MEMO_CACHE_SIZE: 0,
13
+ COMPARE_OBJECTS: false,
14
+ }));
15
+
16
+ interface NumeralOptions {
17
+ [key: string]: any;
18
+ }
19
+
20
+ interface NumeralTexts {
21
+ text: string | RegExp;
22
+ tip?: string;
23
+ label?: string;
24
+ format?: string;
25
+ }
26
+
27
+ const testNumeral = (
28
+ value: number | undefined | null,
29
+ options: NumeralOptions = {},
30
+ texts: NumeralTexts
31
+ ) => {
32
+ const {
33
+ text: mainText,
34
+ tip: tooltipText,
35
+ label: labelText,
36
+ format: formatText,
37
+ } = texts;
38
+
39
+ if (tooltipText) {
40
+ test(`Should display ${value} abbreviated as -> ${mainText} with tooltip -> ${tooltipText} `, async () => {
41
+ const { container } = render(<Numeral number={value} {...options} />);
42
+ const numeral = screen.getByText(mainText);
43
+ const tooltip = container.querySelector("[data-qa-tooltip]");
44
+ fireEvent.mouseOver(numeral);
45
+ const content = await screen.findByText(tooltipText);
46
+ expect(numeral).toBeInTheDocument();
47
+ expect(tooltip).toBeTruthy();
48
+ expect(content).toBeInTheDocument();
49
+
50
+ // formatNumeral test
51
+ if (formatText) {
52
+ expect(formatNumeral({ number: value, ...options })).toEqual(
53
+ formatText
54
+ );
55
+ } else {
56
+ expect(formatNumeral({ number: value, ...options })).toEqual(mainText);
57
+ }
58
+ });
59
+ } else {
60
+ test(`Should display ${value} as -> ${mainText} with no tooltip `, () => {
61
+ const { container } = render(<Numeral number={value} {...options} />);
62
+ const numeral = screen.getByText(mainText);
63
+ const tooltip = container.querySelector("[data-qa-tooltip]");
64
+ expect(numeral).toBeInTheDocument();
65
+ expect(tooltip).toBeFalsy();
66
+ if (labelText) {
67
+ expect(screen.getByText(labelText)).toBeInTheDocument();
68
+ }
69
+
70
+ // formatNumeral test
71
+ if (formatText) {
72
+ expect(formatNumeral({ number: value, ...options })).toEqual(
73
+ formatText
74
+ );
75
+ } else {
76
+ expect(formatNumeral({ number: value, ...options })).toEqual(mainText);
77
+ }
78
+ });
79
+ }
80
+ };
81
+
82
+ export default testNumeral;
@@ -0,0 +1,51 @@
1
+ import testNumeral from "./testNumeral";
2
+
3
+ describe("When using a zero value...", () => {
4
+ describe("... it renders properly", () => {
5
+ testNumeral(
6
+ 0.0,
7
+ {},
8
+ {
9
+ text: "0",
10
+ }
11
+ );
12
+ testNumeral(
13
+ 0,
14
+ {
15
+ format: "percent",
16
+ },
17
+ {
18
+ text: "0%",
19
+ }
20
+ );
21
+ testNumeral(
22
+ 0,
23
+ {
24
+ format: "percent",
25
+ precision: 1,
26
+ },
27
+ {
28
+ text: "0.0%",
29
+ }
30
+ );
31
+ testNumeral(
32
+ 0,
33
+ {
34
+ currency: "USD",
35
+ },
36
+ {
37
+ text: "$0.00",
38
+ }
39
+ );
40
+ testNumeral(
41
+ 0,
42
+ {
43
+ currency: "USD",
44
+ precision: 0,
45
+ },
46
+ {
47
+ text: "$0",
48
+ }
49
+ );
50
+ });
51
+ });
@@ -0,0 +1,16 @@
1
+ import type { EnumNumeralFormat } from "./NumeralTypes";
2
+
3
+ export const DEFAULT_THRESHOLD = 10000;
4
+ export const MEMO_CACHE_SIZE = 10;
5
+ export const COMPARE_OBJECTS = true;
6
+ export const MAX_PRECISION = 20;
7
+ export const ABBREV_PRECISION = 2;
8
+ export const DefaultPrecisions: {
9
+ [key in EnumNumeralFormat]: [number, number];
10
+ } = {
11
+ decimal: [0, 2],
12
+ percent: [0, 1],
13
+ currency: [2, 2],
14
+ };
15
+
16
+ export const EM_DASH = "—"; // shift + option + hyphen on a mac keyboard
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import Numeral, { formatNumeral } from "./Numeral";
2
+
3
+ export default Numeral;
4
+ export { Numeral };
5
+ export { formatNumeral };
6
+ export * from "./NumeralTypes";
@@ -0,0 +1,7 @@
1
+ import "styled-components";
2
+ import { TypeTheme } from "@sproutsocial/seeds-react-theme";
3
+
4
+ declare module "styled-components" {
5
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
6
+ export interface DefaultTheme extends TypeTheme {}
7
+ }
package/src/styles.ts ADDED
@@ -0,0 +1,12 @@
1
+ import styled from "styled-components";
2
+ import Text from "@sproutsocial/seeds-react-text";
3
+
4
+ export const Container = styled(Text)`
5
+ font-variant-numeric: tabular-nums;
6
+ `;
7
+
8
+ export const AbbrContainer = styled(Text)`
9
+ font-variant-numeric: tabular-nums;
10
+ border-bottom: 1px dotted
11
+ ${(props) => props.theme.colors.container.border.base};
12
+ `;
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "@sproutsocial/seeds-tsconfig/bundler/dom/library-monorepo",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "module": "esnext"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist", "coverage"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig((options) => ({
4
+ entry: ["src/index.ts"],
5
+ format: ["cjs", "esm"],
6
+ clean: true,
7
+ legacyOutput: true,
8
+ dts: options.dts,
9
+ external: ["react"],
10
+ sourcemap: true,
11
+ metafile: options.metafile,
12
+ }));