@rango-dev/charts 0.0.0-experimental-936229e8-20251208

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/charts.build.json +1 -0
  3. package/dist/components/BarChart/BarChart.constants.d.ts +17 -0
  4. package/dist/components/BarChart/BarChart.constants.d.ts.map +1 -0
  5. package/dist/components/BarChart/BarChart.d.ts +4 -0
  6. package/dist/components/BarChart/BarChart.d.ts.map +1 -0
  7. package/dist/components/BarChart/BarChart.helpers.d.ts +12 -0
  8. package/dist/components/BarChart/BarChart.helpers.d.ts.map +1 -0
  9. package/dist/components/BarChart/BarChart.styles.d.ts +8 -0
  10. package/dist/components/BarChart/BarChart.styles.d.ts.map +1 -0
  11. package/dist/components/BarChart/BarChart.types.d.ts +49 -0
  12. package/dist/components/BarChart/BarChart.types.d.ts.map +1 -0
  13. package/dist/components/BarChart/index.d.ts +4 -0
  14. package/dist/components/BarChart/index.d.ts.map +1 -0
  15. package/dist/hooks/useIsMobile.d.ts +3 -0
  16. package/dist/hooks/useIsMobile.d.ts.map +1 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +7 -0
  21. package/dist/utils/amountConverter.d.ts +5 -0
  22. package/dist/utils/amountConverter.d.ts.map +1 -0
  23. package/dist/utils/common.d.ts +3 -0
  24. package/dist/utils/common.d.ts.map +1 -0
  25. package/package.json +41 -0
  26. package/readme.md +4 -0
  27. package/src/components/BarChart/BarChart.constants.ts +40 -0
  28. package/src/components/BarChart/BarChart.helpers.ts +153 -0
  29. package/src/components/BarChart/BarChart.styles.ts +55 -0
  30. package/src/components/BarChart/BarChart.tsx +401 -0
  31. package/src/components/BarChart/BarChart.types.ts +50 -0
  32. package/src/components/BarChart/index.ts +10 -0
  33. package/src/hooks/useIsMobile.ts +20 -0
  34. package/src/index.ts +8 -0
  35. package/src/utils/amountConverter.ts +47 -0
  36. package/src/utils/common.ts +22 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,98 @@
