@gelatin-hero/framer-charts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/chunk-24EYBU3B.mjs +9 -0
- package/dist/chunk-24EYBU3B.mjs.map +1 -0
- package/dist/index.mjs +955 -0
- package/dist/index.mjs.map +1 -0
- package/dist/settlement-speeds-PQNHMD2W.mjs +8 -0
- package/dist/settlement-speeds-PQNHMD2W.mjs.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
First, run the development server:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev
|
|
9
|
+
# or
|
|
10
|
+
yarn dev
|
|
11
|
+
# or
|
|
12
|
+
pnpm dev
|
|
13
|
+
# or
|
|
14
|
+
bun dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
+
|
|
19
|
+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
20
|
+
|
|
21
|
+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
22
|
+
|
|
23
|
+
## Learn More
|
|
24
|
+
|
|
25
|
+
To learn more about Next.js, take a look at the following resources:
|
|
26
|
+
|
|
27
|
+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
28
|
+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
29
|
+
|
|
30
|
+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
31
|
+
|
|
32
|
+
## Deploy on Vercel
|
|
33
|
+
|
|
34
|
+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
35
|
+
|
|
36
|
+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/data/settlement-speeds.csv?raw
|
|
4
|
+
var settlement_speeds_default = ",Aug 25,Sep 25,Oct 25,Nov 25,Dec 25,Jan 26,Feb 26\r\nCrypto Instant,86.40%,89.30%,87.00%,85.40%,89.10%,90.60%,84.10%\r\nCrypto Fast,10.10%,7.40%,9.40%,9.00%,6.90%,5.90%,9.80%\r\nCrypto SLA,3.40%,3.20%,3.50%,5.50%,4.00%,3.50%,6.10%\r\nG3 Instant,27.40%,25.60%,41.60%,48.30%,66.50%,67.80%,85.40%\r\nG3 Fast,26.10%,33.40%,29.60%,31.90%,22.60%,15.70%,5.00%\r\nG3 SLA,46.50%,41.00%,28.80%,19.80%,10.90%,16.50%,9.60%\r\nG7 Instant,68.90%,70.60%,87.80%,90.20%,83.20%,88.60%,90.20%\r\nG7 Fast,14.80%,17.40%,5.10%,4.40%,12.00%,5.70%,4.30%\r\nG7 SLA,16.40%,11.90%,7.10%,5.40%,4.80%,5.70%,5.50%";
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
settlement_speeds_default
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=chunk-24EYBU3B.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/settlement-speeds.csv"],"sourcesContent":[",Aug 25,Sep 25,Oct 25,Nov 25,Dec 25,Jan 26,Feb 26\r\nCrypto Instant,86.40%,89.30%,87.00%,85.40%,89.10%,90.60%,84.10%\r\nCrypto Fast,10.10%,7.40%,9.40%,9.00%,6.90%,5.90%,9.80%\r\nCrypto SLA,3.40%,3.20%,3.50%,5.50%,4.00%,3.50%,6.10%\r\nG3 Instant,27.40%,25.60%,41.60%,48.30%,66.50%,67.80%,85.40%\r\nG3 Fast,26.10%,33.40%,29.60%,31.90%,22.60%,15.70%,5.00%\r\nG3 SLA,46.50%,41.00%,28.80%,19.80%,10.90%,16.50%,9.60%\r\nG7 Instant,68.90%,70.60%,87.80%,90.20%,83.20%,88.60%,90.20%\r\nG7 Fast,14.80%,17.40%,5.10%,4.40%,12.00%,5.70%,4.30%\r\nG7 SLA,16.40%,11.90%,7.10%,5.40%,4.80%,5.70%,5.50%"],"mappings":";;;AAAA;","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
settlement_speeds_default
|
|
4
|
+
} from "./chunk-24EYBU3B.mjs";
|
|
5
|
+
|
|
6
|
+
// src/framer/G7SettlementChart.framer.tsx
|
|
7
|
+
import React4 from "react";
|
|
8
|
+
|
|
9
|
+
// src/components/BarChart.tsx
|
|
10
|
+
import React3 from "react";
|
|
11
|
+
import { RiArrowLeftSLine, RiArrowRightSLine } from "@remixicon/react";
|
|
12
|
+
import {
|
|
13
|
+
Bar,
|
|
14
|
+
CartesianGrid,
|
|
15
|
+
Label,
|
|
16
|
+
BarChart as RechartsBarChart,
|
|
17
|
+
Legend as RechartsLegend,
|
|
18
|
+
ResponsiveContainer,
|
|
19
|
+
Tooltip,
|
|
20
|
+
XAxis,
|
|
21
|
+
YAxis
|
|
22
|
+
} from "recharts";
|
|
23
|
+
|
|
24
|
+
// src/lib/useOnWindowResize.ts
|
|
25
|
+
import * as React2 from "react";
|
|
26
|
+
var useOnWindowResize = (handler) => {
|
|
27
|
+
React2.useEffect(() => {
|
|
28
|
+
const handleResize = () => {
|
|
29
|
+
handler();
|
|
30
|
+
};
|
|
31
|
+
handleResize();
|
|
32
|
+
window.addEventListener("resize", handleResize);
|
|
33
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
34
|
+
}, [handler]);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/lib/chartColors.ts
|
|
38
|
+
var chartColors = {
|
|
39
|
+
blue: {
|
|
40
|
+
bg: "bg-blue-500",
|
|
41
|
+
stroke: "stroke-blue-500",
|
|
42
|
+
fill: "fill-blue-500",
|
|
43
|
+
text: "text-blue-500"
|
|
44
|
+
},
|
|
45
|
+
emerald: {
|
|
46
|
+
bg: "bg-emerald-500",
|
|
47
|
+
stroke: "stroke-emerald-500",
|
|
48
|
+
fill: "fill-emerald-500",
|
|
49
|
+
text: "text-emerald-500"
|
|
50
|
+
},
|
|
51
|
+
violet: {
|
|
52
|
+
bg: "bg-violet-500",
|
|
53
|
+
stroke: "stroke-violet-500",
|
|
54
|
+
fill: "fill-violet-500",
|
|
55
|
+
text: "text-violet-500"
|
|
56
|
+
},
|
|
57
|
+
amber: {
|
|
58
|
+
bg: "bg-amber-500",
|
|
59
|
+
stroke: "stroke-amber-500",
|
|
60
|
+
fill: "fill-amber-500",
|
|
61
|
+
text: "text-amber-500"
|
|
62
|
+
},
|
|
63
|
+
gray: {
|
|
64
|
+
bg: "bg-gray-500",
|
|
65
|
+
stroke: "stroke-gray-500",
|
|
66
|
+
fill: "fill-gray-500",
|
|
67
|
+
text: "text-gray-500"
|
|
68
|
+
},
|
|
69
|
+
cyan: {
|
|
70
|
+
bg: "bg-cyan-500",
|
|
71
|
+
stroke: "stroke-cyan-500",
|
|
72
|
+
fill: "fill-cyan-500",
|
|
73
|
+
text: "text-cyan-500"
|
|
74
|
+
},
|
|
75
|
+
pink: {
|
|
76
|
+
bg: "bg-pink-500",
|
|
77
|
+
stroke: "stroke-pink-500",
|
|
78
|
+
fill: "fill-pink-500",
|
|
79
|
+
text: "text-pink-500"
|
|
80
|
+
},
|
|
81
|
+
lime: {
|
|
82
|
+
bg: "bg-lime-500",
|
|
83
|
+
stroke: "stroke-lime-500",
|
|
84
|
+
fill: "fill-lime-500",
|
|
85
|
+
text: "text-lime-500"
|
|
86
|
+
},
|
|
87
|
+
fuchsia: {
|
|
88
|
+
bg: "bg-fuchsia-500",
|
|
89
|
+
stroke: "stroke-fuchsia-500",
|
|
90
|
+
fill: "fill-fuchsia-500",
|
|
91
|
+
text: "text-fuchsia-500"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var AvailableChartColors = Object.keys(
|
|
95
|
+
chartColors
|
|
96
|
+
);
|
|
97
|
+
var constructCategoryColors = (categories, colors) => {
|
|
98
|
+
const categoryColors = /* @__PURE__ */ new Map();
|
|
99
|
+
categories.forEach((category, index) => {
|
|
100
|
+
categoryColors.set(category, colors[index % colors.length]);
|
|
101
|
+
});
|
|
102
|
+
return categoryColors;
|
|
103
|
+
};
|
|
104
|
+
var getColorClassName = (color, type) => {
|
|
105
|
+
var _a;
|
|
106
|
+
const fallbackColor = {
|
|
107
|
+
bg: "bg-gray-500",
|
|
108
|
+
stroke: "stroke-gray-500",
|
|
109
|
+
fill: "fill-gray-500",
|
|
110
|
+
text: "text-gray-500"
|
|
111
|
+
};
|
|
112
|
+
return ((_a = chartColors[color]) == null ? void 0 : _a[type]) ?? fallbackColor[type];
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/lib/cx.ts
|
|
116
|
+
import clsx from "clsx";
|
|
117
|
+
import { twMerge } from "tailwind-merge";
|
|
118
|
+
function cx(...args) {
|
|
119
|
+
return twMerge(clsx(...args));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/lib/getYAxisDomain.ts
|
|
123
|
+
var getYAxisDomain = (autoMinValue, minValue, maxValue) => {
|
|
124
|
+
const minDomain = autoMinValue ? "auto" : minValue ?? 0;
|
|
125
|
+
const maxDomain = maxValue ?? "auto";
|
|
126
|
+
return [minDomain, maxDomain];
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// src/components/BarChart.tsx
|
|
130
|
+
function deepEqual(obj1, obj2) {
|
|
131
|
+
if (obj1 === obj2) return true;
|
|
132
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object" || obj1 === null || obj2 === null) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
const keys1 = Object.keys(obj1);
|
|
136
|
+
const keys2 = Object.keys(obj2);
|
|
137
|
+
if (keys1.length !== keys2.length) return false;
|
|
138
|
+
for (const key of keys1) {
|
|
139
|
+
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
var renderShape = (props, activeBar, activeLegend, layout) => {
|
|
144
|
+
const { fillOpacity, name, payload, value } = props;
|
|
145
|
+
let { x, width, y, height } = props;
|
|
146
|
+
if (layout === "horizontal" && height < 0) {
|
|
147
|
+
y += height;
|
|
148
|
+
height = Math.abs(height);
|
|
149
|
+
} else if (layout === "vertical" && width < 0) {
|
|
150
|
+
x += width;
|
|
151
|
+
width = Math.abs(width);
|
|
152
|
+
}
|
|
153
|
+
return /* @__PURE__ */ React3.createElement(
|
|
154
|
+
"rect",
|
|
155
|
+
{
|
|
156
|
+
x,
|
|
157
|
+
y,
|
|
158
|
+
width,
|
|
159
|
+
height,
|
|
160
|
+
opacity: activeBar || activeLegend && activeLegend !== name ? deepEqual(activeBar, { ...payload, value }) ? fillOpacity : 0.3 : fillOpacity
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
var LegendItem = ({
|
|
165
|
+
name,
|
|
166
|
+
color,
|
|
167
|
+
onClick,
|
|
168
|
+
activeLegend
|
|
169
|
+
}) => {
|
|
170
|
+
const hasOnValueChange = !!onClick;
|
|
171
|
+
return /* @__PURE__ */ React3.createElement(
|
|
172
|
+
"li",
|
|
173
|
+
{
|
|
174
|
+
className: cx(
|
|
175
|
+
"group inline-flex flex-nowrap items-center gap-1.5 rounded-sm px-2 py-1 whitespace-nowrap transition",
|
|
176
|
+
hasOnValueChange ? "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800" : "cursor-default"
|
|
177
|
+
),
|
|
178
|
+
onClick: (e) => {
|
|
179
|
+
e.stopPropagation();
|
|
180
|
+
onClick == null ? void 0 : onClick(name, color);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
/* @__PURE__ */ React3.createElement(
|
|
184
|
+
"span",
|
|
185
|
+
{
|
|
186
|
+
className: cx(
|
|
187
|
+
"size-2 shrink-0 rounded-xs",
|
|
188
|
+
getColorClassName(color, "bg"),
|
|
189
|
+
activeLegend && activeLegend !== name ? "opacity-40" : "opacity-100"
|
|
190
|
+
),
|
|
191
|
+
"aria-hidden": true
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
/* @__PURE__ */ React3.createElement(
|
|
195
|
+
"p",
|
|
196
|
+
{
|
|
197
|
+
className: cx(
|
|
198
|
+
"truncate text-xs whitespace-nowrap",
|
|
199
|
+
"text-black",
|
|
200
|
+
hasOnValueChange && "group-hover:text-gray-700",
|
|
201
|
+
activeLegend && activeLegend !== name ? "opacity-40" : "opacity-100"
|
|
202
|
+
)
|
|
203
|
+
},
|
|
204
|
+
name
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
var ScrollButton = ({ icon, onClick, disabled }) => {
|
|
209
|
+
const Icon = icon;
|
|
210
|
+
const [isPressed, setIsPressed] = React3.useState(false);
|
|
211
|
+
const intervalRef = React3.useRef(null);
|
|
212
|
+
React3.useEffect(() => {
|
|
213
|
+
if (isPressed) {
|
|
214
|
+
intervalRef.current = setInterval(() => {
|
|
215
|
+
onClick == null ? void 0 : onClick();
|
|
216
|
+
}, 300);
|
|
217
|
+
} else {
|
|
218
|
+
clearInterval(intervalRef.current);
|
|
219
|
+
}
|
|
220
|
+
return () => clearInterval(intervalRef.current);
|
|
221
|
+
}, [isPressed, onClick]);
|
|
222
|
+
React3.useEffect(() => {
|
|
223
|
+
if (disabled) {
|
|
224
|
+
clearInterval(intervalRef.current);
|
|
225
|
+
setIsPressed(false);
|
|
226
|
+
}
|
|
227
|
+
}, [disabled]);
|
|
228
|
+
return /* @__PURE__ */ React3.createElement(
|
|
229
|
+
"button",
|
|
230
|
+
{
|
|
231
|
+
type: "button",
|
|
232
|
+
className: cx(
|
|
233
|
+
"group inline-flex size-5 items-center truncate rounded-sm transition",
|
|
234
|
+
disabled ? "cursor-not-allowed text-gray-400 dark:text-gray-600" : "cursor-pointer text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-50"
|
|
235
|
+
),
|
|
236
|
+
disabled,
|
|
237
|
+
onClick: (e) => {
|
|
238
|
+
e.stopPropagation();
|
|
239
|
+
onClick == null ? void 0 : onClick();
|
|
240
|
+
},
|
|
241
|
+
onMouseDown: (e) => {
|
|
242
|
+
e.stopPropagation();
|
|
243
|
+
setIsPressed(true);
|
|
244
|
+
},
|
|
245
|
+
onMouseUp: (e) => {
|
|
246
|
+
e.stopPropagation();
|
|
247
|
+
setIsPressed(false);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
/* @__PURE__ */ React3.createElement(Icon, { className: "size-full", "aria-hidden": "true" })
|
|
251
|
+
);
|
|
252
|
+
};
|
|
253
|
+
var Legend = React3.forwardRef((props, ref) => {
|
|
254
|
+
const {
|
|
255
|
+
categories,
|
|
256
|
+
colors = AvailableChartColors,
|
|
257
|
+
className,
|
|
258
|
+
onClickLegendItem,
|
|
259
|
+
activeLegend,
|
|
260
|
+
enableLegendSlider = false,
|
|
261
|
+
...other
|
|
262
|
+
} = props;
|
|
263
|
+
const scrollableRef = React3.useRef(null);
|
|
264
|
+
const scrollButtonsRef = React3.useRef(null);
|
|
265
|
+
const [hasScroll, setHasScroll] = React3.useState(null);
|
|
266
|
+
const [isKeyDowned, setIsKeyDowned] = React3.useState(null);
|
|
267
|
+
const intervalRef = React3.useRef(null);
|
|
268
|
+
const checkScroll = React3.useCallback(() => {
|
|
269
|
+
const scrollable = scrollableRef == null ? void 0 : scrollableRef.current;
|
|
270
|
+
if (!scrollable) return;
|
|
271
|
+
const hasLeftScroll = scrollable.scrollLeft > 0;
|
|
272
|
+
const hasRightScroll = scrollable.scrollWidth - scrollable.clientWidth > scrollable.scrollLeft;
|
|
273
|
+
setHasScroll({ left: hasLeftScroll, right: hasRightScroll });
|
|
274
|
+
}, [setHasScroll]);
|
|
275
|
+
const scrollToTest = React3.useCallback(
|
|
276
|
+
(direction) => {
|
|
277
|
+
const element = scrollableRef == null ? void 0 : scrollableRef.current;
|
|
278
|
+
const scrollButtons = scrollButtonsRef == null ? void 0 : scrollButtonsRef.current;
|
|
279
|
+
const scrollButtonsWith = (scrollButtons == null ? void 0 : scrollButtons.clientWidth) ?? 0;
|
|
280
|
+
const width = (element == null ? void 0 : element.clientWidth) ?? 0;
|
|
281
|
+
if (element && enableLegendSlider) {
|
|
282
|
+
element.scrollTo({
|
|
283
|
+
left: direction === "left" ? element.scrollLeft - width + scrollButtonsWith : element.scrollLeft + width - scrollButtonsWith,
|
|
284
|
+
behavior: "smooth"
|
|
285
|
+
});
|
|
286
|
+
setTimeout(() => {
|
|
287
|
+
checkScroll();
|
|
288
|
+
}, 400);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
[enableLegendSlider, checkScroll]
|
|
292
|
+
);
|
|
293
|
+
React3.useEffect(() => {
|
|
294
|
+
const keyDownHandler = (key) => {
|
|
295
|
+
if (key === "ArrowLeft") {
|
|
296
|
+
scrollToTest("left");
|
|
297
|
+
} else if (key === "ArrowRight") {
|
|
298
|
+
scrollToTest("right");
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
if (isKeyDowned) {
|
|
302
|
+
keyDownHandler(isKeyDowned);
|
|
303
|
+
intervalRef.current = setInterval(() => {
|
|
304
|
+
keyDownHandler(isKeyDowned);
|
|
305
|
+
}, 300);
|
|
306
|
+
} else {
|
|
307
|
+
clearInterval(intervalRef.current);
|
|
308
|
+
}
|
|
309
|
+
return () => clearInterval(intervalRef.current);
|
|
310
|
+
}, [isKeyDowned, scrollToTest]);
|
|
311
|
+
const keyDown = (e) => {
|
|
312
|
+
e.stopPropagation();
|
|
313
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
|
|
314
|
+
e.preventDefault();
|
|
315
|
+
setIsKeyDowned(e.key);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
const keyUp = (e) => {
|
|
319
|
+
e.stopPropagation();
|
|
320
|
+
setIsKeyDowned(null);
|
|
321
|
+
};
|
|
322
|
+
React3.useEffect(() => {
|
|
323
|
+
const scrollable = scrollableRef == null ? void 0 : scrollableRef.current;
|
|
324
|
+
if (enableLegendSlider) {
|
|
325
|
+
checkScroll();
|
|
326
|
+
scrollable == null ? void 0 : scrollable.addEventListener("keydown", keyDown);
|
|
327
|
+
scrollable == null ? void 0 : scrollable.addEventListener("keyup", keyUp);
|
|
328
|
+
}
|
|
329
|
+
return () => {
|
|
330
|
+
scrollable == null ? void 0 : scrollable.removeEventListener("keydown", keyDown);
|
|
331
|
+
scrollable == null ? void 0 : scrollable.removeEventListener("keyup", keyUp);
|
|
332
|
+
};
|
|
333
|
+
}, [checkScroll, enableLegendSlider]);
|
|
334
|
+
return /* @__PURE__ */ React3.createElement(
|
|
335
|
+
"ol",
|
|
336
|
+
{
|
|
337
|
+
ref,
|
|
338
|
+
className: cx("relative overflow-hidden", className),
|
|
339
|
+
...other
|
|
340
|
+
},
|
|
341
|
+
/* @__PURE__ */ React3.createElement(
|
|
342
|
+
"div",
|
|
343
|
+
{
|
|
344
|
+
ref: scrollableRef,
|
|
345
|
+
tabIndex: 0,
|
|
346
|
+
className: cx(
|
|
347
|
+
"flex h-full",
|
|
348
|
+
enableLegendSlider ? (hasScroll == null ? void 0 : hasScroll.right) || (hasScroll == null ? void 0 : hasScroll.left) ? "snap-mandatory items-center overflow-auto pr-12 pl-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" : "" : "flex-wrap"
|
|
349
|
+
)
|
|
350
|
+
},
|
|
351
|
+
categories.map((category, index) => /* @__PURE__ */ React3.createElement(
|
|
352
|
+
LegendItem,
|
|
353
|
+
{
|
|
354
|
+
key: `item-${index}`,
|
|
355
|
+
name: category,
|
|
356
|
+
color: colors[index],
|
|
357
|
+
onClick: onClickLegendItem,
|
|
358
|
+
activeLegend
|
|
359
|
+
}
|
|
360
|
+
))
|
|
361
|
+
),
|
|
362
|
+
enableLegendSlider && ((hasScroll == null ? void 0 : hasScroll.right) || (hasScroll == null ? void 0 : hasScroll.left)) ? /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
|
|
363
|
+
"div",
|
|
364
|
+
{
|
|
365
|
+
className: cx(
|
|
366
|
+
"absolute top-0 right-0 bottom-0 flex h-full items-center justify-center pr-1",
|
|
367
|
+
"bg-white dark:bg-gray-950"
|
|
368
|
+
)
|
|
369
|
+
},
|
|
370
|
+
/* @__PURE__ */ React3.createElement(
|
|
371
|
+
ScrollButton,
|
|
372
|
+
{
|
|
373
|
+
icon: RiArrowLeftSLine,
|
|
374
|
+
onClick: () => {
|
|
375
|
+
setIsKeyDowned(null);
|
|
376
|
+
scrollToTest("left");
|
|
377
|
+
},
|
|
378
|
+
disabled: !(hasScroll == null ? void 0 : hasScroll.left)
|
|
379
|
+
}
|
|
380
|
+
),
|
|
381
|
+
/* @__PURE__ */ React3.createElement(
|
|
382
|
+
ScrollButton,
|
|
383
|
+
{
|
|
384
|
+
icon: RiArrowRightSLine,
|
|
385
|
+
onClick: () => {
|
|
386
|
+
setIsKeyDowned(null);
|
|
387
|
+
scrollToTest("right");
|
|
388
|
+
},
|
|
389
|
+
disabled: !(hasScroll == null ? void 0 : hasScroll.right)
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
)) : null
|
|
393
|
+
);
|
|
394
|
+
});
|
|
395
|
+
Legend.displayName = "Legend";
|
|
396
|
+
var ChartLegend = ({ payload }, categoryColors, setLegendHeight, activeLegend, onClick, enableLegendSlider, legendPosition, yAxisWidth) => {
|
|
397
|
+
const legendRef = React3.useRef(null);
|
|
398
|
+
useOnWindowResize(() => {
|
|
399
|
+
var _a;
|
|
400
|
+
const calculateHeight = (height) => height ? Number(height) + 15 : 60;
|
|
401
|
+
setLegendHeight(calculateHeight((_a = legendRef.current) == null ? void 0 : _a.clientHeight));
|
|
402
|
+
});
|
|
403
|
+
const filteredPayload = payload.filter((item) => item.type !== "none");
|
|
404
|
+
const paddingLeft = legendPosition === "left" && yAxisWidth ? yAxisWidth - 8 : 0;
|
|
405
|
+
return /* @__PURE__ */ React3.createElement(
|
|
406
|
+
"div",
|
|
407
|
+
{
|
|
408
|
+
style: { paddingLeft },
|
|
409
|
+
ref: legendRef,
|
|
410
|
+
className: cx(
|
|
411
|
+
"flex items-center",
|
|
412
|
+
{ "justify-center": legendPosition === "center" },
|
|
413
|
+
{
|
|
414
|
+
"justify-start": legendPosition === "left"
|
|
415
|
+
},
|
|
416
|
+
{ "justify-end": legendPosition === "right" }
|
|
417
|
+
)
|
|
418
|
+
},
|
|
419
|
+
/* @__PURE__ */ React3.createElement(
|
|
420
|
+
Legend,
|
|
421
|
+
{
|
|
422
|
+
categories: filteredPayload.map((entry) => entry.value),
|
|
423
|
+
colors: filteredPayload.map(
|
|
424
|
+
(entry) => categoryColors.get(entry.value)
|
|
425
|
+
),
|
|
426
|
+
onClickLegendItem: onClick,
|
|
427
|
+
activeLegend,
|
|
428
|
+
enableLegendSlider
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
);
|
|
432
|
+
};
|
|
433
|
+
var ChartTooltip = ({
|
|
434
|
+
active,
|
|
435
|
+
payload,
|
|
436
|
+
label,
|
|
437
|
+
valueFormatter
|
|
438
|
+
}) => {
|
|
439
|
+
if (active && payload && payload.length) {
|
|
440
|
+
return /* @__PURE__ */ React3.createElement(
|
|
441
|
+
"div",
|
|
442
|
+
{
|
|
443
|
+
className: cx(
|
|
444
|
+
"rounded-md border text-sm shadow-md",
|
|
445
|
+
"border-gray-200 dark:border-gray-800",
|
|
446
|
+
"bg-white dark:bg-gray-950"
|
|
447
|
+
)
|
|
448
|
+
},
|
|
449
|
+
/* @__PURE__ */ React3.createElement("div", { className: cx("border-b border-inherit px-4 py-2") }, /* @__PURE__ */ React3.createElement(
|
|
450
|
+
"p",
|
|
451
|
+
{
|
|
452
|
+
className: cx(
|
|
453
|
+
"font-medium",
|
|
454
|
+
"text-gray-900 dark:text-gray-50"
|
|
455
|
+
)
|
|
456
|
+
},
|
|
457
|
+
label
|
|
458
|
+
)),
|
|
459
|
+
/* @__PURE__ */ React3.createElement("div", { className: cx("space-y-1 px-4 py-2") }, payload.map(({ value, category, color }, index) => /* @__PURE__ */ React3.createElement(
|
|
460
|
+
"div",
|
|
461
|
+
{
|
|
462
|
+
key: `id-${index}`,
|
|
463
|
+
className: "flex items-center justify-between space-x-8"
|
|
464
|
+
},
|
|
465
|
+
/* @__PURE__ */ React3.createElement("div", { className: "flex items-center space-x-2" }, /* @__PURE__ */ React3.createElement(
|
|
466
|
+
"span",
|
|
467
|
+
{
|
|
468
|
+
"aria-hidden": "true",
|
|
469
|
+
className: cx(
|
|
470
|
+
"size-2 shrink-0 rounded-xs",
|
|
471
|
+
getColorClassName(color, "bg")
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
), /* @__PURE__ */ React3.createElement(
|
|
475
|
+
"p",
|
|
476
|
+
{
|
|
477
|
+
className: cx(
|
|
478
|
+
"text-right whitespace-nowrap",
|
|
479
|
+
"text-gray-700 dark:text-gray-300"
|
|
480
|
+
)
|
|
481
|
+
},
|
|
482
|
+
category
|
|
483
|
+
)),
|
|
484
|
+
/* @__PURE__ */ React3.createElement(
|
|
485
|
+
"p",
|
|
486
|
+
{
|
|
487
|
+
className: cx(
|
|
488
|
+
"text-right font-medium whitespace-nowrap tabular-nums",
|
|
489
|
+
"text-gray-900 dark:text-gray-50"
|
|
490
|
+
)
|
|
491
|
+
},
|
|
492
|
+
valueFormatter(value)
|
|
493
|
+
)
|
|
494
|
+
)))
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
return null;
|
|
498
|
+
};
|
|
499
|
+
var BarChart = React3.forwardRef(
|
|
500
|
+
(props, forwardedRef) => {
|
|
501
|
+
const {
|
|
502
|
+
data = [],
|
|
503
|
+
categories = [],
|
|
504
|
+
index,
|
|
505
|
+
colors = AvailableChartColors,
|
|
506
|
+
valueFormatter = (value) => value.toString(),
|
|
507
|
+
startEndOnly = false,
|
|
508
|
+
showXAxis = true,
|
|
509
|
+
showYAxis = true,
|
|
510
|
+
showGridLines = true,
|
|
511
|
+
yAxisWidth = 56,
|
|
512
|
+
intervalType = "equidistantPreserveStart",
|
|
513
|
+
showTooltip = true,
|
|
514
|
+
showLegend = true,
|
|
515
|
+
autoMinValue = false,
|
|
516
|
+
minValue,
|
|
517
|
+
maxValue,
|
|
518
|
+
allowDecimals = true,
|
|
519
|
+
className,
|
|
520
|
+
onValueChange,
|
|
521
|
+
enableLegendSlider = false,
|
|
522
|
+
barCategoryGap,
|
|
523
|
+
tickGap = 5,
|
|
524
|
+
xAxisLabel,
|
|
525
|
+
yAxisLabel,
|
|
526
|
+
layout = "horizontal",
|
|
527
|
+
type = "default",
|
|
528
|
+
legendPosition = "right",
|
|
529
|
+
tooltipCallback,
|
|
530
|
+
customTooltip,
|
|
531
|
+
...other
|
|
532
|
+
} = props;
|
|
533
|
+
const CustomTooltip = customTooltip;
|
|
534
|
+
const paddingValue = !showXAxis && !showYAxis || startEndOnly && !showYAxis ? 0 : 20;
|
|
535
|
+
const [legendHeight, setLegendHeight] = React3.useState(60);
|
|
536
|
+
const [activeLegend, setActiveLegend] = React3.useState(
|
|
537
|
+
void 0
|
|
538
|
+
);
|
|
539
|
+
const categoryColors = constructCategoryColors(categories, colors);
|
|
540
|
+
const [activeBar, setActiveBar] = React3.useState(void 0);
|
|
541
|
+
const yAxisDomain = getYAxisDomain(autoMinValue, minValue, maxValue);
|
|
542
|
+
const hasOnValueChange = !!onValueChange;
|
|
543
|
+
const stacked = type === "stacked" || type === "percent";
|
|
544
|
+
const prevActiveRef = React3.useRef(void 0);
|
|
545
|
+
const prevLabelRef = React3.useRef(void 0);
|
|
546
|
+
function valueToPercent(value) {
|
|
547
|
+
return `${(value * 100).toFixed(0)}%`;
|
|
548
|
+
}
|
|
549
|
+
function onBarClick(data2, _, event) {
|
|
550
|
+
var _a, _b, _c, _d;
|
|
551
|
+
event.stopPropagation();
|
|
552
|
+
if (!onValueChange) return;
|
|
553
|
+
if (deepEqual(activeBar, { ...data2.payload, value: data2.value })) {
|
|
554
|
+
setActiveLegend(void 0);
|
|
555
|
+
setActiveBar(void 0);
|
|
556
|
+
onValueChange == null ? void 0 : onValueChange(null);
|
|
557
|
+
} else {
|
|
558
|
+
setActiveLegend((_b = (_a = data2.tooltipPayload) == null ? void 0 : _a[0]) == null ? void 0 : _b.dataKey);
|
|
559
|
+
setActiveBar({
|
|
560
|
+
...data2.payload,
|
|
561
|
+
value: data2.value
|
|
562
|
+
});
|
|
563
|
+
onValueChange == null ? void 0 : onValueChange({
|
|
564
|
+
eventType: "bar",
|
|
565
|
+
categoryClicked: (_d = (_c = data2.tooltipPayload) == null ? void 0 : _c[0]) == null ? void 0 : _d.dataKey,
|
|
566
|
+
...data2.payload
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function onCategoryClick(dataKey) {
|
|
571
|
+
if (!hasOnValueChange) return;
|
|
572
|
+
if (dataKey === activeLegend && !activeBar) {
|
|
573
|
+
setActiveLegend(void 0);
|
|
574
|
+
onValueChange == null ? void 0 : onValueChange(null);
|
|
575
|
+
} else {
|
|
576
|
+
setActiveLegend(dataKey);
|
|
577
|
+
onValueChange == null ? void 0 : onValueChange({
|
|
578
|
+
eventType: "category",
|
|
579
|
+
categoryClicked: dataKey
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
setActiveBar(void 0);
|
|
583
|
+
}
|
|
584
|
+
return /* @__PURE__ */ React3.createElement(
|
|
585
|
+
"div",
|
|
586
|
+
{
|
|
587
|
+
ref: forwardedRef,
|
|
588
|
+
className: cx("h-80 w-full", className),
|
|
589
|
+
"tremor-id": "tremor-raw",
|
|
590
|
+
...other
|
|
591
|
+
},
|
|
592
|
+
/* @__PURE__ */ React3.createElement(ResponsiveContainer, null, /* @__PURE__ */ React3.createElement(
|
|
593
|
+
RechartsBarChart,
|
|
594
|
+
{
|
|
595
|
+
data,
|
|
596
|
+
onClick: hasOnValueChange && (activeLegend || activeBar) ? () => {
|
|
597
|
+
setActiveBar(void 0);
|
|
598
|
+
setActiveLegend(void 0);
|
|
599
|
+
onValueChange == null ? void 0 : onValueChange(null);
|
|
600
|
+
} : void 0,
|
|
601
|
+
margin: {
|
|
602
|
+
bottom: xAxisLabel ? 30 : void 0,
|
|
603
|
+
left: yAxisLabel ? 20 : void 0,
|
|
604
|
+
right: yAxisLabel ? 5 : void 0,
|
|
605
|
+
top: 5
|
|
606
|
+
},
|
|
607
|
+
stackOffset: type === "percent" ? "expand" : void 0,
|
|
608
|
+
layout,
|
|
609
|
+
barCategoryGap
|
|
610
|
+
},
|
|
611
|
+
showGridLines ? /* @__PURE__ */ React3.createElement(
|
|
612
|
+
CartesianGrid,
|
|
613
|
+
{
|
|
614
|
+
className: cx("stroke-gray-100 stroke-1"),
|
|
615
|
+
horizontal: layout !== "vertical",
|
|
616
|
+
vertical: layout === "vertical"
|
|
617
|
+
}
|
|
618
|
+
) : null,
|
|
619
|
+
/* @__PURE__ */ React3.createElement(
|
|
620
|
+
XAxis,
|
|
621
|
+
{
|
|
622
|
+
hide: !showXAxis,
|
|
623
|
+
tick: {
|
|
624
|
+
transform: layout !== "vertical" ? "translate(0, 6)" : void 0
|
|
625
|
+
},
|
|
626
|
+
fill: "",
|
|
627
|
+
stroke: "",
|
|
628
|
+
className: cx(
|
|
629
|
+
"text-xs",
|
|
630
|
+
"fill-gray-500 dark:fill-gray-500",
|
|
631
|
+
{ "mt-4": layout !== "vertical" }
|
|
632
|
+
),
|
|
633
|
+
tickLine: false,
|
|
634
|
+
axisLine: false,
|
|
635
|
+
minTickGap: tickGap,
|
|
636
|
+
...layout !== "vertical" ? {
|
|
637
|
+
padding: {
|
|
638
|
+
left: paddingValue,
|
|
639
|
+
right: paddingValue
|
|
640
|
+
},
|
|
641
|
+
dataKey: index,
|
|
642
|
+
interval: startEndOnly ? "preserveStartEnd" : intervalType,
|
|
643
|
+
ticks: startEndOnly ? [data[0][index], data[data.length - 1][index]] : void 0
|
|
644
|
+
} : {
|
|
645
|
+
type: "number",
|
|
646
|
+
domain: yAxisDomain,
|
|
647
|
+
tickFormatter: type === "percent" ? valueToPercent : valueFormatter,
|
|
648
|
+
allowDecimals
|
|
649
|
+
}
|
|
650
|
+
},
|
|
651
|
+
xAxisLabel && /* @__PURE__ */ React3.createElement(
|
|
652
|
+
Label,
|
|
653
|
+
{
|
|
654
|
+
position: "insideBottom",
|
|
655
|
+
offset: -20,
|
|
656
|
+
className: "fill-gray-800 text-sm font-medium dark:fill-gray-200"
|
|
657
|
+
},
|
|
658
|
+
xAxisLabel
|
|
659
|
+
)
|
|
660
|
+
),
|
|
661
|
+
/* @__PURE__ */ React3.createElement(
|
|
662
|
+
YAxis,
|
|
663
|
+
{
|
|
664
|
+
width: yAxisWidth,
|
|
665
|
+
hide: !showYAxis,
|
|
666
|
+
axisLine: false,
|
|
667
|
+
tickLine: false,
|
|
668
|
+
fill: "",
|
|
669
|
+
stroke: "",
|
|
670
|
+
className: cx(
|
|
671
|
+
"text-xs",
|
|
672
|
+
"fill-gray-500 dark:fill-gray-500"
|
|
673
|
+
),
|
|
674
|
+
tick: {
|
|
675
|
+
transform: layout !== "vertical" ? "translate(-3, 0)" : "translate(0, 0)"
|
|
676
|
+
},
|
|
677
|
+
...layout !== "vertical" ? {
|
|
678
|
+
type: "number",
|
|
679
|
+
domain: yAxisDomain,
|
|
680
|
+
tickFormatter: type === "percent" ? valueToPercent : valueFormatter,
|
|
681
|
+
allowDecimals
|
|
682
|
+
} : {
|
|
683
|
+
dataKey: index,
|
|
684
|
+
ticks: startEndOnly ? [data[0][index], data[data.length - 1][index]] : void 0,
|
|
685
|
+
type: "category",
|
|
686
|
+
interval: "equidistantPreserveStart"
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
yAxisLabel && /* @__PURE__ */ React3.createElement(
|
|
690
|
+
Label,
|
|
691
|
+
{
|
|
692
|
+
position: "insideLeft",
|
|
693
|
+
style: { textAnchor: "middle" },
|
|
694
|
+
angle: -90,
|
|
695
|
+
offset: -15,
|
|
696
|
+
className: "fill-gray-800 text-sm font-medium dark:fill-gray-200"
|
|
697
|
+
},
|
|
698
|
+
yAxisLabel
|
|
699
|
+
)
|
|
700
|
+
),
|
|
701
|
+
/* @__PURE__ */ React3.createElement(
|
|
702
|
+
Tooltip,
|
|
703
|
+
{
|
|
704
|
+
wrapperStyle: { outline: "none", zIndex: 10 },
|
|
705
|
+
isAnimationActive: true,
|
|
706
|
+
animationDuration: 100,
|
|
707
|
+
cursor: { fill: "#d1d5db", opacity: "0.15" },
|
|
708
|
+
offset: 20,
|
|
709
|
+
position: {
|
|
710
|
+
y: layout === "horizontal" ? 0 : void 0,
|
|
711
|
+
x: layout === "horizontal" ? void 0 : yAxisWidth + 20
|
|
712
|
+
},
|
|
713
|
+
content: ({ active, payload, label }) => {
|
|
714
|
+
const cleanPayload = payload ? payload.map((item) => ({
|
|
715
|
+
category: item.dataKey,
|
|
716
|
+
value: item.value,
|
|
717
|
+
index: item.payload[index],
|
|
718
|
+
color: categoryColors.get(
|
|
719
|
+
item.dataKey
|
|
720
|
+
),
|
|
721
|
+
type: item.type,
|
|
722
|
+
payload: item.payload
|
|
723
|
+
})) : [];
|
|
724
|
+
if (tooltipCallback && (active !== prevActiveRef.current || label !== prevLabelRef.current)) {
|
|
725
|
+
tooltipCallback({ active, payload: cleanPayload, label });
|
|
726
|
+
prevActiveRef.current = active;
|
|
727
|
+
prevLabelRef.current = label;
|
|
728
|
+
}
|
|
729
|
+
return showTooltip && active ? CustomTooltip ? /* @__PURE__ */ React3.createElement(
|
|
730
|
+
CustomTooltip,
|
|
731
|
+
{
|
|
732
|
+
active,
|
|
733
|
+
payload: cleanPayload,
|
|
734
|
+
label
|
|
735
|
+
}
|
|
736
|
+
) : /* @__PURE__ */ React3.createElement(
|
|
737
|
+
ChartTooltip,
|
|
738
|
+
{
|
|
739
|
+
active,
|
|
740
|
+
payload: cleanPayload,
|
|
741
|
+
label,
|
|
742
|
+
valueFormatter
|
|
743
|
+
}
|
|
744
|
+
) : null;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
),
|
|
748
|
+
showLegend ? /* @__PURE__ */ React3.createElement(
|
|
749
|
+
RechartsLegend,
|
|
750
|
+
{
|
|
751
|
+
verticalAlign: "top",
|
|
752
|
+
height: legendHeight,
|
|
753
|
+
content: ({ payload }) => ChartLegend(
|
|
754
|
+
{ payload },
|
|
755
|
+
categoryColors,
|
|
756
|
+
setLegendHeight,
|
|
757
|
+
activeLegend,
|
|
758
|
+
hasOnValueChange ? (clickedLegendItem) => onCategoryClick(clickedLegendItem) : void 0,
|
|
759
|
+
enableLegendSlider,
|
|
760
|
+
legendPosition,
|
|
761
|
+
yAxisWidth
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
) : null,
|
|
765
|
+
categories.map((category) => /* @__PURE__ */ React3.createElement(
|
|
766
|
+
Bar,
|
|
767
|
+
{
|
|
768
|
+
className: cx(
|
|
769
|
+
getColorClassName(
|
|
770
|
+
categoryColors.get(category),
|
|
771
|
+
"fill"
|
|
772
|
+
),
|
|
773
|
+
onValueChange ? "cursor-pointer" : ""
|
|
774
|
+
),
|
|
775
|
+
key: category,
|
|
776
|
+
name: category,
|
|
777
|
+
type: "linear",
|
|
778
|
+
dataKey: category,
|
|
779
|
+
stackId: stacked ? "stack" : void 0,
|
|
780
|
+
isAnimationActive: false,
|
|
781
|
+
fill: "",
|
|
782
|
+
shape: (props2) => renderShape(props2, activeBar, activeLegend, layout),
|
|
783
|
+
onClick: onBarClick
|
|
784
|
+
}
|
|
785
|
+
))
|
|
786
|
+
))
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
BarChart.displayName = "BarChart";
|
|
791
|
+
|
|
792
|
+
// src/charts/SettlementSpeedChart.tsx
|
|
793
|
+
function SettlementSpeedChart({
|
|
794
|
+
title,
|
|
795
|
+
subtitle,
|
|
796
|
+
data,
|
|
797
|
+
index,
|
|
798
|
+
categories,
|
|
799
|
+
colors,
|
|
800
|
+
className
|
|
801
|
+
}) {
|
|
802
|
+
return /* @__PURE__ */ React.createElement("div", { className }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-black" }, title), subtitle && /* @__PURE__ */ React.createElement("p", { className: "mt-1 text-sm text-gray-500" }, subtitle), /* @__PURE__ */ React.createElement(
|
|
803
|
+
BarChart,
|
|
804
|
+
{
|
|
805
|
+
className: "mt-4 h-72",
|
|
806
|
+
data,
|
|
807
|
+
index,
|
|
808
|
+
categories,
|
|
809
|
+
colors,
|
|
810
|
+
type: "percent",
|
|
811
|
+
showLegend: true,
|
|
812
|
+
showTooltip: true,
|
|
813
|
+
valueFormatter: (value) => `${value}%`
|
|
814
|
+
}
|
|
815
|
+
));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// src/data/parseSettlementData.ts
|
|
819
|
+
function parsePercentage(value) {
|
|
820
|
+
return parseFloat(value.replace("%", ""));
|
|
821
|
+
}
|
|
822
|
+
function parseSettlementCSV(csv) {
|
|
823
|
+
const lines = csv.trim().split("\n");
|
|
824
|
+
const headers = lines[0].split(",");
|
|
825
|
+
const months = headers.slice(1);
|
|
826
|
+
const rows = {};
|
|
827
|
+
for (let i = 1; i < lines.length; i++) {
|
|
828
|
+
const cols = lines[i].split(",");
|
|
829
|
+
const label = cols[0];
|
|
830
|
+
const values = cols.slice(1).map(parsePercentage);
|
|
831
|
+
rows[label] = values;
|
|
832
|
+
}
|
|
833
|
+
function buildGroup(prefix) {
|
|
834
|
+
return months.map((month, i) => ({
|
|
835
|
+
month,
|
|
836
|
+
Instant: rows[`${prefix} Instant`][i],
|
|
837
|
+
Fast: rows[`${prefix} Fast`][i],
|
|
838
|
+
SLA: rows[`${prefix} SLA`][i]
|
|
839
|
+
}));
|
|
840
|
+
}
|
|
841
|
+
return {
|
|
842
|
+
crypto: buildGroup("Crypto"),
|
|
843
|
+
g3: buildGroup("G3"),
|
|
844
|
+
g7: buildGroup("G7")
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
var settlementData = parseSettlementCSV(settlement_speeds_default);
|
|
848
|
+
|
|
849
|
+
// src/framer/G7SettlementChart.framer.tsx
|
|
850
|
+
var DEFAULT_CSV_URL = "";
|
|
851
|
+
function G7SettlementChart({
|
|
852
|
+
title = "G7",
|
|
853
|
+
subtitle = "Settlement speed distribution",
|
|
854
|
+
csvUrl = DEFAULT_CSV_URL,
|
|
855
|
+
colors,
|
|
856
|
+
width = "100%",
|
|
857
|
+
height = "auto"
|
|
858
|
+
}) {
|
|
859
|
+
const [data, setData] = React4.useState([]);
|
|
860
|
+
React4.useEffect(() => {
|
|
861
|
+
if (!csvUrl) return;
|
|
862
|
+
fetch(csvUrl).then((res) => res.text()).then((csv) => {
|
|
863
|
+
const parsed = parseSettlementCSV(csv);
|
|
864
|
+
setData(parsed.g7);
|
|
865
|
+
}).catch(console.error);
|
|
866
|
+
}, [csvUrl]);
|
|
867
|
+
if (data.length === 0) {
|
|
868
|
+
return /* @__PURE__ */ React4.createElement("div", { style: { width, height }, className: "flex items-center justify-center text-sm text-gray-400" }, csvUrl ? "Loading..." : "Set a CSV URL");
|
|
869
|
+
}
|
|
870
|
+
return /* @__PURE__ */ React4.createElement("div", { style: { width, height } }, /* @__PURE__ */ React4.createElement(
|
|
871
|
+
SettlementSpeedChart,
|
|
872
|
+
{
|
|
873
|
+
title,
|
|
874
|
+
subtitle,
|
|
875
|
+
data,
|
|
876
|
+
index: "month",
|
|
877
|
+
categories: ["Instant", "Fast", "SLA"],
|
|
878
|
+
colors
|
|
879
|
+
}
|
|
880
|
+
));
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// src/framer/G3SettlementChart.framer.tsx
|
|
884
|
+
import React5 from "react";
|
|
885
|
+
function G3SettlementChart({
|
|
886
|
+
title = "G3",
|
|
887
|
+
subtitle = "Settlement speed distribution",
|
|
888
|
+
csvUrl = "",
|
|
889
|
+
colors,
|
|
890
|
+
width = "100%",
|
|
891
|
+
height = "auto"
|
|
892
|
+
}) {
|
|
893
|
+
const [data, setData] = React5.useState([]);
|
|
894
|
+
React5.useEffect(() => {
|
|
895
|
+
if (!csvUrl) return;
|
|
896
|
+
fetch(csvUrl).then((res) => res.text()).then((csv) => {
|
|
897
|
+
const parsed = parseSettlementCSV(csv);
|
|
898
|
+
setData(parsed.g3);
|
|
899
|
+
}).catch(console.error);
|
|
900
|
+
}, [csvUrl]);
|
|
901
|
+
if (data.length === 0) {
|
|
902
|
+
return /* @__PURE__ */ React5.createElement("div", { style: { width, height }, className: "flex items-center justify-center text-sm text-gray-400" }, csvUrl ? "Loading..." : "Set a CSV URL");
|
|
903
|
+
}
|
|
904
|
+
return /* @__PURE__ */ React5.createElement("div", { style: { width, height } }, /* @__PURE__ */ React5.createElement(
|
|
905
|
+
SettlementSpeedChart,
|
|
906
|
+
{
|
|
907
|
+
title,
|
|
908
|
+
subtitle,
|
|
909
|
+
data,
|
|
910
|
+
index: "month",
|
|
911
|
+
categories: ["Instant", "Fast", "SLA"],
|
|
912
|
+
colors
|
|
913
|
+
}
|
|
914
|
+
));
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// src/framer/CryptoSettlementChart.framer.tsx
|
|
918
|
+
import React6 from "react";
|
|
919
|
+
function CryptoSettlementChart({
|
|
920
|
+
title = "Crypto",
|
|
921
|
+
subtitle = "Settlement speed distribution",
|
|
922
|
+
csvUrl = "",
|
|
923
|
+
colors,
|
|
924
|
+
width = "100%",
|
|
925
|
+
height = "auto"
|
|
926
|
+
}) {
|
|
927
|
+
const [data, setData] = React6.useState([]);
|
|
928
|
+
React6.useEffect(() => {
|
|
929
|
+
if (!csvUrl) return;
|
|
930
|
+
fetch(csvUrl).then((res) => res.text()).then((csv) => {
|
|
931
|
+
const parsed = parseSettlementCSV(csv);
|
|
932
|
+
setData(parsed.crypto);
|
|
933
|
+
}).catch(console.error);
|
|
934
|
+
}, [csvUrl]);
|
|
935
|
+
if (data.length === 0) {
|
|
936
|
+
return /* @__PURE__ */ React6.createElement("div", { style: { width, height }, className: "flex items-center justify-center text-sm text-gray-400" }, csvUrl ? "Loading..." : "Set a CSV URL");
|
|
937
|
+
}
|
|
938
|
+
return /* @__PURE__ */ React6.createElement("div", { style: { width, height } }, /* @__PURE__ */ React6.createElement(
|
|
939
|
+
SettlementSpeedChart,
|
|
940
|
+
{
|
|
941
|
+
title,
|
|
942
|
+
subtitle,
|
|
943
|
+
data,
|
|
944
|
+
index: "month",
|
|
945
|
+
categories: ["Instant", "Fast", "SLA"],
|
|
946
|
+
colors
|
|
947
|
+
}
|
|
948
|
+
));
|
|
949
|
+
}
|
|
950
|
+
export {
|
|
951
|
+
CryptoSettlementChart,
|
|
952
|
+
G3SettlementChart,
|
|
953
|
+
G7SettlementChart
|
|
954
|
+
};
|
|
955
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/framer/G7SettlementChart.framer.tsx","../src/components/BarChart.tsx","../src/lib/useOnWindowResize.ts","../src/lib/chartColors.ts","../src/lib/cx.ts","../src/lib/getYAxisDomain.ts","../src/charts/SettlementSpeedChart.tsx","../src/data/parseSettlementData.ts","../src/framer/G3SettlementChart.framer.tsx","../src/framer/CryptoSettlementChart.framer.tsx"],"sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { SettlementSpeedChart } from \"../charts/SettlementSpeedChart\"\nimport { parseSettlementCSV } from \"../data/parseSettlementData\"\nimport type { AvailableChartColorsKeys } from \"../lib/chartColors\"\n\ninterface Props {\n title?: string\n subtitle?: string\n csvUrl?: string\n colors?: AvailableChartColorsKeys[]\n width?: number | string\n height?: number | string\n}\n\nconst DEFAULT_CSV_URL = \"\"\n\nexport default function G7SettlementChart({\n title = \"G7\",\n subtitle = \"Settlement speed distribution\",\n csvUrl = DEFAULT_CSV_URL,\n colors,\n width = \"100%\",\n height = \"auto\",\n}: Props) {\n const [data, setData] = React.useState<Record<string, any>[]>([])\n\n React.useEffect(() => {\n if (!csvUrl) return\n fetch(csvUrl)\n .then((res) => res.text())\n .then((csv) => {\n const parsed = parseSettlementCSV(csv)\n setData(parsed.g7)\n })\n .catch(console.error)\n }, [csvUrl])\n\n if (data.length === 0) {\n return (\n <div style={{ width, height }} className=\"flex items-center justify-center text-sm text-gray-400\">\n {csvUrl ? \"Loading...\" : \"Set a CSV URL\"}\n </div>\n )\n }\n\n return (\n <div style={{ width, height }}>\n <SettlementSpeedChart\n title={title}\n subtitle={subtitle}\n data={data}\n index=\"month\"\n categories={[\"Instant\", \"Fast\", \"SLA\"]}\n colors={colors}\n />\n </div>\n )\n}\n","// Tremor BarChart [v1.0.0]\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n\"use client\"\n\nimport React from \"react\"\nimport { RiArrowLeftSLine, RiArrowRightSLine } from \"@remixicon/react\"\nimport {\n Bar,\n CartesianGrid,\n Label,\n BarChart as RechartsBarChart,\n Legend as RechartsLegend,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\"\nimport type { AxisDomain } from \"recharts/types/util/types\"\n\nimport { useOnWindowResize } from \"@/lib/useOnWindowResize\"\nimport {\n AvailableChartColors,\n type AvailableChartColorsKeys,\n constructCategoryColors,\n getColorClassName,\n} from \"@/lib/chartColors\"\nimport { cx } from \"@/lib/cx\"\nimport { getYAxisDomain } from \"@/lib/getYAxisDomain\"\n\nfunction deepEqual<T>(obj1: T, obj2: T): boolean {\n if (obj1 === obj2) return true\n if (\n typeof obj1 !== \"object\" ||\n typeof obj2 !== \"object\" ||\n obj1 === null ||\n obj2 === null\n ) {\n return false\n }\n const keys1 = Object.keys(obj1) as Array<keyof T>\n const keys2 = Object.keys(obj2) as Array<keyof T>\n if (keys1.length !== keys2.length) return false\n for (const key of keys1) {\n if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false\n }\n return true\n}\n\nconst renderShape = (\n props: any,\n activeBar: any | undefined,\n activeLegend: string | undefined,\n layout: string,\n) => {\n const { fillOpacity, name, payload, value } = props\n let { x, width, y, height } = props\n if (layout === \"horizontal\" && height < 0) {\n y += height\n height = Math.abs(height)\n } else if (layout === \"vertical\" && width < 0) {\n x += width\n width = Math.abs(width)\n }\n return (\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n opacity={\n activeBar || (activeLegend && activeLegend !== name)\n ? deepEqual(activeBar, { ...payload, value })\n ? fillOpacity\n : 0.3\n : fillOpacity\n }\n />\n )\n}\n\ninterface LegendItemProps {\n name: string\n color: AvailableChartColorsKeys\n onClick?: (name: string, color: AvailableChartColorsKeys) => void\n activeLegend?: string\n}\n\nconst LegendItem = ({\n name,\n color,\n onClick,\n activeLegend,\n}: LegendItemProps) => {\n const hasOnValueChange = !!onClick\n return (\n <li\n className={cx(\n \"group inline-flex flex-nowrap items-center gap-1.5 rounded-sm px-2 py-1 whitespace-nowrap transition\",\n hasOnValueChange\n ? \"cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800\"\n : \"cursor-default\",\n )}\n onClick={(e) => {\n e.stopPropagation()\n onClick?.(name, color)\n }}\n >\n <span\n className={cx(\n \"size-2 shrink-0 rounded-xs\",\n getColorClassName(color, \"bg\"),\n activeLegend && activeLegend !== name ? \"opacity-40\" : \"opacity-100\",\n )}\n aria-hidden={true}\n />\n <p\n className={cx(\n \"truncate text-xs whitespace-nowrap\",\n \"text-black\",\n hasOnValueChange && \"group-hover:text-gray-700\",\n activeLegend && activeLegend !== name ? \"opacity-40\" : \"opacity-100\",\n )}\n >\n {name}\n </p>\n </li>\n )\n}\n\ninterface ScrollButtonProps {\n icon: React.ElementType\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScrollButton = ({ icon, onClick, disabled }: ScrollButtonProps) => {\n const Icon = icon\n const [isPressed, setIsPressed] = React.useState(false)\n const intervalRef = React.useRef<NodeJS.Timeout | null>(null)\n\n React.useEffect(() => {\n if (isPressed) {\n intervalRef.current = setInterval(() => {\n onClick?.()\n }, 300)\n } else {\n clearInterval(intervalRef.current as NodeJS.Timeout)\n }\n return () => clearInterval(intervalRef.current as NodeJS.Timeout)\n }, [isPressed, onClick])\n\n React.useEffect(() => {\n if (disabled) {\n clearInterval(intervalRef.current as NodeJS.Timeout)\n setIsPressed(false)\n }\n }, [disabled])\n\n return (\n <button\n type=\"button\"\n className={cx(\n \"group inline-flex size-5 items-center truncate rounded-sm transition\",\n disabled\n ? \"cursor-not-allowed text-gray-400 dark:text-gray-600\"\n : \"cursor-pointer text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-50\",\n )}\n disabled={disabled}\n onClick={(e) => {\n e.stopPropagation()\n onClick?.()\n }}\n onMouseDown={(e) => {\n e.stopPropagation()\n setIsPressed(true)\n }}\n onMouseUp={(e) => {\n e.stopPropagation()\n setIsPressed(false)\n }}\n >\n <Icon className=\"size-full\" aria-hidden=\"true\" />\n </button>\n )\n}\n\ninterface LegendProps extends React.OlHTMLAttributes<HTMLOListElement> {\n categories: string[]\n colors?: AvailableChartColorsKeys[]\n onClickLegendItem?: (category: string, color: string) => void\n activeLegend?: string\n enableLegendSlider?: boolean\n}\n\ntype HasScrollProps = {\n left: boolean\n right: boolean\n}\n\nconst Legend = React.forwardRef<HTMLOListElement, LegendProps>((props, ref) => {\n const {\n categories,\n colors = AvailableChartColors,\n className,\n onClickLegendItem,\n activeLegend,\n enableLegendSlider = false,\n ...other\n } = props\n const scrollableRef = React.useRef<HTMLInputElement>(null)\n const scrollButtonsRef = React.useRef<HTMLDivElement>(null)\n const [hasScroll, setHasScroll] = React.useState<HasScrollProps | null>(null)\n const [isKeyDowned, setIsKeyDowned] = React.useState<string | null>(null)\n const intervalRef = React.useRef<NodeJS.Timeout | null>(null)\n\n const checkScroll = React.useCallback(() => {\n const scrollable = scrollableRef?.current\n if (!scrollable) return\n const hasLeftScroll = scrollable.scrollLeft > 0\n const hasRightScroll =\n scrollable.scrollWidth - scrollable.clientWidth > scrollable.scrollLeft\n setHasScroll({ left: hasLeftScroll, right: hasRightScroll })\n }, [setHasScroll])\n\n const scrollToTest = React.useCallback(\n (direction: \"left\" | \"right\") => {\n const element = scrollableRef?.current\n const scrollButtons = scrollButtonsRef?.current\n const scrollButtonsWith = scrollButtons?.clientWidth ?? 0\n const width = element?.clientWidth ?? 0\n if (element && enableLegendSlider) {\n element.scrollTo({\n left:\n direction === \"left\"\n ? element.scrollLeft - width + scrollButtonsWith\n : element.scrollLeft + width - scrollButtonsWith,\n behavior: \"smooth\",\n })\n setTimeout(() => {\n checkScroll()\n }, 400)\n }\n },\n [enableLegendSlider, checkScroll],\n )\n\n React.useEffect(() => {\n const keyDownHandler = (key: string) => {\n if (key === \"ArrowLeft\") {\n scrollToTest(\"left\")\n } else if (key === \"ArrowRight\") {\n scrollToTest(\"right\")\n }\n }\n if (isKeyDowned) {\n keyDownHandler(isKeyDowned)\n intervalRef.current = setInterval(() => {\n keyDownHandler(isKeyDowned)\n }, 300)\n } else {\n clearInterval(intervalRef.current as NodeJS.Timeout)\n }\n return () => clearInterval(intervalRef.current as NodeJS.Timeout)\n }, [isKeyDowned, scrollToTest])\n\n const keyDown = (e: KeyboardEvent) => {\n e.stopPropagation()\n if (e.key === \"ArrowLeft\" || e.key === \"ArrowRight\") {\n e.preventDefault()\n setIsKeyDowned(e.key)\n }\n }\n const keyUp = (e: KeyboardEvent) => {\n e.stopPropagation()\n setIsKeyDowned(null)\n }\n\n React.useEffect(() => {\n const scrollable = scrollableRef?.current\n if (enableLegendSlider) {\n checkScroll()\n scrollable?.addEventListener(\"keydown\", keyDown)\n scrollable?.addEventListener(\"keyup\", keyUp)\n }\n return () => {\n scrollable?.removeEventListener(\"keydown\", keyDown)\n scrollable?.removeEventListener(\"keyup\", keyUp)\n }\n }, [checkScroll, enableLegendSlider])\n\n return (\n <ol\n ref={ref}\n className={cx(\"relative overflow-hidden\", className)}\n {...other}\n >\n <div\n ref={scrollableRef}\n tabIndex={0}\n className={cx(\n \"flex h-full\",\n enableLegendSlider\n ? hasScroll?.right || hasScroll?.left\n ? \"snap-mandatory items-center overflow-auto pr-12 pl-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n : \"\"\n : \"flex-wrap\",\n )}\n >\n {categories.map((category, index) => (\n <LegendItem\n key={`item-${index}`}\n name={category}\n color={colors[index] as AvailableChartColorsKeys}\n onClick={onClickLegendItem}\n activeLegend={activeLegend}\n />\n ))}\n </div>\n {enableLegendSlider && (hasScroll?.right || hasScroll?.left) ? (\n <>\n <div\n className={cx(\n \"absolute top-0 right-0 bottom-0 flex h-full items-center justify-center pr-1\",\n \"bg-white dark:bg-gray-950\",\n )}\n >\n <ScrollButton\n icon={RiArrowLeftSLine}\n onClick={() => {\n setIsKeyDowned(null)\n scrollToTest(\"left\")\n }}\n disabled={!hasScroll?.left}\n />\n <ScrollButton\n icon={RiArrowRightSLine}\n onClick={() => {\n setIsKeyDowned(null)\n scrollToTest(\"right\")\n }}\n disabled={!hasScroll?.right}\n />\n </div>\n </>\n ) : null}\n </ol>\n )\n})\n\nLegend.displayName = \"Legend\"\n\nconst ChartLegend = (\n { payload }: any,\n categoryColors: Map<string, AvailableChartColorsKeys>,\n setLegendHeight: React.Dispatch<React.SetStateAction<number>>,\n activeLegend: string | undefined,\n onClick?: (category: string, color: string) => void,\n enableLegendSlider?: boolean,\n legendPosition?: \"left\" | \"center\" | \"right\",\n yAxisWidth?: number,\n) => {\n const legendRef = React.useRef<HTMLDivElement>(null)\n\n useOnWindowResize(() => {\n const calculateHeight = (height: number | undefined) =>\n height ? Number(height) + 15 : 60\n setLegendHeight(calculateHeight(legendRef.current?.clientHeight))\n })\n\n const filteredPayload = payload.filter((item: any) => item.type !== \"none\")\n\n const paddingLeft =\n legendPosition === \"left\" && yAxisWidth ? yAxisWidth - 8 : 0\n\n return (\n <div\n style={{ paddingLeft: paddingLeft }}\n ref={legendRef}\n className={cx(\n \"flex items-center\",\n { \"justify-center\": legendPosition === \"center\" },\n {\n \"justify-start\": legendPosition === \"left\",\n },\n { \"justify-end\": legendPosition === \"right\" },\n )}\n >\n <Legend\n categories={filteredPayload.map((entry: any) => entry.value)}\n colors={filteredPayload.map((entry: any) =>\n categoryColors.get(entry.value),\n )}\n onClickLegendItem={onClick}\n activeLegend={activeLegend}\n enableLegendSlider={enableLegendSlider}\n />\n </div>\n )\n}\n\ntype TooltipProps = Pick<ChartTooltipProps, \"active\" | \"payload\" | \"label\">\n\ntype PayloadItem = {\n category: string\n value: number\n index: string\n color: AvailableChartColorsKeys\n type?: string\n payload: any\n}\n\ninterface ChartTooltipProps {\n active: boolean | undefined\n payload: PayloadItem[]\n label: string\n valueFormatter: (value: number) => string\n}\n\nconst ChartTooltip = ({\n active,\n payload,\n label,\n valueFormatter,\n}: ChartTooltipProps) => {\n if (active && payload && payload.length) {\n return (\n <div\n className={cx(\n \"rounded-md border text-sm shadow-md\",\n \"border-gray-200 dark:border-gray-800\",\n \"bg-white dark:bg-gray-950\",\n )}\n >\n <div className={cx(\"border-b border-inherit px-4 py-2\")}>\n <p\n className={cx(\n \"font-medium\",\n \"text-gray-900 dark:text-gray-50\",\n )}\n >\n {label}\n </p>\n </div>\n <div className={cx(\"space-y-1 px-4 py-2\")}>\n {payload.map(({ value, category, color }, index) => (\n <div\n key={`id-${index}`}\n className=\"flex items-center justify-between space-x-8\"\n >\n <div className=\"flex items-center space-x-2\">\n <span\n aria-hidden=\"true\"\n className={cx(\n \"size-2 shrink-0 rounded-xs\",\n getColorClassName(color, \"bg\"),\n )}\n />\n <p\n className={cx(\n \"text-right whitespace-nowrap\",\n \"text-gray-700 dark:text-gray-300\",\n )}\n >\n {category}\n </p>\n </div>\n <p\n className={cx(\n \"text-right font-medium whitespace-nowrap tabular-nums\",\n \"text-gray-900 dark:text-gray-50\",\n )}\n >\n {valueFormatter(value)}\n </p>\n </div>\n ))}\n </div>\n </div>\n )\n }\n return null\n}\n\ntype BaseEventProps = {\n eventType: \"category\" | \"bar\"\n categoryClicked: string\n [key: string]: number | string\n}\n\ntype BarChartEventProps = BaseEventProps | null | undefined\n\ninterface BarChartProps extends React.HTMLAttributes<HTMLDivElement> {\n data: Record<string, any>[]\n index: string\n categories: string[]\n colors?: AvailableChartColorsKeys[]\n valueFormatter?: (value: number) => string\n startEndOnly?: boolean\n showXAxis?: boolean\n showYAxis?: boolean\n showGridLines?: boolean\n yAxisWidth?: number\n intervalType?: \"preserveStartEnd\" | \"equidistantPreserveStart\"\n showTooltip?: boolean\n showLegend?: boolean\n autoMinValue?: boolean\n minValue?: number\n maxValue?: number\n allowDecimals?: boolean\n onValueChange?: (value: BarChartEventProps) => void\n enableLegendSlider?: boolean\n tickGap?: number\n barCategoryGap?: string | number\n xAxisLabel?: string\n yAxisLabel?: string\n layout?: \"vertical\" | \"horizontal\"\n type?: \"default\" | \"stacked\" | \"percent\"\n legendPosition?: \"left\" | \"center\" | \"right\"\n tooltipCallback?: (tooltipCallbackContent: TooltipProps) => void\n customTooltip?: React.ComponentType<TooltipProps>\n}\n\nconst BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(\n (props, forwardedRef) => {\n const {\n data = [],\n categories = [],\n index,\n colors = AvailableChartColors,\n valueFormatter = (value: number) => value.toString(),\n startEndOnly = false,\n showXAxis = true,\n showYAxis = true,\n showGridLines = true,\n yAxisWidth = 56,\n intervalType = \"equidistantPreserveStart\",\n showTooltip = true,\n showLegend = true,\n autoMinValue = false,\n minValue,\n maxValue,\n allowDecimals = true,\n className,\n onValueChange,\n enableLegendSlider = false,\n barCategoryGap,\n tickGap = 5,\n xAxisLabel,\n yAxisLabel,\n layout = \"horizontal\",\n type = \"default\",\n legendPosition = \"right\",\n tooltipCallback,\n customTooltip,\n ...other\n } = props\n const CustomTooltip = customTooltip\n const paddingValue =\n (!showXAxis && !showYAxis) || (startEndOnly && !showYAxis) ? 0 : 20\n const [legendHeight, setLegendHeight] = React.useState(60)\n const [activeLegend, setActiveLegend] = React.useState<string | undefined>(\n undefined,\n )\n const categoryColors = constructCategoryColors(categories, colors)\n const [activeBar, setActiveBar] = React.useState<any | undefined>(undefined)\n const yAxisDomain = getYAxisDomain(autoMinValue, minValue, maxValue)\n const hasOnValueChange = !!onValueChange\n const stacked = type === \"stacked\" || type === \"percent\"\n\n const prevActiveRef = React.useRef<boolean | undefined>(undefined)\n const prevLabelRef = React.useRef<string | undefined>(undefined)\n\n function valueToPercent(value: number) {\n return `${(value * 100).toFixed(0)}%`\n }\n\n function onBarClick(data: any, _: any, event: React.MouseEvent) {\n event.stopPropagation()\n if (!onValueChange) return\n if (deepEqual(activeBar, { ...data.payload, value: data.value })) {\n setActiveLegend(undefined)\n setActiveBar(undefined)\n onValueChange?.(null)\n } else {\n setActiveLegend(data.tooltipPayload?.[0]?.dataKey)\n setActiveBar({\n ...data.payload,\n value: data.value,\n })\n onValueChange?.({\n eventType: \"bar\",\n categoryClicked: data.tooltipPayload?.[0]?.dataKey,\n ...data.payload,\n })\n }\n }\n\n function onCategoryClick(dataKey: string) {\n if (!hasOnValueChange) return\n if (dataKey === activeLegend && !activeBar) {\n setActiveLegend(undefined)\n onValueChange?.(null)\n } else {\n setActiveLegend(dataKey)\n onValueChange?.({\n eventType: \"category\",\n categoryClicked: dataKey,\n })\n }\n setActiveBar(undefined)\n }\n\n return (\n <div\n ref={forwardedRef}\n className={cx(\"h-80 w-full\", className)}\n tremor-id=\"tremor-raw\"\n {...other}\n >\n <ResponsiveContainer>\n <RechartsBarChart\n data={data}\n onClick={\n hasOnValueChange && (activeLegend || activeBar)\n ? () => {\n setActiveBar(undefined)\n setActiveLegend(undefined)\n onValueChange?.(null)\n }\n : undefined\n }\n margin={{\n bottom: xAxisLabel ? 30 : undefined,\n left: yAxisLabel ? 20 : undefined,\n right: yAxisLabel ? 5 : undefined,\n top: 5,\n }}\n stackOffset={type === \"percent\" ? \"expand\" : undefined}\n layout={layout}\n barCategoryGap={barCategoryGap}\n >\n {showGridLines ? (\n <CartesianGrid\n className={cx(\"stroke-gray-100 stroke-1\")}\n horizontal={layout !== \"vertical\"}\n vertical={layout === \"vertical\"}\n />\n ) : null}\n <XAxis\n hide={!showXAxis}\n tick={{\n transform:\n layout !== \"vertical\" ? \"translate(0, 6)\" : undefined,\n }}\n fill=\"\"\n stroke=\"\"\n className={cx(\n \"text-xs\",\n \"fill-gray-500 dark:fill-gray-500\",\n { \"mt-4\": layout !== \"vertical\" },\n )}\n tickLine={false}\n axisLine={false}\n minTickGap={tickGap}\n {...(layout !== \"vertical\"\n ? {\n padding: {\n left: paddingValue,\n right: paddingValue,\n },\n dataKey: index,\n interval: startEndOnly ? \"preserveStartEnd\" : intervalType,\n ticks: startEndOnly\n ? [data[0][index], data[data.length - 1][index]]\n : undefined,\n }\n : {\n type: \"number\",\n domain: yAxisDomain as AxisDomain,\n tickFormatter:\n type === \"percent\" ? valueToPercent : valueFormatter,\n allowDecimals: allowDecimals,\n })}\n >\n {xAxisLabel && (\n <Label\n position=\"insideBottom\"\n offset={-20}\n className=\"fill-gray-800 text-sm font-medium dark:fill-gray-200\"\n >\n {xAxisLabel}\n </Label>\n )}\n </XAxis>\n <YAxis\n width={yAxisWidth}\n hide={!showYAxis}\n axisLine={false}\n tickLine={false}\n fill=\"\"\n stroke=\"\"\n className={cx(\n \"text-xs\",\n \"fill-gray-500 dark:fill-gray-500\",\n )}\n tick={{\n transform:\n layout !== \"vertical\"\n ? \"translate(-3, 0)\"\n : \"translate(0, 0)\",\n }}\n {...(layout !== \"vertical\"\n ? {\n type: \"number\",\n domain: yAxisDomain as AxisDomain,\n tickFormatter:\n type === \"percent\" ? valueToPercent : valueFormatter,\n allowDecimals: allowDecimals,\n }\n : {\n dataKey: index,\n ticks: startEndOnly\n ? [data[0][index], data[data.length - 1][index]]\n : undefined,\n type: \"category\",\n interval: \"equidistantPreserveStart\",\n })}\n >\n {yAxisLabel && (\n <Label\n position=\"insideLeft\"\n style={{ textAnchor: \"middle\" }}\n angle={-90}\n offset={-15}\n className=\"fill-gray-800 text-sm font-medium dark:fill-gray-200\"\n >\n {yAxisLabel}\n </Label>\n )}\n </YAxis>\n <Tooltip\n wrapperStyle={{ outline: \"none\", zIndex: 10 }}\n isAnimationActive={true}\n animationDuration={100}\n cursor={{ fill: \"#d1d5db\", opacity: \"0.15\" }}\n offset={20}\n position={{\n y: layout === \"horizontal\" ? 0 : undefined,\n x: layout === \"horizontal\" ? undefined : yAxisWidth + 20,\n }}\n content={({ active, payload, label }) => {\n const cleanPayload: TooltipProps[\"payload\"] = payload\n ? payload.map((item: any) => ({\n category: item.dataKey,\n value: item.value,\n index: item.payload[index],\n color: categoryColors.get(\n item.dataKey,\n ) as AvailableChartColorsKeys,\n type: item.type,\n payload: item.payload,\n }))\n : []\n\n if (\n tooltipCallback &&\n (active !== prevActiveRef.current ||\n label !== prevLabelRef.current)\n ) {\n tooltipCallback({ active, payload: cleanPayload, label })\n prevActiveRef.current = active\n prevLabelRef.current = label\n }\n\n return showTooltip && active ? (\n CustomTooltip ? (\n <CustomTooltip\n active={active}\n payload={cleanPayload}\n label={label}\n />\n ) : (\n <ChartTooltip\n active={active}\n payload={cleanPayload}\n label={label}\n valueFormatter={valueFormatter}\n />\n )\n ) : null\n }}\n />\n {showLegend ? (\n <RechartsLegend\n verticalAlign=\"top\"\n height={legendHeight}\n content={({ payload }) =>\n ChartLegend(\n { payload },\n categoryColors,\n setLegendHeight,\n activeLegend,\n hasOnValueChange\n ? (clickedLegendItem: string) =>\n onCategoryClick(clickedLegendItem)\n : undefined,\n enableLegendSlider,\n legendPosition,\n yAxisWidth,\n )\n }\n />\n ) : null}\n {categories.map((category) => (\n <Bar\n className={cx(\n getColorClassName(\n categoryColors.get(category) as AvailableChartColorsKeys,\n \"fill\",\n ),\n onValueChange ? \"cursor-pointer\" : \"\",\n )}\n key={category}\n name={category}\n type=\"linear\"\n dataKey={category}\n stackId={stacked ? \"stack\" : undefined}\n isAnimationActive={false}\n fill=\"\"\n shape={(props: any) =>\n renderShape(props, activeBar, activeLegend, layout)\n }\n onClick={onBarClick}\n />\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </div>\n )\n },\n)\n\nBarChart.displayName = \"BarChart\"\n\nexport { BarChart, type BarChartEventProps, type TooltipProps }\n","// Tremor useOnWindowResize [v0.0.2]\n\nimport * as React from \"react\"\n\nexport const useOnWindowResize = (handler: () => void) => {\n React.useEffect(() => {\n const handleResize = () => {\n handler()\n }\n handleResize()\n window.addEventListener(\"resize\", handleResize)\n\n return () => window.removeEventListener(\"resize\", handleResize)\n }, [handler])\n}\n","// Tremor chartColors [v0.1.0]\n\nexport type ColorUtility = \"bg\" | \"stroke\" | \"fill\" | \"text\"\n\nexport const chartColors = {\n blue: {\n bg: \"bg-blue-500\",\n stroke: \"stroke-blue-500\",\n fill: \"fill-blue-500\",\n text: \"text-blue-500\",\n },\n emerald: {\n bg: \"bg-emerald-500\",\n stroke: \"stroke-emerald-500\",\n fill: \"fill-emerald-500\",\n text: \"text-emerald-500\",\n },\n violet: {\n bg: \"bg-violet-500\",\n stroke: \"stroke-violet-500\",\n fill: \"fill-violet-500\",\n text: \"text-violet-500\",\n },\n amber: {\n bg: \"bg-amber-500\",\n stroke: \"stroke-amber-500\",\n fill: \"fill-amber-500\",\n text: \"text-amber-500\",\n },\n gray: {\n bg: \"bg-gray-500\",\n stroke: \"stroke-gray-500\",\n fill: \"fill-gray-500\",\n text: \"text-gray-500\",\n },\n cyan: {\n bg: \"bg-cyan-500\",\n stroke: \"stroke-cyan-500\",\n fill: \"fill-cyan-500\",\n text: \"text-cyan-500\",\n },\n pink: {\n bg: \"bg-pink-500\",\n stroke: \"stroke-pink-500\",\n fill: \"fill-pink-500\",\n text: \"text-pink-500\",\n },\n lime: {\n bg: \"bg-lime-500\",\n stroke: \"stroke-lime-500\",\n fill: \"fill-lime-500\",\n text: \"text-lime-500\",\n },\n fuchsia: {\n bg: \"bg-fuchsia-500\",\n stroke: \"stroke-fuchsia-500\",\n fill: \"fill-fuchsia-500\",\n text: \"text-fuchsia-500\",\n },\n} as const satisfies {\n [color: string]: {\n [key in ColorUtility]: string\n }\n}\n\nexport type AvailableChartColorsKeys = keyof typeof chartColors\n\nexport const AvailableChartColors: AvailableChartColorsKeys[] = Object.keys(\n chartColors,\n) as Array<AvailableChartColorsKeys>\n\nexport const constructCategoryColors = (\n categories: string[],\n colors: AvailableChartColorsKeys[],\n): Map<string, AvailableChartColorsKeys> => {\n const categoryColors = new Map<string, AvailableChartColorsKeys>()\n categories.forEach((category, index) => {\n categoryColors.set(category, colors[index % colors.length])\n })\n return categoryColors\n}\n\nexport const getColorClassName = (\n color: AvailableChartColorsKeys,\n type: ColorUtility,\n): string => {\n const fallbackColor = {\n bg: \"bg-gray-500\",\n stroke: \"stroke-gray-500\",\n fill: \"fill-gray-500\",\n text: \"text-gray-500\",\n }\n return chartColors[color]?.[type] ?? fallbackColor[type]\n}\n","// Tremor cx [v0.0.0]\n\nimport clsx, { type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cx(...args: ClassValue[]) {\n return twMerge(clsx(...args))\n}\n","// Tremor getYAxisDomain [v0.0.0]\n\nexport const getYAxisDomain = (\n autoMinValue: boolean,\n minValue: number | undefined,\n maxValue: number | undefined,\n) => {\n const minDomain = autoMinValue ? \"auto\" : (minValue ?? 0)\n const maxDomain = maxValue ?? \"auto\"\n return [minDomain, maxDomain]\n}\n","\"use client\"\n\nimport { BarChart } from \"@/components/BarChart\"\nimport type { AvailableChartColorsKeys } from \"@/lib/chartColors\"\n\ninterface SettlementSpeedChartProps {\n title: string\n subtitle?: string\n data: Record<string, any>[]\n index: string\n categories: string[]\n colors?: AvailableChartColorsKeys[]\n className?: string\n}\n\nexport function SettlementSpeedChart({\n title,\n subtitle,\n data,\n index,\n categories,\n colors,\n className,\n}: SettlementSpeedChartProps) {\n return (\n <div className={className}>\n <h3 className=\"text-lg font-semibold text-black\">\n {title}\n </h3>\n {subtitle && (\n <p className=\"mt-1 text-sm text-gray-500\">\n {subtitle}\n </p>\n )}\n <BarChart\n className=\"mt-4 h-72\"\n data={data}\n index={index}\n categories={categories}\n colors={colors}\n type=\"percent\"\n showLegend={true}\n showTooltip={true}\n valueFormatter={(value) => `${value}%`}\n />\n </div>\n )\n}\n","interface SettlementRow {\n month: string\n Instant: number\n Fast: number\n SLA: number\n}\n\nexport interface SettlementData {\n crypto: SettlementRow[]\n g3: SettlementRow[]\n g7: SettlementRow[]\n}\n\nfunction parsePercentage(value: string): number {\n return parseFloat(value.replace(\"%\", \"\"))\n}\n\nexport function parseSettlementCSV(csv: string): SettlementData {\n const lines = csv.trim().split(\"\\n\")\n const headers = lines[0].split(\",\")\n const months = headers.slice(1) // [\"Aug 25\", \"Sep 25\", ...]\n\n const rows: Record<string, number[]> = {}\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(\",\")\n const label = cols[0]\n const values = cols.slice(1).map(parsePercentage)\n rows[label] = values\n }\n\n function buildGroup(prefix: string): SettlementRow[] {\n return months.map((month, i) => ({\n month,\n Instant: rows[`${prefix} Instant`][i],\n Fast: rows[`${prefix} Fast`][i],\n SLA: rows[`${prefix} SLA`][i],\n }))\n }\n\n return {\n crypto: buildGroup(\"Crypto\"),\n g3: buildGroup(\"G3\"),\n g7: buildGroup(\"G7\"),\n }\n}\n\n// For local dev: import CSV statically\n// For Framer: components fetch CSV at runtime via URL\nlet _cachedData: SettlementData | null = null\n\nexport async function loadSettlementData(): Promise<SettlementData> {\n if (_cachedData) return _cachedData\n const rawCSV = (await import(\"./settlement-speeds.csv?raw\")).default\n _cachedData = parseSettlementCSV(rawCSV)\n return _cachedData\n}\n\n// Synchronous access for static import (local dev)\nimport rawCSV from \"./settlement-speeds.csv?raw\"\nexport const settlementData = parseSettlementCSV(rawCSV)\n","\"use client\"\n\nimport React from \"react\"\nimport { SettlementSpeedChart } from \"../charts/SettlementSpeedChart\"\nimport { parseSettlementCSV } from \"../data/parseSettlementData\"\nimport type { AvailableChartColorsKeys } from \"../lib/chartColors\"\n\ninterface Props {\n title?: string\n subtitle?: string\n csvUrl?: string\n colors?: AvailableChartColorsKeys[]\n width?: number | string\n height?: number | string\n}\n\nexport default function G3SettlementChart({\n title = \"G3\",\n subtitle = \"Settlement speed distribution\",\n csvUrl = \"\",\n colors,\n width = \"100%\",\n height = \"auto\",\n}: Props) {\n const [data, setData] = React.useState<Record<string, any>[]>([])\n\n React.useEffect(() => {\n if (!csvUrl) return\n fetch(csvUrl)\n .then((res) => res.text())\n .then((csv) => {\n const parsed = parseSettlementCSV(csv)\n setData(parsed.g3)\n })\n .catch(console.error)\n }, [csvUrl])\n\n if (data.length === 0) {\n return (\n <div style={{ width, height }} className=\"flex items-center justify-center text-sm text-gray-400\">\n {csvUrl ? \"Loading...\" : \"Set a CSV URL\"}\n </div>\n )\n }\n\n return (\n <div style={{ width, height }}>\n <SettlementSpeedChart\n title={title}\n subtitle={subtitle}\n data={data}\n index=\"month\"\n categories={[\"Instant\", \"Fast\", \"SLA\"]}\n colors={colors}\n />\n </div>\n )\n}\n","\"use client\"\n\nimport React from \"react\"\nimport { SettlementSpeedChart } from \"../charts/SettlementSpeedChart\"\nimport { parseSettlementCSV } from \"../data/parseSettlementData\"\nimport type { AvailableChartColorsKeys } from \"../lib/chartColors\"\n\ninterface Props {\n title?: string\n subtitle?: string\n csvUrl?: string\n colors?: AvailableChartColorsKeys[]\n width?: number | string\n height?: number | string\n}\n\nexport default function CryptoSettlementChart({\n title = \"Crypto\",\n subtitle = \"Settlement speed distribution\",\n csvUrl = \"\",\n colors,\n width = \"100%\",\n height = \"auto\",\n}: Props) {\n const [data, setData] = React.useState<Record<string, any>[]>([])\n\n React.useEffect(() => {\n if (!csvUrl) return\n fetch(csvUrl)\n .then((res) => res.text())\n .then((csv) => {\n const parsed = parseSettlementCSV(csv)\n setData(parsed.crypto)\n })\n .catch(console.error)\n }, [csvUrl])\n\n if (data.length === 0) {\n return (\n <div style={{ width, height }} className=\"flex items-center justify-center text-sm text-gray-400\">\n {csvUrl ? \"Loading...\" : \"Set a CSV URL\"}\n </div>\n )\n }\n\n return (\n <div style={{ width, height }}>\n <SettlementSpeedChart\n title={title}\n subtitle={subtitle}\n data={data}\n index=\"month\"\n categories={[\"Instant\", \"Fast\", \"SLA\"]}\n colors={colors}\n />\n </div>\n )\n}\n"],"mappings":"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","names":["React","React","React","React","data","props","React","React","React","React","React"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gelatin-hero/framer-charts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Settlement speed chart components for Framer",
|
|
5
|
+
"main": "dist/index.mjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"files": ["dist"],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "next dev",
|
|
10
|
+
"build": "next build",
|
|
11
|
+
"build:lib": "tsup",
|
|
12
|
+
"start": "next start",
|
|
13
|
+
"lint": "next lint",
|
|
14
|
+
"prepublishOnly": "npm run build:lib"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"react": ">=18",
|
|
18
|
+
"react-dom": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@remixicon/react": "^4.9.0",
|
|
22
|
+
"clsx": "^2.1.1",
|
|
23
|
+
"next": "14.2.28",
|
|
24
|
+
"react": "^18",
|
|
25
|
+
"react-dom": "^18",
|
|
26
|
+
"recharts": "^3.7.0",
|
|
27
|
+
"tailwind-merge": "^3.5.0",
|
|
28
|
+
"tailwind-variants": "^3.2.2"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
32
|
+
"@types/node": "^20",
|
|
33
|
+
"@types/react": "^18",
|
|
34
|
+
"@types/react-dom": "^18",
|
|
35
|
+
"eslint": "^8",
|
|
36
|
+
"eslint-config-next": "14.2.28",
|
|
37
|
+
"postcss": "^8",
|
|
38
|
+
"tailwindcss": "^4.2.1",
|
|
39
|
+
"tsup": "^8.5.1",
|
|
40
|
+
"typescript": "^5"
|
|
41
|
+
}
|
|
42
|
+
}
|