@marcoschwartz/lite-ui 0.11.0 → 0.16.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/dist/index.d.mts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1021 -466
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1021 -466
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3182,6 +3182,7 @@ var RichTextEditor = ({
|
|
|
3182
3182
|
const [showImageModal, setShowImageModal] = useState12(false);
|
|
3183
3183
|
const [imageUrl, setImageUrl] = useState12("");
|
|
3184
3184
|
const [imageAlt, setImageAlt] = useState12("");
|
|
3185
|
+
const savedSelection = useRef7(null);
|
|
3185
3186
|
useLayoutEffect(() => {
|
|
3186
3187
|
const styleId = "rich-text-editor-styles";
|
|
3187
3188
|
if (!document.getElementById(styleId)) {
|
|
@@ -3208,6 +3209,15 @@ var RichTextEditor = ({
|
|
|
3208
3209
|
font-weight: bold;
|
|
3209
3210
|
margin: 0.83em 0;
|
|
3210
3211
|
}
|
|
3212
|
+
[contenteditable] p {
|
|
3213
|
+
margin: 0.5em 0;
|
|
3214
|
+
}
|
|
3215
|
+
[contenteditable] p:first-child {
|
|
3216
|
+
margin-top: 0;
|
|
3217
|
+
}
|
|
3218
|
+
[contenteditable] p:last-child {
|
|
3219
|
+
margin-bottom: 0;
|
|
3220
|
+
}
|
|
3211
3221
|
[contenteditable] ul, [contenteditable] ol {
|
|
3212
3222
|
margin: 1em 0;
|
|
3213
3223
|
padding-left: 2em;
|
|
@@ -3236,11 +3246,60 @@ var RichTextEditor = ({
|
|
|
3236
3246
|
}
|
|
3237
3247
|
}, []);
|
|
3238
3248
|
const isInitialRender = useRef7(true);
|
|
3249
|
+
const isInternalUpdate = useRef7(false);
|
|
3239
3250
|
useEffect8(() => {
|
|
3240
|
-
if (
|
|
3251
|
+
if (isInitialRender.current && editorRef.current) {
|
|
3241
3252
|
editorRef.current.innerHTML = value;
|
|
3253
|
+
isInitialRender.current = false;
|
|
3254
|
+
try {
|
|
3255
|
+
document.execCommand("defaultParagraphSeparator", false, "p");
|
|
3256
|
+
} catch (e) {
|
|
3257
|
+
console.warn("Could not set defaultParagraphSeparator", e);
|
|
3258
|
+
}
|
|
3242
3259
|
}
|
|
3243
|
-
|
|
3260
|
+
}, []);
|
|
3261
|
+
useEffect8(() => {
|
|
3262
|
+
if (!isInitialRender.current && !isInternalUpdate.current && editorRef.current) {
|
|
3263
|
+
const currentHtml = editorRef.current.innerHTML;
|
|
3264
|
+
if (currentHtml !== value) {
|
|
3265
|
+
const selection = window.getSelection();
|
|
3266
|
+
const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
3267
|
+
const preSelectionRange = range ? range.cloneRange() : null;
|
|
3268
|
+
if (preSelectionRange && editorRef.current.contains(preSelectionRange.startContainer)) {
|
|
3269
|
+
preSelectionRange.selectNodeContents(editorRef.current);
|
|
3270
|
+
preSelectionRange.setEnd(range.startContainer, range.startOffset);
|
|
3271
|
+
const start = preSelectionRange.toString().length;
|
|
3272
|
+
editorRef.current.innerHTML = value;
|
|
3273
|
+
const textNodes = [];
|
|
3274
|
+
const getTextNodes = (node) => {
|
|
3275
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
3276
|
+
textNodes.push(node);
|
|
3277
|
+
} else {
|
|
3278
|
+
node.childNodes.forEach(getTextNodes);
|
|
3279
|
+
}
|
|
3280
|
+
};
|
|
3281
|
+
getTextNodes(editorRef.current);
|
|
3282
|
+
let charCount = 0;
|
|
3283
|
+
let foundStart = false;
|
|
3284
|
+
for (const textNode of textNodes) {
|
|
3285
|
+
const textLength = textNode.textContent?.length || 0;
|
|
3286
|
+
if (!foundStart && charCount + textLength >= start) {
|
|
3287
|
+
const newRange = document.createRange();
|
|
3288
|
+
newRange.setStart(textNode, start - charCount);
|
|
3289
|
+
newRange.collapse(true);
|
|
3290
|
+
selection?.removeAllRanges();
|
|
3291
|
+
selection?.addRange(newRange);
|
|
3292
|
+
foundStart = true;
|
|
3293
|
+
break;
|
|
3294
|
+
}
|
|
3295
|
+
charCount += textLength;
|
|
3296
|
+
}
|
|
3297
|
+
} else {
|
|
3298
|
+
editorRef.current.innerHTML = value;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
isInternalUpdate.current = false;
|
|
3244
3303
|
}, [value]);
|
|
3245
3304
|
const updateActiveFormats = useCallback(() => {
|
|
3246
3305
|
const formats = /* @__PURE__ */ new Set();
|
|
@@ -3261,10 +3320,25 @@ var RichTextEditor = ({
|
|
|
3261
3320
|
}, []);
|
|
3262
3321
|
const handleInput = useCallback(() => {
|
|
3263
3322
|
if (editorRef.current && onChange) {
|
|
3323
|
+
isInternalUpdate.current = true;
|
|
3264
3324
|
onChange(editorRef.current.innerHTML);
|
|
3265
3325
|
}
|
|
3266
3326
|
updateActiveFormats();
|
|
3267
3327
|
}, [onChange, updateActiveFormats]);
|
|
3328
|
+
const handleFocus = useCallback(() => {
|
|
3329
|
+
setIsFocused(true);
|
|
3330
|
+
if (editorRef.current && (!editorRef.current.innerHTML || editorRef.current.innerHTML === "")) {
|
|
3331
|
+
editorRef.current.innerHTML = "<p><br></p>";
|
|
3332
|
+
const selection = window.getSelection();
|
|
3333
|
+
const range = document.createRange();
|
|
3334
|
+
if (editorRef.current.firstChild) {
|
|
3335
|
+
range.setStart(editorRef.current.firstChild, 0);
|
|
3336
|
+
range.collapse(true);
|
|
3337
|
+
selection?.removeAllRanges();
|
|
3338
|
+
selection?.addRange(range);
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
}, []);
|
|
3268
3342
|
const handleFormat = useCallback((command) => {
|
|
3269
3343
|
if (disabled) return;
|
|
3270
3344
|
document.execCommand(command, false);
|
|
@@ -3288,16 +3362,29 @@ var RichTextEditor = ({
|
|
|
3288
3362
|
}, [disabled, updateActiveFormats, handleInput]);
|
|
3289
3363
|
const handleLink = useCallback(() => {
|
|
3290
3364
|
if (disabled) return;
|
|
3365
|
+
const selection = window.getSelection();
|
|
3366
|
+
if (selection && selection.rangeCount > 0) {
|
|
3367
|
+
savedSelection.current = selection.getRangeAt(0).cloneRange();
|
|
3368
|
+
}
|
|
3291
3369
|
setShowLinkModal(true);
|
|
3292
3370
|
}, [disabled]);
|
|
3293
3371
|
const insertLink = useCallback(() => {
|
|
3294
|
-
if (linkUrl)
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3372
|
+
if (!linkUrl || !editorRef.current) return;
|
|
3373
|
+
const selection = window.getSelection();
|
|
3374
|
+
if (savedSelection.current && selection) {
|
|
3375
|
+
try {
|
|
3376
|
+
selection.removeAllRanges();
|
|
3377
|
+
selection.addRange(savedSelection.current);
|
|
3378
|
+
document.execCommand("createLink", false, linkUrl);
|
|
3379
|
+
savedSelection.current = null;
|
|
3380
|
+
} catch (e) {
|
|
3381
|
+
console.warn("Could not insert link at saved position", e);
|
|
3382
|
+
}
|
|
3300
3383
|
}
|
|
3384
|
+
setShowLinkModal(false);
|
|
3385
|
+
setLinkUrl("");
|
|
3386
|
+
editorRef.current?.focus();
|
|
3387
|
+
handleInput();
|
|
3301
3388
|
}, [linkUrl, handleInput]);
|
|
3302
3389
|
const handleCode = useCallback(() => {
|
|
3303
3390
|
if (disabled) return;
|
|
@@ -3317,33 +3404,82 @@ var RichTextEditor = ({
|
|
|
3317
3404
|
}, [disabled, handleInput]);
|
|
3318
3405
|
const handleImage = useCallback(() => {
|
|
3319
3406
|
if (disabled) return;
|
|
3407
|
+
const selection = window.getSelection();
|
|
3408
|
+
if (selection && selection.rangeCount > 0) {
|
|
3409
|
+
savedSelection.current = selection.getRangeAt(0).cloneRange();
|
|
3410
|
+
}
|
|
3320
3411
|
setShowImageModal(true);
|
|
3321
3412
|
}, [disabled]);
|
|
3322
3413
|
const insertImage = useCallback(() => {
|
|
3323
|
-
if (!imageUrl) return;
|
|
3414
|
+
if (!imageUrl || !editorRef.current) return;
|
|
3415
|
+
editorRef.current.focus();
|
|
3324
3416
|
const img = document.createElement("img");
|
|
3325
3417
|
img.src = imageUrl;
|
|
3326
3418
|
img.alt = imageAlt || "";
|
|
3327
3419
|
img.style.maxWidth = "100%";
|
|
3328
3420
|
img.style.height = "auto";
|
|
3329
3421
|
const selection = window.getSelection();
|
|
3330
|
-
if (
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3422
|
+
if (savedSelection.current && selection && editorRef.current.contains(savedSelection.current.commonAncestorContainer)) {
|
|
3423
|
+
try {
|
|
3424
|
+
selection.removeAllRanges();
|
|
3425
|
+
selection.addRange(savedSelection.current);
|
|
3426
|
+
savedSelection.current.deleteContents();
|
|
3427
|
+
savedSelection.current.insertNode(img);
|
|
3428
|
+
const br = document.createElement("br");
|
|
3429
|
+
savedSelection.current.setStartAfter(img);
|
|
3430
|
+
savedSelection.current.insertNode(br);
|
|
3431
|
+
savedSelection.current.setStartAfter(br);
|
|
3432
|
+
savedSelection.current.collapse(true);
|
|
3433
|
+
selection.removeAllRanges();
|
|
3434
|
+
selection.addRange(savedSelection.current);
|
|
3435
|
+
savedSelection.current = null;
|
|
3436
|
+
} catch (e) {
|
|
3437
|
+
console.warn("Could not insert at saved position", e);
|
|
3438
|
+
if (selection.rangeCount > 0) {
|
|
3439
|
+
const range = selection.getRangeAt(0);
|
|
3440
|
+
if (editorRef.current.contains(range.commonAncestorContainer)) {
|
|
3441
|
+
range.insertNode(img);
|
|
3442
|
+
const br = document.createElement("br");
|
|
3443
|
+
range.setStartAfter(img);
|
|
3444
|
+
range.insertNode(br);
|
|
3445
|
+
range.setStartAfter(br);
|
|
3446
|
+
range.collapse(true);
|
|
3447
|
+
} else {
|
|
3448
|
+
editorRef.current.appendChild(img);
|
|
3449
|
+
editorRef.current.appendChild(document.createElement("br"));
|
|
3450
|
+
}
|
|
3451
|
+
} else {
|
|
3452
|
+
editorRef.current.appendChild(img);
|
|
3453
|
+
editorRef.current.appendChild(document.createElement("br"));
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
} else {
|
|
3457
|
+
if (selection && selection.rangeCount > 0) {
|
|
3458
|
+
const range = selection.getRangeAt(0);
|
|
3459
|
+
if (editorRef.current.contains(range.commonAncestorContainer)) {
|
|
3460
|
+
range.deleteContents();
|
|
3461
|
+
range.insertNode(img);
|
|
3462
|
+
const br = document.createElement("br");
|
|
3463
|
+
range.setStartAfter(img);
|
|
3464
|
+
range.insertNode(br);
|
|
3465
|
+
range.setStartAfter(br);
|
|
3466
|
+
range.collapse(true);
|
|
3467
|
+
selection.removeAllRanges();
|
|
3468
|
+
selection.addRange(range);
|
|
3469
|
+
} else {
|
|
3470
|
+
editorRef.current.appendChild(img);
|
|
3471
|
+
editorRef.current.appendChild(document.createElement("br"));
|
|
3472
|
+
}
|
|
3473
|
+
} else {
|
|
3474
|
+
editorRef.current.appendChild(img);
|
|
3475
|
+
editorRef.current.appendChild(document.createElement("br"));
|
|
3476
|
+
}
|
|
3340
3477
|
}
|
|
3341
3478
|
setShowImageModal(false);
|
|
3342
3479
|
setImageUrl("");
|
|
3343
3480
|
setImageAlt("");
|
|
3344
|
-
editorRef.current?.focus();
|
|
3345
3481
|
handleInput();
|
|
3346
|
-
}, [imageUrl, imageAlt, handleInput
|
|
3482
|
+
}, [imageUrl, imageAlt, handleInput]);
|
|
3347
3483
|
const getButtonClass = (isActive) => {
|
|
3348
3484
|
const baseClass = themeName === "minimalistic" ? "border border-white text-white transition-colors" : "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 transition-colors";
|
|
3349
3485
|
const activeClass = themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900 border-blue-500 dark:border-blue-400";
|
|
@@ -3507,11 +3643,10 @@ var RichTextEditor = ({
|
|
|
3507
3643
|
ref: editorRef,
|
|
3508
3644
|
contentEditable: !disabled,
|
|
3509
3645
|
onInput: handleInput,
|
|
3510
|
-
onFocus:
|
|
3646
|
+
onFocus: handleFocus,
|
|
3511
3647
|
onBlur: () => setIsFocused(false),
|
|
3512
3648
|
onMouseUp: updateActiveFormats,
|
|
3513
3649
|
onKeyUp: updateActiveFormats,
|
|
3514
|
-
dangerouslySetInnerHTML: { __html: value },
|
|
3515
3650
|
className: `
|
|
3516
3651
|
w-full px-4 py-3 rounded-b-lg outline-none overflow-y-auto
|
|
3517
3652
|
${editorBaseClass} ${focusClass} ${errorClass}
|
|
@@ -5000,8 +5135,10 @@ var defaultColors = [
|
|
|
5000
5135
|
];
|
|
5001
5136
|
var LineChart = ({
|
|
5002
5137
|
data,
|
|
5003
|
-
width
|
|
5004
|
-
height
|
|
5138
|
+
width: providedWidth,
|
|
5139
|
+
height: providedHeight,
|
|
5140
|
+
aspectRatio = 16 / 9,
|
|
5141
|
+
responsive = true,
|
|
5005
5142
|
showGrid = true,
|
|
5006
5143
|
showXAxis = true,
|
|
5007
5144
|
showYAxis = true,
|
|
@@ -5012,12 +5149,32 @@ var LineChart = ({
|
|
|
5012
5149
|
strokeWidth = 2,
|
|
5013
5150
|
className = "",
|
|
5014
5151
|
xAxisLabel,
|
|
5015
|
-
yAxisLabel
|
|
5152
|
+
yAxisLabel,
|
|
5153
|
+
baseFontSize = 14
|
|
5016
5154
|
}) => {
|
|
5155
|
+
const viewBoxWidth = 1e3;
|
|
5156
|
+
const viewBoxHeight = 600;
|
|
5157
|
+
const containerRef = React26.useRef(null);
|
|
5158
|
+
const svgRef = React26.useRef(null);
|
|
5159
|
+
const [tooltipPosition, setTooltipPosition] = React26.useState(null);
|
|
5017
5160
|
const [hoveredPoint, setHoveredPoint] = React26.useState(null);
|
|
5018
|
-
const
|
|
5019
|
-
const
|
|
5020
|
-
const
|
|
5161
|
+
const chartId = React26.useId();
|
|
5162
|
+
const wrapperClass = `chart-svg-wrapper-${chartId.replace(/:/g, "-")}`;
|
|
5163
|
+
const gridLabelClass = `chart-grid-label-${chartId.replace(/:/g, "-")}`;
|
|
5164
|
+
const axisLabelClass = `chart-axis-label-${chartId.replace(/:/g, "-")}`;
|
|
5165
|
+
const lineClass = `chart-line-${chartId.replace(/:/g, "-")}`;
|
|
5166
|
+
const pointClass = `chart-point-${chartId.replace(/:/g, "-")}`;
|
|
5167
|
+
const padding = {
|
|
5168
|
+
top: 50,
|
|
5169
|
+
right: 50,
|
|
5170
|
+
bottom: showXAxis ? 120 : 50,
|
|
5171
|
+
left: showYAxis ? 130 : 50
|
|
5172
|
+
};
|
|
5173
|
+
const chartWidth = viewBoxWidth - padding.left - padding.right;
|
|
5174
|
+
const chartHeight = viewBoxHeight - padding.top - padding.bottom;
|
|
5175
|
+
const gridLabelFontSize = viewBoxWidth * 0.045;
|
|
5176
|
+
const axisLabelFontSize = viewBoxWidth * 0.05;
|
|
5177
|
+
const titleFontSize = viewBoxWidth * 0.055;
|
|
5021
5178
|
const allPoints = data.flatMap((series) => series.data);
|
|
5022
5179
|
const allYValues = allPoints.map((p) => p.y);
|
|
5023
5180
|
const firstXValue = data[0]?.data[0]?.x;
|
|
@@ -5030,7 +5187,7 @@ var LineChart = ({
|
|
|
5030
5187
|
const minY = Math.min(0, ...allYValues);
|
|
5031
5188
|
const maxY = Math.max(...allYValues);
|
|
5032
5189
|
const yRange = maxY - minY;
|
|
5033
|
-
const yMin = minY - yRange * 0.1;
|
|
5190
|
+
const yMin = Math.max(0, minY - yRange * 0.1);
|
|
5034
5191
|
const yMax = maxY + yRange * 0.1;
|
|
5035
5192
|
const scaleX = (x, index) => {
|
|
5036
5193
|
const numX = isStringX ? index : x;
|
|
@@ -5077,28 +5234,32 @@ var LineChart = ({
|
|
|
5077
5234
|
x2: chartWidth,
|
|
5078
5235
|
y2: y,
|
|
5079
5236
|
stroke: "currentColor",
|
|
5080
|
-
strokeWidth: "
|
|
5237
|
+
strokeWidth: "0.5",
|
|
5081
5238
|
className: "text-gray-200 dark:text-gray-700",
|
|
5082
|
-
strokeDasharray: "
|
|
5239
|
+
strokeDasharray: "4,4"
|
|
5083
5240
|
}
|
|
5084
5241
|
),
|
|
5085
5242
|
showYAxis && /* @__PURE__ */ jsx108(
|
|
5086
5243
|
"text",
|
|
5087
5244
|
{
|
|
5088
|
-
x: -
|
|
5089
|
-
y
|
|
5245
|
+
x: -25,
|
|
5246
|
+
y,
|
|
5090
5247
|
textAnchor: "end",
|
|
5091
|
-
|
|
5248
|
+
dominantBaseline: "middle",
|
|
5249
|
+
fontSize: gridLabelFontSize,
|
|
5250
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
5092
5251
|
children: yValue.toFixed(1)
|
|
5093
5252
|
}
|
|
5094
5253
|
)
|
|
5095
5254
|
] }, `grid-h-${i}`)
|
|
5096
5255
|
);
|
|
5097
5256
|
}
|
|
5098
|
-
const numXGridLines = Math.min(allPoints.length, 6);
|
|
5257
|
+
const numXGridLines = Math.max(2, Math.min(allPoints.length, 6));
|
|
5258
|
+
const xGridStep = numXGridLines > 1 ? 1 / (numXGridLines - 1) : 0;
|
|
5099
5259
|
for (let i = 0; i < numXGridLines; i++) {
|
|
5100
|
-
const x = chartWidth
|
|
5101
|
-
const
|
|
5260
|
+
const x = chartWidth * (i * xGridStep);
|
|
5261
|
+
const dataIndex = Math.floor((data[0]?.data.length - 1) * (i * xGridStep));
|
|
5262
|
+
const xValue = data[0]?.data[Math.max(0, Math.min(dataIndex, data[0].data.length - 1))]?.x || "";
|
|
5102
5263
|
gridLines.push(
|
|
5103
5264
|
/* @__PURE__ */ jsxs35("g", { children: [
|
|
5104
5265
|
/* @__PURE__ */ jsx108(
|
|
@@ -5109,18 +5270,20 @@ var LineChart = ({
|
|
|
5109
5270
|
x2: x,
|
|
5110
5271
|
y2: chartHeight,
|
|
5111
5272
|
stroke: "currentColor",
|
|
5112
|
-
strokeWidth: "
|
|
5273
|
+
strokeWidth: "0.5",
|
|
5113
5274
|
className: "text-gray-200 dark:text-gray-700",
|
|
5114
|
-
strokeDasharray: "
|
|
5275
|
+
strokeDasharray: "4,4"
|
|
5115
5276
|
}
|
|
5116
5277
|
),
|
|
5117
5278
|
showXAxis && /* @__PURE__ */ jsx108(
|
|
5118
5279
|
"text",
|
|
5119
5280
|
{
|
|
5120
5281
|
x,
|
|
5121
|
-
y: chartHeight +
|
|
5282
|
+
y: chartHeight + 35,
|
|
5122
5283
|
textAnchor: "middle",
|
|
5123
|
-
|
|
5284
|
+
dominantBaseline: "hanging",
|
|
5285
|
+
fontSize: gridLabelFontSize,
|
|
5286
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
5124
5287
|
children: xValue
|
|
5125
5288
|
}
|
|
5126
5289
|
)
|
|
@@ -5128,108 +5291,197 @@ var LineChart = ({
|
|
|
5128
5291
|
);
|
|
5129
5292
|
}
|
|
5130
5293
|
}
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5294
|
+
const getTooltipPosition = React26.useCallback((x, y) => {
|
|
5295
|
+
if (!containerRef.current) return { x, y };
|
|
5296
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5297
|
+
const tooltipWidth = 120;
|
|
5298
|
+
const tooltipHeight = 80;
|
|
5299
|
+
let tooltipX = x + 10;
|
|
5300
|
+
let tooltipY = y - 30;
|
|
5301
|
+
if (tooltipX + tooltipWidth > rect.width) {
|
|
5302
|
+
tooltipX = x - tooltipWidth - 10;
|
|
5303
|
+
}
|
|
5304
|
+
if (tooltipY + tooltipHeight > rect.height) {
|
|
5305
|
+
tooltipY = y + 30;
|
|
5306
|
+
}
|
|
5307
|
+
return { x: tooltipX, y: tooltipY };
|
|
5308
|
+
}, []);
|
|
5309
|
+
const containerStyle = {
|
|
5310
|
+
"--font-size-base": `${baseFontSize}px`,
|
|
5311
|
+
"--font-size-lg": `calc(var(--font-size-base) * 1.125)`,
|
|
5312
|
+
"--font-size-sm": `calc(var(--font-size-base) * 0.875)`,
|
|
5313
|
+
"--font-size-xs": `calc(var(--font-size-base) * 0.75)`
|
|
5314
|
+
};
|
|
5315
|
+
return /* @__PURE__ */ jsxs35(
|
|
5316
|
+
"div",
|
|
5317
|
+
{
|
|
5318
|
+
ref: containerRef,
|
|
5319
|
+
className: `relative flex flex-col gap-4 ${responsive ? "w-full" : "inline-block"} ${className}`,
|
|
5320
|
+
style: {
|
|
5321
|
+
...containerStyle
|
|
5322
|
+
},
|
|
5323
|
+
children: [
|
|
5324
|
+
/* @__PURE__ */ jsx108("style", { children: `
|
|
5325
|
+
/* Mobile: Large fonts, hidden axis titles, thicker lines (default) */
|
|
5326
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize}px !important; }
|
|
5327
|
+
.${axisLabelClass} { display: none; }
|
|
5328
|
+
.${lineClass} { stroke-width: ${strokeWidth * 2.5} !important; }
|
|
5329
|
+
.${pointClass} { r: 6 !important; stroke-width: 3 !important; }
|
|
5330
|
+
|
|
5331
|
+
/* Tablet: Medium fonts, show axis titles, medium lines */
|
|
5332
|
+
@media (min-width: 640px) {
|
|
5333
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.7}px !important; }
|
|
5334
|
+
.${axisLabelClass} {
|
|
5335
|
+
font-size: ${axisLabelFontSize * 0.7}px !important;
|
|
5336
|
+
display: block;
|
|
5337
|
+
}
|
|
5338
|
+
.${lineClass} { stroke-width: ${strokeWidth * 1.5} !important; }
|
|
5339
|
+
.${pointClass} { r: 4 !important; stroke-width: 2 !important; }
|
|
5340
|
+
}
|
|
5341
|
+
|
|
5342
|
+
/* Desktop: Small fonts, show axis titles, normal lines */
|
|
5343
|
+
@media (min-width: 1024px) {
|
|
5344
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.4}px !important; }
|
|
5345
|
+
.${axisLabelClass} {
|
|
5346
|
+
font-size: ${axisLabelFontSize * 0.4}px !important;
|
|
5347
|
+
display: block;
|
|
5348
|
+
}
|
|
5349
|
+
.${lineClass} { stroke-width: ${strokeWidth} !important; }
|
|
5350
|
+
.${pointClass} { r: 3 !important; stroke-width: 1.5 !important; }
|
|
5351
|
+
}
|
|
5352
|
+
` }),
|
|
5353
|
+
/* @__PURE__ */ jsx108(
|
|
5354
|
+
"svg",
|
|
5355
|
+
{
|
|
5356
|
+
ref: svgRef,
|
|
5357
|
+
width: "100%",
|
|
5358
|
+
viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
|
5359
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
5360
|
+
className: "bg-white dark:bg-gray-800 block w-full",
|
|
5361
|
+
style: { height: "auto", overflow: "visible" },
|
|
5362
|
+
children: /* @__PURE__ */ jsxs35("g", { transform: `translate(${padding.left}, ${padding.top})`, children: [
|
|
5363
|
+
gridLines,
|
|
5364
|
+
data.map((series, seriesIndex) => /* @__PURE__ */ jsx108(
|
|
5365
|
+
"path",
|
|
5160
5366
|
{
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
className:
|
|
5168
|
-
onMouseEnter: () => showTooltip && setHoveredPoint({ seriesIndex, pointIndex, x, y }),
|
|
5169
|
-
onMouseLeave: () => setHoveredPoint(null)
|
|
5367
|
+
d: generatePath(series),
|
|
5368
|
+
fill: "none",
|
|
5369
|
+
stroke: series.color || defaultColors[seriesIndex % defaultColors.length],
|
|
5370
|
+
strokeWidth,
|
|
5371
|
+
strokeLinecap: "round",
|
|
5372
|
+
strokeLinejoin: "round",
|
|
5373
|
+
className: lineClass
|
|
5170
5374
|
},
|
|
5171
|
-
`
|
|
5172
|
-
)
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5375
|
+
`line-${seriesIndex}`
|
|
5376
|
+
)),
|
|
5377
|
+
showDots && data.map(
|
|
5378
|
+
(series, seriesIndex) => series.data.map((point, pointIndex) => {
|
|
5379
|
+
const x = scaleX(point.x, pointIndex);
|
|
5380
|
+
const y = scaleY(point.y);
|
|
5381
|
+
const isHovered = hoveredPoint?.seriesIndex === seriesIndex && hoveredPoint?.pointIndex === pointIndex;
|
|
5382
|
+
return /* @__PURE__ */ jsx108(
|
|
5383
|
+
"circle",
|
|
5384
|
+
{
|
|
5385
|
+
cx: x,
|
|
5386
|
+
cy: y,
|
|
5387
|
+
r: isHovered ? 5 : 3,
|
|
5388
|
+
fill: series.color || defaultColors[seriesIndex % defaultColors.length],
|
|
5389
|
+
stroke: "white",
|
|
5390
|
+
strokeWidth: "1.5",
|
|
5391
|
+
className: `cursor-pointer transition-all ${pointClass}`,
|
|
5392
|
+
onMouseEnter: (e) => {
|
|
5393
|
+
if (showTooltip && containerRef.current) {
|
|
5394
|
+
setHoveredPoint({ seriesIndex, pointIndex, x, y });
|
|
5395
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
5396
|
+
const mouseX = e.clientX - containerRect.left;
|
|
5397
|
+
const mouseY = e.clientY - containerRect.top;
|
|
5398
|
+
setTooltipPosition(getTooltipPosition(mouseX, mouseY));
|
|
5399
|
+
}
|
|
5400
|
+
},
|
|
5401
|
+
onMouseMove: (e) => {
|
|
5402
|
+
if (showTooltip && hoveredPoint?.seriesIndex === seriesIndex && hoveredPoint?.pointIndex === pointIndex && containerRef.current) {
|
|
5403
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
5404
|
+
const mouseX = e.clientX - containerRect.left;
|
|
5405
|
+
const mouseY = e.clientY - containerRect.top;
|
|
5406
|
+
setTooltipPosition(getTooltipPosition(mouseX, mouseY));
|
|
5407
|
+
}
|
|
5408
|
+
},
|
|
5409
|
+
onMouseLeave: () => {
|
|
5410
|
+
setHoveredPoint(null);
|
|
5411
|
+
setTooltipPosition(null);
|
|
5412
|
+
}
|
|
5413
|
+
},
|
|
5414
|
+
`point-${seriesIndex}-${pointIndex}`
|
|
5415
|
+
);
|
|
5416
|
+
})
|
|
5417
|
+
),
|
|
5418
|
+
xAxisLabel && showXAxis && /* @__PURE__ */ jsx108(
|
|
5419
|
+
"text",
|
|
5420
|
+
{
|
|
5421
|
+
x: chartWidth / 2,
|
|
5422
|
+
y: chartHeight + 80,
|
|
5423
|
+
textAnchor: "middle",
|
|
5424
|
+
dominantBaseline: "hanging",
|
|
5425
|
+
fontSize: axisLabelFontSize,
|
|
5426
|
+
fontWeight: "600",
|
|
5427
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
5428
|
+
children: xAxisLabel
|
|
5429
|
+
}
|
|
5430
|
+
),
|
|
5431
|
+
yAxisLabel && showYAxis && /* @__PURE__ */ jsx108(
|
|
5432
|
+
"text",
|
|
5433
|
+
{
|
|
5434
|
+
x: -chartHeight / 2,
|
|
5435
|
+
y: -100,
|
|
5436
|
+
textAnchor: "middle",
|
|
5437
|
+
dominantBaseline: "middle",
|
|
5438
|
+
fontSize: axisLabelFontSize,
|
|
5439
|
+
fontWeight: "600",
|
|
5440
|
+
transform: "rotate(-90)",
|
|
5441
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
5442
|
+
children: yAxisLabel
|
|
5443
|
+
}
|
|
5444
|
+
)
|
|
5445
|
+
] })
|
|
5446
|
+
}
|
|
5447
|
+
),
|
|
5448
|
+
showLegend && /* @__PURE__ */ jsx108("div", { className: "flex flex-wrap gap-3 justify-center px-4", children: data.map((series, index) => /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
5449
|
+
/* @__PURE__ */ jsx108(
|
|
5450
|
+
"div",
|
|
5177
5451
|
{
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
children: xAxisLabel
|
|
5452
|
+
className: "w-3 h-3 rounded-sm flex-shrink-0",
|
|
5453
|
+
style: {
|
|
5454
|
+
backgroundColor: series.color || defaultColors[index % defaultColors.length]
|
|
5455
|
+
}
|
|
5183
5456
|
}
|
|
5184
5457
|
),
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5458
|
+
/* @__PURE__ */ jsx108("span", { className: "text-gray-700 dark:text-gray-300", children: series.name })
|
|
5459
|
+
] }, `legend-${index}`)) }),
|
|
5460
|
+
showTooltip && hoveredPoint && tooltipPosition && /* @__PURE__ */ jsxs35(
|
|
5461
|
+
"div",
|
|
5462
|
+
{
|
|
5463
|
+
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg pointer-events-none z-50 text-sm whitespace-nowrap",
|
|
5464
|
+
style: {
|
|
5465
|
+
left: `${tooltipPosition.x}px`,
|
|
5466
|
+
top: `${tooltipPosition.y}px`,
|
|
5467
|
+
transform: "translateZ(0)"
|
|
5468
|
+
},
|
|
5469
|
+
children: [
|
|
5470
|
+
/* @__PURE__ */ jsx108("div", { className: "font-semibold", children: data[hoveredPoint.seriesIndex].name }),
|
|
5471
|
+
/* @__PURE__ */ jsxs35("div", { className: "text-xs opacity-90", children: [
|
|
5472
|
+
"x: ",
|
|
5473
|
+
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].x
|
|
5474
|
+
] }),
|
|
5475
|
+
/* @__PURE__ */ jsxs35("div", { className: "text-xs opacity-90", children: [
|
|
5476
|
+
"y: ",
|
|
5477
|
+
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].y
|
|
5478
|
+
] })
|
|
5479
|
+
]
|
|
5206
5480
|
}
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
showTooltip && hoveredPoint && /* @__PURE__ */ jsxs35(
|
|
5212
|
-
"div",
|
|
5213
|
-
{
|
|
5214
|
-
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg text-sm pointer-events-none z-50",
|
|
5215
|
-
style: {
|
|
5216
|
-
left: `${padding.left + hoveredPoint.x + 10}px`,
|
|
5217
|
-
top: `${padding.top + hoveredPoint.y - 30}px`
|
|
5218
|
-
},
|
|
5219
|
-
children: [
|
|
5220
|
-
/* @__PURE__ */ jsx108("div", { className: "font-semibold", children: data[hoveredPoint.seriesIndex].name }),
|
|
5221
|
-
/* @__PURE__ */ jsxs35("div", { children: [
|
|
5222
|
-
"x: ",
|
|
5223
|
-
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].x
|
|
5224
|
-
] }),
|
|
5225
|
-
/* @__PURE__ */ jsxs35("div", { children: [
|
|
5226
|
-
"y: ",
|
|
5227
|
-
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].y
|
|
5228
|
-
] })
|
|
5229
|
-
]
|
|
5230
|
-
}
|
|
5231
|
-
)
|
|
5232
|
-
] });
|
|
5481
|
+
)
|
|
5482
|
+
]
|
|
5483
|
+
}
|
|
5484
|
+
);
|
|
5233
5485
|
};
|
|
5234
5486
|
|
|
5235
5487
|
// src/components/BarChart.tsx
|
|
@@ -5251,8 +5503,10 @@ var defaultColors2 = [
|
|
|
5251
5503
|
];
|
|
5252
5504
|
var BarChart = ({
|
|
5253
5505
|
data,
|
|
5254
|
-
width
|
|
5255
|
-
height
|
|
5506
|
+
width: providedWidth,
|
|
5507
|
+
height: providedHeight,
|
|
5508
|
+
aspectRatio = 16 / 9,
|
|
5509
|
+
responsive = true,
|
|
5256
5510
|
showGrid = true,
|
|
5257
5511
|
showXAxis = true,
|
|
5258
5512
|
showYAxis = true,
|
|
@@ -5264,24 +5518,38 @@ var BarChart = ({
|
|
|
5264
5518
|
barWidth = 0.8,
|
|
5265
5519
|
className = "",
|
|
5266
5520
|
xAxisLabel,
|
|
5267
|
-
yAxisLabel
|
|
5521
|
+
yAxisLabel,
|
|
5522
|
+
baseFontSize = 14,
|
|
5523
|
+
colors = defaultColors2
|
|
5268
5524
|
}) => {
|
|
5525
|
+
const viewBoxWidth = 1e3;
|
|
5526
|
+
const viewBoxHeight = 600;
|
|
5527
|
+
const containerRef = React27.useRef(null);
|
|
5528
|
+
const [tooltipPosition, setTooltipPosition] = React27.useState(null);
|
|
5269
5529
|
const [hoveredBar, setHoveredBar] = React27.useState(null);
|
|
5530
|
+
const chartId = React27.useId();
|
|
5531
|
+
const wrapperClass = `chart-svg-wrapper-${chartId.replace(/:/g, "-")}`;
|
|
5532
|
+
const gridLabelClass = `chart-grid-label-${chartId.replace(/:/g, "-")}`;
|
|
5533
|
+
const axisLabelClass = `chart-axis-label-${chartId.replace(/:/g, "-")}`;
|
|
5534
|
+
const barClass = `chart-bar-${chartId.replace(/:/g, "-")}`;
|
|
5270
5535
|
const padding = {
|
|
5271
|
-
top:
|
|
5272
|
-
right:
|
|
5273
|
-
bottom: showXAxis ? horizontal ?
|
|
5274
|
-
left: showYAxis ? horizontal ?
|
|
5536
|
+
top: 50,
|
|
5537
|
+
right: 50,
|
|
5538
|
+
bottom: showXAxis ? horizontal ? 120 : 140 : 50,
|
|
5539
|
+
left: showYAxis ? horizontal ? 140 : 130 : 50
|
|
5275
5540
|
};
|
|
5276
|
-
const chartWidth =
|
|
5277
|
-
const chartHeight =
|
|
5541
|
+
const chartWidth = viewBoxWidth - padding.left - padding.right;
|
|
5542
|
+
const chartHeight = viewBoxHeight - padding.top - padding.bottom;
|
|
5543
|
+
const gridLabelFontSize = viewBoxWidth * 0.045;
|
|
5544
|
+
const axisLabelFontSize = viewBoxWidth * 0.05;
|
|
5545
|
+
const titleFontSize = viewBoxWidth * 0.055;
|
|
5278
5546
|
const allYValues = stacked ? data[0]?.data.map(
|
|
5279
5547
|
(_, i) => data.reduce((sum, series) => sum + (series.data[i]?.y || 0), 0)
|
|
5280
5548
|
) || [] : data.flatMap((series) => series.data.map((p) => p.y));
|
|
5281
5549
|
const minY = Math.min(0, ...allYValues);
|
|
5282
5550
|
const maxY = Math.max(...allYValues);
|
|
5283
5551
|
const yRange = maxY - minY;
|
|
5284
|
-
const yMin = minY - yRange * 0.1;
|
|
5552
|
+
const yMin = Math.max(0, minY - yRange * 0.1);
|
|
5285
5553
|
const yMax = maxY + yRange * 0.1;
|
|
5286
5554
|
const numBars = data[0]?.data.length || 0;
|
|
5287
5555
|
const numSeries = data.length;
|
|
@@ -5308,18 +5576,20 @@ var BarChart = ({
|
|
|
5308
5576
|
x2: chartWidth,
|
|
5309
5577
|
y2: y,
|
|
5310
5578
|
stroke: "currentColor",
|
|
5311
|
-
strokeWidth: "
|
|
5579
|
+
strokeWidth: "0.5",
|
|
5312
5580
|
className: "text-gray-200 dark:text-gray-700",
|
|
5313
|
-
strokeDasharray: "
|
|
5581
|
+
strokeDasharray: "4,4"
|
|
5314
5582
|
}
|
|
5315
5583
|
),
|
|
5316
5584
|
showYAxis && !horizontal && /* @__PURE__ */ jsx109(
|
|
5317
5585
|
"text",
|
|
5318
5586
|
{
|
|
5319
|
-
x: -
|
|
5320
|
-
y
|
|
5587
|
+
x: -25,
|
|
5588
|
+
y,
|
|
5321
5589
|
textAnchor: "end",
|
|
5322
|
-
|
|
5590
|
+
dominantBaseline: "middle",
|
|
5591
|
+
fontSize: gridLabelFontSize,
|
|
5592
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
5323
5593
|
children: yValue.toFixed(0)
|
|
5324
5594
|
}
|
|
5325
5595
|
)
|
|
@@ -5368,12 +5638,20 @@ var BarChart = ({
|
|
|
5368
5638
|
x: xPos,
|
|
5369
5639
|
y: yPos,
|
|
5370
5640
|
width: barW,
|
|
5371
|
-
height:
|
|
5372
|
-
fill: data[seriesIndex].color ||
|
|
5373
|
-
className:
|
|
5641
|
+
height: Math.abs(scaleY(0) - yPos),
|
|
5642
|
+
fill: data[seriesIndex].color || colors[seriesIndex % colors.length],
|
|
5643
|
+
className: `cursor-pointer transition-opacity ${barClass}`,
|
|
5374
5644
|
opacity: isHovered ? 0.8 : 1,
|
|
5375
|
-
onMouseEnter: () =>
|
|
5376
|
-
|
|
5645
|
+
onMouseEnter: () => {
|
|
5646
|
+
if (showTooltip) {
|
|
5647
|
+
setHoveredBar({ seriesIndex, barIndex, x: xPos + barW / 2, y: yPos });
|
|
5648
|
+
setTooltipPosition(getTooltipPosition(padding.left + xPos + barW / 2, padding.top + yPos));
|
|
5649
|
+
}
|
|
5650
|
+
},
|
|
5651
|
+
onMouseLeave: () => {
|
|
5652
|
+
setHoveredBar(null);
|
|
5653
|
+
setTooltipPosition(null);
|
|
5654
|
+
}
|
|
5377
5655
|
},
|
|
5378
5656
|
`bar-${seriesIndex}-${barIndex}`
|
|
5379
5657
|
)
|
|
@@ -5398,8 +5676,8 @@ var BarChart = ({
|
|
|
5398
5676
|
y: yPos,
|
|
5399
5677
|
width: actualBarWidth,
|
|
5400
5678
|
height: barHeight,
|
|
5401
|
-
fill: data[seriesIndex].color ||
|
|
5402
|
-
className:
|
|
5679
|
+
fill: data[seriesIndex].color || colors[seriesIndex % colors.length],
|
|
5680
|
+
className: `cursor-pointer transition-opacity ${barClass}`,
|
|
5403
5681
|
opacity: isHovered ? 0.8 : 1,
|
|
5404
5682
|
onMouseEnter: () => showTooltip && setHoveredBar({ seriesIndex, barIndex, x: xPos + actualBarWidth / 2, y: yPos }),
|
|
5405
5683
|
onMouseLeave: () => setHoveredBar(null)
|
|
@@ -5413,9 +5691,12 @@ var BarChart = ({
|
|
|
5413
5691
|
"text",
|
|
5414
5692
|
{
|
|
5415
5693
|
x: xPos + actualBarWidth / 2,
|
|
5416
|
-
y: yPos -
|
|
5694
|
+
y: yPos - 10,
|
|
5417
5695
|
textAnchor: "middle",
|
|
5418
|
-
|
|
5696
|
+
dominantBaseline: "middle",
|
|
5697
|
+
fontSize: "11",
|
|
5698
|
+
fontWeight: "600",
|
|
5699
|
+
className: "fill-gray-700 dark:fill-gray-300",
|
|
5419
5700
|
children: point.y
|
|
5420
5701
|
},
|
|
5421
5702
|
`value-${seriesIndex}-${barIndex}`
|
|
@@ -5433,81 +5714,145 @@ var BarChart = ({
|
|
|
5433
5714
|
"text",
|
|
5434
5715
|
{
|
|
5435
5716
|
x: xPos,
|
|
5436
|
-
y: chartHeight +
|
|
5717
|
+
y: chartHeight + 35,
|
|
5437
5718
|
textAnchor: "middle",
|
|
5438
|
-
|
|
5719
|
+
dominantBaseline: "hanging",
|
|
5720
|
+
fontSize: gridLabelFontSize,
|
|
5721
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
5439
5722
|
children: point.x
|
|
5440
5723
|
},
|
|
5441
5724
|
`x-label-${i}`
|
|
5442
5725
|
);
|
|
5443
5726
|
});
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5727
|
+
const getTooltipPosition = React27.useCallback((x, y) => {
|
|
5728
|
+
if (!containerRef.current) return { x, y };
|
|
5729
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5730
|
+
const tooltipWidth = 140;
|
|
5731
|
+
const tooltipHeight = 80;
|
|
5732
|
+
let tooltipX = x + 10;
|
|
5733
|
+
let tooltipY = y - 30;
|
|
5734
|
+
if (tooltipX + tooltipWidth > rect.width) {
|
|
5735
|
+
tooltipX = x - tooltipWidth - 10;
|
|
5736
|
+
}
|
|
5737
|
+
if (tooltipY + tooltipHeight > rect.height) {
|
|
5738
|
+
tooltipY = y + 30;
|
|
5739
|
+
}
|
|
5740
|
+
return { x: tooltipX, y: tooltipY };
|
|
5741
|
+
}, []);
|
|
5742
|
+
const containerStyle = {
|
|
5743
|
+
"--font-size-base": `${baseFontSize}px`,
|
|
5744
|
+
"--font-size-lg": `calc(var(--font-size-base) * 1.125)`,
|
|
5745
|
+
"--font-size-sm": `calc(var(--font-size-base) * 0.875)`,
|
|
5746
|
+
"--font-size-xs": `calc(var(--font-size-base) * 0.75)`
|
|
5747
|
+
};
|
|
5748
|
+
return /* @__PURE__ */ jsxs36(
|
|
5749
|
+
"div",
|
|
5750
|
+
{
|
|
5751
|
+
ref: containerRef,
|
|
5752
|
+
className: `relative flex flex-col gap-4 ${responsive ? "w-full" : "inline-block"} ${className}`,
|
|
5753
|
+
style: {
|
|
5754
|
+
...containerStyle
|
|
5755
|
+
},
|
|
5756
|
+
children: [
|
|
5757
|
+
/* @__PURE__ */ jsx109("style", { children: `
|
|
5758
|
+
/* Mobile: Large fonts, hidden axis titles, thicker bars (default) */
|
|
5759
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize}px !important; }
|
|
5760
|
+
.${axisLabelClass} { display: none; }
|
|
5761
|
+
|
|
5762
|
+
/* Tablet: Medium fonts, show axis titles */
|
|
5763
|
+
@media (min-width: 640px) {
|
|
5764
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.7}px !important; }
|
|
5765
|
+
.${axisLabelClass} {
|
|
5766
|
+
font-size: ${axisLabelFontSize * 0.7}px !important;
|
|
5767
|
+
display: block;
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
|
|
5771
|
+
/* Desktop: Small fonts, show axis titles */
|
|
5772
|
+
@media (min-width: 1024px) {
|
|
5773
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.4}px !important; }
|
|
5774
|
+
.${axisLabelClass} {
|
|
5775
|
+
font-size: ${axisLabelFontSize * 0.4}px !important;
|
|
5776
|
+
display: block;
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
5779
|
+
` }),
|
|
5780
|
+
/* @__PURE__ */ jsx109(
|
|
5781
|
+
"svg",
|
|
5782
|
+
{
|
|
5783
|
+
width: "100%",
|
|
5784
|
+
viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
|
5785
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
5786
|
+
className: "bg-white dark:bg-gray-800 block w-full",
|
|
5787
|
+
style: { height: "auto", overflow: "visible" },
|
|
5788
|
+
children: /* @__PURE__ */ jsxs36("g", { transform: `translate(${padding.left}, ${padding.top})`, children: [
|
|
5789
|
+
gridLines,
|
|
5790
|
+
renderBars(),
|
|
5791
|
+
showXAxis && xAxisLabels,
|
|
5792
|
+
xAxisLabel && showXAxis && /* @__PURE__ */ jsx109(
|
|
5793
|
+
"text",
|
|
5794
|
+
{
|
|
5795
|
+
x: chartWidth / 2,
|
|
5796
|
+
y: chartHeight + 80,
|
|
5797
|
+
textAnchor: "middle",
|
|
5798
|
+
dominantBaseline: "hanging",
|
|
5799
|
+
fontSize: axisLabelFontSize,
|
|
5800
|
+
fontWeight: "600",
|
|
5801
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
5802
|
+
children: xAxisLabel
|
|
5803
|
+
}
|
|
5804
|
+
),
|
|
5805
|
+
yAxisLabel && showYAxis && /* @__PURE__ */ jsx109(
|
|
5806
|
+
"text",
|
|
5807
|
+
{
|
|
5808
|
+
x: -chartHeight / 2,
|
|
5809
|
+
y: -100,
|
|
5810
|
+
textAnchor: "middle",
|
|
5811
|
+
dominantBaseline: "middle",
|
|
5812
|
+
fontSize: axisLabelFontSize,
|
|
5813
|
+
fontWeight: "600",
|
|
5814
|
+
transform: "rotate(-90)",
|
|
5815
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
5816
|
+
children: yAxisLabel
|
|
5817
|
+
}
|
|
5818
|
+
)
|
|
5819
|
+
] })
|
|
5820
|
+
}
|
|
5821
|
+
),
|
|
5822
|
+
showLegend && /* @__PURE__ */ jsx109("div", { className: "flex flex-wrap gap-3 justify-center px-4", children: data.map((series, index) => /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
5823
|
+
/* @__PURE__ */ jsx109(
|
|
5824
|
+
"div",
|
|
5458
5825
|
{
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
children: xAxisLabel
|
|
5826
|
+
className: "w-3 h-3 rounded-sm flex-shrink-0",
|
|
5827
|
+
style: {
|
|
5828
|
+
backgroundColor: series.color || colors[index % colors.length]
|
|
5829
|
+
}
|
|
5464
5830
|
}
|
|
5465
5831
|
),
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
style: {
|
|
5486
|
-
backgroundColor: series.color || defaultColors2[index % defaultColors2.length]
|
|
5832
|
+
/* @__PURE__ */ jsx109("span", { className: "text-gray-700 dark:text-gray-300", children: series.name })
|
|
5833
|
+
] }, `legend-${index}`)) }),
|
|
5834
|
+
showTooltip && hoveredBar && tooltipPosition && /* @__PURE__ */ jsxs36(
|
|
5835
|
+
"div",
|
|
5836
|
+
{
|
|
5837
|
+
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg pointer-events-none z-50 text-sm whitespace-nowrap",
|
|
5838
|
+
style: {
|
|
5839
|
+
left: `${tooltipPosition.x}px`,
|
|
5840
|
+
top: `${tooltipPosition.y}px`,
|
|
5841
|
+
transform: "translateZ(0)"
|
|
5842
|
+
},
|
|
5843
|
+
children: [
|
|
5844
|
+
/* @__PURE__ */ jsx109("div", { className: "font-semibold", children: data[hoveredBar.seriesIndex].name }),
|
|
5845
|
+
/* @__PURE__ */ jsxs36("div", { className: "text-xs opacity-90", children: [
|
|
5846
|
+
data[hoveredBar.seriesIndex].data[hoveredBar.barIndex].x,
|
|
5847
|
+
": ",
|
|
5848
|
+
data[hoveredBar.seriesIndex].data[hoveredBar.barIndex].y
|
|
5849
|
+
] })
|
|
5850
|
+
]
|
|
5487
5851
|
}
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
showTooltip && hoveredBar && /* @__PURE__ */ jsxs36(
|
|
5493
|
-
"div",
|
|
5494
|
-
{
|
|
5495
|
-
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg text-sm pointer-events-none z-50",
|
|
5496
|
-
style: {
|
|
5497
|
-
left: `${padding.left + hoveredBar.x + 10}px`,
|
|
5498
|
-
top: `${padding.top + hoveredBar.y - 30}px`
|
|
5499
|
-
},
|
|
5500
|
-
children: [
|
|
5501
|
-
/* @__PURE__ */ jsx109("div", { className: "font-semibold", children: data[hoveredBar.seriesIndex].name }),
|
|
5502
|
-
/* @__PURE__ */ jsxs36("div", { children: [
|
|
5503
|
-
data[hoveredBar.seriesIndex].data[hoveredBar.barIndex].x,
|
|
5504
|
-
": ",
|
|
5505
|
-
data[hoveredBar.seriesIndex].data[hoveredBar.barIndex].y
|
|
5506
|
-
] })
|
|
5507
|
-
]
|
|
5508
|
-
}
|
|
5509
|
-
)
|
|
5510
|
-
] });
|
|
5852
|
+
)
|
|
5853
|
+
]
|
|
5854
|
+
}
|
|
5855
|
+
);
|
|
5511
5856
|
};
|
|
5512
5857
|
|
|
5513
5858
|
// src/components/AreaChart.tsx
|
|
@@ -5529,8 +5874,10 @@ var defaultColors3 = [
|
|
|
5529
5874
|
];
|
|
5530
5875
|
var AreaChart = ({
|
|
5531
5876
|
data,
|
|
5532
|
-
width
|
|
5533
|
-
height
|
|
5877
|
+
width: providedWidth,
|
|
5878
|
+
height: providedHeight,
|
|
5879
|
+
aspectRatio = 16 / 9,
|
|
5880
|
+
responsive = true,
|
|
5534
5881
|
showGrid = true,
|
|
5535
5882
|
showXAxis = true,
|
|
5536
5883
|
showYAxis = true,
|
|
@@ -5543,12 +5890,32 @@ var AreaChart = ({
|
|
|
5543
5890
|
strokeWidth = 2,
|
|
5544
5891
|
className = "",
|
|
5545
5892
|
xAxisLabel,
|
|
5546
|
-
yAxisLabel
|
|
5893
|
+
yAxisLabel,
|
|
5894
|
+
baseFontSize = 14
|
|
5547
5895
|
}) => {
|
|
5896
|
+
const viewBoxWidth = 1e3;
|
|
5897
|
+
const viewBoxHeight = 600;
|
|
5898
|
+
const containerRef = React28.useRef(null);
|
|
5899
|
+
const svgRef = React28.useRef(null);
|
|
5900
|
+
const [tooltipPosition, setTooltipPosition] = React28.useState(null);
|
|
5548
5901
|
const [hoveredPoint, setHoveredPoint] = React28.useState(null);
|
|
5549
|
-
const
|
|
5550
|
-
const
|
|
5551
|
-
const
|
|
5902
|
+
const chartId = React28.useId();
|
|
5903
|
+
const wrapperClass = `chart-svg-wrapper-${chartId.replace(/:/g, "-")}`;
|
|
5904
|
+
const gridLabelClass = `chart-grid-label-${chartId.replace(/:/g, "-")}`;
|
|
5905
|
+
const axisLabelClass = `chart-axis-label-${chartId.replace(/:/g, "-")}`;
|
|
5906
|
+
const lineClass = `chart-line-${chartId.replace(/:/g, "-")}`;
|
|
5907
|
+
const pointClass = `chart-point-${chartId.replace(/:/g, "-")}`;
|
|
5908
|
+
const padding = {
|
|
5909
|
+
top: 50,
|
|
5910
|
+
right: 50,
|
|
5911
|
+
bottom: showXAxis ? 120 : 50,
|
|
5912
|
+
left: showYAxis ? 130 : 50
|
|
5913
|
+
};
|
|
5914
|
+
const chartWidth = viewBoxWidth - padding.left - padding.right;
|
|
5915
|
+
const chartHeight = viewBoxHeight - padding.top - padding.bottom;
|
|
5916
|
+
const gridLabelFontSize = viewBoxWidth * 0.045;
|
|
5917
|
+
const axisLabelFontSize = viewBoxWidth * 0.05;
|
|
5918
|
+
const titleFontSize = viewBoxWidth * 0.055;
|
|
5552
5919
|
const allPoints = data.flatMap((series) => series.data);
|
|
5553
5920
|
const allYValues = stacked ? data[0]?.data.map(
|
|
5554
5921
|
(_, i) => data.reduce((sum, series) => sum + (series.data[i]?.y || 0), 0)
|
|
@@ -5562,7 +5929,7 @@ var AreaChart = ({
|
|
|
5562
5929
|
const minY = Math.min(0, ...allYValues);
|
|
5563
5930
|
const maxY = Math.max(...allYValues);
|
|
5564
5931
|
const yRange = maxY - minY;
|
|
5565
|
-
const yMin = minY - yRange * 0.1;
|
|
5932
|
+
const yMin = Math.max(0, minY - yRange * 0.1);
|
|
5566
5933
|
const yMax = maxY + yRange * 0.1;
|
|
5567
5934
|
const scaleX = (x, index) => {
|
|
5568
5935
|
const numX = isStringX ? index : x;
|
|
@@ -5643,19 +6010,21 @@ var AreaChart = ({
|
|
|
5643
6010
|
x2: chartWidth,
|
|
5644
6011
|
y2: y,
|
|
5645
6012
|
stroke: "currentColor",
|
|
5646
|
-
strokeWidth: "
|
|
6013
|
+
strokeWidth: "0.5",
|
|
5647
6014
|
className: "text-gray-200 dark:text-gray-700",
|
|
5648
|
-
strokeDasharray: "
|
|
6015
|
+
strokeDasharray: "4,4"
|
|
5649
6016
|
}
|
|
5650
6017
|
),
|
|
5651
6018
|
showYAxis && /* @__PURE__ */ jsx110(
|
|
5652
6019
|
"text",
|
|
5653
6020
|
{
|
|
5654
|
-
x: -
|
|
5655
|
-
y
|
|
6021
|
+
x: -25,
|
|
6022
|
+
y,
|
|
5656
6023
|
textAnchor: "end",
|
|
5657
|
-
|
|
5658
|
-
|
|
6024
|
+
dominantBaseline: "middle",
|
|
6025
|
+
fontSize: gridLabelFontSize,
|
|
6026
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
6027
|
+
children: yValue.toFixed(1)
|
|
5659
6028
|
}
|
|
5660
6029
|
)
|
|
5661
6030
|
] }, `grid-h-${i}`)
|
|
@@ -5675,18 +6044,20 @@ var AreaChart = ({
|
|
|
5675
6044
|
x2: x,
|
|
5676
6045
|
y2: chartHeight,
|
|
5677
6046
|
stroke: "currentColor",
|
|
5678
|
-
strokeWidth: "
|
|
6047
|
+
strokeWidth: "0.5",
|
|
5679
6048
|
className: "text-gray-200 dark:text-gray-700",
|
|
5680
|
-
strokeDasharray: "
|
|
6049
|
+
strokeDasharray: "4,4"
|
|
5681
6050
|
}
|
|
5682
6051
|
),
|
|
5683
6052
|
showXAxis && /* @__PURE__ */ jsx110(
|
|
5684
6053
|
"text",
|
|
5685
6054
|
{
|
|
5686
6055
|
x,
|
|
5687
|
-
y: chartHeight +
|
|
6056
|
+
y: chartHeight + 35,
|
|
5688
6057
|
textAnchor: "middle",
|
|
5689
|
-
|
|
6058
|
+
dominantBaseline: "hanging",
|
|
6059
|
+
fontSize: gridLabelFontSize,
|
|
6060
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
5690
6061
|
children: xValue
|
|
5691
6062
|
}
|
|
5692
6063
|
)
|
|
@@ -5698,130 +6069,217 @@ var AreaChart = ({
|
|
|
5698
6069
|
if (stacked) {
|
|
5699
6070
|
cumulativeValues = Array(data[0]?.data.length || 0).fill(0);
|
|
5700
6071
|
}
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
6072
|
+
const getTooltipPosition = React28.useCallback((x, y) => {
|
|
6073
|
+
if (!containerRef.current) return { x, y };
|
|
6074
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
6075
|
+
const tooltipWidth = 120;
|
|
6076
|
+
const tooltipHeight = 80;
|
|
6077
|
+
let tooltipX = x + 10;
|
|
6078
|
+
let tooltipY = y - 30;
|
|
6079
|
+
if (tooltipX + tooltipWidth > rect.width) {
|
|
6080
|
+
tooltipX = x - tooltipWidth - 10;
|
|
6081
|
+
}
|
|
6082
|
+
if (tooltipY + tooltipHeight > rect.height) {
|
|
6083
|
+
tooltipY = y + 30;
|
|
6084
|
+
}
|
|
6085
|
+
return { x: tooltipX, y: tooltipY };
|
|
6086
|
+
}, []);
|
|
6087
|
+
const containerStyle = {
|
|
6088
|
+
"--font-size-base": `${baseFontSize}px`,
|
|
6089
|
+
"--font-size-lg": `calc(var(--font-size-base) * 1.125)`,
|
|
6090
|
+
"--font-size-sm": `calc(var(--font-size-base) * 0.875)`,
|
|
6091
|
+
"--font-size-xs": `calc(var(--font-size-base) * 0.75)`
|
|
6092
|
+
};
|
|
6093
|
+
return /* @__PURE__ */ jsxs37(
|
|
6094
|
+
"div",
|
|
6095
|
+
{
|
|
6096
|
+
ref: containerRef,
|
|
6097
|
+
className: `relative flex flex-col gap-4 ${responsive ? "w-full" : "inline-block"} ${className}`,
|
|
6098
|
+
style: containerStyle,
|
|
6099
|
+
children: [
|
|
6100
|
+
/* @__PURE__ */ jsx110("style", { children: `
|
|
6101
|
+
/* Mobile: Large fonts, hidden axis titles, thicker lines (default) */
|
|
6102
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize}px !important; }
|
|
6103
|
+
.${axisLabelClass} { display: none; }
|
|
6104
|
+
.${lineClass} { stroke-width: ${strokeWidth * 2.5} !important; }
|
|
6105
|
+
.${pointClass} { r: 6 !important; stroke-width: 3 !important; }
|
|
6106
|
+
|
|
6107
|
+
/* Tablet: Medium fonts, show axis titles, medium lines */
|
|
6108
|
+
@media (min-width: 640px) {
|
|
6109
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.7}px !important; }
|
|
6110
|
+
.${axisLabelClass} {
|
|
6111
|
+
font-size: ${axisLabelFontSize * 0.7}px !important;
|
|
6112
|
+
display: block;
|
|
6113
|
+
}
|
|
6114
|
+
.${lineClass} { stroke-width: ${strokeWidth * 1.5} !important; }
|
|
6115
|
+
.${pointClass} { r: 4 !important; stroke-width: 2 !important; }
|
|
6116
|
+
}
|
|
6117
|
+
|
|
6118
|
+
/* Desktop: Small fonts, show axis titles, normal lines */
|
|
6119
|
+
@media (min-width: 1024px) {
|
|
6120
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.4}px !important; }
|
|
6121
|
+
.${axisLabelClass} {
|
|
6122
|
+
font-size: ${axisLabelFontSize * 0.4}px !important;
|
|
6123
|
+
display: block;
|
|
6124
|
+
}
|
|
6125
|
+
.${lineClass} { stroke-width: ${strokeWidth} !important; }
|
|
6126
|
+
.${pointClass} { r: 3 !important; stroke-width: 1.5 !important; }
|
|
6127
|
+
}
|
|
6128
|
+
` }),
|
|
6129
|
+
/* @__PURE__ */ jsx110(
|
|
6130
|
+
"svg",
|
|
6131
|
+
{
|
|
6132
|
+
ref: svgRef,
|
|
6133
|
+
width: "100%",
|
|
6134
|
+
viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
|
6135
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
6136
|
+
className: "bg-white dark:bg-gray-800 block w-full",
|
|
6137
|
+
style: { height: "auto", overflow: "visible" },
|
|
6138
|
+
children: /* @__PURE__ */ jsxs37("g", { transform: `translate(${padding.left}, ${padding.top})`, children: [
|
|
6139
|
+
gridLines,
|
|
6140
|
+
data.map((series, seriesIndex) => {
|
|
6141
|
+
const baselineYValues = stacked ? [...cumulativeValues] : void 0;
|
|
6142
|
+
const areaPath = generateAreaPath(series, baselineYValues);
|
|
6143
|
+
const linePath = generateLinePath(series, baselineYValues);
|
|
6144
|
+
if (stacked) {
|
|
6145
|
+
series.data.forEach((point, i) => {
|
|
6146
|
+
cumulativeValues[i] += point.y;
|
|
6147
|
+
});
|
|
6148
|
+
}
|
|
6149
|
+
return /* @__PURE__ */ jsxs37("g", { children: [
|
|
6150
|
+
/* @__PURE__ */ jsx110(
|
|
6151
|
+
"path",
|
|
6152
|
+
{
|
|
6153
|
+
d: areaPath,
|
|
6154
|
+
fill: series.color || defaultColors3[seriesIndex % defaultColors3.length],
|
|
6155
|
+
opacity: fillOpacity
|
|
6156
|
+
}
|
|
6157
|
+
),
|
|
6158
|
+
/* @__PURE__ */ jsx110(
|
|
6159
|
+
"path",
|
|
6160
|
+
{
|
|
6161
|
+
d: linePath,
|
|
6162
|
+
fill: "none",
|
|
6163
|
+
stroke: series.color || defaultColors3[seriesIndex % defaultColors3.length],
|
|
6164
|
+
strokeWidth,
|
|
6165
|
+
strokeLinecap: "round",
|
|
6166
|
+
strokeLinejoin: "round",
|
|
6167
|
+
className: lineClass
|
|
6168
|
+
}
|
|
6169
|
+
)
|
|
6170
|
+
] }, `area-${seriesIndex}`);
|
|
6171
|
+
}),
|
|
6172
|
+
showDots && data.map((series, seriesIndex) => {
|
|
6173
|
+
const baselineYValues = stacked ? data.slice(0, seriesIndex).reduce((acc, s) => {
|
|
6174
|
+
return acc.map((val, i) => val + (s.data[i]?.y || 0));
|
|
6175
|
+
}, Array(series.data.length).fill(0)) : void 0;
|
|
6176
|
+
return series.data.map((point, pointIndex) => {
|
|
6177
|
+
const x = scaleX(point.x, pointIndex);
|
|
6178
|
+
const y = baselineYValues ? scaleY(baselineYValues[pointIndex] + point.y) : scaleY(point.y);
|
|
6179
|
+
const isHovered = hoveredPoint?.seriesIndex === seriesIndex && hoveredPoint?.pointIndex === pointIndex;
|
|
6180
|
+
return /* @__PURE__ */ jsx110(
|
|
6181
|
+
"circle",
|
|
6182
|
+
{
|
|
6183
|
+
cx: x,
|
|
6184
|
+
cy: y,
|
|
6185
|
+
r: isHovered ? 6 : 4,
|
|
6186
|
+
fill: series.color || defaultColors3[seriesIndex % defaultColors3.length],
|
|
6187
|
+
stroke: "white",
|
|
6188
|
+
strokeWidth: "2",
|
|
6189
|
+
className: `cursor-pointer transition-all ${pointClass}`,
|
|
6190
|
+
onMouseEnter: (e) => {
|
|
6191
|
+
if (showTooltip && containerRef.current) {
|
|
6192
|
+
setHoveredPoint({ seriesIndex, pointIndex, x, y });
|
|
6193
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
6194
|
+
const mouseX = e.clientX - containerRect.left;
|
|
6195
|
+
const mouseY = e.clientY - containerRect.top;
|
|
6196
|
+
setTooltipPosition(getTooltipPosition(mouseX, mouseY));
|
|
6197
|
+
}
|
|
6198
|
+
},
|
|
6199
|
+
onMouseMove: (e) => {
|
|
6200
|
+
if (showTooltip && hoveredPoint?.seriesIndex === seriesIndex && hoveredPoint?.pointIndex === pointIndex && containerRef.current) {
|
|
6201
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
6202
|
+
const mouseX = e.clientX - containerRect.left;
|
|
6203
|
+
const mouseY = e.clientY - containerRect.top;
|
|
6204
|
+
setTooltipPosition(getTooltipPosition(mouseX, mouseY));
|
|
6205
|
+
}
|
|
6206
|
+
},
|
|
6207
|
+
onMouseLeave: () => {
|
|
6208
|
+
setHoveredPoint(null);
|
|
6209
|
+
setTooltipPosition(null);
|
|
6210
|
+
}
|
|
6211
|
+
},
|
|
6212
|
+
`point-${seriesIndex}-${pointIndex}`
|
|
6213
|
+
);
|
|
6214
|
+
});
|
|
6215
|
+
}),
|
|
6216
|
+
xAxisLabel && showXAxis && /* @__PURE__ */ jsx110(
|
|
6217
|
+
"text",
|
|
5723
6218
|
{
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
6219
|
+
x: chartWidth / 2,
|
|
6220
|
+
y: chartHeight + 80,
|
|
6221
|
+
textAnchor: "middle",
|
|
6222
|
+
dominantBaseline: "hanging",
|
|
6223
|
+
fontSize: axisLabelFontSize,
|
|
6224
|
+
fontWeight: "600",
|
|
6225
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
6226
|
+
children: xAxisLabel
|
|
5727
6227
|
}
|
|
5728
6228
|
),
|
|
5729
|
-
/* @__PURE__ */ jsx110(
|
|
5730
|
-
"
|
|
6229
|
+
yAxisLabel && showYAxis && /* @__PURE__ */ jsx110(
|
|
6230
|
+
"text",
|
|
5731
6231
|
{
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
6232
|
+
x: -chartHeight / 2,
|
|
6233
|
+
y: -100,
|
|
6234
|
+
textAnchor: "middle",
|
|
6235
|
+
dominantBaseline: "middle",
|
|
6236
|
+
fontSize: axisLabelFontSize,
|
|
6237
|
+
fontWeight: "600",
|
|
6238
|
+
transform: "rotate(-90)",
|
|
6239
|
+
className: `fill-gray-700 dark:fill-gray-300 ${axisLabelClass}`,
|
|
6240
|
+
children: yAxisLabel
|
|
5738
6241
|
}
|
|
5739
6242
|
)
|
|
5740
|
-
] }
|
|
5741
|
-
}
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
return series.data.map((point, pointIndex) => {
|
|
5747
|
-
const x = scaleX(point.x, pointIndex);
|
|
5748
|
-
const y = baselineYValues ? scaleY(baselineYValues[pointIndex] + point.y) : scaleY(point.y);
|
|
5749
|
-
const isHovered = hoveredPoint?.seriesIndex === seriesIndex && hoveredPoint?.pointIndex === pointIndex;
|
|
5750
|
-
return /* @__PURE__ */ jsx110(
|
|
5751
|
-
"circle",
|
|
5752
|
-
{
|
|
5753
|
-
cx: x,
|
|
5754
|
-
cy: y,
|
|
5755
|
-
r: isHovered ? 6 : 4,
|
|
5756
|
-
fill: series.color || defaultColors3[seriesIndex % defaultColors3.length],
|
|
5757
|
-
stroke: "white",
|
|
5758
|
-
strokeWidth: "2",
|
|
5759
|
-
className: "cursor-pointer transition-all",
|
|
5760
|
-
onMouseEnter: () => showTooltip && setHoveredPoint({ seriesIndex, pointIndex, x, y }),
|
|
5761
|
-
onMouseLeave: () => setHoveredPoint(null)
|
|
5762
|
-
},
|
|
5763
|
-
`point-${seriesIndex}-${pointIndex}`
|
|
5764
|
-
);
|
|
5765
|
-
});
|
|
5766
|
-
}),
|
|
5767
|
-
xAxisLabel && showXAxis && /* @__PURE__ */ jsx110(
|
|
5768
|
-
"text",
|
|
6243
|
+
] })
|
|
6244
|
+
}
|
|
6245
|
+
),
|
|
6246
|
+
showLegend && /* @__PURE__ */ jsx110("div", { className: "flex flex-wrap gap-3 justify-center px-4", children: data.map((series, index) => /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
6247
|
+
/* @__PURE__ */ jsx110(
|
|
6248
|
+
"div",
|
|
5769
6249
|
{
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
children: xAxisLabel
|
|
6250
|
+
className: "w-3 h-3 rounded-sm flex-shrink-0",
|
|
6251
|
+
style: {
|
|
6252
|
+
backgroundColor: series.color || defaultColors3[index % defaultColors3.length]
|
|
6253
|
+
}
|
|
5775
6254
|
}
|
|
5776
6255
|
),
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
6256
|
+
/* @__PURE__ */ jsx110("span", { className: "text-gray-700 dark:text-gray-300", children: series.name })
|
|
6257
|
+
] }, `legend-${index}`)) }),
|
|
6258
|
+
showTooltip && hoveredPoint && tooltipPosition && /* @__PURE__ */ jsxs37(
|
|
6259
|
+
"div",
|
|
6260
|
+
{
|
|
6261
|
+
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg pointer-events-none z-50 text-sm whitespace-nowrap",
|
|
6262
|
+
style: {
|
|
6263
|
+
left: `${tooltipPosition.x}px`,
|
|
6264
|
+
top: `${tooltipPosition.y}px`,
|
|
6265
|
+
transform: "translateZ(0)"
|
|
6266
|
+
},
|
|
6267
|
+
children: [
|
|
6268
|
+
/* @__PURE__ */ jsx110("div", { className: "font-semibold", children: data[hoveredPoint.seriesIndex].name }),
|
|
6269
|
+
/* @__PURE__ */ jsxs37("div", { className: "text-xs opacity-90", children: [
|
|
6270
|
+
"x: ",
|
|
6271
|
+
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].x
|
|
6272
|
+
] }),
|
|
6273
|
+
/* @__PURE__ */ jsxs37("div", { className: "text-xs opacity-90", children: [
|
|
6274
|
+
"y: ",
|
|
6275
|
+
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].y
|
|
6276
|
+
] })
|
|
6277
|
+
]
|
|
5798
6278
|
}
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
showTooltip && hoveredPoint && /* @__PURE__ */ jsxs37(
|
|
5804
|
-
"div",
|
|
5805
|
-
{
|
|
5806
|
-
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg text-sm pointer-events-none z-50",
|
|
5807
|
-
style: {
|
|
5808
|
-
left: `${padding.left + hoveredPoint.x + 10}px`,
|
|
5809
|
-
top: `${padding.top + hoveredPoint.y - 30}px`
|
|
5810
|
-
},
|
|
5811
|
-
children: [
|
|
5812
|
-
/* @__PURE__ */ jsx110("div", { className: "font-semibold", children: data[hoveredPoint.seriesIndex].name }),
|
|
5813
|
-
/* @__PURE__ */ jsxs37("div", { children: [
|
|
5814
|
-
"x: ",
|
|
5815
|
-
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].x
|
|
5816
|
-
] }),
|
|
5817
|
-
/* @__PURE__ */ jsxs37("div", { children: [
|
|
5818
|
-
"y: ",
|
|
5819
|
-
data[hoveredPoint.seriesIndex].data[hoveredPoint.pointIndex].y
|
|
5820
|
-
] })
|
|
5821
|
-
]
|
|
5822
|
-
}
|
|
5823
|
-
)
|
|
5824
|
-
] });
|
|
6279
|
+
)
|
|
6280
|
+
]
|
|
6281
|
+
}
|
|
6282
|
+
);
|
|
5825
6283
|
};
|
|
5826
6284
|
|
|
5827
6285
|
// src/components/PieChart.tsx
|
|
@@ -5847,22 +6305,37 @@ var defaultColors4 = [
|
|
|
5847
6305
|
];
|
|
5848
6306
|
var PieChart = ({
|
|
5849
6307
|
data,
|
|
5850
|
-
width
|
|
5851
|
-
height
|
|
6308
|
+
width: providedWidth,
|
|
6309
|
+
height: providedHeight,
|
|
6310
|
+
aspectRatio = 1,
|
|
6311
|
+
responsive = true,
|
|
5852
6312
|
showLegend = true,
|
|
5853
6313
|
showLabels = true,
|
|
5854
6314
|
showValues = false,
|
|
5855
6315
|
showPercentages = false,
|
|
5856
6316
|
donut = false,
|
|
5857
6317
|
donutWidth = 60,
|
|
5858
|
-
className = ""
|
|
6318
|
+
className = "",
|
|
6319
|
+
baseFontSize = 14
|
|
5859
6320
|
}) => {
|
|
6321
|
+
const viewBoxWidth = 600;
|
|
6322
|
+
const viewBoxHeight = 600;
|
|
6323
|
+
const containerRef = React29.useRef(null);
|
|
6324
|
+
const [tooltipPosition, setTooltipPosition] = React29.useState(null);
|
|
5860
6325
|
const [hoveredSlice, setHoveredSlice] = React29.useState(null);
|
|
6326
|
+
const chartId = React29.useId();
|
|
6327
|
+
const wrapperClass = `chart-svg-wrapper-${chartId.replace(/:/g, "-")}`;
|
|
6328
|
+
const gridLabelClass = `chart-grid-label-${chartId.replace(/:/g, "-")}`;
|
|
6329
|
+
const axisLabelClass = `chart-axis-label-${chartId.replace(/:/g, "-")}`;
|
|
6330
|
+
const sliceClass = `chart-slice-${chartId.replace(/:/g, "-")}`;
|
|
5861
6331
|
const total = data.reduce((sum, item) => sum + item.value, 0);
|
|
5862
|
-
const centerX =
|
|
5863
|
-
const centerY =
|
|
5864
|
-
const radius = Math.min(
|
|
6332
|
+
const centerX = viewBoxWidth / 2;
|
|
6333
|
+
const centerY = viewBoxHeight / 2;
|
|
6334
|
+
const radius = Math.min(viewBoxWidth, viewBoxHeight) / 2 - 40;
|
|
5865
6335
|
const innerRadius = donut ? radius - donutWidth : 0;
|
|
6336
|
+
const gridLabelFontSize = viewBoxWidth * 0.045;
|
|
6337
|
+
const axisLabelFontSize = viewBoxWidth * 0.05;
|
|
6338
|
+
const titleFontSize = viewBoxWidth * 0.055;
|
|
5866
6339
|
let currentAngle = -90;
|
|
5867
6340
|
const slices = data.map((item, index) => {
|
|
5868
6341
|
const percentage = item.value / total * 100;
|
|
@@ -5914,112 +6387,194 @@ var PieChart = ({
|
|
|
5914
6387
|
index
|
|
5915
6388
|
};
|
|
5916
6389
|
});
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
6390
|
+
const getTooltipPosition = React29.useCallback((x, y) => {
|
|
6391
|
+
if (!containerRef.current) return { x, y };
|
|
6392
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
6393
|
+
const tooltipWidth = 120;
|
|
6394
|
+
const tooltipHeight = 80;
|
|
6395
|
+
let tooltipX = x + 10;
|
|
6396
|
+
let tooltipY = y - 30;
|
|
6397
|
+
if (tooltipX + tooltipWidth > rect.width) {
|
|
6398
|
+
tooltipX = x - tooltipWidth - 10;
|
|
6399
|
+
}
|
|
6400
|
+
if (tooltipY + tooltipHeight > rect.height) {
|
|
6401
|
+
tooltipY = y + 30;
|
|
6402
|
+
}
|
|
6403
|
+
return { x: tooltipX, y: tooltipY };
|
|
6404
|
+
}, []);
|
|
6405
|
+
const containerStyle = {
|
|
6406
|
+
"--font-size-base": `${baseFontSize}px`,
|
|
6407
|
+
"--font-size-lg": `calc(var(--font-size-base) * 1.125)`,
|
|
6408
|
+
"--font-size-sm": `calc(var(--font-size-base) * 0.875)`,
|
|
6409
|
+
"--font-size-xs": `calc(var(--font-size-base) * 0.75)`,
|
|
6410
|
+
"--font-size-xl": `calc(var(--font-size-base) * 1.5)`,
|
|
6411
|
+
"--font-size-2xl": `calc(var(--font-size-base) * 2)`
|
|
6412
|
+
};
|
|
6413
|
+
if (responsive) {
|
|
6414
|
+
containerStyle["--font-size-base"] = `clamp(${baseFontSize * 0.8}px, 4vw, ${baseFontSize}px)`;
|
|
6415
|
+
}
|
|
6416
|
+
return /* @__PURE__ */ jsxs38(
|
|
6417
|
+
"div",
|
|
6418
|
+
{
|
|
6419
|
+
ref: containerRef,
|
|
6420
|
+
className: `relative flex flex-col gap-4 ${responsive ? "w-full" : "inline-block"} ${className}`,
|
|
6421
|
+
style: containerStyle,
|
|
6422
|
+
children: [
|
|
6423
|
+
/* @__PURE__ */ jsx111("style", { children: `
|
|
6424
|
+
/* Mobile: Large fonts (default) */
|
|
6425
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize}px !important; }
|
|
6426
|
+
.${axisLabelClass} { font-size: ${titleFontSize}px !important; }
|
|
6427
|
+
|
|
6428
|
+
/* Tablet: Medium fonts */
|
|
6429
|
+
@media (min-width: 640px) {
|
|
6430
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.7}px !important; }
|
|
6431
|
+
.${axisLabelClass} { font-size: ${titleFontSize * 0.7}px !important; }
|
|
6432
|
+
}
|
|
6433
|
+
|
|
6434
|
+
/* Desktop: Small fonts */
|
|
6435
|
+
@media (min-width: 1024px) {
|
|
6436
|
+
.${gridLabelClass} { font-size: ${gridLabelFontSize * 0.4}px !important; }
|
|
6437
|
+
.${axisLabelClass} { font-size: ${titleFontSize * 0.4}px !important; }
|
|
6438
|
+
}
|
|
6439
|
+
` }),
|
|
6440
|
+
/* @__PURE__ */ jsxs38(
|
|
6441
|
+
"svg",
|
|
6442
|
+
{
|
|
6443
|
+
width: "100%",
|
|
6444
|
+
viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
|
6445
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
6446
|
+
className: "bg-white dark:bg-gray-800 block w-full",
|
|
6447
|
+
style: { height: "auto", overflow: "visible" },
|
|
6448
|
+
children: [
|
|
6449
|
+
slices.map((slice) => {
|
|
6450
|
+
const isHovered = hoveredSlice === slice.index;
|
|
6451
|
+
return /* @__PURE__ */ jsxs38("g", { children: [
|
|
6452
|
+
/* @__PURE__ */ jsx111(
|
|
6453
|
+
"path",
|
|
6454
|
+
{
|
|
6455
|
+
d: slice.path,
|
|
6456
|
+
fill: slice.color,
|
|
6457
|
+
stroke: "white",
|
|
6458
|
+
strokeWidth: "2",
|
|
6459
|
+
className: "cursor-pointer transition-opacity",
|
|
6460
|
+
opacity: isHovered ? 0.8 : 1,
|
|
6461
|
+
onMouseEnter: (e) => {
|
|
6462
|
+
setHoveredSlice(slice.index);
|
|
6463
|
+
if (containerRef.current) {
|
|
6464
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
6465
|
+
const svgX = e.clientX - rect.left;
|
|
6466
|
+
const svgY = e.clientY - rect.top;
|
|
6467
|
+
setTooltipPosition(getTooltipPosition(svgX, svgY));
|
|
6468
|
+
}
|
|
6469
|
+
},
|
|
6470
|
+
onMouseLeave: () => {
|
|
6471
|
+
setHoveredSlice(null);
|
|
6472
|
+
setTooltipPosition(null);
|
|
6473
|
+
}
|
|
6474
|
+
}
|
|
6475
|
+
),
|
|
6476
|
+
showLabels && slice.percentage > 5 && /* @__PURE__ */ jsxs38(
|
|
6477
|
+
"text",
|
|
6478
|
+
{
|
|
6479
|
+
x: slice.labelX,
|
|
6480
|
+
y: slice.labelY,
|
|
6481
|
+
textAnchor: "middle",
|
|
6482
|
+
dominantBaseline: "middle",
|
|
6483
|
+
fontSize: gridLabelFontSize,
|
|
6484
|
+
fontWeight: "600",
|
|
6485
|
+
className: `fill-gray-700 dark:fill-gray-200 pointer-events-none ${gridLabelClass}`,
|
|
6486
|
+
children: [
|
|
6487
|
+
showPercentages && `${slice.percentage.toFixed(1)}%`,
|
|
6488
|
+
showPercentages && showValues && " ",
|
|
6489
|
+
showValues && `(${slice.value})`,
|
|
6490
|
+
!showPercentages && !showValues && slice.label
|
|
6491
|
+
]
|
|
6492
|
+
}
|
|
6493
|
+
)
|
|
6494
|
+
] }, slice.index);
|
|
6495
|
+
}),
|
|
6496
|
+
donut && /* @__PURE__ */ jsxs38("g", { children: [
|
|
6497
|
+
/* @__PURE__ */ jsx111(
|
|
6498
|
+
"text",
|
|
6499
|
+
{
|
|
6500
|
+
x: centerX,
|
|
6501
|
+
y: centerY - 10,
|
|
6502
|
+
textAnchor: "middle",
|
|
6503
|
+
dominantBaseline: "middle",
|
|
6504
|
+
fontSize: titleFontSize,
|
|
6505
|
+
fontWeight: "700",
|
|
6506
|
+
className: `fill-gray-900 dark:fill-gray-100 ${axisLabelClass}`,
|
|
6507
|
+
children: total
|
|
6508
|
+
}
|
|
6509
|
+
),
|
|
6510
|
+
/* @__PURE__ */ jsx111(
|
|
6511
|
+
"text",
|
|
6512
|
+
{
|
|
6513
|
+
x: centerX,
|
|
6514
|
+
y: centerY + 15,
|
|
6515
|
+
textAnchor: "middle",
|
|
6516
|
+
dominantBaseline: "middle",
|
|
6517
|
+
fontSize: axisLabelFontSize,
|
|
6518
|
+
className: `fill-gray-600 dark:fill-gray-400 ${gridLabelClass}`,
|
|
6519
|
+
children: "Total"
|
|
6520
|
+
}
|
|
6521
|
+
)
|
|
6522
|
+
] })
|
|
6523
|
+
]
|
|
6524
|
+
}
|
|
6525
|
+
),
|
|
6526
|
+
showLegend && /* @__PURE__ */ jsx111("div", { className: "flex flex-wrap gap-3 justify-center px-4", children: data.map((item, index) => /* @__PURE__ */ jsxs38(
|
|
6527
|
+
"div",
|
|
6528
|
+
{
|
|
6529
|
+
className: "flex items-center gap-2 text-sm cursor-pointer",
|
|
6530
|
+
onMouseEnter: () => setHoveredSlice(index),
|
|
6531
|
+
onMouseLeave: () => setHoveredSlice(null),
|
|
6532
|
+
children: [
|
|
5928
6533
|
/* @__PURE__ */ jsx111(
|
|
5929
|
-
"
|
|
6534
|
+
"div",
|
|
5930
6535
|
{
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
className: "cursor-pointer transition-opacity",
|
|
5936
|
-
opacity: isHovered ? 0.8 : 1,
|
|
5937
|
-
onMouseEnter: () => setHoveredSlice(slice.index),
|
|
5938
|
-
onMouseLeave: () => setHoveredSlice(null)
|
|
6536
|
+
className: "w-3 h-3 rounded-sm flex-shrink-0",
|
|
6537
|
+
style: {
|
|
6538
|
+
backgroundColor: item.color || defaultColors4[index % defaultColors4.length]
|
|
6539
|
+
}
|
|
5939
6540
|
}
|
|
5940
6541
|
),
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
"
|
|
5962
|
-
{
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
children: "Total"
|
|
5978
|
-
}
|
|
5979
|
-
)
|
|
5980
|
-
] })
|
|
5981
|
-
]
|
|
5982
|
-
}
|
|
5983
|
-
),
|
|
5984
|
-
showLegend && /* @__PURE__ */ jsx111("div", { className: "flex flex-wrap gap-4 mt-4 justify-center", children: data.map((item, index) => /* @__PURE__ */ jsxs38(
|
|
5985
|
-
"div",
|
|
5986
|
-
{
|
|
5987
|
-
className: "flex items-center gap-2 cursor-pointer",
|
|
5988
|
-
onMouseEnter: () => setHoveredSlice(index),
|
|
5989
|
-
onMouseLeave: () => setHoveredSlice(null),
|
|
5990
|
-
children: [
|
|
5991
|
-
/* @__PURE__ */ jsx111(
|
|
5992
|
-
"div",
|
|
5993
|
-
{
|
|
5994
|
-
className: "w-4 h-4 rounded-sm",
|
|
5995
|
-
style: {
|
|
5996
|
-
backgroundColor: item.color || defaultColors4[index % defaultColors4.length]
|
|
5997
|
-
}
|
|
5998
|
-
}
|
|
5999
|
-
),
|
|
6000
|
-
/* @__PURE__ */ jsxs38("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: [
|
|
6001
|
-
item.label,
|
|
6002
|
-
": ",
|
|
6003
|
-
item.value,
|
|
6004
|
-
showPercentages && ` (${(item.value / total * 100).toFixed(1)}%)`
|
|
6005
|
-
] })
|
|
6006
|
-
]
|
|
6007
|
-
},
|
|
6008
|
-
`legend-${index}`
|
|
6009
|
-
)) }),
|
|
6010
|
-
hoveredSlice !== null && /* @__PURE__ */ jsxs38("div", { className: "absolute top-2 right-2 bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg text-sm pointer-events-none z-50", children: [
|
|
6011
|
-
/* @__PURE__ */ jsx111("div", { className: "font-semibold", children: data[hoveredSlice].label }),
|
|
6012
|
-
/* @__PURE__ */ jsxs38("div", { children: [
|
|
6013
|
-
"Value: ",
|
|
6014
|
-
data[hoveredSlice].value
|
|
6015
|
-
] }),
|
|
6016
|
-
/* @__PURE__ */ jsxs38("div", { children: [
|
|
6017
|
-
"Percentage: ",
|
|
6018
|
-
(data[hoveredSlice].value / total * 100).toFixed(1),
|
|
6019
|
-
"%"
|
|
6020
|
-
] })
|
|
6021
|
-
] })
|
|
6022
|
-
] });
|
|
6542
|
+
/* @__PURE__ */ jsxs38("span", { className: "text-gray-700 dark:text-gray-300", children: [
|
|
6543
|
+
item.label,
|
|
6544
|
+
": ",
|
|
6545
|
+
item.value,
|
|
6546
|
+
showPercentages && ` (${(item.value / total * 100).toFixed(1)}%)`
|
|
6547
|
+
] })
|
|
6548
|
+
]
|
|
6549
|
+
},
|
|
6550
|
+
`legend-${index}`
|
|
6551
|
+
)) }),
|
|
6552
|
+
hoveredSlice !== null && tooltipPosition && /* @__PURE__ */ jsxs38(
|
|
6553
|
+
"div",
|
|
6554
|
+
{
|
|
6555
|
+
className: "absolute bg-gray-900 dark:bg-gray-700 text-white px-3 py-2 rounded shadow-lg pointer-events-none z-50 text-sm whitespace-nowrap",
|
|
6556
|
+
style: {
|
|
6557
|
+
left: `${tooltipPosition.x}px`,
|
|
6558
|
+
top: `${tooltipPosition.y}px`,
|
|
6559
|
+
transform: "translateZ(0)"
|
|
6560
|
+
},
|
|
6561
|
+
children: [
|
|
6562
|
+
/* @__PURE__ */ jsx111("div", { className: "font-semibold", children: data[hoveredSlice].label }),
|
|
6563
|
+
/* @__PURE__ */ jsxs38("div", { className: "text-xs opacity-90", children: [
|
|
6564
|
+
"Value: ",
|
|
6565
|
+
data[hoveredSlice].value
|
|
6566
|
+
] }),
|
|
6567
|
+
/* @__PURE__ */ jsxs38("div", { className: "text-xs opacity-90", children: [
|
|
6568
|
+
"Percentage: ",
|
|
6569
|
+
(data[hoveredSlice].value / total * 100).toFixed(1),
|
|
6570
|
+
"%"
|
|
6571
|
+
] })
|
|
6572
|
+
]
|
|
6573
|
+
}
|
|
6574
|
+
)
|
|
6575
|
+
]
|
|
6576
|
+
}
|
|
6577
|
+
);
|
|
6023
6578
|
};
|
|
6024
6579
|
|
|
6025
6580
|
// src/utils/theme-script.ts
|