1
+ # [0.20.0](https://github.com/rango-exchange/rango-client/compare/charts@0.19.1...charts@0.20.0) (2025-12-02)
2
+
3
+
4
+
5
+ ## [0.19.1](https://github.com/rango-exchange/rango-client/compare/charts@0.19.0...charts@0.19.1) (2025-11-22)
6
+
7
+
8
+
9
+ # [0.17.0](https://github.com/rango-exchange/rango-client/compare/charts@0.16.0...charts@0.17.0) (2025-10-29)
10
+
11
+
12
+
13
+ # [0.16.0](https://github.com/rango-exchange/rango-client/compare/charts@0.15.0...charts@0.16.0) (2025-09-29)
14
+
15
+
16
+
17
+ # [0.15.0](https://github.com/rango-exchange/rango-client/compare/charts@0.14.0...charts@0.15.0) (2025-09-06)
18
+
19
+
20
+
21
+ # [0.14.0](https://github.com/rango-exchange/rango-client/compare/charts@0.13.0...charts@0.14.0) (2025-08-27)
22
+
23
+
24
+
25
+ # [0.13.0](https://github.com/rango-exchange/rango-client/compare/charts@0.12.0...charts@0.13.0) (2025-08-19)
26
+
27
+
28
+
29
+ # [0.12.0](https://github.com/rango-exchange/rango-client/compare/charts@0.11.0...charts@0.12.0) (2025-08-05)
30
+
31
+
32
+
33
+ # [0.11.0](https://github.com/rango-exchange/rango-client/compare/charts@0.10.0...charts@0.11.0) (2025-07-22)
34
+
35
+
36
+ ### Reverts
37
+
38
+ * Revert "chore(release): publish" ([064ce15](https://github.com/rango-exchange/rango-client/commit/064ce157a2f819856f647f83aeb1c0410542e8d7))
39
+
40
+
41
+
42
+ # [0.9.0](https://github.com/rango-exchange/rango-client/compare/charts@0.8.1...charts@0.9.0) (2025-06-09)
43
+
44
+
45
+ ### Bug Fixes
46
+
47
+ * if data exceed 90 days, bottom axis should be shown correctly ([34c0606](https://github.com/rango-exchange/rango-client/commit/34c0606986b72aab97e5174a9bce2f1e1e5a159a))
48
+
49
+
50
+
51
+ ## [0.8.1](https://github.com/rango-exchange/rango-client/compare/charts@0.8.0...charts@0.8.1) (2025-05-04)
52
+
53
+
54
+
55
+ # [0.8.0](https://github.com/rango-exchange/rango-client/compare/charts@0.7.0...charts@0.8.0) (2025-04-30)
56
+
57
+
58
+
59
+ # [0.7.0](https://github.com/rango-exchange/rango-client/compare/charts@0.6.0...charts@0.7.0) (2025-03-11)
60
+
61
+
62
+
63
+ # [0.6.0](https://github.com/rango-exchange/rango-client/compare/charts@0.5.0...charts@0.6.0) (2025-02-23)
64
+
65
+
66
+
67
+ # [0.5.0](https://github.com/rango-exchange/rango-client/compare/charts@0.4.0...charts@0.5.0) (2024-12-30)
68
+
69
+
70
+
71
+ # [0.4.0](https://github.com/rango-exchange/rango-client/compare/charts@0.3.0...charts@0.4.0) (2024-11-27)
72
+
73
+
74
+
75
+ # [0.3.0](https://github.com/rango-exchange/rango-client/compare/charts@0.2.0...charts@0.3.0) (2024-11-12)
76
+
77
+
78
+ ### Bug Fixes
79
+
80
+ * improve y-axis display for bar charts with smaller data sets ([ad13491](https://github.com/rango-exchange/rango-client/commit/ad1349157f38d172ae2028981881ae4276ddab8d))
81
+
82
+
83
+
84
+ # 0.2.0 (2024-10-12)
85
+
86
+
87
+ ### Bug Fixes
88
+
89
+ * add chart icon and handle dark theme in BarChart component ([fd4f246](https://github.com/rango-exchange/rango-client/commit/fd4f24684e42deb1b47fb9a6584ac4f9a1519599))
90
+ * add prepare data function for chart package ([a9f8c6b](https://github.com/rango-exchange/rango-client/commit/a9f8c6b092ca5343756e220238c943dbc369a62b))
91
+
92
+
93
+ ### Features
94
+
95
+ * add chart package ([f5ae7e4](https://github.com/rango-exchange/rango-client/commit/f5ae7e449ec1e385188ff904e9d59862fa8ef1d2))
96
+
97
+
98
+
@@ -0,0 +1 @@
1
+ {"inputs":{"src/hooks/useIsMobile.ts":{"bytes":494,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/utils/amountConverter.ts":{"bytes":1092,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/utils/common.ts":{"bytes":381,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/components/BarChart/BarChart.constants.ts":{"bytes":1033,"imports":[],"format":"esm"},"src/components/BarChart/BarChart.helpers.ts":{"bytes":4337,"imports":[{"path":"src/components/BarChart/BarChart.constants.ts","kind":"import-statement","original":"./BarChart.constants.js"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/components/BarChart/BarChart.styles.ts":{"bytes":1117,"imports":[{"path":"@rango-dev/ui","kind":"import-statement","external":true}],"format":"esm"},"src/components/BarChart/BarChart.tsx":{"bytes":11717,"imports":[{"path":"@rango-dev/ui","kind":"import-statement","external":true},{"path":"@visx/axis","kind":"import-statement","external":true},{"path":"@visx/event","kind":"import-statement","external":true},{"path":"@visx/grid","kind":"import-statement","external":true},{"path":"@visx/group","kind":"import-statement","external":true},{"path":"@visx/scale","kind":"import-statement","external":true},{"path":"@visx/shape","kind":"import-statement","external":true},{"path":"@visx/tooltip","kind":"import-statement","external":true},{"path":"dayjs","kind":"import-statement","external":true},{"path":"dayjs/plugin/utc.js","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/hooks/useIsMobile.ts","kind":"import-statement","original":"../../hooks/useIsMobile.js"},{"path":"src/utils/amountConverter.ts","kind":"import-statement","original":"../../utils/amountConverter.js"},{"path":"src/utils/common.ts","kind":"import-statement","original":"../../utils/common.js"},{"path":"src/components/BarChart/BarChart.constants.ts","kind":"import-statement","original":"./BarChart.constants.js"},{"path":"src/components/BarChart/BarChart.helpers.ts","kind":"import-statement","original":"./BarChart.helpers.js"},{"path":"src/components/BarChart/BarChart.styles.ts","kind":"import-statement","original":"./BarChart.styles.js"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/components/BarChart/index.ts":{"bytes":248,"imports":[{"path":"src/components/BarChart/BarChart.tsx","kind":"import-statement","original":"./BarChart.js"},{"path":"src/components/BarChart/BarChart.helpers.ts","kind":"import-statement","original":"./BarChart.helpers.js"}],"format":"esm"},"src/index.ts":{"bytes":235,"imports":[{"path":"src/components/BarChart/index.ts","kind":"import-statement","original":"./components/BarChart/index.js"}],"format":"esm"}},"outputs":{"dist/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":33657},"dist/index.js":{"imports":[{"path":"@rango-dev/ui","kind":"import-statement","external":true},{"path":"@visx/axis","kind":"import-statement","external":true},{"path":"@visx/event","kind":"import-statement","external":true},{"path":"@visx/grid","kind":"import-statement","external":true},{"path":"@visx/group","kind":"import-statement","external":true},{"path":"@visx/scale","kind":"import-statement","external":true},{"path":"@visx/shape","kind":"import-statement","external":true},{"path":"@visx/tooltip","kind":"import-statement","external":true},{"path":"dayjs","kind":"import-statement","external":true},{"path":"dayjs/plugin/utc.js","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@rango-dev/ui","kind":"import-statement","external":true}],"exports":["BarChart","prepareBarChartData"],"entryPoint":"src/index.ts","inputs":{"src/components/BarChart/BarChart.tsx":{"bytesInOutput":3977},"src/hooks/useIsMobile.ts":{"bytesInOutput":269},"src/utils/amountConverter.ts":{"bytesInOutput":318},"src/utils/common.ts":{"bytesInOutput":129},"src/components/BarChart/BarChart.constants.ts":{"bytesInOutput":566},"src/components/BarChart/BarChart.helpers.ts":{"bytesInOutput":1285},"src/components/BarChart/BarChart.styles.ts":{"bytesInOutput":756},"src/components/BarChart/index.ts":{"bytesInOutput":0},"src/index.ts":{"bytesInOutput":0}},"bytes":7464}}}
@@ -0,0 +1,17 @@
1
+ import type { BottomAxisData } from './BarChart.types.js';
2
+ export declare const DEFAULT_MARGIN: {
3
+ top: number;
4
+ right: number;
5
+ bottom: number;
6
+ left: number;
7
+ };
8
+ export declare const TOOLTIP_DELAY_MS = 100;
9
+ export declare const TOOLTIP_HIDE_DELAY_MS = 300;
10
+ export declare const DEFAULT_CHART_COLORS: string[];
11
+ export declare const bottomAxisData: {
12
+ [key: string]: {
13
+ [key: number]: BottomAxisData;
14
+ };
15
+ };
16
+ export declare const MAX_BAR_BUCKETS = 10;
17
+ //# sourceMappingURL=BarChart.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.constants.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/BarChart.constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,cAAc;;;;;CAA6C,CAAC;AAEzE,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAaxC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC;KAC/B,CAAC;CAYH,CAAC;AAEF,eAAO,MAAM,eAAe,KAAK,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { BarChartPropTypes } from './BarChart.types.js';
2
+ import React from 'react';
3
+ export declare const BarChart: (props: BarChartPropTypes) => React.JSX.Element | null;
4
+ //# sourceMappingURL=BarChart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/BarChart.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,qBAAqB,CAAC;AAa7B,OAAO,KAAsC,MAAM,OAAO,CAAC;AAmC3D,eAAO,MAAM,QAAQ,UAAW,iBAAiB,6BA0VhD,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { BarStackDataType, ChartOptionsType, ColorBucketMapType } from './BarChart.types.js';
2
+ export declare const getTotalValueDates: (data: BarStackDataType[], buckets: string[]) => number[];
3
+ export declare const generateTickValues: (dates: string[], start: number, interval: number) => string[];
4
+ export declare const getTotalValue: (dataColumn: BarStackDataType) => number;
5
+ export declare const getDaysRange: (lengthValue: number) => 7 | 30 | 90;
6
+ export declare const prepareBarChartData: (chartOption: ChartOptionsType) => {
7
+ chartData: BarStackDataType[];
8
+ colorBucketMap: ColorBucketMapType;
9
+ buckets: string[];
10
+ };
11
+ export declare const getEvenlySpacedNumber: (max: number, count: number) => number;
12
+ //# sourceMappingURL=BarChart.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.helpers.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/BarChart.helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AAI7B,eAAO,MAAM,kBAAkB,SACvB,gBAAgB,EAAE,WACf,MAAM,EAAE,aAclB,CAAC;AAGF,eAAO,MAAM,kBAAkB,UACtB,MAAM,EAAE,SACR,MAAM,YACH,MAAM,aAOjB,CAAC;AAEF,eAAO,MAAM,aAAa,eAAgB,gBAAgB,WAWzD,CAAC;AAEF,eAAO,MAAM,YAAY,gBAAiB,MAAM,gBAQ/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,gBAAiB,gBAAgB;;;;CAmFhE,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAS,MAAM,SAAS,MAAM,WAG/D,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const Container: any;
2
+ export declare const TooltipContainer: any;
3
+ export declare const TooltipInfoRow: any;
4
+ export declare const Line: any;
5
+ export declare const InfoContainer: any;
6
+ export declare const Circle: any;
7
+ export declare const NameWrapper: any;
8
+ //# sourceMappingURL=BarChart.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.styles.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/BarChart.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,KAEpB,CAAC;AAEH,eAAO,MAAM,gBAAgB,KAW3B,CAAC;AAEH,eAAO,MAAM,cAAc,KAQzB,CAAC;AAEH,eAAO,MAAM,IAAI,KAIf,CAAC;AAEH,eAAO,MAAM,aAAa,KAOxB,CAAC;AAEH,eAAO,MAAM,MAAM,KAIjB,CAAC;AAEH,eAAO,MAAM,WAAW,KAItB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import type { SeriesPoint } from '@visx/shape/lib/types/barStack.js';
2
+ export interface BarChartPropTypes {
3
+ data: BarStackDataType[];
4
+ width: number;
5
+ height: number;
6
+ colorBucketMap: ColorBucketMapType;
7
+ buckets: string[];
8
+ margin?: {
9
+ top: number;
10
+ right: number;
11
+ bottom: number;
12
+ left: number;
13
+ };
14
+ getLabel?: (value: string) => string;
15
+ isDarkTheme?: boolean;
16
+ }
17
+ export type BarStackDataType = {
18
+ [key: string]: string;
19
+ };
20
+ export type ColorBucketMapType = Map<string, string>;
21
+ export type TooltipDataType = {
22
+ bar: {
23
+ bar: SeriesPoint<BarStackDataType>;
24
+ key: string;
25
+ index: number;
26
+ height: number;
27
+ width: number;
28
+ x: number;
29
+ y: number;
30
+ color: string;
31
+ };
32
+ hoveredIndex: number;
33
+ };
34
+ export type DailyDataType = {
35
+ date: string;
36
+ bucket: string;
37
+ value: number;
38
+ };
39
+ export type ChartOptionsType = {
40
+ dailyData: DailyDataType[];
41
+ barChartColors: string[];
42
+ label?: string;
43
+ };
44
+ export interface BottomAxisData {
45
+ numBottomAxis: number;
46
+ startBottomAxis: number;
47
+ intervalBottomAxis: number;
48
+ }
49
+ //# sourceMappingURL=BarChart.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.types.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/BarChart.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,kBAAkB,CAAC;IACnC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE;QACH,GAAG,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;QACnC,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,4 @@
1
+ export { BarChart } from './BarChart.js';
2
+ export { prepareBarChartData } from './BarChart.helpers.js';
3
+ export type { BarStackDataType, ColorBucketMapType, BarChartPropTypes, ChartOptionsType, DailyDataType, } from './BarChart.types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/BarChart/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const useIsMobile: () => boolean;
2
+ export default useIsMobile;
3
+ //# sourceMappingURL=useIsMobile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIsMobile.d.ts","sourceRoot":"","sources":["../../src/hooks/useIsMobile.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,WAAW,eAehB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { BarStackDataType, ColorBucketMapType, BarChartPropTypes, ChartOptionsType, DailyDataType, } from './components/BarChart/index.js';
2
+ export { BarChart, prepareBarChartData } from './components/BarChart/index.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var kt=Object.defineProperty;var r=(t,e)=>kt(t,"name",{value:e,configurable:!0});import{Divider as st}from"@rango-dev/ui";import{AxisBottom as Mt,AxisLeft as Et}from"@visx/axis";import{localPoint as lt}from"@visx/event";import{Grid as Lt}from"@visx/grid";import{Group as Nt}from"@visx/group";import{scaleBand as wt,scaleLinear as Ot,scaleOrdinal as Ft}from"@visx/scale";import{BarStack as It}from"@visx/shape";import{TooltipWithBounds as $t,useTooltip as _t}from"@visx/tooltip";import pt from"dayjs";import Pt from"dayjs/plugin/utc.js";import a,{Fragment as Vt,useEffect as zt,useRef as Gt}from"react";import{useEffect as At,useState as Dt}from"react";var Ct=r(()=>{let[t,e]=Dt(!1);return At(()=>{let o=r(()=>{e(window.innerWidth<=640)},"handleResize");return o(),window.addEventListener("resize",o),()=>window.removeEventListener("resize",o)},[]),t},"useIsMobile"),G=Ct;var vt=["","K","M","B"];function O(t){let e=Math.sign(t),o=0;for(;Math.abs(t)>1e3;)o=o+1,t=Math.floor(Math.abs(t)/10)/100;return e*Math.abs(t)+vt[o]}r(O,"AmountConverter");function H(t){return!t||isNaN(t)?"0":Intl.NumberFormat("en-US",{notation:"compact",maximumFractionDigits:1}).format(t)}r(H,"compactNumberFormat");function U(t){let e=new Date(t),o=e.toLocaleDateString("en-US",{month:"short"});return`${e.getDate()} ${o}`}r(U,"getDayOfMonth");var j={top:40,right:0,bottom:0,left:20},R=100,W=300,Y=["#469BF5","#29DABA","#D629DA","#4658F5","#9DF546","#F01DA8","#FF8B66","#44F1E6","#29DA7A","#F17606","#8B62FF","#F4C932"],F={desktop:{7:{numBottomAxis:7,startBottomAxis:0,intervalBottomAxis:1},30:{numBottomAxis:6,startBottomAxis:4,intervalBottomAxis:5},90:{numBottomAxis:8,startBottomAxis:5,intervalBottomAxis:10}},mobile:{7:{numBottomAxis:3,startBottomAxis:1,intervalBottomAxis:2},30:{numBottomAxis:3,startBottomAxis:3,intervalBottomAxis:10},90:{numBottomAxis:3,startBottomAxis:10,intervalBottomAxis:30}}},E=10;var J=r((t,e)=>t.reduce((p,m)=>{let B=e.reduce((l,h)=>(l+=isNaN(Number(m[h]))?0:Number(m[h]),l),0);return p.push(B),p},[]),"getTotalValueDates"),K=r((t,e,o)=>{let p=[];for(let m=e;m<t.length;m+=o)p.push(t[m]);return p},"generateTickValues"),X=r(t=>{let e=0;return Object.keys(t).forEach(o=>{if(o!=="date"){let p=t[o];isNaN(Number(p))||(e+=Number(p))}}),e},"getTotalValue"),q=r(t=>t<15?7:t<50?30:90,"getDaysRange"),Q=r(t=>{let{dailyData:e,label:o="Count"}=t,p=[],m=new Map,B=[],{barChartColors:l}=t,h=new Map;e.forEach(i=>{let f=i.bucket||o,g=h.get(f)||0,c=i.value;h.set(f,g+c)});let d=Array.from(h).sort((i,f)=>f[1]-i[1]).map(i=>i[0]).slice(0,E),k=h.size;d.forEach((i,f)=>{m.set(i,l[f%l.length]),B.push(i)}),k>E&&(m.set("Others",l[l.length-1]),B.push("Others"));let b=new Map;return e.forEach(i=>{b.has(i.date)||b.set(i.date,[]),b.get(i.date)?.push(i)}),b.forEach((i,f)=>{let g={date:f};if(i.filter(c=>d.includes(c.bucket||o)).forEach(c=>{let T=c.value;g[c.bucket||o]=T?T.toString():"0"}),d.forEach(c=>{c in g||(g[c]="0")}),k>E){let T=i.filter(y=>y.bucket&&!d.includes(y.bucket)).map(y=>y.value).reduce((y,v)=>y+v,0);g.Others=T.toString()}p.push(g)}),{chartData:p,colorBucketMap:m,buckets:B}},"prepareBarChartData"),Z=r((t,e)=>{let o=t/e;return Math.round(o)},"getEvenlySpacedNumber");import{darkTheme as St,styled as C}from"@rango-dev/ui";var tt=C("div",{position:"relative"}),et=C("div",{width:165,borderRadius:"$sm",backgroundColor:"$background",$$color:"$colors$neutral500",[`.${St} &`]:{$$color:"$colors$neutral100"},boxShadow:"0px 5px 20px 0px $$color"}),ot=C("div",{display:"flex",alignItems:"center",fontSize:"$12",justifyContent:"space-between",padding:"$8 $10",fontWeight:"$medium",color:"$foreground"}),rt=C("div",{height:1,width:"100%",backgroundColor:"$neutral300"}),at=C("div",{display:"flex",alignItems:"center",justifyContent:"space-between",fontSize:"$10",padding:"$5 $10",color:"$foreground"}),nt=C("div",{width:"$6",height:"$6",borderRadius:3}),it=C("div",{display:"flex",alignItems:"center",justifyContent:"flex-start"});pt.extend(Pt);var ct=r(t=>{let{data:e,width:o,height:p,colorBucketMap:m,buckets:B,margin:l=j,getLabel:h,isDarkTheme:L=!1}=t,d=G(),k=q(e.length),b;if(e.length>90){let n=Z(e.length,7);b={numBottomAxis:7,intervalBottomAxis:n,startBottomAxis:n-10}}else b=o<700?F.mobile[k]:F.desktop[k];let{intervalBottomAxis:i,numBottomAxis:f,startBottomAxis:g}=b,c,T=Gt(null),y=o-l.left-20,v=p-l.top-30,N=r(s=>s.date,"getDate"),ut=e.map(N),mt=K(ut,g,i),{tooltipOpen:I,tooltipLeft:dt,tooltipTop:ht,tooltipData:A,hideTooltip:$,showTooltip:_}=_t(),ft=J(e,B),S=wt({domain:e.map(N),paddingInner:k===7?.3:.46,paddingOuter:k===90?1:.3}),P=Math.max(...ft),V=P+P/5,M=Ot({domain:[0,V<.5?.5:V],nice:!0}),xt=Ft({domain:B,range:Y});if(zt(()=>{function s(n){d&&T?.current&&!T.current.contains(n.target)&&$()}return r(s,"handleClickOutside"),document.addEventListener("click",s,!0),()=>{document.removeEventListener("click",s,!0)}},[T,d]),S.range([0,y]),M.range([v,0]),o<10)return null;let Bt=r((s,n,u)=>{if(d){c&&clearTimeout(c);let x=lt(s),D=n.x+n.width/2;setTimeout(()=>{_({tooltipData:{bar:n,hoveredIndex:u},tooltipTop:x?.y,tooltipLeft:D})},R)}},"handleBarClick"),gt=r(()=>{d||(c=window.setTimeout(()=>{$()},W))},"handleMouseLeave"),Tt=r((s,n,u)=>{if(!d){c&&clearTimeout(c);let x=lt(s),D=n.x+n.width/2+40;_({tooltipData:{bar:n,hoveredIndex:u},tooltipTop:x?.y,tooltipLeft:D})}},"handleMouseMove"),z=r(s=>O(Number(X(s).toFixed(2))),"getFormattedTotalValue");return a.createElement(tt,null,a.createElement("svg",{width:o,height:p},a.createElement("rect",{x:0,y:0,width:o,height:p,fill:"transparent",rx:14}),a.createElement(Lt,{top:l.top,left:l.left+10,xScale:S,yScale:M,width:y,height:v,stroke:"black",strokeOpacity:.1,numTicksRows:5,numTicksColumns:0,columnLineStyle:{display:"none"},rowLineStyle:{stroke:"#B8B8B8"}}),a.createElement(Nt,{top:l.top,left:l.left+10},a.createElement(It,{data:e,keys:B,x:N,xScale:S,yScale:M,color:xt},s=>s.map(n=>n.bars.map((u,x)=>{let yt=!(A?.hoveredIndex===x)&&I,bt=m.get(n.key)||u.color;return a.createElement("rect",{key:`bar-stack-${n.index}-${u.index}`,x:u.x,y:u.y,height:u.height,width:u.width,fill:bt,opacity:yt?.5:1,onClick:w=>Bt(w,u,x),onMouseLeave:gt,onMouseMove:w=>Tt(w,u,x)})})))),a.createElement(Mt,{top:v+l.top,left:l.left+10,scale:S,hideAxisLine:!0,hideTicks:!0,numTicks:f,tickValues:mt,tickFormat:s=>U(s),tickLabelProps:()=>({fontSize:d?10:12,fill:L?"#B8B8B8":"#A2A2A2",textAnchor:"middle"})}),a.createElement(Et,{hideAxisLine:!0,hideTicks:!0,numTicks:d?3:5,top:l.top,left:l.left,scale:M,tickFormat:s=>H(Number(s)),tickLabelProps:()=>({fontSize:d?10:12,fill:L?"#B8B8B8":"#A2A2A2",textAnchor:"middle"})})),A&&I&&a.createElement($t,{top:ht,left:dt,style:{backgroundColor:"transparent",boxShadow:"none",position:"absolute",zIndex:"99999999"}},a.createElement(et,{ref:T},A?.bar.bar.data.date&&a.createElement(ot,null,a.createElement("div",null,pt.utc(A.bar.bar.data.date).local().format("YYYY/MM/DD").toString()),a.createElement("div",null,h?h(z(A.bar.bar.data)):z(A.bar.bar.data))),Array.from(m).map(s=>{let[n,u]=s,x=A?.bar.bar.data[n],D=isNaN(Number(x))?"0":O(Number(Number(x).toFixed(2)));return a.createElement(Vt,{key:n},a.createElement(rt,null),a.createElement(at,null,a.createElement(it,null,a.createElement(nt,{style:{backgroundColor:u}}),a.createElement(st,{direction:"horizontal",size:"4"}),a.createElement("span",null,n)),a.createElement(st,{direction:"horizontal",size:"10"}),a.createElement("span",null,h?h(D):D)))}))))},"BarChart");export{ct as BarChart,Q as prepareBarChartData};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/BarChart/BarChart.tsx", "../src/hooks/useIsMobile.ts", "../src/utils/amountConverter.ts", "../src/utils/common.ts", "../src/components/BarChart/BarChart.constants.ts", "../src/components/BarChart/BarChart.helpers.ts", "../src/components/BarChart/BarChart.styles.ts"],
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-magic-numbers */\nimport type {\n BarChartPropTypes,\n BarStackDataType,\n BottomAxisData,\n TooltipDataType,\n} from './BarChart.types.js';\nimport type { BarGroupBar, SeriesPoint } from '@visx/shape/lib/types';\n\nimport { Divider } from '@rango-dev/ui';\nimport { AxisBottom, AxisLeft } from '@visx/axis';\nimport { localPoint } from '@visx/event';\nimport { Grid } from '@visx/grid';\nimport { Group } from '@visx/group';\nimport { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale';\nimport { BarStack } from '@visx/shape';\nimport { TooltipWithBounds, useTooltip } from '@visx/tooltip';\nimport dayjs from 'dayjs';\nimport utc from 'dayjs/plugin/utc.js';\nimport React, { Fragment, useEffect, useRef } from 'react';\n\nimport useIsMobile from '../../hooks/useIsMobile.js';\nimport {\n AmountConverter,\n compactNumberFormat,\n} from '../../utils/amountConverter.js';\nimport { getDayOfMonth } from '../../utils/common.js';\n\nimport {\n bottomAxisData,\n DEFAULT_CHART_COLORS,\n DEFAULT_MARGIN,\n TOOLTIP_DELAY_MS,\n TOOLTIP_HIDE_DELAY_MS,\n} from './BarChart.constants.js';\nimport {\n generateTickValues,\n getDaysRange,\n getEvenlySpacedNumber,\n getTotalValue,\n getTotalValueDates,\n} from './BarChart.helpers.js';\nimport {\n Circle,\n Container,\n InfoContainer,\n Line,\n NameWrapper,\n TooltipContainer,\n TooltipInfoRow,\n} from './BarChart.styles.js';\n\ndayjs.extend(utc);\n\nexport const BarChart = (props: BarChartPropTypes) => {\n const {\n data,\n width,\n height,\n colorBucketMap,\n buckets,\n margin = DEFAULT_MARGIN,\n getLabel,\n isDarkTheme = false,\n } = props;\n\n const isMobile = useIsMobile();\n const daysRange = getDaysRange(data.length);\n\n let bottomAxis: BottomAxisData;\n if (data.length > 90) {\n const count = 7;\n const interval = getEvenlySpacedNumber(data.length, count);\n bottomAxis = {\n numBottomAxis: count,\n intervalBottomAxis: interval,\n startBottomAxis: interval - 10,\n };\n } else {\n bottomAxis =\n width < 700\n ? bottomAxisData.mobile[daysRange]\n : bottomAxisData.desktop[daysRange];\n }\n\n const { intervalBottomAxis, numBottomAxis, startBottomAxis } = bottomAxis;\n\n let tooltipTimeout: number;\n const tooltipRef = useRef<HTMLInputElement>(null);\n\n // bounds\n const xMax = width - margin.left - 20;\n const yMax = height - margin.top - 30;\n\n // accessors\n const getDate = (d: BarStackDataType) => d.date;\n\n // handle bottom axis data\n const allDate = data.map(getDate);\n\n const bottomAxisValue = generateTickValues(\n allDate,\n startBottomAxis,\n intervalBottomAxis\n );\n\n const {\n tooltipOpen,\n tooltipLeft,\n tooltipTop,\n tooltipData,\n hideTooltip,\n showTooltip,\n } = useTooltip<TooltipDataType>();\n\n const totalValueDates = getTotalValueDates(data, buckets);\n\n // scales\n const dateScale = scaleBand<string>({\n domain: data.map(getDate),\n paddingInner: daysRange === 7 ? 0.3 : 0.46,\n paddingOuter: daysRange === 90 ? 1 : 0.3,\n });\n\n const totalValue = Math.max(...totalValueDates);\n\n const scaledMaxValue = totalValue + totalValue / 5;\n const valueScale = scaleLinear<number>({\n domain: [0, scaledMaxValue < 0.5 ? 0.5 : scaledMaxValue],\n nice: true,\n });\n const colorScale = scaleOrdinal<string, string>({\n domain: buckets,\n range: DEFAULT_CHART_COLORS,\n });\n\n useEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function handleClickOutside(event: any) {\n if (\n isMobile &&\n tooltipRef?.current &&\n !tooltipRef.current.contains(event.target)\n ) {\n hideTooltip();\n }\n }\n document.addEventListener('click', handleClickOutside, true);\n return () => {\n document.removeEventListener('click', handleClickOutside, true);\n };\n }, [tooltipRef, isMobile]);\n\n dateScale.range([0, xMax]);\n valueScale.range([yMax, 0]);\n\n if (width < 10) {\n return null;\n }\n\n const handleBarClick = (\n event: React.MouseEvent<SVGRectElement, MouseEvent>,\n bar: Omit<BarGroupBar<string>, 'key' | 'value'> & {\n bar: SeriesPoint<BarStackDataType>;\n key: string;\n },\n index: number\n ) => {\n if (isMobile) {\n if (tooltipTimeout) {\n clearTimeout(tooltipTimeout);\n }\n const eventSvgCoords = localPoint(event);\n const left = bar.x + bar.width / 2;\n setTimeout(() => {\n showTooltip({\n tooltipData: { bar, hoveredIndex: index },\n tooltipTop: eventSvgCoords?.y,\n tooltipLeft: left,\n });\n }, TOOLTIP_DELAY_MS);\n }\n };\n\n const handleMouseLeave = () => {\n if (!isMobile) {\n tooltipTimeout = window.setTimeout(() => {\n hideTooltip();\n }, TOOLTIP_HIDE_DELAY_MS);\n }\n };\n\n const handleMouseMove = (\n event: React.MouseEvent<SVGRectElement, MouseEvent>,\n bar: Omit<BarGroupBar<string>, 'key' | 'value'> & {\n bar: SeriesPoint<BarStackDataType>;\n key: string;\n },\n index: number\n ) => {\n if (!isMobile) {\n if (tooltipTimeout) {\n clearTimeout(tooltipTimeout);\n }\n /*\n * TooltipInPortal expects coordinates to be relative to containerRef\n * localPoint returns coordinates relative to the nearest SVG, which\n * is what containerRef is set to in this example.\n */\n const eventSvgCoords = localPoint(event);\n const left = bar.x + bar.width / 2 + 40;\n\n // make sure to pass the index of the hovered bar\n showTooltip({\n tooltipData: { bar, hoveredIndex: index },\n tooltipTop: eventSvgCoords?.y,\n tooltipLeft: left,\n });\n }\n };\n\n const getFormattedTotalValue = (data: BarStackDataType) =>\n AmountConverter(Number(getTotalValue(data).toFixed(2)));\n\n return (\n <Container>\n <svg width={width} height={height}>\n <rect\n x={0}\n y={0}\n width={width}\n height={height}\n fill=\"transparent\"\n rx={14}\n />\n <Grid\n top={margin.top}\n left={margin.left + 10}\n xScale={dateScale}\n yScale={valueScale}\n width={xMax}\n height={yMax}\n stroke=\"black\"\n strokeOpacity={0.1}\n numTicksRows={5}\n numTicksColumns={0}\n columnLineStyle={{ display: 'none' }}\n rowLineStyle={{\n stroke: '#B8B8B8',\n }}\n />\n\n <Group top={margin.top} left={margin.left + 10}>\n <BarStack\n data={data}\n keys={buckets}\n x={getDate}\n xScale={dateScale}\n yScale={valueScale}\n color={colorScale}>\n {(barStacks) => {\n /*\n * barStacks returns an array of series objects broken down by key.\n */\n return barStacks.map((barStack) =>\n /*\n * each barStack contains an array of bars, which contain the data\n * for only that series for a given data point. the number of bars in a\n * given stack corresponds to the number of data points in our data array\n */\n\n barStack.bars.map((bar, index) => {\n /*\n * we can then assume that the data in each stack at a given index\n * is related to the data in all other stacks at that index.\n */\n const shouldBeHighlighted =\n tooltipData?.hoveredIndex === index;\n\n /*\n * we can then decide the opacity for our stacks based on whether the\n * tooltip is open, and whether the stack being hovered matches the\n * index passed to our tooltipData\n */\n const shouldHavePartialOpacity =\n !shouldBeHighlighted && tooltipOpen;\n\n const barColor =\n colorBucketMap.get(barStack.key) || bar.color;\n\n return (\n <rect\n key={`bar-stack-${barStack.index}-${bar.index}`}\n x={bar.x}\n y={bar.y}\n height={bar.height}\n width={bar.width}\n fill={barColor}\n opacity={shouldHavePartialOpacity ? 0.5 : 1}\n onClick={(event) => handleBarClick(event, bar, index)}\n onMouseLeave={handleMouseLeave}\n onMouseMove={(event) =>\n handleMouseMove(event, bar, index)\n }\n />\n );\n })\n );\n }}\n </BarStack>\n </Group>\n\n <AxisBottom\n top={yMax + margin.top}\n left={margin.left + 10}\n scale={dateScale}\n hideAxisLine\n hideTicks\n numTicks={numBottomAxis}\n tickValues={bottomAxisValue}\n tickFormat={(d) => getDayOfMonth(d)}\n tickLabelProps={() => ({\n fontSize: isMobile ? 10 : 12,\n fill: isDarkTheme ? '#B8B8B8' : '#A2A2A2',\n textAnchor: 'middle',\n })}\n />\n\n <AxisLeft\n hideAxisLine\n hideTicks\n numTicks={isMobile ? 3 : 5}\n top={margin.top}\n left={margin.left}\n scale={valueScale}\n tickFormat={(d) => compactNumberFormat(Number(d))}\n tickLabelProps={() => ({\n fontSize: isMobile ? 10 : 12,\n fill: isDarkTheme ? '#B8B8B8' : '#A2A2A2',\n textAnchor: 'middle',\n })}\n />\n </svg>\n\n {tooltipData && tooltipOpen && (\n <TooltipWithBounds\n top={tooltipTop}\n left={tooltipLeft}\n style={{\n backgroundColor: 'transparent',\n boxShadow: 'none',\n position: 'absolute',\n zIndex: '99999999',\n }}>\n <TooltipContainer ref={tooltipRef}>\n {tooltipData?.bar.bar.data.date && (\n <TooltipInfoRow>\n <div>\n {dayjs\n .utc(tooltipData.bar.bar.data.date)\n .local()\n .format('YYYY/MM/DD')\n .toString()}\n </div>\n <div>\n {getLabel\n ? getLabel(getFormattedTotalValue(tooltipData.bar.bar.data))\n : getFormattedTotalValue(tooltipData.bar.bar.data)}\n </div>\n </TooltipInfoRow>\n )}\n {Array.from(colorBucketMap).map((mapItem) => {\n const [bucketItem, bucketColor] = mapItem;\n const value = tooltipData?.bar.bar.data[bucketItem];\n const formattedValue = !isNaN(Number(value))\n ? AmountConverter(Number(Number(value).toFixed(2)))\n : '0';\n return (\n <Fragment key={bucketItem}>\n <Line />\n <InfoContainer>\n <NameWrapper>\n <Circle style={{ backgroundColor: bucketColor }} />\n <Divider direction=\"horizontal\" size={'4'} />\n <span>{bucketItem}</span>\n </NameWrapper>\n <Divider direction=\"horizontal\" size={'10'} />\n\n <span>\n {getLabel ? getLabel(formattedValue) : formattedValue}\n </span>\n </InfoContainer>\n </Fragment>\n );\n })}\n </TooltipContainer>\n </TooltipWithBounds>\n )}\n </Container>\n );\n};\n", "import { useEffect, useState } from 'react';\n\nconst useIsMobile = () => {\n const [isMobile, setIsMobile] = useState<boolean>(false);\n\n useEffect(() => {\n const handleResize = () => {\n const mobileBreakpoint = 640;\n setIsMobile(window.innerWidth <= mobileBreakpoint);\n };\n\n handleResize();\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n return isMobile;\n};\n\nexport default useIsMobile;\n", "const THRESHOLD = 1000;\nconst BASE_TEN = 10;\nconst PERCENTAGE_MULTIPLIER = 100;\n\nconst unitList = ['', 'K', 'M', 'B'];\nexport function AmountConverter(number: number) {\n const sign = Math.sign(number);\n let unit = 0;\n while (Math.abs(number) > THRESHOLD) {\n unit = unit + 1;\n number = Math.floor(Math.abs(number) / BASE_TEN) / PERCENTAGE_MULTIPLIER;\n }\n return sign * Math.abs(number) + unitList[unit];\n}\n\nexport function getPercentageChange(\n input: number | null,\n output: number | null\n) {\n if (!input || !output) {\n return null;\n }\n return parseFloat(\n Number((output / input - 1) * PERCENTAGE_MULTIPLIER).toFixed(2)\n );\n}\n\nexport function numberWithCommas(number: number) {\n if (!number || isNaN(number)) {\n return number;\n }\n\n return number.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n}\n\nexport function compactNumberFormat(number: number) {\n if (!number || isNaN(number)) {\n return '0';\n }\n\n const numberFormat = Intl.NumberFormat('en-US', {\n notation: 'compact',\n maximumFractionDigits: 1,\n }).format(number);\n\n return numberFormat;\n}\n", "export const monthsShort = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n];\n\nexport function getDayOfMonth(dateString: string) {\n const date = new Date(dateString);\n const monthName = date.toLocaleDateString('en-US', { month: 'short' });\n const dayNumber = date.getDate();\n\n return `${dayNumber} ${monthName}`;\n}\n", "import type { BottomAxisData } from './BarChart.types.js';\n\nexport const DEFAULT_MARGIN = { top: 40, right: 0, bottom: 0, left: 20 };\n\nexport const TOOLTIP_DELAY_MS = 100;\nexport const TOOLTIP_HIDE_DELAY_MS = 300;\n\nexport const DEFAULT_CHART_COLORS: string[] = [\n '#469BF5',\n '#29DABA',\n '#D629DA',\n '#4658F5',\n '#9DF546',\n '#F01DA8',\n '#FF8B66',\n '#44F1E6',\n '#29DA7A',\n '#F17606',\n '#8B62FF',\n '#F4C932',\n];\n\nexport const bottomAxisData: {\n [key: string]: {\n [key: number]: BottomAxisData;\n };\n} = {\n desktop: {\n 7: { numBottomAxis: 7, startBottomAxis: 0, intervalBottomAxis: 1 },\n 30: { numBottomAxis: 6, startBottomAxis: 4, intervalBottomAxis: 5 },\n 90: { numBottomAxis: 8, startBottomAxis: 5, intervalBottomAxis: 10 },\n },\n mobile: {\n 7: { numBottomAxis: 3, startBottomAxis: 1, intervalBottomAxis: 2 },\n 30: { numBottomAxis: 3, startBottomAxis: 3, intervalBottomAxis: 10 },\n 90: { numBottomAxis: 3, startBottomAxis: 10, intervalBottomAxis: 30 },\n },\n};\n\nexport const MAX_BAR_BUCKETS = 10;\n", "/* eslint-disable @typescript-eslint/no-magic-numbers */\nimport type {\n BarStackDataType,\n ChartOptionsType,\n ColorBucketMapType,\n DailyDataType,\n} from './BarChart.types.js';\n\nimport { MAX_BAR_BUCKETS } from './BarChart.constants.js';\n\nexport const getTotalValueDates = (\n data: BarStackDataType[],\n buckets: string[]\n) => {\n const totalValueDates = data.reduce((accumulator, currentData) => {\n const totalValuePerDate = buckets.reduce((dailyTotal, currentBucket) => {\n dailyTotal += !isNaN(Number(currentData[currentBucket]))\n ? Number(currentData[currentBucket])\n : 0;\n return dailyTotal;\n }, 0);\n accumulator.push(totalValuePerDate);\n return accumulator;\n }, [] as number[]);\n\n return totalValueDates;\n};\n\n// Function to generate tick values at intervals of 5, starting from the 5th element\nexport const generateTickValues = (\n dates: string[],\n start: number,\n interval: number\n) => {\n const tickValues = [];\n for (let i = start; i < dates.length; i += interval) {\n tickValues.push(dates[i]);\n }\n return tickValues;\n};\n\nexport const getTotalValue = (dataColumn: BarStackDataType) => {\n let result = 0;\n Object.keys(dataColumn).forEach((key) => {\n if (key !== 'date') {\n const value = dataColumn[key];\n if (!isNaN(Number(value))) {\n result += Number(value);\n }\n }\n });\n return result;\n};\n\nexport const getDaysRange = (lengthValue: number) => {\n if (lengthValue < 15) {\n return 7;\n }\n if (lengthValue < 50) {\n return 30;\n }\n return 90;\n};\n\nexport const prepareBarChartData = (chartOption: ChartOptionsType) => {\n const { dailyData, label = 'Count' } = chartOption;\n const chartData: BarStackDataType[] = [];\n const colorBucketMap: ColorBucketMapType = new Map();\n const buckets: string[] = [];\n\n const { barChartColors } = chartOption;\n\n // map sum of value for each bucket\n const sumBucketMap = new Map<string, number>();\n dailyData.forEach((dailyItem) => {\n const keyItem = dailyItem.bucket || label;\n\n const sum = sumBucketMap.get(keyItem) || 0;\n const newValue = dailyItem.value;\n sumBucketMap.set(keyItem, sum + newValue);\n });\n\n const sortedBucket = Array.from(sumBucketMap).sort((a, b) => b[1] - a[1]);\n\n // get top buckets for stack bars\n const topBucket = sortedBucket\n .map((sortedItem) => sortedItem[0])\n .slice(0, MAX_BAR_BUCKETS);\n\n const bucketCount = sumBucketMap.size;\n\n // create map structure for assign color for each bucket\n topBucket.forEach((bucketItem, index) => {\n colorBucketMap.set(\n bucketItem,\n barChartColors[index % barChartColors.length]\n );\n buckets.push(bucketItem);\n });\n\n if (bucketCount > MAX_BAR_BUCKETS) {\n colorBucketMap.set('Others', barChartColors[barChartColors.length - 1]);\n buckets.push('Others');\n }\n\n // create map structure for assign chart data for each date\n const dateMap = new Map<string, DailyDataType[]>();\n dailyData.forEach((dailyItem) => {\n if (!dateMap.has(dailyItem.date)) {\n dateMap.set(dailyItem.date, []);\n }\n\n const dateItem = dateMap.get(dailyItem.date);\n dateItem?.push(dailyItem);\n });\n\n // create data result for bar stack chart\n dateMap.forEach((dateDailyList, keyDate) => {\n const dataItem: BarStackDataType = { date: keyDate };\n dateDailyList\n .filter((dailyItem) => topBucket.includes(dailyItem.bucket || label))\n .forEach((topDailyItem) => {\n const bucketValue = topDailyItem.value;\n dataItem[topDailyItem.bucket || label] = bucketValue\n ? bucketValue.toString()\n : '0';\n });\n\n topBucket.forEach((topItem) => {\n if (!(topItem in dataItem)) {\n dataItem[topItem] = '0';\n }\n });\n\n if (bucketCount > MAX_BAR_BUCKETS) {\n const otherBuckets = dateDailyList.filter(\n (dailyItem) => dailyItem.bucket && !topBucket.includes(dailyItem.bucket)\n );\n const othersValue = otherBuckets\n .map((dailyItem) => dailyItem.value)\n .reduce((accumulator, currentValue) => accumulator + currentValue, 0);\n dataItem['Others'] = othersValue.toString();\n }\n\n chartData.push(dataItem);\n });\n return { chartData, colorBucketMap, buckets };\n};\n\nexport const getEvenlySpacedNumber = (max: number, count: number) => {\n const interval = max / count;\n return Math.round(interval);\n};\n", "import { darkTheme, styled } from '@rango-dev/ui';\n\nexport const Container = styled('div', {\n position: 'relative',\n});\n\nexport const TooltipContainer = styled('div', {\n width: 165,\n borderRadius: '$sm',\n backgroundColor: '$background',\n\n $$color: '$colors$neutral500',\n [`.${darkTheme} &`]: {\n $$color: '$colors$neutral100',\n },\n\n boxShadow: '0px 5px 20px 0px $$color',\n});\n\nexport const TooltipInfoRow = styled('div', {\n display: 'flex',\n alignItems: 'center',\n fontSize: '$12',\n justifyContent: 'space-between',\n padding: '$8 $10',\n fontWeight: '$medium',\n color: '$foreground',\n});\n\nexport const Line = styled('div', {\n height: 1,\n width: '100%',\n backgroundColor: '$neutral300',\n});\n\nexport const InfoContainer = styled('div', {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontSize: '$10',\n padding: '$5 $10',\n color: '$foreground',\n});\n\nexport const Circle = styled('div', {\n width: '$6',\n height: '$6',\n borderRadius: 3,\n});\n\nexport const NameWrapper = styled('div', {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-start',\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["Divider", "AxisBottom", "AxisLeft", "localPoint", "Grid", "Group", "scaleBand", "scaleLinear", "scaleOrdinal", "BarStack", "TooltipWithBounds", "useTooltip", "dayjs", "utc", "React", "Fragment", "useEffect", "useRef", "useEffect", "useState", "useIsMobile", "__name", "isMobile", "setIsMobile", "useState", "useEffect", "handleResize", "useIsMobile_default", "unitList", "AmountConverter", "number", "sign", "unit", "__name", "compactNumberFormat", "number", "__name", "getDayOfMonth", "dateString", "date", "monthName", "__name", "DEFAULT_MARGIN", "TOOLTIP_DELAY_MS", "TOOLTIP_HIDE_DELAY_MS", "DEFAULT_CHART_COLORS", "bottomAxisData", "MAX_BAR_BUCKETS", "getTotalValueDates", "__name", "data", "buckets", "accumulator", "currentData", "totalValuePerDate", "dailyTotal", "currentBucket", "generateTickValues", "dates", "start", "interval", "tickValues", "i", "getTotalValue", "dataColumn", "result", "key", "value", "getDaysRange", "lengthValue", "prepareBarChartData", "chartOption", "dailyData", "label", "chartData", "colorBucketMap", "barChartColors", "sumBucketMap", "dailyItem", "keyItem", "sum", "newValue", "topBucket", "a", "b", "sortedItem", "MAX_BAR_BUCKETS", "bucketCount", "bucketItem", "index", "dateMap", "dateDailyList", "keyDate", "dataItem", "topDailyItem", "bucketValue", "topItem", "othersValue", "currentValue", "getEvenlySpacedNumber", "max", "count", "darkTheme", "styled", "Container", "TooltipContainer", "TooltipInfoRow", "Line", "InfoContainer", "Circle", "NameWrapper", "dayjs", "utc", "BarChart", "__name", "props", "data", "width", "height", "colorBucketMap", "buckets", "margin", "DEFAULT_MARGIN", "getLabel", "isDarkTheme", "isMobile", "useIsMobile_default", "daysRange", "getDaysRange", "bottomAxis", "interval", "getEvenlySpacedNumber", "bottomAxisData", "intervalBottomAxis", "numBottomAxis", "startBottomAxis", "tooltipTimeout", "tooltipRef", "useRef", "xMax", "yMax", "getDate", "d", "allDate", "bottomAxisValue", "generateTickValues", "tooltipOpen", "tooltipLeft", "tooltipTop", "tooltipData", "hideTooltip", "showTooltip", "useTooltip", "totalValueDates", "getTotalValueDates", "dateScale", "scaleBand", "totalValue", "scaledMaxValue", "valueScale", "scaleLinear", "colorScale", "scaleOrdinal", "DEFAULT_CHART_COLORS", "useEffect", "handleClickOutside", "event", "handleBarClick", "bar", "index", "eventSvgCoords", "localPoint", "left", "TOOLTIP_DELAY_MS", "handleMouseLeave", "TOOLTIP_HIDE_DELAY_MS", "handleMouseMove", "getFormattedTotalValue", "AmountConverter", "getTotalValue", "React", "Container", "Grid", "Group", "BarStack", "barStacks", "barStack", "shouldHavePartialOpacity", "barColor", "AxisBottom", "getDayOfMonth", "AxisLeft", "compactNumberFormat", "TooltipWithBounds", "TooltipContainer", "TooltipInfoRow", "mapItem", "bucketItem", "bucketColor", "value", "formattedValue", "Fragment", "Line", "InfoContainer", "NameWrapper", "Circle", "Divider"]
7
+ }
@@ -0,0 +1,5 @@
1
+ export declare function AmountConverter(number: number): string;
2
+ export declare function getPercentageChange(input: number | null, output: number | null): number | null;
3
+ export declare function numberWithCommas(number: number): string | number;
4
+ export declare function compactNumberFormat(number: number): string;
5
+ //# sourceMappingURL=amountConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amountConverter.d.ts","sourceRoot":"","sources":["../../src/utils/amountConverter.ts"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,UAQ7C;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,MAAM,EAAE,MAAM,GAAG,IAAI,iBAQtB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,mBAM9C;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,UAWjD"}
@@ -0,0 +1,3 @@
1
+ export declare const monthsShort: string[];
2
+ export declare function getDayOfMonth(dateString: string): string;
3
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,UAavB,CAAC;AAEF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,UAM/C"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@rango-dev/charts",
3
+ "version": "0.0.0-experimental-936229e8-20251208",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "source": "./src/index.ts",
7
+ "main": "./dist/index.js",
8
+ "exports": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "typings": "./dist/index.d.ts",
13
+ "files": [
14
+ "dist",
15
+ "src"
16
+ ],
17
+ "scripts": {
18
+ "build": "node ../../scripts/build/command.mjs --path widget/charts",
19
+ "ts-check": "tsc --declaration --emitDeclarationOnly -p ./tsconfig.json",
20
+ "clean": "rimraf dist",
21
+ "format": "prettier --write '{.,src}/**/*.{ts,tsx}'",
22
+ "lint": "eslint \"**/*.{ts,tsx}\""
23
+ },
24
+ "peerDependencies": {
25
+ "react": ">=16",
26
+ "react-dom": ">=16"
27
+ },
28
+ "dependencies": {
29
+ "@rango-dev/ui": "^0.0.0-experimental-936229e8-20251208",
30
+ "@visx/axis": "2.18.0",
31
+ "@visx/event": "2.17.0",
32
+ "@visx/grid": "2.18.0",
33
+ "@visx/scale": "2.18.0",
34
+ "@visx/shape": "2.18.0",
35
+ "@visx/tooltip": "2.17.0",
36
+ "dayjs": "^1.11.6"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ }
41
+ }
package/readme.md ADDED
@@ -0,0 +1,4 @@
1
+ # @rango-dev/charts
2
+
3
+ Rango charts
4
+
@@ -0,0 +1,40 @@
1
+ import type { BottomAxisData } from './BarChart.types.js';
2
+
3
+ export const DEFAULT_MARGIN = { top: 40, right: 0, bottom: 0, left: 20 };
4
+
5
+ export const TOOLTIP_DELAY_MS = 100;
6
+ export const TOOLTIP_HIDE_DELAY_MS = 300;
7
+
8
+ export const DEFAULT_CHART_COLORS: string[] = [
9
+ '#469BF5',
10
+ '#29DABA',
11
+ '#D629DA',
12
+ '#4658F5',
13
+ '#9DF546',
14
+ '#F01DA8',
15
+ '#FF8B66',
16
+ '#44F1E6',
17
+ '#29DA7A',
18
+ '#F17606',
19
+ '#8B62FF',
20
+ '#F4C932',
21
+ ];
22
+
23
+ export const bottomAxisData: {
24
+ [key: string]: {
25
+ [key: number]: BottomAxisData;
26
+ };
27
+ } = {
28
+ desktop: {
29
+ 7: { numBottomAxis: 7, startBottomAxis: 0, intervalBottomAxis: 1 },
30
+ 30: { numBottomAxis: 6, startBottomAxis: 4, intervalBottomAxis: 5 },
31
+ 90: { numBottomAxis: 8, startBottomAxis: 5, intervalBottomAxis: 10 },
32
+ },
33
+ mobile: {
34
+ 7: { numBottomAxis: 3, startBottomAxis: 1, intervalBottomAxis: 2 },
35
+ 30: { numBottomAxis: 3, startBottomAxis: 3, intervalBottomAxis: 10 },
36
+ 90: { numBottomAxis: 3, startBottomAxis: 10, intervalBottomAxis: 30 },
37
+ },
38
+ };
39
+
40
+ export const MAX_BAR_BUCKETS = 10;
@@ -0,0 +1,153 @@
1
+ /* eslint-disable @typescript-eslint/no-magic-numbers */
2
+ import type {
3
+ BarStackDataType,
4
+ ChartOptionsType,
5
+ ColorBucketMapType,
6
+ DailyDataType,
7
+ } from './BarChart.types.js';
8
+
9
+ import { MAX_BAR_BUCKETS } from './BarChart.constants.js';
10
+
11
+ export const getTotalValueDates = (
12
+ data: BarStackDataType[],
13
+ buckets: string[]
14
+ ) => {
15
+ const totalValueDates = data.reduce((accumulator, currentData) => {
16
+ const totalValuePerDate = buckets.reduce((dailyTotal, currentBucket) => {
17
+ dailyTotal += !isNaN(Number(currentData[currentBucket]))
18
+ ? Number(currentData[currentBucket])
19
+ : 0;
20
+ return dailyTotal;
21
+ }, 0);
22
+ accumulator.push(totalValuePerDate);
23
+ return accumulator;
24
+ }, [] as number[]);
25
+
26
+ return totalValueDates;
27
+ };
28
+
29
+ // Function to generate tick values at intervals of 5, starting from the 5th element
30
+ export const generateTickValues = (
31
+ dates: string[],
32
+ start: number,
33
+ interval: number
34
+ ) => {
35
+ const tickValues = [];
36
+ for (let i = start; i < dates.length; i += interval) {
37
+ tickValues.push(dates[i]);
38
+ }
39
+ return tickValues;
40
+ };
41
+
42
+ export const getTotalValue = (dataColumn: BarStackDataType) => {
43
+ let result = 0;
44
+ Object.keys(dataColumn).forEach((key) => {
45
+ if (key !== 'date') {
46
+ const value = dataColumn[key];
47
+ if (!isNaN(Number(value))) {
48
+ result += Number(value);
49
+ }
50
+ }
51
+ });
52
+ return result;
53
+ };
54
+
55
+ export const getDaysRange = (lengthValue: number) => {
56
+ if (lengthValue < 15) {
57
+ return 7;
58
+ }
59
+ if (lengthValue < 50) {
60
+ return 30;
61
+ }
62
+ return 90;
63
+ };
64
+
65
+ export const prepareBarChartData = (chartOption: ChartOptionsType) => {
66
+ const { dailyData, label = 'Count' } = chartOption;
67
+ const chartData: BarStackDataType[] = [];
68
+ const colorBucketMap: ColorBucketMapType = new Map();
69
+ const buckets: string[] = [];
70
+
71
+ const { barChartColors } = chartOption;
72
+
73
+ // map sum of value for each bucket
74
+ const sumBucketMap = new Map<string, number>();
75
+ dailyData.forEach((dailyItem) => {
76
+ const keyItem = dailyItem.bucket || label;
77
+
78
+ const sum = sumBucketMap.get(keyItem) || 0;
79
+ const newValue = dailyItem.value;
80
+ sumBucketMap.set(keyItem, sum + newValue);
81
+ });
82
+
83
+ const sortedBucket = Array.from(sumBucketMap).sort((a, b) => b[1] - a[1]);
84
+
85
+ // get top buckets for stack bars
86
+ const topBucket = sortedBucket
87
+ .map((sortedItem) => sortedItem[0])
88
+ .slice(0, MAX_BAR_BUCKETS);
89
+
90
+ const bucketCount = sumBucketMap.size;
91
+
92
+ // create map structure for assign color for each bucket
93
+ topBucket.forEach((bucketItem, index) => {
94
+ colorBucketMap.set(
95
+ bucketItem,
96
+ barChartColors[index % barChartColors.length]
97
+ );
98
+ buckets.push(bucketItem);
99
+ });
100
+
101
+ if (bucketCount > MAX_BAR_BUCKETS) {
102
+ colorBucketMap.set('Others', barChartColors[barChartColors.length - 1]);
103
+ buckets.push('Others');
104
+ }
105
+
106
+ // create map structure for assign chart data for each date
107
+ const dateMap = new Map<string, DailyDataType[]>();
108
+ dailyData.forEach((dailyItem) => {
109
+ if (!dateMap.has(dailyItem.date)) {
110
+ dateMap.set(dailyItem.date, []);
111
+ }
112
+
113
+ const dateItem = dateMap.get(dailyItem.date);
114
+ dateItem?.push(dailyItem);
115
+ });
116
+
117
+ // create data result for bar stack chart
118
+ dateMap.forEach((dateDailyList, keyDate) => {
119
+ const dataItem: BarStackDataType = { date: keyDate };
120
+ dateDailyList
121
+ .filter((dailyItem) => topBucket.includes(dailyItem.bucket || label))
122
+ .forEach((topDailyItem) => {
123
+ const bucketValue = topDailyItem.value;
124
+ dataItem[topDailyItem.bucket || label] = bucketValue
125
+ ? bucketValue.toString()
126
+ : '0';
127
+ });
128
+
129
+ topBucket.forEach((topItem) => {
130
+ if (!(topItem in dataItem)) {
131
+ dataItem[topItem] = '0';
132
+ }
133
+ });
134
+
135
+ if (bucketCount > MAX_BAR_BUCKETS) {
136
+ const otherBuckets = dateDailyList.filter(
137
+ (dailyItem) => dailyItem.bucket && !topBucket.includes(dailyItem.bucket)
138
+ );
139
+ const othersValue = otherBuckets
140
+ .map((dailyItem) => dailyItem.value)
141
+ .reduce((accumulator, currentValue) => accumulator + currentValue, 0);
142
+ dataItem['Others'] = othersValue.toString();
143
+ }
144
+
145
+ chartData.push(dataItem);
146
+ });
147
+ return { chartData, colorBucketMap, buckets };
148
+ };
149
+
150
+ export const getEvenlySpacedNumber = (max: number, count: number) => {
151
+ const interval = max / count;
152
+ return Math.round(interval);
153
+ };
@@ -0,0 +1,55 @@
1
+ import { darkTheme, styled } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ position: 'relative',
5
+ });
6
+
7
+ export const TooltipContainer = styled('div', {
8
+ width: 165,
9
+ borderRadius: '$sm',
10
+ backgroundColor: '$background',
11
+
12
+ $$color: '$colors$neutral500',
13
+ [`.${darkTheme} &`]: {
14
+ $$color: '$colors$neutral100',
15
+ },
16
+
17
+ boxShadow: '0px 5px 20px 0px $$color',
18
+ });
19
+
20
+ export const TooltipInfoRow = styled('div', {
21
+ display: 'flex',
22
+ alignItems: 'center',
23
+ fontSize: '$12',
24
+ justifyContent: 'space-between',
25
+ padding: '$8 $10',
26
+ fontWeight: '$medium',
27
+ color: '$foreground',
28
+ });
29
+
30
+ export const Line = styled('div', {
31
+ height: 1,
32
+ width: '100%',
33
+ backgroundColor: '$neutral300',
34
+ });
35
+
36
+ export const InfoContainer = styled('div', {
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ justifyContent: 'space-between',
40
+ fontSize: '$10',
41
+ padding: '$5 $10',
42
+ color: '$foreground',
43
+ });
44
+
45
+ export const Circle = styled('div', {
46
+ width: '$6',
47
+ height: '$6',
48
+ borderRadius: 3,
49
+ });
50
+
51
+ export const NameWrapper = styled('div', {
52
+ display: 'flex',
53
+ alignItems: 'center',
54
+ justifyContent: 'flex-start',
55
+ });
@@ -0,0 +1,401 @@
1
+ /* eslint-disable @typescript-eslint/no-magic-numbers */
2
+ import type {
3
+ BarChartPropTypes,
4
+ BarStackDataType,
5
+ BottomAxisData,
6
+ TooltipDataType,
7
+ } from './BarChart.types.js';
8
+ import type { BarGroupBar, SeriesPoint } from '@visx/shape/lib/types';
9
+
10
+ import { Divider } from '@rango-dev/ui';
11
+ import { AxisBottom, AxisLeft } from '@visx/axis';
12
+ import { localPoint } from '@visx/event';
13
+ import { Grid } from '@visx/grid';
14
+ import { Group } from '@visx/group';
15
+ import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale';
16
+ import { BarStack } from '@visx/shape';
17
+ import { TooltipWithBounds, useTooltip } from '@visx/tooltip';
18
+ import dayjs from 'dayjs';
19
+ import utc from 'dayjs/plugin/utc.js';
20
+ import React, { Fragment, useEffect, useRef } from 'react';
21
+
22
+ import useIsMobile from '../../hooks/useIsMobile.js';
23
+ import {
24
+ AmountConverter,
25
+ compactNumberFormat,
26
+ } from '../../utils/amountConverter.js';
27
+ import { getDayOfMonth } from '../../utils/common.js';
28
+
29
+ import {
30
+ bottomAxisData,
31
+ DEFAULT_CHART_COLORS,
32
+ DEFAULT_MARGIN,
33
+ TOOLTIP_DELAY_MS,
34
+ TOOLTIP_HIDE_DELAY_MS,
35
+ } from './BarChart.constants.js';
36
+ import {
37
+ generateTickValues,
38
+ getDaysRange,
39
+ getEvenlySpacedNumber,
40
+ getTotalValue,
41
+ getTotalValueDates,
42
+ } from './BarChart.helpers.js';
43
+ import {
44
+ Circle,
45
+ Container,
46
+ InfoContainer,
47
+ Line,
48
+ NameWrapper,
49
+ TooltipContainer,
50
+ TooltipInfoRow,
51
+ } from './BarChart.styles.js';
52
+
53
+ dayjs.extend(utc);
54
+
55
+ export const BarChart = (props: BarChartPropTypes) => {
56
+ const {
57
+ data,
58
+ width,
59
+ height,
60
+ colorBucketMap,
61
+ buckets,
62
+ margin = DEFAULT_MARGIN,
63
+ getLabel,
64
+ isDarkTheme = false,
65
+ } = props;
66
+
67
+ const isMobile = useIsMobile();
68
+ const daysRange = getDaysRange(data.length);
69
+
70
+ let bottomAxis: BottomAxisData;
71
+ if (data.length > 90) {
72
+ const count = 7;
73
+ const interval = getEvenlySpacedNumber(data.length, count);
74
+ bottomAxis = {
75
+ numBottomAxis: count,
76
+ intervalBottomAxis: interval,
77
+ startBottomAxis: interval - 10,
78
+ };
79
+ } else {
80
+ bottomAxis =
81
+ width < 700
82
+ ? bottomAxisData.mobile[daysRange]
83
+ : bottomAxisData.desktop[daysRange];
84
+ }
85
+
86
+ const { intervalBottomAxis, numBottomAxis, startBottomAxis } = bottomAxis;
87
+
88
+ let tooltipTimeout: number;
89
+ const tooltipRef = useRef<HTMLInputElement>(null);
90
+
91
+ // bounds
92
+ const xMax = width - margin.left - 20;
93
+ const yMax = height - margin.top - 30;
94
+
95
+ // accessors
96
+ const getDate = (d: BarStackDataType) => d.date;
97
+
98
+ // handle bottom axis data
99
+ const allDate = data.map(getDate);
100
+
101
+ const bottomAxisValue = generateTickValues(
102
+ allDate,
103
+ startBottomAxis,
104
+ intervalBottomAxis
105
+ );
106
+
107
+ const {
108
+ tooltipOpen,
109
+ tooltipLeft,
110
+ tooltipTop,
111
+ tooltipData,
112
+ hideTooltip,
113
+ showTooltip,
114
+ } = useTooltip<TooltipDataType>();
115
+
116
+ const totalValueDates = getTotalValueDates(data, buckets);
117
+
118
+ // scales
119
+ const dateScale = scaleBand<string>({
120
+ domain: data.map(getDate),
121
+ paddingInner: daysRange === 7 ? 0.3 : 0.46,
122
+ paddingOuter: daysRange === 90 ? 1 : 0.3,
123
+ });
124
+
125
+ const totalValue = Math.max(...totalValueDates);
126
+
127
+ const scaledMaxValue = totalValue + totalValue / 5;
128
+ const valueScale = scaleLinear<number>({
129
+ domain: [0, scaledMaxValue < 0.5 ? 0.5 : scaledMaxValue],
130
+ nice: true,
131
+ });
132
+ const colorScale = scaleOrdinal<string, string>({
133
+ domain: buckets,
134
+ range: DEFAULT_CHART_COLORS,
135
+ });
136
+
137
+ useEffect(() => {
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ function handleClickOutside(event: any) {
140
+ if (
141
+ isMobile &&
142
+ tooltipRef?.current &&
143
+ !tooltipRef.current.contains(event.target)
144
+ ) {
145
+ hideTooltip();
146
+ }
147
+ }
148
+ document.addEventListener('click', handleClickOutside, true);
149
+ return () => {
150
+ document.removeEventListener('click', handleClickOutside, true);
151
+ };
152
+ }, [tooltipRef, isMobile]);
153
+
154
+ dateScale.range([0, xMax]);
155
+ valueScale.range([yMax, 0]);
156
+
157
+ if (width < 10) {
158
+ return null;
159
+ }
160
+
161
+ const handleBarClick = (
162
+ event: React.MouseEvent<SVGRectElement, MouseEvent>,
163
+ bar: Omit<BarGroupBar<string>, 'key' | 'value'> & {
164
+ bar: SeriesPoint<BarStackDataType>;
165
+ key: string;
166
+ },
167
+ index: number
168
+ ) => {
169
+ if (isMobile) {
170
+ if (tooltipTimeout) {
171
+ clearTimeout(tooltipTimeout);
172
+ }
173
+ const eventSvgCoords = localPoint(event);
174
+ const left = bar.x + bar.width / 2;
175
+ setTimeout(() => {
176
+ showTooltip({
177
+ tooltipData: { bar, hoveredIndex: index },
178
+ tooltipTop: eventSvgCoords?.y,
179
+ tooltipLeft: left,
180
+ });
181
+ }, TOOLTIP_DELAY_MS);
182
+ }
183
+ };
184
+
185
+ const handleMouseLeave = () => {
186
+ if (!isMobile) {
187
+ tooltipTimeout = window.setTimeout(() => {
188
+ hideTooltip();
189
+ }, TOOLTIP_HIDE_DELAY_MS);
190
+ }
191
+ };
192
+
193
+ const handleMouseMove = (
194
+ event: React.MouseEvent<SVGRectElement, MouseEvent>,
195
+ bar: Omit<BarGroupBar<string>, 'key' | 'value'> & {
196
+ bar: SeriesPoint<BarStackDataType>;
197
+ key: string;
198
+ },
199
+ index: number
200
+ ) => {
201
+ if (!isMobile) {
202
+ if (tooltipTimeout) {
203
+ clearTimeout(tooltipTimeout);
204
+ }
205
+ /*
206
+ * TooltipInPortal expects coordinates to be relative to containerRef
207
+ * localPoint returns coordinates relative to the nearest SVG, which
208
+ * is what containerRef is set to in this example.
209
+ */
210
+ const eventSvgCoords = localPoint(event);
211
+ const left = bar.x + bar.width / 2 + 40;
212
+
213
+ // make sure to pass the index of the hovered bar
214
+ showTooltip({
215
+ tooltipData: { bar, hoveredIndex: index },
216
+ tooltipTop: eventSvgCoords?.y,
217
+ tooltipLeft: left,
218
+ });
219
+ }
220
+ };
221
+
222
+ const getFormattedTotalValue = (data: BarStackDataType) =>
223
+ AmountConverter(Number(getTotalValue(data).toFixed(2)));
224
+
225
+ return (
226
+ <Container>
227
+ <svg width={width} height={height}>
228
+ <rect
229
+ x={0}
230
+ y={0}
231
+ width={width}
232
+ height={height}
233
+ fill="transparent"
234
+ rx={14}
235
+ />
236
+ <Grid
237
+ top={margin.top}
238
+ left={margin.left + 10}
239
+ xScale={dateScale}
240
+ yScale={valueScale}
241
+ width={xMax}
242
+ height={yMax}
243
+ stroke="black"
244
+ strokeOpacity={0.1}
245
+ numTicksRows={5}
246
+ numTicksColumns={0}
247
+ columnLineStyle={{ display: 'none' }}
248
+ rowLineStyle={{
249
+ stroke: '#B8B8B8',
250
+ }}
251
+ />
252
+
253
+ <Group top={margin.top} left={margin.left + 10}>
254
+ <BarStack
255
+ data={data}
256
+ keys={buckets}
257
+ x={getDate}
258
+ xScale={dateScale}
259
+ yScale={valueScale}
260
+ color={colorScale}>
261
+ {(barStacks) => {
262
+ /*
263
+ * barStacks returns an array of series objects broken down by key.
264
+ */
265
+ return barStacks.map((barStack) =>
266
+ /*
267
+ * each barStack contains an array of bars, which contain the data
268
+ * for only that series for a given data point. the number of bars in a
269
+ * given stack corresponds to the number of data points in our data array
270
+ */
271
+
272
+ barStack.bars.map((bar, index) => {
273
+ /*
274
+ * we can then assume that the data in each stack at a given index
275
+ * is related to the data in all other stacks at that index.
276
+ */
277
+ const shouldBeHighlighted =
278
+ tooltipData?.hoveredIndex === index;
279
+
280
+ /*
281
+ * we can then decide the opacity for our stacks based on whether the
282
+ * tooltip is open, and whether the stack being hovered matches the
283
+ * index passed to our tooltipData
284
+ */
285
+ const shouldHavePartialOpacity =
286
+ !shouldBeHighlighted && tooltipOpen;
287
+
288
+ const barColor =
289
+ colorBucketMap.get(barStack.key) || bar.color;
290
+
291
+ return (
292
+ <rect
293
+ key={`bar-stack-${barStack.index}-${bar.index}`}
294
+ x={bar.x}
295
+ y={bar.y}
296
+ height={bar.height}
297
+ width={bar.width}
298
+ fill={barColor}
299
+ opacity={shouldHavePartialOpacity ? 0.5 : 1}
300
+ onClick={(event) => handleBarClick(event, bar, index)}
301
+ onMouseLeave={handleMouseLeave}
302
+ onMouseMove={(event) =>
303
+ handleMouseMove(event, bar, index)
304
+ }
305
+ />
306
+ );
307
+ })
308
+ );
309
+ }}
310
+ </BarStack>
311
+ </Group>
312
+
313
+ <AxisBottom
314
+ top={yMax + margin.top}
315
+ left={margin.left + 10}
316
+ scale={dateScale}
317
+ hideAxisLine
318
+ hideTicks
319
+ numTicks={numBottomAxis}
320
+ tickValues={bottomAxisValue}
321
+ tickFormat={(d) => getDayOfMonth(d)}
322
+ tickLabelProps={() => ({
323
+ fontSize: isMobile ? 10 : 12,
324
+ fill: isDarkTheme ? '#B8B8B8' : '#A2A2A2',
325
+ textAnchor: 'middle',
326
+ })}
327
+ />
328
+
329
+ <AxisLeft
330
+ hideAxisLine
331
+ hideTicks
332
+ numTicks={isMobile ? 3 : 5}
333
+ top={margin.top}
334
+ left={margin.left}
335
+ scale={valueScale}
336
+ tickFormat={(d) => compactNumberFormat(Number(d))}
337
+ tickLabelProps={() => ({
338
+ fontSize: isMobile ? 10 : 12,
339
+ fill: isDarkTheme ? '#B8B8B8' : '#A2A2A2',
340
+ textAnchor: 'middle',
341
+ })}
342
+ />
343
+ </svg>
344
+
345
+ {tooltipData && tooltipOpen && (
346
+ <TooltipWithBounds
347
+ top={tooltipTop}
348
+ left={tooltipLeft}
349
+ style={{
350
+ backgroundColor: 'transparent',
351
+ boxShadow: 'none',
352
+ position: 'absolute',
353
+ zIndex: '99999999',
354
+ }}>
355
+ <TooltipContainer ref={tooltipRef}>
356
+ {tooltipData?.bar.bar.data.date && (
357
+ <TooltipInfoRow>
358
+ <div>
359
+ {dayjs
360
+ .utc(tooltipData.bar.bar.data.date)
361
+ .local()
362
+ .format('YYYY/MM/DD')
363
+ .toString()}
364
+ </div>
365
+ <div>
366
+ {getLabel
367
+ ? getLabel(getFormattedTotalValue(tooltipData.bar.bar.data))
368
+ : getFormattedTotalValue(tooltipData.bar.bar.data)}
369
+ </div>
370
+ </TooltipInfoRow>
371
+ )}
372
+ {Array.from(colorBucketMap).map((mapItem) => {
373
+ const [bucketItem, bucketColor] = mapItem;
374
+ const value = tooltipData?.bar.bar.data[bucketItem];
375
+ const formattedValue = !isNaN(Number(value))
376
+ ? AmountConverter(Number(Number(value).toFixed(2)))
377
+ : '0';
378
+ return (
379
+ <Fragment key={bucketItem}>
380
+ <Line />
381
+ <InfoContainer>
382
+ <NameWrapper>
383
+ <Circle style={{ backgroundColor: bucketColor }} />
384
+ <Divider direction="horizontal" size={'4'} />
385
+ <span>{bucketItem}</span>
386
+ </NameWrapper>
387
+ <Divider direction="horizontal" size={'10'} />
388
+
389
+ <span>
390
+ {getLabel ? getLabel(formattedValue) : formattedValue}
391
+ </span>
392
+ </InfoContainer>
393
+ </Fragment>
394
+ );
395
+ })}
396
+ </TooltipContainer>
397
+ </TooltipWithBounds>
398
+ )}
399
+ </Container>
400
+ );
401
+ };
@@ -0,0 +1,50 @@
1
+ import type { SeriesPoint } from '@visx/shape/lib/types/barStack.js';
2
+
3
+ export interface BarChartPropTypes {
4
+ data: BarStackDataType[];
5
+ width: number;
6
+ height: number;
7
+ colorBucketMap: ColorBucketMapType;
8
+ buckets: string[];
9
+ margin?: { top: number; right: number; bottom: number; left: number };
10
+ getLabel?: (value: string) => string;
11
+ isDarkTheme?: boolean;
12
+ }
13
+
14
+ export type BarStackDataType = {
15
+ [key: string]: string;
16
+ };
17
+
18
+ export type ColorBucketMapType = Map<string, string>;
19
+
20
+ export type TooltipDataType = {
21
+ bar: {
22
+ bar: SeriesPoint<BarStackDataType>;
23
+ key: string;
24
+ index: number;
25
+ height: number;
26
+ width: number;
27
+ x: number;
28
+ y: number;
29
+ color: string;
30
+ };
31
+ hoveredIndex: number;
32
+ };
33
+
34
+ export type DailyDataType = {
35
+ date: string;
36
+ bucket: string;
37
+ value: number;
38
+ };
39
+
40
+ export type ChartOptionsType = {
41
+ dailyData: DailyDataType[];
42
+ barChartColors: string[];
43
+ label?: string;
44
+ };
45
+
46
+ export interface BottomAxisData {
47
+ numBottomAxis: number;
48
+ startBottomAxis: number;
49
+ intervalBottomAxis: number;
50
+ }
@@ -0,0 +1,10 @@
1
+ export { BarChart } from './BarChart.js';
2
+ export { prepareBarChartData } from './BarChart.helpers.js';
3
+
4
+ export type {
5
+ BarStackDataType,
6
+ ColorBucketMapType,
7
+ BarChartPropTypes,
8
+ ChartOptionsType,
9
+ DailyDataType,
10
+ } from './BarChart.types.js';
@@ -0,0 +1,20 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ const useIsMobile = () => {
4
+ const [isMobile, setIsMobile] = useState<boolean>(false);
5
+
6
+ useEffect(() => {
7
+ const handleResize = () => {
8
+ const mobileBreakpoint = 640;
9
+ setIsMobile(window.innerWidth <= mobileBreakpoint);
10
+ };
11
+
12
+ handleResize();
13
+ window.addEventListener('resize', handleResize);
14
+ return () => window.removeEventListener('resize', handleResize);
15
+ }, []);
16
+
17
+ return isMobile;
18
+ };
19
+
20
+ export default useIsMobile;
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export type {
2
+ BarStackDataType,
3
+ ColorBucketMapType,
4
+ BarChartPropTypes,
5
+ ChartOptionsType,
6
+ DailyDataType,
7
+ } from './components/BarChart/index.js';
8
+ export { BarChart, prepareBarChartData } from './components/BarChart/index.js';
@@ -0,0 +1,47 @@
1
+ const THRESHOLD = 1000;
2
+ const BASE_TEN = 10;
3
+ const PERCENTAGE_MULTIPLIER = 100;
4
+
5
+ const unitList = ['', 'K', 'M', 'B'];
6
+ export function AmountConverter(number: number) {
7
+ const sign = Math.sign(number);
8
+ let unit = 0;
9
+ while (Math.abs(number) > THRESHOLD) {
10
+ unit = unit + 1;
11
+ number = Math.floor(Math.abs(number) / BASE_TEN) / PERCENTAGE_MULTIPLIER;
12
+ }
13
+ return sign * Math.abs(number) + unitList[unit];
14
+ }
15
+
16
+ export function getPercentageChange(
17
+ input: number | null,
18
+ output: number | null
19
+ ) {
20
+ if (!input || !output) {
21
+ return null;
22
+ }
23
+ return parseFloat(
24
+ Number((output / input - 1) * PERCENTAGE_MULTIPLIER).toFixed(2)
25
+ );
26
+ }
27
+
28
+ export function numberWithCommas(number: number) {
29
+ if (!number || isNaN(number)) {
30
+ return number;
31
+ }
32
+
33
+ return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
34
+ }
35
+
36
+ export function compactNumberFormat(number: number) {
37
+ if (!number || isNaN(number)) {
38
+ return '0';
39
+ }
40
+
41
+ const numberFormat = Intl.NumberFormat('en-US', {
42
+ notation: 'compact',
43
+ maximumFractionDigits: 1,
44
+ }).format(number);
45
+
46
+ return numberFormat;
47
+ }
@@ -0,0 +1,22 @@
1
+ export const monthsShort = [
2
+ 'Jan',
3
+ 'Feb',
4
+ 'Mar',
5
+ 'Apr',
6
+ 'May',
7
+ 'Jun',
8
+ 'Jul',
9
+ 'Aug',
10
+ 'Sep',
11
+ 'Oct',
12
+ 'Nov',
13
+ 'Dec',
14
+ ];
15
+
16
+ export function getDayOfMonth(dateString: string) {
17
+ const date = new Date(dateString);
18
+ const monthName = date.toLocaleDateString('en-US', { month: 'short' });
19
+ const dayNumber = date.getDate();
20
+
21
+ return `${dayNumber} ${monthName}`;
22
+ }