@mlw-packages/react-components 1.5.4 → 1.5.6

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.js CHANGED
@@ -500,6 +500,7 @@ __export(index_exports, {
500
500
  AvatarFallbackBase: () => AvatarFallbackBase,
501
501
  AvatarImageBase: () => AvatarImageBase,
502
502
  BadgeBase: () => BadgeBase,
503
+ BarChart: () => BarChart_default,
503
504
  BreadcrumbBase: () => BreadcrumbBase,
504
505
  BreadcrumbEllipsisBase: () => BreadcrumbEllipsisBase,
505
506
  BreadcrumbItemBase: () => BreadcrumbItemBase,
@@ -521,6 +522,7 @@ __export(index_exports, {
521
522
  CarouselItemBase: () => CarouselItemBase,
522
523
  CarouselNextBase: () => CarouselNextBase,
523
524
  CarouselPrevious: () => CarouselPrevious,
525
+ Chart: () => Chart_default,
524
526
  CheckboxBase: () => CheckboxBase,
525
527
  CollapsibleBase: () => CollapsibleBase,
526
528
  CollapsibleContentBase: () => CollapsibleContentBase,
@@ -596,6 +598,7 @@ __export(index_exports, {
596
598
  InputOTPSeparatorBase: () => InputOTPSeparatorBase,
597
599
  InputOTPSlotBase: () => InputOTPSlotBase,
598
600
  LabelBase: () => LabelBase_default,
601
+ LineChart: () => LineChart_default,
599
602
  ModeToggleBase: () => ModeToggleBase,
600
603
  MultiCombobox: () => MultiCombobox,
601
604
  NavigationMenuBase: () => NavigationMenuBase,
@@ -606,6 +609,7 @@ __export(index_exports, {
606
609
  NavigationMenuListBase: () => NavigationMenuListBase,
607
610
  NavigationMenuTriggerBase: () => NavigationMenuTriggerBase,
608
611
  NavigationMenuViewportBase: () => NavigationMenuViewportBase,
612
+ PieChart: () => PieChart_default,
609
613
  PopoverAnchorBase: () => PopoverAnchorBase,
610
614
  PopoverBase: () => PopoverBase,
611
615
  PopoverContentBase: () => PopoverContentBase,
@@ -689,6 +693,7 @@ __export(index_exports, {
689
693
  badgeVariants: () => badgeVariants,
690
694
  buttonVariantsBase: () => buttonVariantsBase,
691
695
  toast: () => toast,
696
+ useDrag: () => useDrag,
692
697
  useIsMobile: () => useIsMobile,
693
698
  useTheme: () => useTheme
694
699
  });
@@ -838,7 +843,7 @@ var AlertDialogFooterBase = ({
838
843
  "div",
839
844
  {
840
845
  className: cn(
841
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
846
+ "flex flex-col-reverse sm:flex-row sm:justify-end",
842
847
  className
843
848
  ),
844
849
  ...props
@@ -879,11 +884,7 @@ var AlertDialogCancelBase = React2.forwardRef(({ className, testid = "alertdialo
879
884
  AlertDialogPrimitive.Cancel,
880
885
  {
881
886
  ref,
882
- className: cn(
883
- buttonVariantsBase({ variant: "outline" }),
884
- "mt-2 sm:mt-0",
885
- className
886
- ),
887
+ className: cn(buttonVariantsBase({ variant: "outline" }), className),
887
888
  "data-testid": testid,
888
889
  ...props
889
890
  }
@@ -5055,3 +5056,3105 @@ var DestructiveDialog = ({
5055
5056
  )
5056
5057
  ] });
5057
5058
  };
5059
+
5060
+ // src/components/rechart/LineChart.tsx
5061
+ var import_react33 = require("react");
5062
+ var import_recharts = require("recharts");
5063
+
5064
+ // src/components/rechart/DraggableTooltip.tsx
5065
+ var import_react31 = require("react");
5066
+ var import_react32 = require("@phosphor-icons/react");
5067
+ var import_ssr2 = require("@phosphor-icons/react/dist/ssr");
5068
+
5069
+ // src/components/rechart/CloseAllButton.tsx
5070
+ var import_ssr = require("@phosphor-icons/react/dist/ssr");
5071
+ var import_jsx_runtime48 = require("react/jsx-runtime");
5072
+ var CloseAllButton = ({
5073
+ count,
5074
+ onCloseAll,
5075
+ position = "top-center",
5076
+ variant = "floating"
5077
+ }) => {
5078
+ if (count <= 1) return null;
5079
+ const getPositionClasses = () => {
5080
+ if (variant === "inline") return "";
5081
+ switch (position) {
5082
+ case "top-left":
5083
+ return "fixed top-6 left-6 z-50";
5084
+ case "top-right":
5085
+ return "fixed top-6 right-6 z-50";
5086
+ case "top-center":
5087
+ return "fixed top-6 left-1/2 transform -translate-x-1/2 z-50";
5088
+ default:
5089
+ return "fixed top-6 left-1/2 transform -translate-x-1/2 z-50";
5090
+ }
5091
+ };
5092
+ const getVariantClasses = () => {
5093
+ if (variant === "inline") {
5094
+ return "text-xs px-2 py-1 h-auto bg-card border border-border shadow-sm hover:bg-accent";
5095
+ }
5096
+ return `
5097
+ rounded-full px-4 py-2.5 bg-transparent hover:bg-white/15 active:bg-white/20
5098
+ text-white font-semibold text-sm
5099
+ transition-all duration-200 ease-in-out
5100
+ hover:scale-105 active:scale-95 hover:shadow-2xl
5101
+ flex items-center gap-2.5
5102
+ group
5103
+ min-w-max
5104
+ `;
5105
+ };
5106
+ if (variant === "inline") {
5107
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "absolute top-4 right-4 z-30", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
5108
+ ButtonBase,
5109
+ {
5110
+ variant: "ghost",
5111
+ size: "sm",
5112
+ onClick: onCloseAll,
5113
+ className: getVariantClasses(),
5114
+ children: [
5115
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ssr.XIcon, { size: 12, className: "mr-1" }),
5116
+ "Fechar Todos"
5117
+ ]
5118
+ }
5119
+ ) });
5120
+ }
5121
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: `${getPositionClasses()} animate-in fade-in slide-in-from-top-2 duration-300`, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "bg-red-500 rounded-full shadow-xl border border-white/20 backdrop-blur-sm", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
5122
+ ButtonBase,
5123
+ {
5124
+ onClick: onCloseAll,
5125
+ variant: "destructive",
5126
+ size: "sm",
5127
+ className: getVariantClasses(),
5128
+ children: [
5129
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5130
+ import_ssr.XIcon,
5131
+ {
5132
+ size: 18,
5133
+ className: "\n group-hover:rotate-90 transition-all duration-300 ease-out\n drop-shadow-sm\n "
5134
+ }
5135
+ ),
5136
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 tracking-wide", children: "Fechar Todos" }),
5137
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5138
+ "div",
5139
+ {
5140
+ className: "\n bg-white/20 text-white text-xs font-bold\n rounded-full w-6 h-6 \n flex items-center justify-center\n transition-colors duration-200\n ",
5141
+ children: count
5142
+ }
5143
+ )
5144
+ ]
5145
+ }
5146
+ ) }) });
5147
+ };
5148
+ var CloseAllButton_default = CloseAllButton;
5149
+
5150
+ // src/components/rechart/DraggableTooltip.tsx
5151
+ var import_jsx_runtime49 = require("react/jsx-runtime");
5152
+ var DraggableTooltip = ({
5153
+ id,
5154
+ data,
5155
+ position,
5156
+ title,
5157
+ dataKeys,
5158
+ finalColors,
5159
+ onClose,
5160
+ periodLabel = "Per\xEDodo Selecionado",
5161
+ dataLabel = "Dados do Per\xEDodo",
5162
+ showCloseAllButton = false,
5163
+ globalTooltipCount,
5164
+ onCloseAll,
5165
+ closeAllButtonPosition = "top-center",
5166
+ closeAllButtonVariant = "floating",
5167
+ onPositionChange
5168
+ }) => {
5169
+ const [localPos, setLocalPos] = (0, import_react31.useState)(
5170
+ position
5171
+ );
5172
+ const [dragging, setDragging] = (0, import_react31.useState)(false);
5173
+ const offsetRef = (0, import_react31.useRef)({ x: 0, y: 0 });
5174
+ const lastMouse = (0, import_react31.useRef)({ x: 0, y: 0 });
5175
+ const [alignmentGuides, setAlignmentGuides] = (0, import_react31.useState)([]);
5176
+ const [globalTooltipCountLocal, setGlobalTooltipCountLocal] = (0, import_react31.useState)(0);
5177
+ (0, import_react31.useEffect)(() => setLocalPos(position), [position]);
5178
+ const ALIGNMENT_THRESHOLD = 25;
5179
+ const GUIDE_THRESHOLD = 60;
5180
+ const STRONG_SNAP_THRESHOLD = 35;
5181
+ const PRECISION_SNAP_THRESHOLD = 8;
5182
+ const getAllTooltips = (0, import_react31.useCallback)(() => {
5183
+ const response = [];
5184
+ const ev = new CustomEvent("requestGlobalTooltips", {
5185
+ detail: { requesterId: id, response }
5186
+ });
5187
+ window.dispatchEvent(ev);
5188
+ return response;
5189
+ }, [id]);
5190
+ const updateAlignmentGuides = (0, import_react31.useCallback)(
5191
+ (currentPosition) => {
5192
+ const allTooltips = getAllTooltips();
5193
+ const otherTooltips = allTooltips.filter((t) => t.id !== id);
5194
+ const guides = [];
5195
+ const tooltipDimensions = { width: 224, height: 120 };
5196
+ otherTooltips.forEach((tooltip) => {
5197
+ const topDiff = Math.abs(currentPosition.top - tooltip.position.top);
5198
+ if (topDiff <= GUIDE_THRESHOLD) {
5199
+ guides.push({
5200
+ type: "horizontal",
5201
+ position: tooltip.position.top,
5202
+ sourceTooltip: {
5203
+ top: currentPosition.top,
5204
+ left: currentPosition.left,
5205
+ width: tooltipDimensions.width,
5206
+ height: tooltipDimensions.height
5207
+ },
5208
+ targetTooltip: {
5209
+ top: tooltip.position.top,
5210
+ left: tooltip.position.left,
5211
+ width: tooltipDimensions.width,
5212
+ height: tooltipDimensions.height
5213
+ }
5214
+ });
5215
+ }
5216
+ const leftDiff = Math.abs(currentPosition.left - tooltip.position.left);
5217
+ if (leftDiff <= GUIDE_THRESHOLD) {
5218
+ guides.push({
5219
+ type: "vertical",
5220
+ position: tooltip.position.left,
5221
+ sourceTooltip: {
5222
+ top: currentPosition.top,
5223
+ left: currentPosition.left,
5224
+ width: tooltipDimensions.width,
5225
+ height: tooltipDimensions.height
5226
+ },
5227
+ targetTooltip: {
5228
+ top: tooltip.position.top,
5229
+ left: tooltip.position.left,
5230
+ width: tooltipDimensions.width,
5231
+ height: tooltipDimensions.height
5232
+ }
5233
+ });
5234
+ }
5235
+ });
5236
+ setAlignmentGuides(guides);
5237
+ },
5238
+ [getAllTooltips, id]
5239
+ );
5240
+ const snapToGuides = (0, import_react31.useCallback)(
5241
+ (position2) => {
5242
+ const snappedPosition = { ...position2 };
5243
+ let hasSnapped = false;
5244
+ alignmentGuides.forEach((guide) => {
5245
+ if (guide.type === "horizontal") {
5246
+ const diff = Math.abs(position2.top - guide.position);
5247
+ if (diff <= PRECISION_SNAP_THRESHOLD) {
5248
+ snappedPosition.top = guide.position;
5249
+ hasSnapped = true;
5250
+ }
5251
+ } else {
5252
+ const diff = Math.abs(position2.left - guide.position);
5253
+ if (diff <= PRECISION_SNAP_THRESHOLD) {
5254
+ snappedPosition.left = guide.position;
5255
+ hasSnapped = true;
5256
+ }
5257
+ }
5258
+ });
5259
+ if (!hasSnapped) {
5260
+ alignmentGuides.forEach((guide) => {
5261
+ if (guide.type === "horizontal") {
5262
+ const diff = Math.abs(position2.top - guide.position);
5263
+ if (diff <= STRONG_SNAP_THRESHOLD)
5264
+ snappedPosition.top = guide.position;
5265
+ } else {
5266
+ const diff = Math.abs(position2.left - guide.position);
5267
+ if (diff <= STRONG_SNAP_THRESHOLD)
5268
+ snappedPosition.left = guide.position;
5269
+ }
5270
+ });
5271
+ }
5272
+ alignmentGuides.forEach((guide) => {
5273
+ if (guide.type === "horizontal") {
5274
+ const diff = Math.abs(position2.top - guide.position);
5275
+ if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.top === position2.top)
5276
+ snappedPosition.top = guide.position;
5277
+ } else {
5278
+ const diff = Math.abs(position2.left - guide.position);
5279
+ if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.left === position2.left)
5280
+ snappedPosition.left = guide.position;
5281
+ }
5282
+ });
5283
+ return snappedPosition;
5284
+ },
5285
+ [alignmentGuides]
5286
+ );
5287
+ (0, import_react31.useEffect)(() => {
5288
+ let rafId = null;
5289
+ const handleMouseMove = (e) => {
5290
+ if (!dragging) return;
5291
+ lastMouse.current = { x: e.clientX, y: e.clientY };
5292
+ if (rafId) cancelAnimationFrame(rafId);
5293
+ rafId = requestAnimationFrame(() => {
5294
+ const newLeft = lastMouse.current.x - offsetRef.current.x;
5295
+ const newTop = lastMouse.current.y - offsetRef.current.y;
5296
+ const rawPosition = {
5297
+ top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
5298
+ left: Math.max(0, Math.min(newLeft, window.innerWidth - 250))
5299
+ };
5300
+ updateAlignmentGuides(rawPosition);
5301
+ const snapped = snapToGuides(rawPosition);
5302
+ setLocalPos(snapped);
5303
+ if (onPositionChange) onPositionChange(id, snapped);
5304
+ });
5305
+ };
5306
+ const handleMouseUp = () => {
5307
+ if (dragging) {
5308
+ setDragging(false);
5309
+ setAlignmentGuides([]);
5310
+ if (rafId) cancelAnimationFrame(rafId);
5311
+ }
5312
+ };
5313
+ if (dragging) {
5314
+ document.addEventListener("mousemove", handleMouseMove, {
5315
+ passive: true
5316
+ });
5317
+ document.addEventListener("mouseup", handleMouseUp);
5318
+ document.body.style.cursor = "grabbing";
5319
+ document.body.style.userSelect = "none";
5320
+ }
5321
+ return () => {
5322
+ if (rafId) cancelAnimationFrame(rafId);
5323
+ document.removeEventListener("mousemove", handleMouseMove);
5324
+ document.removeEventListener("mouseup", handleMouseUp);
5325
+ document.body.style.cursor = "";
5326
+ document.body.style.userSelect = "";
5327
+ };
5328
+ }, [dragging, snapToGuides, updateAlignmentGuides, id, onPositionChange]);
5329
+ (0, import_react31.useEffect)(() => {
5330
+ const handleCloseAll = () => {
5331
+ onClose(id);
5332
+ };
5333
+ const handleRequestTooltipCount = () => {
5334
+ window.dispatchEvent(
5335
+ new CustomEvent("tooltipCountResponse", { detail: { count: 1 } })
5336
+ );
5337
+ };
5338
+ const handleRequestGlobalTooltips = (event) => {
5339
+ const customEvent = event;
5340
+ const detail = customEvent.detail;
5341
+ if (detail && detail.response && detail.requesterId) {
5342
+ if (!detail.response.find((t) => t.id === id)) {
5343
+ detail.response.push({ id, position: localPos });
5344
+ }
5345
+ }
5346
+ };
5347
+ window.addEventListener("closeAllTooltips", handleCloseAll);
5348
+ window.addEventListener("requestTooltipCount", handleRequestTooltipCount);
5349
+ window.addEventListener(
5350
+ "requestGlobalTooltips",
5351
+ handleRequestGlobalTooltips
5352
+ );
5353
+ return () => {
5354
+ window.removeEventListener("closeAllTooltips", handleCloseAll);
5355
+ window.removeEventListener(
5356
+ "requestTooltipCount",
5357
+ handleRequestTooltipCount
5358
+ );
5359
+ window.removeEventListener(
5360
+ "requestGlobalTooltips",
5361
+ handleRequestGlobalTooltips
5362
+ );
5363
+ };
5364
+ }, [id, localPos, onClose]);
5365
+ (0, import_react31.useEffect)(() => {
5366
+ if (dragging) return;
5367
+ let total = 0;
5368
+ const handleCountResponse = (event) => {
5369
+ const customEvent = event;
5370
+ total += customEvent.detail.count || 0;
5371
+ };
5372
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
5373
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
5374
+ const timeoutId = setTimeout(() => {
5375
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
5376
+ setGlobalTooltipCountLocal(total);
5377
+ }, 50);
5378
+ return () => {
5379
+ clearTimeout(timeoutId);
5380
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
5381
+ };
5382
+ }, [localPos, dragging]);
5383
+ (0, import_react31.useEffect)(() => {
5384
+ const recount = () => {
5385
+ if (dragging) return;
5386
+ let total = 0;
5387
+ const handleCountResponse = (event) => {
5388
+ const customEvent = event;
5389
+ total += customEvent.detail.count || 0;
5390
+ };
5391
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
5392
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
5393
+ setTimeout(() => {
5394
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
5395
+ setGlobalTooltipCountLocal(total);
5396
+ }, 50);
5397
+ };
5398
+ window.addEventListener("recountTooltips", recount);
5399
+ return () => window.removeEventListener("recountTooltips", recount);
5400
+ }, [dragging]);
5401
+ const handleMouseDownLocal = (e) => {
5402
+ e.preventDefault();
5403
+ e.stopPropagation();
5404
+ const rect = e.currentTarget.getBoundingClientRect();
5405
+ offsetRef.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };
5406
+ setDragging(true);
5407
+ };
5408
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
5409
+ dragging && alignmentGuides.map((guide, index) => {
5410
+ const isHorizontal = guide.type === "horizontal";
5411
+ const color = isHorizontal ? "#3b82f6" : "#ef4444";
5412
+ const startX = isHorizontal ? Math.min(
5413
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
5414
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
5415
+ ) : guide.sourceTooltip.left + guide.sourceTooltip.width / 2;
5416
+ const endX = isHorizontal ? Math.max(
5417
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
5418
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
5419
+ ) : guide.targetTooltip.left + guide.targetTooltip.width / 2;
5420
+ const startY = isHorizontal ? guide.sourceTooltip.top + guide.sourceTooltip.height / 2 : Math.min(
5421
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
5422
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
5423
+ );
5424
+ const endY = isHorizontal ? guide.targetTooltip.top + guide.targetTooltip.height / 2 : Math.max(
5425
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
5426
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
5427
+ );
5428
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { children: [
5429
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5430
+ "div",
5431
+ {
5432
+ className: "fixed pointer-events-none z-30",
5433
+ style: {
5434
+ left: startX,
5435
+ top: startY,
5436
+ width: isHorizontal ? endX - startX : "2px",
5437
+ height: isHorizontal ? "2px" : endY - startY,
5438
+ backgroundColor: color,
5439
+ boxShadow: `0 0 8px ${color}60`,
5440
+ opacity: 0.9,
5441
+ borderStyle: "dashed",
5442
+ borderWidth: "1px",
5443
+ borderColor: color,
5444
+ transform: "translateZ(0)"
5445
+ }
5446
+ }
5447
+ ),
5448
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5449
+ "div",
5450
+ {
5451
+ className: "fixed pointer-events-none z-31",
5452
+ style: {
5453
+ left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
5454
+ top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
5455
+ width: "8px",
5456
+ height: "8px",
5457
+ backgroundColor: color,
5458
+ borderRadius: "50%",
5459
+ boxShadow: `0 0 4px ${color}80`,
5460
+ opacity: 0.8
5461
+ }
5462
+ }
5463
+ ),
5464
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5465
+ "div",
5466
+ {
5467
+ className: "fixed pointer-events-none z-31",
5468
+ style: {
5469
+ left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
5470
+ top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
5471
+ width: "8px",
5472
+ height: "8px",
5473
+ backgroundColor: color,
5474
+ borderRadius: "50%",
5475
+ boxShadow: `0 0 4px ${color}80`,
5476
+ opacity: 0.8
5477
+ }
5478
+ }
5479
+ )
5480
+ ] }, index);
5481
+ }),
5482
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
5483
+ "div",
5484
+ {
5485
+ className: "fixed bg-card border border-border rounded-lg shadow-lg z-50 min-w-56 select-none",
5486
+ style: {
5487
+ top: localPos.top,
5488
+ left: localPos.left,
5489
+ cursor: dragging ? "grabbing" : "grab"
5490
+ },
5491
+ onMouseDown: handleMouseDownLocal,
5492
+ onClick: (e) => e.stopPropagation(),
5493
+ children: [
5494
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center justify-between mb-2 p-3 pb-2 border-b bg-muted/20 rounded-t-lg", children: [
5495
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex flex-col gap-1", children: title && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
5496
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-2 h-2 bg-blue-500 rounded-full" }),
5497
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "font-bold text-foreground text-base", children: title })
5498
+ ] }) }),
5499
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5500
+ "button",
5501
+ {
5502
+ onClick: (e) => {
5503
+ e.stopPropagation();
5504
+ onClose(id);
5505
+ },
5506
+ className: "text-muted-foreground hover:text-destructive ml-2 text-sm hover:bg-destructive/10 rounded p-1",
5507
+ title: "Fechar este tooltip",
5508
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ssr2.XIcon, { size: 14 })
5509
+ }
5510
+ )
5511
+ ] }),
5512
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "px-3 py-2 bg-accent/30 border-l-4 border-primary", children: [
5513
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: periodLabel }) }),
5514
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "font-bold text-lg text-foreground mt-1", children: data.name })
5515
+ ] }),
5516
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "p-3 pt-2 space-y-2", children: [
5517
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2", children: dataLabel }),
5518
+ dataKeys.map((key) => {
5519
+ const value = data[key];
5520
+ if (value === void 0) return null;
5521
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
5522
+ "div",
5523
+ {
5524
+ className: "flex items-center justify-between gap-3 text-sm mb-2 p-2 rounded bg-muted/20 hover:bg-muted/40 transition-colors",
5525
+ children: [
5526
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
5527
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5528
+ "div",
5529
+ {
5530
+ className: "w-3 h-3 rounded-sm shadow-sm",
5531
+ style: { backgroundColor: finalColors[key] || "#666" }
5532
+ }
5533
+ ),
5534
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium text-foreground", children: key.charAt(0).toUpperCase() + key.slice(1) })
5535
+ ] }),
5536
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-semibold text-foreground bg-background px-2 py-1 rounded text-xs", children: value.toLocaleString("pt-BR") })
5537
+ ]
5538
+ },
5539
+ key
5540
+ );
5541
+ }),
5542
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "mt-3 pt-2 border-t", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("p", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
5543
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_react32.MouseIcon, {}) }),
5544
+ "Arraste para mover \u2022 Clique no ",
5545
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ssr2.XIcon, { size: 12 }),
5546
+ " para remover"
5547
+ ] }) })
5548
+ ] })
5549
+ ]
5550
+ }
5551
+ ),
5552
+ showCloseAllButton && onCloseAll && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
5553
+ CloseAllButton_default,
5554
+ {
5555
+ count: typeof globalTooltipCount === "number" ? globalTooltipCount : globalTooltipCountLocal,
5556
+ onCloseAll,
5557
+ position: closeAllButtonPosition,
5558
+ variant: closeAllButtonVariant
5559
+ }
5560
+ )
5561
+ ] });
5562
+ };
5563
+ var DraggableTooltip_default = DraggableTooltip;
5564
+
5565
+ // src/components/rechart/pillLabelRenderer.tsx
5566
+ var import_jsx_runtime50 = require("react/jsx-runtime");
5567
+ var formatCompactNumber = (value) => {
5568
+ if (value >= 1e9)
5569
+ return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
5570
+ if (value >= 1e6)
5571
+ return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
5572
+ if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
5573
+ return value.toString();
5574
+ };
5575
+ var parseNumber = (v) => {
5576
+ if (typeof v === "number") return v;
5577
+ if (typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v)))
5578
+ return Number(v);
5579
+ return void 0;
5580
+ };
5581
+ var renderPillLabel = (color, variant) => {
5582
+ return (props) => {
5583
+ const { x, y, value } = props;
5584
+ const text = typeof value === "number" ? formatCompactNumber(value) : String(value ?? "");
5585
+ const paddingX = 8;
5586
+ const approxCharWidth = 7;
5587
+ const pillWidth = Math.max(
5588
+ 40,
5589
+ String(text).length * approxCharWidth + paddingX * 2
5590
+ );
5591
+ const pillHeight = 20;
5592
+ const xNum = parseNumber(x);
5593
+ const px = parseNumber(props.x);
5594
+ const pWidth = parseNumber(props.width);
5595
+ const vb = props.viewBox;
5596
+ const cxNum = parseNumber(props.cx);
5597
+ let centerX;
5598
+ if (typeof px === "number" && typeof pWidth === "number") {
5599
+ centerX = px + pWidth / 2;
5600
+ } else if (typeof xNum === "number" && typeof pWidth === "number") {
5601
+ centerX = xNum + pWidth / 2;
5602
+ } else if (typeof cxNum === "number") {
5603
+ centerX = cxNum;
5604
+ } else if (vb && typeof vb.x === "number" && typeof vb.width === "number" && typeof props.index === "number") {
5605
+ const approxCols = Math.max(1, props.index + 1);
5606
+ const colWidth = vb.width / approxCols;
5607
+ centerX = vb.x + colWidth * (props.index + 0.5);
5608
+ } else if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
5609
+ centerX = vb.x + vb.width / 2;
5610
+ } else {
5611
+ centerX = typeof props.index === "number" ? props.index * 40 + 24 : 0;
5612
+ }
5613
+ if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
5614
+ const minX = vb.x + 0 + pillWidth / 22;
5615
+ const maxX = vb.x + vb.width - 2 - pillWidth / 2;
5616
+ centerX = Math.max(minX, Math.min(maxX, centerX));
5617
+ }
5618
+ const yNum = parseNumber(y);
5619
+ const py = parseNumber(props.y);
5620
+ const cyNum = parseNumber(props.cy);
5621
+ const centerY = yNum ?? (typeof py === "number" ? py : vb && typeof vb.y === "number" && typeof vb.height === "number" ? vb.y + vb.height / 2 : typeof cyNum === "number" ? cyNum : 0);
5622
+ const rectX = centerX - pillWidth / 2;
5623
+ const rectY = centerY - pillHeight - 6;
5624
+ const textX = centerX;
5625
+ const textY = rectY + pillHeight / 2 + 3;
5626
+ const rectFill = variant === "filled" ? color : variant === "soft" ? `${color}` : "#ffffff";
5627
+ const rectStroke = variant === "outline" ? `${color}CC` : void 0;
5628
+ const textColor = variant === "filled" ? "#ffffff" : variant === "outline" ? color : "#111827";
5629
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("g", { children: [
5630
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
5631
+ "rect",
5632
+ {
5633
+ x: rectX,
5634
+ y: rectY,
5635
+ rx: pillHeight / 2,
5636
+ width: pillWidth,
5637
+ height: pillHeight,
5638
+ fill: rectFill,
5639
+ stroke: rectStroke,
5640
+ strokeWidth: rectStroke ? 1 : 0
5641
+ }
5642
+ ),
5643
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
5644
+ "text",
5645
+ {
5646
+ x: textX,
5647
+ y: textY - 3,
5648
+ fill: textColor,
5649
+ fontSize: 13,
5650
+ fontWeight: 700,
5651
+ textAnchor: "middle",
5652
+ dominantBaseline: "central",
5653
+ letterSpacing: 0.2,
5654
+ children: text
5655
+ }
5656
+ )
5657
+ ] });
5658
+ };
5659
+ };
5660
+ var pillLabelRenderer_default = renderPillLabel;
5661
+
5662
+ // src/components/rechart/LineChart.tsx
5663
+ var import_jsx_runtime51 = require("react/jsx-runtime");
5664
+ var defaultData = [
5665
+ { name: "A", value: 100 },
5666
+ { name: "B", value: 200 },
5667
+ { name: "C", value: 150 }
5668
+ ];
5669
+ var DEFAULT_COLORS = ["#55af7d", "#8e68ff", "#2273e1"];
5670
+ var generateAdditionalColors = (baseColors, count) => {
5671
+ const colors2 = [...baseColors];
5672
+ const variations = [
5673
+ "#ff6b6b",
5674
+ "#4ecdc4",
5675
+ "#45b7d1",
5676
+ "#f9ca24",
5677
+ "#6c5ce7",
5678
+ "#a29bfe",
5679
+ "#fd79a8",
5680
+ "#00b894"
5681
+ ];
5682
+ while (colors2.length < count) {
5683
+ colors2.push(
5684
+ variations[(colors2.length - baseColors.length) % variations.length]
5685
+ );
5686
+ }
5687
+ return colors2;
5688
+ };
5689
+ var compactTick = (value) => {
5690
+ if (value >= 1e9)
5691
+ return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
5692
+ if (value >= 1e6)
5693
+ return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
5694
+ if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
5695
+ return String(value);
5696
+ };
5697
+ var CustomLineChart = ({
5698
+ data = defaultData,
5699
+ className,
5700
+ height = 300,
5701
+ width = "100%",
5702
+ colors: colors2 = DEFAULT_COLORS,
5703
+ gridColor,
5704
+ showGrid = true,
5705
+ showTooltip = true,
5706
+ showLegend = true,
5707
+ title,
5708
+ titlePosition = "left",
5709
+ strokeWidth = 2,
5710
+ showDots = true,
5711
+ showLabels = false
5712
+ }) => {
5713
+ const [activeTooltips, setActiveTooltips] = (0, import_react33.useState)([]);
5714
+ const [isDragging, setIsDragging] = (0, import_react33.useState)(null);
5715
+ const [dragOffset, setDragOffset] = (0, import_react33.useState)({
5716
+ x: 0,
5717
+ y: 0
5718
+ });
5719
+ const [globalTooltipCount, setGlobalTooltipCount] = (0, import_react33.useState)(0);
5720
+ const [alignmentGuides, setAlignmentGuides] = (0, import_react33.useState)([]);
5721
+ const generateColors = (dataKeys2) => {
5722
+ const colorMap = {};
5723
+ const allColors = generateAdditionalColors(colors2, dataKeys2.length);
5724
+ dataKeys2.forEach((key, index) => {
5725
+ colorMap[key] = allColors[index] || colors2[index % colors2.length];
5726
+ });
5727
+ return colorMap;
5728
+ };
5729
+ const dataKeys = (0, import_react33.useMemo)(
5730
+ () => data.length > 0 ? Object.keys(data[0]).filter((key) => key !== "name") : [],
5731
+ [data]
5732
+ );
5733
+ const finalColors = generateColors(dataKeys);
5734
+ const niceCeil = (value) => {
5735
+ if (!isFinite(value) || value <= 0) return 1;
5736
+ const pow = Math.pow(10, Math.floor(Math.log10(value)));
5737
+ const normalized = value / pow;
5738
+ const multipliers = [
5739
+ 1,
5740
+ 1.25,
5741
+ 1.5,
5742
+ 2,
5743
+ 2.5,
5744
+ 3,
5745
+ 4,
5746
+ 5,
5747
+ 7.5,
5748
+ 10,
5749
+ 15,
5750
+ 20,
5751
+ 25,
5752
+ 50,
5753
+ 100
5754
+ ];
5755
+ for (const m of multipliers) {
5756
+ if (m >= normalized) return Math.ceil(m * pow);
5757
+ }
5758
+ return Math.ceil(100 * pow);
5759
+ };
5760
+ const maxDataValue = (0, import_react33.useMemo)(() => {
5761
+ let max = 0;
5762
+ for (const row of data) {
5763
+ const r = row;
5764
+ for (const key of dataKeys) {
5765
+ const v = r[key];
5766
+ if (typeof v === "number" && Number.isFinite(v) && v > max)
5767
+ max = v;
5768
+ }
5769
+ }
5770
+ return max;
5771
+ }, [data, dataKeys]);
5772
+ const niceMax = (0, import_react33.useMemo)(() => {
5773
+ let padding = 0.08;
5774
+ if (maxDataValue > 1e6) padding = 0.05;
5775
+ if (maxDataValue > 1e7) padding = 0.03;
5776
+ if (maxDataValue === 0) padding = 0.12;
5777
+ const padded = maxDataValue * (1 + padding);
5778
+ return niceCeil(padded);
5779
+ }, [maxDataValue]);
5780
+ const ClickableDot = (props) => {
5781
+ const { cx, cy, payload, dataKey } = props;
5782
+ const handleDotClick = (e) => {
5783
+ e.stopPropagation();
5784
+ if (!payload || !cx || !cy) return;
5785
+ const tooltipId = `${payload.name}`;
5786
+ const existingIndex = activeTooltips.findIndex(
5787
+ (tooltip) => tooltip.id === tooltipId
5788
+ );
5789
+ if (existingIndex !== -1) {
5790
+ setActiveTooltips(
5791
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
5792
+ );
5793
+ } else {
5794
+ const newTooltip = {
5795
+ id: tooltipId,
5796
+ data: payload,
5797
+ position: {
5798
+ top: cy - 50,
5799
+ // Posição relativa ao SVG
5800
+ left: cx - 100
5801
+ }
5802
+ };
5803
+ setActiveTooltips((prev) => [...prev, newTooltip]);
5804
+ }
5805
+ };
5806
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
5807
+ "circle",
5808
+ {
5809
+ cx,
5810
+ cy,
5811
+ r: 6,
5812
+ fill: finalColors[dataKey || ""] || colors2[0],
5813
+ stroke: finalColors[dataKey || ""] || colors2[0],
5814
+ strokeWidth: 2,
5815
+ style: { cursor: "pointer" },
5816
+ onClick: handleDotClick
5817
+ }
5818
+ );
5819
+ };
5820
+ const handleChartClick = (e) => {
5821
+ if (e && e.activePayload && e.activePayload.length > 0) {
5822
+ const clickedData = e.activePayload[0].payload;
5823
+ const tooltipId = `${clickedData.name}`;
5824
+ const existingIndex = activeTooltips.findIndex(
5825
+ (tooltip) => tooltip.id === tooltipId
5826
+ );
5827
+ if (existingIndex !== -1) {
5828
+ setActiveTooltips(
5829
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
5830
+ );
5831
+ } else {
5832
+ const newTooltip = {
5833
+ id: tooltipId,
5834
+ data: clickedData,
5835
+ position: {
5836
+ top: (e.chartY || 100) - 10,
5837
+ left: (e.chartX || 100) - 100
5838
+ }
5839
+ };
5840
+ setActiveTooltips((prev) => [...prev, newTooltip]);
5841
+ }
5842
+ } else {
5843
+ }
5844
+ };
5845
+ const handleChartBackgroundClick = () => {
5846
+ setActiveTooltips([]);
5847
+ };
5848
+ const handleCloseAllTooltips = (0, import_react33.useCallback)(() => {
5849
+ window.dispatchEvent(new CustomEvent("closeAllTooltips"));
5850
+ }, []);
5851
+ const updateAlignmentGuides = (0, import_react33.useCallback)(
5852
+ (draggedTooltipId, draggedPosition) => {
5853
+ const SNAP_THRESHOLD = 15;
5854
+ const draggedTooltip = activeTooltips.find(
5855
+ (t) => t.id === draggedTooltipId
5856
+ );
5857
+ if (!draggedTooltip) return;
5858
+ const tooltipWidth = 200;
5859
+ const tooltipHeight = 80;
5860
+ const globalTooltips = [];
5861
+ window.dispatchEvent(
5862
+ new CustomEvent("requestGlobalTooltips", {
5863
+ detail: { requesterId: draggedTooltipId }
5864
+ })
5865
+ );
5866
+ activeTooltips.forEach((tooltip) => {
5867
+ if (tooltip.id !== draggedTooltipId) {
5868
+ globalTooltips.push({
5869
+ top: tooltip.position.top,
5870
+ left: tooltip.position.left,
5871
+ width: tooltipWidth,
5872
+ height: tooltipHeight,
5873
+ id: tooltip.id
5874
+ });
5875
+ }
5876
+ });
5877
+ const newGuides = [];
5878
+ globalTooltips.forEach((otherTooltip) => {
5879
+ const draggedCenter = {
5880
+ x: draggedPosition.left + tooltipWidth / 2,
5881
+ y: draggedPosition.top + tooltipHeight / 2
5882
+ };
5883
+ const otherCenter = {
5884
+ x: otherTooltip.left + otherTooltip.width / 2,
5885
+ y: otherTooltip.top + otherTooltip.height / 2
5886
+ };
5887
+ const horizontalDistance = Math.abs(draggedCenter.y - otherCenter.y);
5888
+ if (horizontalDistance <= SNAP_THRESHOLD) {
5889
+ newGuides.push({
5890
+ type: "horizontal",
5891
+ position: otherCenter.y,
5892
+ visible: true,
5893
+ sourceTooltip: {
5894
+ top: draggedPosition.top,
5895
+ left: draggedPosition.left,
5896
+ width: tooltipWidth,
5897
+ height: tooltipHeight
5898
+ },
5899
+ targetTooltip: {
5900
+ top: otherTooltip.top,
5901
+ left: otherTooltip.left,
5902
+ width: otherTooltip.width,
5903
+ height: otherTooltip.height
5904
+ }
5905
+ });
5906
+ }
5907
+ const verticalDistance = Math.abs(draggedCenter.x - otherCenter.x);
5908
+ if (verticalDistance <= SNAP_THRESHOLD) {
5909
+ newGuides.push({
5910
+ type: "vertical",
5911
+ position: otherCenter.x,
5912
+ visible: true,
5913
+ sourceTooltip: {
5914
+ top: draggedPosition.top,
5915
+ left: draggedPosition.left,
5916
+ width: tooltipWidth,
5917
+ height: tooltipHeight
5918
+ },
5919
+ targetTooltip: {
5920
+ top: otherTooltip.top,
5921
+ left: otherTooltip.left,
5922
+ width: otherTooltip.width,
5923
+ height: otherTooltip.height
5924
+ }
5925
+ });
5926
+ }
5927
+ });
5928
+ setAlignmentGuides(newGuides);
5929
+ },
5930
+ [activeTooltips]
5931
+ );
5932
+ const snapToGuides = (0, import_react33.useCallback)(
5933
+ (position) => {
5934
+ const SNAP_DISTANCE = 10;
5935
+ const snappedPosition = { ...position };
5936
+ alignmentGuides.forEach((guide) => {
5937
+ if (guide.type === "horizontal") {
5938
+ const tooltipCenter = position.top + 40;
5939
+ if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
5940
+ snappedPosition.top = guide.position - 40;
5941
+ }
5942
+ } else if (guide.type === "vertical") {
5943
+ const tooltipCenter = position.left + 100;
5944
+ if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
5945
+ snappedPosition.left = guide.position - 100;
5946
+ }
5947
+ }
5948
+ });
5949
+ return snappedPosition;
5950
+ },
5951
+ [alignmentGuides]
5952
+ );
5953
+ const handleMouseDown = (tooltipId, e) => {
5954
+ const rect = e.target.getBoundingClientRect();
5955
+ const offsetX = e.clientX - rect.left;
5956
+ const offsetY = e.clientY - rect.top;
5957
+ setIsDragging(tooltipId);
5958
+ setDragOffset({ x: offsetX, y: offsetY });
5959
+ };
5960
+ (0, import_react33.useEffect)(() => {
5961
+ let rafId;
5962
+ let lastMousePosition = { x: 0, y: 0 };
5963
+ const handleGlobalMouseMove = (e) => {
5964
+ if (!isDragging) return;
5965
+ lastMousePosition = { x: e.clientX, y: e.clientY };
5966
+ if (rafId) cancelAnimationFrame(rafId);
5967
+ rafId = requestAnimationFrame(() => {
5968
+ const newLeft = lastMousePosition.x - dragOffset.x;
5969
+ const newTop = lastMousePosition.y - dragOffset.y;
5970
+ let finalPosition = { top: newTop, left: newLeft };
5971
+ finalPosition = snapToGuides(finalPosition);
5972
+ setActiveTooltips(
5973
+ (prev) => prev.map(
5974
+ (tooltip) => tooltip.id === isDragging ? { ...tooltip, position: finalPosition } : tooltip
5975
+ )
5976
+ );
5977
+ updateAlignmentGuides(isDragging, finalPosition);
5978
+ });
5979
+ };
5980
+ const handleGlobalMouseUp = () => {
5981
+ if (rafId) cancelAnimationFrame(rafId);
5982
+ setIsDragging(null);
5983
+ setAlignmentGuides([]);
5984
+ document.body.style.cursor = "";
5985
+ document.body.style.userSelect = "";
5986
+ };
5987
+ if (isDragging) {
5988
+ document.body.style.cursor = "grabbing";
5989
+ document.body.style.userSelect = "none";
5990
+ window.addEventListener("mousemove", handleGlobalMouseMove);
5991
+ window.addEventListener("mouseup", handleGlobalMouseUp);
5992
+ }
5993
+ return () => {
5994
+ if (rafId) cancelAnimationFrame(rafId);
5995
+ window.removeEventListener("mousemove", handleGlobalMouseMove);
5996
+ window.removeEventListener("mouseup", handleGlobalMouseUp);
5997
+ document.body.style.cursor = "";
5998
+ document.body.style.userSelect = "";
5999
+ };
6000
+ }, [
6001
+ isDragging,
6002
+ dragOffset,
6003
+ alignmentGuides,
6004
+ updateAlignmentGuides,
6005
+ snapToGuides
6006
+ ]);
6007
+ (0, import_react33.useEffect)(() => {
6008
+ const handleCloseAllTooltips2 = () => {
6009
+ setActiveTooltips([]);
6010
+ setGlobalTooltipCount(0);
6011
+ };
6012
+ window.addEventListener("closeAllTooltips", handleCloseAllTooltips2);
6013
+ return () => {
6014
+ window.removeEventListener("closeAllTooltips", handleCloseAllTooltips2);
6015
+ };
6016
+ }, []);
6017
+ (0, import_react33.useEffect)(() => {
6018
+ const handleTooltipCountRequest = () => {
6019
+ window.dispatchEvent(
6020
+ new CustomEvent("tooltipCountResponse", {
6021
+ detail: { count: activeTooltips.length }
6022
+ })
6023
+ );
6024
+ };
6025
+ const handleGlobalTooltipsRequest = (event) => {
6026
+ const requesterId = event.detail?.requesterId;
6027
+ activeTooltips.forEach((tooltip) => {
6028
+ if (tooltip.id !== requesterId) {
6029
+ window.dispatchEvent(
6030
+ new CustomEvent("globalTooltipResponse", {
6031
+ detail: {
6032
+ tooltip: {
6033
+ top: tooltip.position.top,
6034
+ left: tooltip.position.left,
6035
+ width: 200,
6036
+ height: 80,
6037
+ id: tooltip.id
6038
+ }
6039
+ }
6040
+ })
6041
+ );
6042
+ }
6043
+ });
6044
+ };
6045
+ window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
6046
+ window.addEventListener(
6047
+ "requestGlobalTooltips",
6048
+ handleGlobalTooltipsRequest
6049
+ );
6050
+ return () => {
6051
+ window.removeEventListener(
6052
+ "requestTooltipCount",
6053
+ handleTooltipCountRequest
6054
+ );
6055
+ window.removeEventListener(
6056
+ "requestGlobalTooltips",
6057
+ handleGlobalTooltipsRequest
6058
+ );
6059
+ };
6060
+ }, [activeTooltips]);
6061
+ (0, import_react33.useEffect)(() => {
6062
+ if (isDragging) return;
6063
+ let totalCount = 0;
6064
+ const handleCountResponse = (event) => {
6065
+ const customEvent = event;
6066
+ totalCount += customEvent.detail.count;
6067
+ };
6068
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
6069
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
6070
+ const timeoutId = setTimeout(() => {
6071
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
6072
+ setGlobalTooltipCount(totalCount);
6073
+ }, 5);
6074
+ return () => {
6075
+ clearTimeout(timeoutId);
6076
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
6077
+ };
6078
+ }, [activeTooltips.length, isDragging]);
6079
+ const getTitleClass = () => {
6080
+ switch (titlePosition) {
6081
+ case "center":
6082
+ return "text-center";
6083
+ case "right":
6084
+ return "text-right";
6085
+ default:
6086
+ return "text-left";
6087
+ }
6088
+ };
6089
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: cn("relative", className), children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
6090
+ "div",
6091
+ {
6092
+ className: "rounded-lg bg-card p-4 relative border border-border",
6093
+ style: {
6094
+ width: typeof width === "number" ? `${width + 32}px` : "fit-content",
6095
+ maxWidth: "100%"
6096
+ },
6097
+ onClick: handleChartBackgroundClick,
6098
+ children: [
6099
+ title && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: cn("mb-4", getTitleClass()), children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: title }) }),
6100
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
6101
+ import_recharts.LineChart,
6102
+ {
6103
+ data,
6104
+ width: typeof width === "number" ? width : 900,
6105
+ height,
6106
+ margin: {
6107
+ top: showLabels ? 48 : 20,
6108
+ right: 30,
6109
+ left: 20,
6110
+ bottom: 5
6111
+ },
6112
+ onClick: handleChartClick,
6113
+ children: [
6114
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6115
+ import_recharts.CartesianGrid,
6116
+ {
6117
+ strokeDasharray: "3 3",
6118
+ stroke: gridColor || "hsl(var(--muted-foreground))",
6119
+ opacity: 0.3
6120
+ }
6121
+ ),
6122
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6123
+ import_recharts.XAxis,
6124
+ {
6125
+ dataKey: "name",
6126
+ className: "fill-muted-foreground text-xs",
6127
+ fontSize: 12
6128
+ }
6129
+ ),
6130
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6131
+ import_recharts.YAxis,
6132
+ {
6133
+ className: "fill-muted-foreground text-xs",
6134
+ fontSize: 12,
6135
+ tickFormatter: (value) => compactTick(Number(value)),
6136
+ domain: [0, niceMax],
6137
+ tickCount: 6
6138
+ }
6139
+ ),
6140
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_recharts.Tooltip, { content: () => null }),
6141
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6142
+ import_recharts.Legend,
6143
+ {
6144
+ wrapperStyle: {
6145
+ fontSize: "12px",
6146
+ color: "hsl(var(--muted-foreground))"
6147
+ }
6148
+ }
6149
+ ),
6150
+ dataKeys.map((key) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6151
+ import_recharts.Line,
6152
+ {
6153
+ type: "monotone",
6154
+ dataKey: key,
6155
+ stroke: finalColors[key],
6156
+ strokeWidth,
6157
+ dot: showDots ? { r: 4, cursor: "pointer" } : false,
6158
+ activeDot: (props) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ClickableDot, { ...props, dataKey: key }),
6159
+ children: showLabels && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6160
+ import_recharts.LabelList,
6161
+ {
6162
+ dataKey: key,
6163
+ position: "top",
6164
+ content: pillLabelRenderer_default(
6165
+ finalColors[key] || "#000",
6166
+ "filled"
6167
+ ),
6168
+ offset: 14
6169
+ }
6170
+ )
6171
+ },
6172
+ key
6173
+ ))
6174
+ ]
6175
+ }
6176
+ ),
6177
+ alignmentGuides.map((guide, index) => {
6178
+ const isHorizontal = guide.type === "horizontal";
6179
+ const color = isHorizontal ? "#3b82f6" : "#ef4444";
6180
+ const startX = isHorizontal ? Math.min(
6181
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
6182
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
6183
+ ) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
6184
+ const endX = isHorizontal ? Math.max(
6185
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
6186
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
6187
+ ) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
6188
+ const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
6189
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
6190
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
6191
+ );
6192
+ const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
6193
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
6194
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
6195
+ );
6196
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { children: [
6197
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6198
+ "div",
6199
+ {
6200
+ className: "fixed pointer-events-none z-30",
6201
+ style: {
6202
+ left: startX,
6203
+ top: startY,
6204
+ width: isHorizontal ? endX - startX : "2px",
6205
+ height: isHorizontal ? "2px" : endY - startY,
6206
+ backgroundColor: color,
6207
+ boxShadow: `0 0 8px ${color}60`,
6208
+ opacity: 0.9,
6209
+ borderStyle: "dashed",
6210
+ borderWidth: "1px",
6211
+ borderColor: color,
6212
+ transform: "translateZ(0)"
6213
+ }
6214
+ }
6215
+ ),
6216
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6217
+ "div",
6218
+ {
6219
+ className: "fixed pointer-events-none z-31",
6220
+ style: {
6221
+ left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
6222
+ top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
6223
+ width: "8px",
6224
+ height: "8px",
6225
+ backgroundColor: color,
6226
+ borderRadius: "50%",
6227
+ boxShadow: `0 0 4px ${color}80`,
6228
+ opacity: 0.8
6229
+ }
6230
+ }
6231
+ ),
6232
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6233
+ "div",
6234
+ {
6235
+ className: "fixed pointer-events-none z-31",
6236
+ style: {
6237
+ left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
6238
+ top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
6239
+ width: "8px",
6240
+ height: "8px",
6241
+ backgroundColor: color,
6242
+ borderRadius: "50%",
6243
+ boxShadow: `0 0 4px ${color}80`,
6244
+ opacity: 0.8
6245
+ }
6246
+ }
6247
+ )
6248
+ ] }, index);
6249
+ }),
6250
+ activeTooltips.map((tooltip, index) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
6251
+ DraggableTooltip_default,
6252
+ {
6253
+ id: tooltip.id,
6254
+ data: tooltip.data,
6255
+ position: tooltip.position,
6256
+ isDragging: isDragging === tooltip.id,
6257
+ title,
6258
+ dataKeys,
6259
+ finalColors,
6260
+ onMouseDown: (id, e) => handleMouseDown(id, e),
6261
+ onClose: (id) => {
6262
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
6263
+ },
6264
+ periodLabel: "Ponto Selecionado",
6265
+ dataLabel: "Dados do Ponto",
6266
+ showCloseAllButton: index === 0,
6267
+ globalTooltipCount,
6268
+ onCloseAll: handleCloseAllTooltips,
6269
+ closeAllButtonPosition: "top-center",
6270
+ closeAllButtonVariant: "floating"
6271
+ },
6272
+ tooltip.id
6273
+ ))
6274
+ ]
6275
+ }
6276
+ ) });
6277
+ };
6278
+ var LineChart_default = CustomLineChart;
6279
+
6280
+ // src/components/rechart/PieChart.tsx
6281
+ var import_recharts2 = require("recharts");
6282
+ var import_jsx_runtime52 = require("react/jsx-runtime");
6283
+ var defaultData2 = [
6284
+ { name: "Vendas", value: 4e3 },
6285
+ { name: "Marketing", value: 3e3 },
6286
+ { name: "Desenvolvimento", value: 2e3 },
6287
+ { name: "Suporte", value: 1e3 },
6288
+ { name: "Outros", value: 800 }
6289
+ ];
6290
+ var DEFAULT_COLORS2 = [
6291
+ "#55af7d",
6292
+ // verde do projeto
6293
+ "#8e68ff",
6294
+ // roxo do projeto
6295
+ "#2273e1",
6296
+ // azul do projeto
6297
+ "#f59e0b",
6298
+ // amarelo complementar
6299
+ "#ef4444",
6300
+ // vermelho complementar
6301
+ "#8b5cf6",
6302
+ // roxo claro
6303
+ "#06b6d4",
6304
+ // ciano
6305
+ "#84cc16"
6306
+ // verde lima
6307
+ ];
6308
+ var RADIAN = Math.PI / 180;
6309
+ var renderCustomizedLabel = ({ cx = 0, cy = 0, midAngle = 0, innerRadius = 0, outerRadius = 0, percent = 0 }) => {
6310
+ const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
6311
+ const x = cx + radius * Math.cos(-midAngle * RADIAN);
6312
+ const y = cy + radius * Math.sin(-midAngle * RADIAN);
6313
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
6314
+ "text",
6315
+ {
6316
+ x,
6317
+ y,
6318
+ fill: "white",
6319
+ textAnchor: x > cx ? "start" : "end",
6320
+ dominantBaseline: "central",
6321
+ fontSize: 12,
6322
+ fontWeight: "600",
6323
+ children: `${(percent * 100).toFixed(0)}%`
6324
+ }
6325
+ );
6326
+ };
6327
+ var CustomPieChart = ({
6328
+ data = defaultData2,
6329
+ className,
6330
+ height = 400,
6331
+ width = "100%",
6332
+ colors: colors2,
6333
+ showTooltip = true,
6334
+ showLegend = true,
6335
+ showLabels = true,
6336
+ innerRadius = 0,
6337
+ outerRadius = 120,
6338
+ centerX = "50%",
6339
+ centerY = "50%"
6340
+ }) => {
6341
+ const finalColors = colors2 || DEFAULT_COLORS2;
6342
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: cn("w-full rounded-lg bg-card p-4", className), children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_recharts2.ResponsiveContainer, { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_recharts2.PieChart, { children: [
6343
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
6344
+ import_recharts2.Pie,
6345
+ {
6346
+ data,
6347
+ cx: centerX,
6348
+ cy: centerY,
6349
+ labelLine: false,
6350
+ label: showLabels ? renderCustomizedLabel : false,
6351
+ outerRadius,
6352
+ innerRadius,
6353
+ fill: "#8884d8",
6354
+ dataKey: "value",
6355
+ children: data.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
6356
+ import_recharts2.Cell,
6357
+ {
6358
+ fill: finalColors[index % finalColors.length]
6359
+ },
6360
+ `cell-${entry.name}-${index}`
6361
+ ))
6362
+ }
6363
+ ),
6364
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
6365
+ import_recharts2.Tooltip,
6366
+ {
6367
+ contentStyle: {
6368
+ backgroundColor: "hsl(var(--popover))",
6369
+ border: "1px solid hsl(var(--border))",
6370
+ borderRadius: "6px",
6371
+ color: "hsl(var(--popover-foreground))"
6372
+ }
6373
+ }
6374
+ ),
6375
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_recharts2.Legend, {})
6376
+ ] }) }) });
6377
+ };
6378
+ var PieChart_default = CustomPieChart;
6379
+
6380
+ // src/components/rechart/BarChart.tsx
6381
+ var import_react34 = require("react");
6382
+ var import_recharts3 = require("recharts");
6383
+ var import_jsx_runtime53 = require("react/jsx-runtime");
6384
+ var formatFieldName = (fieldName) => {
6385
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
6386
+ };
6387
+ var detectXAxis = (data) => {
6388
+ if (!data || data.length === 0) return "name";
6389
+ const firstItem = data[0];
6390
+ const stringFields = Object.keys(firstItem).filter(
6391
+ (key) => typeof firstItem[key] === "string" || typeof firstItem[key] === "number" && String(firstItem[key]).length <= 4
6392
+ // Anos, IDs curtos
6393
+ );
6394
+ return stringFields[0] || Object.keys(firstItem)[0] || "name";
6395
+ };
6396
+ var detectDataFields = (data, xAxisKey) => {
6397
+ if (!data || data.length === 0) return [];
6398
+ const firstItem = data[0];
6399
+ return Object.keys(firstItem).filter(
6400
+ (key) => key !== xAxisKey && typeof firstItem[key] === "number"
6401
+ );
6402
+ };
6403
+ var DEFAULT_COLORS3 = ["#55af7d", "#8e68ff", "#2273e1"];
6404
+ var generateAdditionalColors2 = (baseColors, count) => {
6405
+ const colors2 = [...baseColors];
6406
+ const variations = [
6407
+ "#ff6b6b",
6408
+ "#4ecdc4",
6409
+ "#45b7d1",
6410
+ "#f9ca24",
6411
+ "#6c5ce7",
6412
+ "#a29bfe",
6413
+ "#fd79a8",
6414
+ "#00b894"
6415
+ ];
6416
+ while (colors2.length < count) {
6417
+ colors2.push(
6418
+ variations[(colors2.length - baseColors.length) % variations.length]
6419
+ );
6420
+ }
6421
+ return colors2;
6422
+ };
6423
+ var BarChart = ({
6424
+ data,
6425
+ className,
6426
+ height = 350,
6427
+ width = 900,
6428
+ colors: colors2 = DEFAULT_COLORS3,
6429
+ gridColor,
6430
+ showGrid = true,
6431
+ showTooltip = true,
6432
+ showLegend = true,
6433
+ title,
6434
+ titlePosition = "left",
6435
+ showLabels = false,
6436
+ xAxis,
6437
+ mapper,
6438
+ yAxis,
6439
+ labelMap,
6440
+ autoDetect = false
6441
+ }) => {
6442
+ const smartConfig = (0, import_react34.useMemo)(() => {
6443
+ const providedMapper = yAxis ?? mapper;
6444
+ if (autoDetect === true || xAxis == null || providedMapper == null) {
6445
+ const detectedXAxis = detectXAxis(data);
6446
+ const detectedFields = detectDataFields(data, detectedXAxis);
6447
+ return {
6448
+ xAxisConfig: {
6449
+ dataKey: detectedXAxis,
6450
+ label: labelMap?.[detectedXAxis] ?? formatFieldName(detectedXAxis),
6451
+ autoLabel: true
6452
+ },
6453
+ mapperConfig: detectedFields.reduce((acc, field) => {
6454
+ acc[field] = {
6455
+ label: labelMap?.[field] ?? formatFieldName(field),
6456
+ type: "number",
6457
+ visible: true
6458
+ };
6459
+ return acc;
6460
+ }, {})
6461
+ };
6462
+ }
6463
+ const xAxisConfig2 = typeof xAxis === "string" ? { dataKey: xAxis, label: formatFieldName(xAxis), autoLabel: true } : xAxis;
6464
+ let mapperConfig2;
6465
+ if (Array.isArray(providedMapper)) {
6466
+ mapperConfig2 = providedMapper.reduce((acc, field) => {
6467
+ acc[field] = {
6468
+ label: labelMap?.[field] ?? formatFieldName(field),
6469
+ type: "auto",
6470
+ visible: true
6471
+ };
6472
+ return acc;
6473
+ }, {});
6474
+ } else {
6475
+ mapperConfig2 = Object.keys(providedMapper).reduce(
6476
+ (acc, key) => {
6477
+ acc[key] = {
6478
+ label: providedMapper[key]?.label ?? labelMap?.[key] ?? formatFieldName(key),
6479
+ type: "auto",
6480
+ visible: true,
6481
+ ...providedMapper[key]
6482
+ // Sobrescreve com configurações do usuário
6483
+ };
6484
+ return acc;
6485
+ },
6486
+ {}
6487
+ );
6488
+ }
6489
+ return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
6490
+ }, [data, xAxis, mapper, yAxis, autoDetect, labelMap]);
6491
+ const { xAxisConfig, mapperConfig } = smartConfig;
6492
+ const [activeTooltips, setActiveTooltips] = (0, import_react34.useState)([]);
6493
+ const [isDragging, setIsDragging] = (0, import_react34.useState)(null);
6494
+ const [dragOffset, setDragOffset] = (0, import_react34.useState)({
6495
+ x: 0,
6496
+ y: 0
6497
+ });
6498
+ const [globalTooltipCount, setGlobalTooltipCount] = (0, import_react34.useState)(0);
6499
+ const [alignmentGuides, setAlignmentGuides] = (0, import_react34.useState)([]);
6500
+ const processedData = data.map((item) => ({
6501
+ ...item,
6502
+ name: String(item[xAxisConfig.dataKey] || "N/A")
6503
+ // Garantir propriedade 'name' para tooltip
6504
+ }));
6505
+ const generateColors = (dataKeys2) => {
6506
+ const colorMap = {};
6507
+ const allColors = generateAdditionalColors2(colors2, dataKeys2.length);
6508
+ dataKeys2.forEach((key, index) => {
6509
+ colorMap[key] = allColors[index] || colors2[index % colors2.length];
6510
+ });
6511
+ return colorMap;
6512
+ };
6513
+ const dataKeys = Object.keys(mapperConfig);
6514
+ const finalColors = generateColors(dataKeys);
6515
+ const adaptDataForTooltip = (universalData) => {
6516
+ return {
6517
+ ...universalData,
6518
+ name: String(universalData[xAxisConfig.dataKey] || "N/A")
6519
+ // Garantir que tem a propriedade 'name'
6520
+ };
6521
+ };
6522
+ const niceCeil = (value) => {
6523
+ if (!isFinite(value) || value <= 0) return 1;
6524
+ const pow = Math.pow(10, Math.floor(Math.log10(value)));
6525
+ const normalized = value / pow;
6526
+ const multipliers = [
6527
+ 1,
6528
+ 1.25,
6529
+ 1.5,
6530
+ 2,
6531
+ 2.5,
6532
+ 3,
6533
+ 4,
6534
+ 5,
6535
+ 7.5,
6536
+ 10,
6537
+ 15,
6538
+ 20,
6539
+ 25,
6540
+ 50,
6541
+ 100
6542
+ ];
6543
+ for (const m of multipliers) {
6544
+ if (m >= normalized) return Math.ceil(m * pow);
6545
+ }
6546
+ return Math.ceil(100 * pow);
6547
+ };
6548
+ const maxDataValue = (0, import_react34.useMemo)(() => {
6549
+ let max = 0;
6550
+ const keys = Object.keys(mapperConfig);
6551
+ for (const row of processedData) {
6552
+ const r = row;
6553
+ for (const key of keys) {
6554
+ const v = r[key];
6555
+ if (typeof v === "number" && Number.isFinite(v) && v > max)
6556
+ max = v;
6557
+ }
6558
+ }
6559
+ return max;
6560
+ }, [processedData, mapperConfig]);
6561
+ const niceMax = (0, import_react34.useMemo)(() => {
6562
+ let padding = 0.08;
6563
+ if (maxDataValue > 1e6) padding = 0.05;
6564
+ if (maxDataValue > 1e7) padding = 0.03;
6565
+ if (maxDataValue === 0) padding = 0.12;
6566
+ const padded = maxDataValue * (1 + padding);
6567
+ return niceCeil(padded);
6568
+ }, [maxDataValue]);
6569
+ const handleBarClick = (data2, index, event) => {
6570
+ event.stopPropagation();
6571
+ const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
6572
+ const tooltipId = `${xAxisValue}`;
6573
+ const rect = event.target.getBoundingClientRect();
6574
+ const existingIndex = activeTooltips.findIndex(
6575
+ (tooltip) => tooltip.id === tooltipId
6576
+ );
6577
+ if (existingIndex !== -1) {
6578
+ setActiveTooltips(
6579
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
6580
+ );
6581
+ } else {
6582
+ const newTooltip = {
6583
+ id: tooltipId,
6584
+ data: data2,
6585
+ position: {
6586
+ top: rect.top - 10,
6587
+ // Posição fixa da viewport
6588
+ left: rect.right + 10
6589
+ // À direita da barra clicada
6590
+ }
6591
+ };
6592
+ setActiveTooltips((prev) => [...prev, newTooltip]);
6593
+ }
6594
+ };
6595
+ const handleChartClick = () => {
6596
+ setActiveTooltips([]);
6597
+ };
6598
+ const ALIGNMENT_THRESHOLD = 25;
6599
+ const GUIDE_THRESHOLD = 60;
6600
+ const STRONG_SNAP_THRESHOLD = 35;
6601
+ const PRECISION_SNAP_THRESHOLD = 8;
6602
+ const updateAlignmentGuides = (0, import_react34.useCallback)(
6603
+ (draggedTooltipId, currentPosition) => {
6604
+ if (!isDragging) return;
6605
+ const getAllTooltips = () => {
6606
+ const allTooltips2 = [];
6607
+ allTooltips2.push(...activeTooltips);
6608
+ const globalEvent = new CustomEvent("requestGlobalTooltips", {
6609
+ detail: { requesterId: draggedTooltipId, response: allTooltips2 }
6610
+ });
6611
+ window.dispatchEvent(globalEvent);
6612
+ return allTooltips2;
6613
+ };
6614
+ const allTooltips = getAllTooltips();
6615
+ const otherTooltips = allTooltips.filter(
6616
+ (t) => t.id !== draggedTooltipId
6617
+ );
6618
+ const guides = [];
6619
+ const tooltipDimensions = { width: 224, height: 120 };
6620
+ otherTooltips.forEach((tooltip) => {
6621
+ const topDiff = Math.abs(currentPosition.top - tooltip.position.top);
6622
+ if (topDiff <= GUIDE_THRESHOLD) {
6623
+ guides.push({
6624
+ type: "horizontal",
6625
+ position: tooltip.position.top,
6626
+ visible: true,
6627
+ sourceTooltip: {
6628
+ top: currentPosition.top,
6629
+ left: currentPosition.left,
6630
+ width: tooltipDimensions.width,
6631
+ height: tooltipDimensions.height
6632
+ },
6633
+ targetTooltip: {
6634
+ top: tooltip.position.top,
6635
+ left: tooltip.position.left,
6636
+ width: tooltipDimensions.width,
6637
+ height: tooltipDimensions.height
6638
+ }
6639
+ });
6640
+ }
6641
+ const leftDiff = Math.abs(currentPosition.left - tooltip.position.left);
6642
+ if (leftDiff <= GUIDE_THRESHOLD) {
6643
+ guides.push({
6644
+ type: "vertical",
6645
+ position: tooltip.position.left,
6646
+ visible: true,
6647
+ sourceTooltip: {
6648
+ top: currentPosition.top,
6649
+ left: currentPosition.left,
6650
+ width: tooltipDimensions.width,
6651
+ height: tooltipDimensions.height
6652
+ },
6653
+ targetTooltip: {
6654
+ top: tooltip.position.top,
6655
+ left: tooltip.position.left,
6656
+ width: tooltipDimensions.width,
6657
+ height: tooltipDimensions.height
6658
+ }
6659
+ });
6660
+ }
6661
+ });
6662
+ setAlignmentGuides(guides);
6663
+ },
6664
+ [isDragging, activeTooltips]
6665
+ );
6666
+ const snapToGuides = (0, import_react34.useCallback)(
6667
+ (position) => {
6668
+ const snappedPosition = { ...position };
6669
+ let hasSnapped = false;
6670
+ alignmentGuides.forEach((guide) => {
6671
+ if (guide.type === "horizontal") {
6672
+ const diff = Math.abs(position.top - guide.position);
6673
+ if (diff <= PRECISION_SNAP_THRESHOLD) {
6674
+ snappedPosition.top = guide.position;
6675
+ hasSnapped = true;
6676
+ }
6677
+ } else if (guide.type === "vertical") {
6678
+ const diff = Math.abs(position.left - guide.position);
6679
+ if (diff <= PRECISION_SNAP_THRESHOLD) {
6680
+ snappedPosition.left = guide.position;
6681
+ hasSnapped = true;
6682
+ }
6683
+ }
6684
+ });
6685
+ if (!hasSnapped) {
6686
+ alignmentGuides.forEach((guide) => {
6687
+ if (guide.type === "horizontal") {
6688
+ const diff = Math.abs(position.top - guide.position);
6689
+ if (diff <= STRONG_SNAP_THRESHOLD) {
6690
+ snappedPosition.top = guide.position;
6691
+ }
6692
+ } else if (guide.type === "vertical") {
6693
+ const diff = Math.abs(position.left - guide.position);
6694
+ if (diff <= STRONG_SNAP_THRESHOLD) {
6695
+ snappedPosition.left = guide.position;
6696
+ }
6697
+ }
6698
+ });
6699
+ }
6700
+ alignmentGuides.forEach((guide) => {
6701
+ if (guide.type === "horizontal") {
6702
+ const diff = Math.abs(position.top - guide.position);
6703
+ if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.top === position.top) {
6704
+ snappedPosition.top = guide.position;
6705
+ }
6706
+ } else if (guide.type === "vertical") {
6707
+ const diff = Math.abs(position.left - guide.position);
6708
+ if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.left === position.left) {
6709
+ snappedPosition.left = guide.position;
6710
+ }
6711
+ }
6712
+ });
6713
+ return snappedPosition;
6714
+ },
6715
+ [alignmentGuides]
6716
+ );
6717
+ const handleMouseDown = (e, tooltipId) => {
6718
+ e.preventDefault();
6719
+ e.stopPropagation();
6720
+ const tooltip = activeTooltips.find((t) => t.id === tooltipId);
6721
+ if (!tooltip) return;
6722
+ const rect = e.currentTarget.getBoundingClientRect();
6723
+ const offsetX = e.clientX - rect.left;
6724
+ const offsetY = e.clientY - rect.top;
6725
+ setIsDragging(tooltipId);
6726
+ setDragOffset({ x: offsetX, y: offsetY });
6727
+ };
6728
+ (0, import_react34.useEffect)(() => {
6729
+ let rafId;
6730
+ let lastMousePosition = { x: 0, y: 0 };
6731
+ const handleGlobalMouseMove = (e) => {
6732
+ if (!isDragging) return;
6733
+ lastMousePosition = { x: e.clientX, y: e.clientY };
6734
+ if (rafId) cancelAnimationFrame(rafId);
6735
+ rafId = requestAnimationFrame(() => {
6736
+ const newLeft = lastMousePosition.x - dragOffset.x;
6737
+ const newTop = lastMousePosition.y - dragOffset.y;
6738
+ const rawPosition = {
6739
+ top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
6740
+ left: Math.max(0, Math.min(newLeft, window.innerWidth - 250))
6741
+ };
6742
+ updateAlignmentGuides(isDragging, rawPosition);
6743
+ const snappedPosition = snapToGuides(rawPosition);
6744
+ setActiveTooltips(
6745
+ (prev) => prev.map((tooltip) => {
6746
+ if (tooltip.id === isDragging) {
6747
+ return {
6748
+ ...tooltip,
6749
+ position: snappedPosition
6750
+ };
6751
+ }
6752
+ return tooltip;
6753
+ })
6754
+ );
6755
+ });
6756
+ };
6757
+ const handleGlobalMouseUp = () => {
6758
+ if (isDragging) {
6759
+ setIsDragging(null);
6760
+ setAlignmentGuides([]);
6761
+ if (rafId) cancelAnimationFrame(rafId);
6762
+ }
6763
+ };
6764
+ if (isDragging) {
6765
+ document.addEventListener("mousemove", handleGlobalMouseMove, {
6766
+ passive: true
6767
+ });
6768
+ document.addEventListener("mouseup", handleGlobalMouseUp);
6769
+ document.body.style.cursor = "grabbing";
6770
+ document.body.style.userSelect = "none";
6771
+ }
6772
+ return () => {
6773
+ if (rafId) cancelAnimationFrame(rafId);
6774
+ document.removeEventListener("mousemove", handleGlobalMouseMove);
6775
+ document.removeEventListener("mouseup", handleGlobalMouseUp);
6776
+ document.body.style.cursor = "";
6777
+ document.body.style.userSelect = "";
6778
+ };
6779
+ }, [
6780
+ isDragging,
6781
+ dragOffset,
6782
+ alignmentGuides,
6783
+ updateAlignmentGuides,
6784
+ snapToGuides
6785
+ ]);
6786
+ (0, import_react34.useEffect)(() => {
6787
+ const handleCloseAllTooltips = () => {
6788
+ setActiveTooltips([]);
6789
+ setGlobalTooltipCount(0);
6790
+ };
6791
+ window.addEventListener("closeAllTooltips", handleCloseAllTooltips);
6792
+ return () => {
6793
+ window.removeEventListener("closeAllTooltips", handleCloseAllTooltips);
6794
+ };
6795
+ }, []);
6796
+ (0, import_react34.useEffect)(() => {
6797
+ const handleTooltipCountRequest = () => {
6798
+ window.dispatchEvent(
6799
+ new CustomEvent("tooltipCountResponse", {
6800
+ detail: { count: activeTooltips.length }
6801
+ })
6802
+ );
6803
+ };
6804
+ const handleGlobalTooltipsRequest = (event) => {
6805
+ const { detail } = event;
6806
+ if (detail && detail.response && detail.requesterId) {
6807
+ activeTooltips.forEach((tooltip) => {
6808
+ if (!detail.response.find(
6809
+ (t) => t.id === tooltip.id
6810
+ )) {
6811
+ detail.response.push({
6812
+ id: tooltip.id,
6813
+ position: tooltip.position
6814
+ });
6815
+ }
6816
+ });
6817
+ }
6818
+ };
6819
+ window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
6820
+ window.addEventListener(
6821
+ "requestGlobalTooltips",
6822
+ handleGlobalTooltipsRequest
6823
+ );
6824
+ return () => {
6825
+ window.removeEventListener(
6826
+ "requestTooltipCount",
6827
+ handleTooltipCountRequest
6828
+ );
6829
+ window.removeEventListener(
6830
+ "requestGlobalTooltips",
6831
+ handleGlobalTooltipsRequest
6832
+ );
6833
+ };
6834
+ }, [activeTooltips]);
6835
+ (0, import_react34.useEffect)(() => {
6836
+ if (isDragging) return;
6837
+ let totalCount = 0;
6838
+ const handleCountResponse = (event) => {
6839
+ const customEvent = event;
6840
+ totalCount += customEvent.detail.count;
6841
+ };
6842
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
6843
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
6844
+ const timeoutId = setTimeout(() => {
6845
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
6846
+ setGlobalTooltipCount(totalCount);
6847
+ }, 5);
6848
+ return () => {
6849
+ clearTimeout(timeoutId);
6850
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
6851
+ };
6852
+ }, [activeTooltips.length, isDragging]);
6853
+ const CustomTooltip = ({
6854
+ active,
6855
+ payload,
6856
+ label
6857
+ }) => {
6858
+ if (!active || !payload) return null;
6859
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "bg-card border border-border rounded-lg p-3 shadow-lg", children: [
6860
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "font-medium text-foreground mb-2", children: label }),
6861
+ payload.map(
6862
+ (entry, index) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2 text-sm", children: [
6863
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6864
+ "div",
6865
+ {
6866
+ className: "w-3 h-3 rounded-sm",
6867
+ style: { backgroundColor: entry.color }
6868
+ }
6869
+ ),
6870
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "text-muted-foreground", children: [
6871
+ entry.name,
6872
+ ":"
6873
+ ] }),
6874
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-foreground font-medium", children: entry.value?.toLocaleString("pt-BR") })
6875
+ ] }, index)
6876
+ ),
6877
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-xs text-muted-foreground mt-1", children: "Clique para fixar este tooltip" })
6878
+ ] });
6879
+ };
6880
+ const getTitleClassName = (position) => {
6881
+ const baseClasses = "text-xl font-semibold text-foreground mb-3";
6882
+ switch (position) {
6883
+ case "center":
6884
+ return `${baseClasses} text-center`;
6885
+ case "right":
6886
+ return `${baseClasses} text-right`;
6887
+ default:
6888
+ return `${baseClasses} text-left`;
6889
+ }
6890
+ };
6891
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
6892
+ "div",
6893
+ {
6894
+ className: cn("rounded-lg bg-card p-4 relative", className),
6895
+ style: {
6896
+ width: typeof width === "number" ? `${width + 32}px` : "fit-content",
6897
+ maxWidth: "100%"
6898
+ },
6899
+ children: [
6900
+ title && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("h3", { className: getTitleClassName(titlePosition), children: title }),
6901
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
6902
+ import_recharts3.BarChart,
6903
+ {
6904
+ data: processedData,
6905
+ width: typeof width === "number" ? width : 900,
6906
+ height,
6907
+ margin: { top: showLabels ? 48 : 20, right: 30, left: 20, bottom: 5 },
6908
+ onClick: handleChartClick,
6909
+ children: [
6910
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6911
+ import_recharts3.CartesianGrid,
6912
+ {
6913
+ strokeDasharray: "3 3",
6914
+ stroke: gridColor || "hsl(var(--muted-foreground))",
6915
+ opacity: 0.5
6916
+ }
6917
+ ),
6918
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6919
+ import_recharts3.XAxis,
6920
+ {
6921
+ dataKey: xAxisConfig.dataKey,
6922
+ stroke: "hsl(var(--muted-foreground))",
6923
+ fontSize: 12,
6924
+ tickLine: false,
6925
+ axisLine: false,
6926
+ tickFormatter: xAxisConfig.formatter
6927
+ }
6928
+ ),
6929
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6930
+ import_recharts3.YAxis,
6931
+ {
6932
+ stroke: "hsl(var(--muted-foreground))",
6933
+ fontSize: 12,
6934
+ tickLine: false,
6935
+ axisLine: false,
6936
+ tickFormatter: (value) => value.toLocaleString("pt-BR"),
6937
+ domain: [0, niceMax],
6938
+ tickCount: 6
6939
+ }
6940
+ ),
6941
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6942
+ import_recharts3.Tooltip,
6943
+ {
6944
+ content: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CustomTooltip, {}),
6945
+ cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
6946
+ }
6947
+ ),
6948
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6949
+ import_recharts3.Legend,
6950
+ {
6951
+ wrapperStyle: {
6952
+ color: "hsl(var(--foreground))",
6953
+ fontSize: "14px"
6954
+ }
6955
+ }
6956
+ ),
6957
+ dataKeys.map((key) => {
6958
+ const fieldConfig = mapperConfig[key];
6959
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6960
+ import_recharts3.Bar,
6961
+ {
6962
+ dataKey: key,
6963
+ name: fieldConfig?.label || key,
6964
+ fill: fieldConfig?.color || finalColors[key],
6965
+ radius: [4, 4, 0, 0],
6966
+ onClick: handleBarClick,
6967
+ style: { cursor: "pointer" },
6968
+ activeBar: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6969
+ import_recharts3.Rectangle,
6970
+ {
6971
+ fill: finalColors[key],
6972
+ stroke: finalColors[key],
6973
+ strokeWidth: 2,
6974
+ opacity: 0.8
6975
+ }
6976
+ ),
6977
+ children: showLabels && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6978
+ import_recharts3.LabelList,
6979
+ {
6980
+ dataKey: key,
6981
+ position: "top",
6982
+ content: pillLabelRenderer_default(
6983
+ finalColors[key] || "#000",
6984
+ "filled"
6985
+ )
6986
+ }
6987
+ )
6988
+ },
6989
+ key
6990
+ );
6991
+ })
6992
+ ]
6993
+ }
6994
+ ),
6995
+ alignmentGuides.map((guide, index) => {
6996
+ const isHorizontal = guide.type === "horizontal";
6997
+ const color = isHorizontal ? "#3b82f6" : "#ef4444";
6998
+ const startX = isHorizontal ? Math.min(
6999
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
7000
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
7001
+ ) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
7002
+ const endX = isHorizontal ? Math.max(
7003
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
7004
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
7005
+ ) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
7006
+ const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
7007
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
7008
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
7009
+ );
7010
+ const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
7011
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
7012
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
7013
+ );
7014
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
7015
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
7016
+ "div",
7017
+ {
7018
+ className: "fixed pointer-events-none z-30",
7019
+ style: {
7020
+ left: startX,
7021
+ top: startY,
7022
+ width: isHorizontal ? endX - startX : "2px",
7023
+ height: isHorizontal ? "2px" : endY - startY,
7024
+ backgroundColor: color,
7025
+ boxShadow: `0 0 8px ${color}60`,
7026
+ opacity: 0.9,
7027
+ borderStyle: "dashed",
7028
+ borderWidth: "1px",
7029
+ borderColor: color,
7030
+ transform: "translateZ(0)"
7031
+ }
7032
+ }
7033
+ ),
7034
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
7035
+ "div",
7036
+ {
7037
+ className: "fixed pointer-events-none z-31",
7038
+ style: {
7039
+ left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
7040
+ top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
7041
+ width: "8px",
7042
+ height: "8px",
7043
+ backgroundColor: color,
7044
+ borderRadius: "50%",
7045
+ boxShadow: `0 0 4px ${color}80`,
7046
+ opacity: 0.8
7047
+ }
7048
+ }
7049
+ ),
7050
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
7051
+ "div",
7052
+ {
7053
+ className: "fixed pointer-events-none z-31",
7054
+ style: {
7055
+ left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
7056
+ top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
7057
+ width: "8px",
7058
+ height: "8px",
7059
+ backgroundColor: color,
7060
+ borderRadius: "50%",
7061
+ boxShadow: `0 0 4px ${color}80`,
7062
+ opacity: 0.8
7063
+ }
7064
+ }
7065
+ )
7066
+ ] }, index);
7067
+ }),
7068
+ activeTooltips.map((tooltip, index) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
7069
+ DraggableTooltip_default,
7070
+ {
7071
+ id: tooltip.id,
7072
+ data: adaptDataForTooltip(tooltip.data),
7073
+ position: tooltip.position,
7074
+ isDragging: isDragging === tooltip.id,
7075
+ title,
7076
+ dataKeys,
7077
+ finalColors,
7078
+ onMouseDown: (id, e) => handleMouseDown(e, id),
7079
+ onClose: (id) => {
7080
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
7081
+ },
7082
+ periodLabel: "Per\xEDodo Selecionado",
7083
+ dataLabel: "Dados do Per\xEDodo",
7084
+ showCloseAllButton: index === 0,
7085
+ globalTooltipCount,
7086
+ onCloseAll: () => {
7087
+ window.dispatchEvent(new Event("closeAllTooltips"));
7088
+ },
7089
+ closeAllButtonPosition: "top-center",
7090
+ closeAllButtonVariant: "floating"
7091
+ },
7092
+ tooltip.id
7093
+ ))
7094
+ ]
7095
+ }
7096
+ );
7097
+ };
7098
+ var BarChart_default = BarChart;
7099
+
7100
+ // src/components/rechart/Chart.tsx
7101
+ var import_react37 = require("react");
7102
+ var import_recharts4 = require("recharts");
7103
+
7104
+ // src/components/rechart/helpers.ts
7105
+ var formatFieldName2 = (fieldName) => {
7106
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
7107
+ };
7108
+ var detectDataFields2 = (data, xAxisKey) => {
7109
+ if (!data || data.length === 0) return [];
7110
+ const firstItem = data[0];
7111
+ return Object.keys(firstItem).filter(
7112
+ (key) => key !== xAxisKey && typeof firstItem[key] === "number"
7113
+ );
7114
+ };
7115
+ var generateAdditionalColors3 = (baseColors, count) => {
7116
+ const hexToRgb = (hex) => {
7117
+ const clean = hex.replace("#", "");
7118
+ const bigint = parseInt(
7119
+ clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean,
7120
+ 16
7121
+ );
7122
+ return { r: bigint >> 16 & 255, g: bigint >> 8 & 255, b: bigint & 255 };
7123
+ };
7124
+ const rgbToHsl = ({ r, g, b }) => {
7125
+ r /= 255;
7126
+ g /= 255;
7127
+ b /= 255;
7128
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
7129
+ let h = 0;
7130
+ let s = 0;
7131
+ const l = (max + min) / 2;
7132
+ if (max !== min) {
7133
+ const d = max - min;
7134
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
7135
+ switch (max) {
7136
+ case r:
7137
+ h = (g - b) / d + (g < b ? 6 : 0);
7138
+ break;
7139
+ case g:
7140
+ h = (b - r) / d + 2;
7141
+ break;
7142
+ case b:
7143
+ h = (r - g) / d + 4;
7144
+ break;
7145
+ }
7146
+ h /= 6;
7147
+ }
7148
+ return {
7149
+ h: Math.round(h * 360),
7150
+ s: Math.round(s * 100),
7151
+ l: Math.round(l * 100)
7152
+ };
7153
+ };
7154
+ const hslToHex = (h, s, l) => {
7155
+ s /= 100;
7156
+ l /= 100;
7157
+ const k = (n) => (n + h / 30) % 5;
7158
+ const a = s * Math.min(l, 1 - l);
7159
+ const f = (n) => {
7160
+ const color = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
7161
+ return Math.round(255 * color).toString(16).padStart(2, "0");
7162
+ };
7163
+ return `#${f(0)}${f(8)}${f(4)}`;
7164
+ };
7165
+ const anchors = baseColors.map((c) => rgbToHsl(hexToRgb(c)));
7166
+ const colors2 = [...baseColors];
7167
+ let i = 0;
7168
+ while (colors2.length < count) {
7169
+ const anchor = anchors[i % anchors.length];
7170
+ const step = Math.floor(i / anchors.length + 1);
7171
+ const hueOffset = step * 25 * (i % 2 === 0 ? 1 : -1);
7172
+ const satOffset = i % 3 === 0 ? -6 : 6;
7173
+ const lightOffset = i % 4 === 0 ? 6 : -4;
7174
+ const newH = (anchor.h + hueOffset + 360) % 360;
7175
+ const newS = Math.max(30, Math.min(95, anchor.s + satOffset));
7176
+ const newL = Math.max(25, Math.min(45, anchor.l + lightOffset));
7177
+ colors2.push(hslToHex(newH, newS, newL));
7178
+ i += 1;
7179
+ }
7180
+ return colors2.slice(0, count);
7181
+ };
7182
+
7183
+ // src/components/rechart/PeriodsDropdown.tsx
7184
+ var import_react35 = require("react");
7185
+ var import_framer_motion7 = require("framer-motion");
7186
+ var import_ssr3 = require("@phosphor-icons/react/dist/ssr");
7187
+ var import_ssr4 = require("@phosphor-icons/react/dist/ssr");
7188
+ var import_jsx_runtime54 = require("react/jsx-runtime");
7189
+ var menuVariants = {
7190
+ hidden: { opacity: 0, y: -6, scale: 0.98 },
7191
+ visible: { opacity: 1, y: 0, scale: 1 },
7192
+ exit: { opacity: 0, y: -6, scale: 0.98 }
7193
+ };
7194
+ var itemVariants = {
7195
+ hidden: { opacity: 0, x: -6 },
7196
+ visible: { opacity: 1, x: 0 }
7197
+ };
7198
+ var PeriodsDropdown = ({
7199
+ processedData,
7200
+ onOpenPeriod,
7201
+ rightOffset,
7202
+ topOffset,
7203
+ activePeriod,
7204
+ activePeriods
7205
+ }) => {
7206
+ const periods = processedData.map((d) => String(d.name));
7207
+ const [open, setOpen] = (0, import_react35.useState)(false);
7208
+ const wrapperRef = (0, import_react35.useRef)(null);
7209
+ const firstItemRef = (0, import_react35.useRef)(null);
7210
+ const listRef = (0, import_react35.useRef)(null);
7211
+ (0, import_react35.useEffect)(() => {
7212
+ const handleClickOutside = (e) => {
7213
+ if (!wrapperRef.current) return;
7214
+ if (!wrapperRef.current.contains(e.target)) setOpen(false);
7215
+ };
7216
+ const handleEscape = (e) => {
7217
+ if (e.key === "Escape") setOpen(false);
7218
+ };
7219
+ document.addEventListener("mousedown", handleClickOutside);
7220
+ document.addEventListener("keydown", handleEscape);
7221
+ return () => {
7222
+ document.removeEventListener("mousedown", handleClickOutside);
7223
+ document.removeEventListener("keydown", handleEscape);
7224
+ };
7225
+ }, []);
7226
+ (0, import_react35.useEffect)(() => {
7227
+ if (open && firstItemRef.current) {
7228
+ firstItemRef.current.focus();
7229
+ }
7230
+ }, [open]);
7231
+ const handleSelect = (p) => {
7232
+ onOpenPeriod(p);
7233
+ setOpen(false);
7234
+ };
7235
+ const containerStyle = typeof rightOffset === "number" ? { position: "relative", zIndex: 60 } : { position: "relative", zIndex: 60 };
7236
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { ref: wrapperRef, style: containerStyle, className: "mr-4", children: [
7237
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
7238
+ "button",
7239
+ {
7240
+ className: "relative p-2 rounded-md hover:bg-accent/10 focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transition z-10 flex items-center",
7241
+ "aria-expanded": open,
7242
+ onClick: () => setOpen((v) => !v),
7243
+ onKeyDown: (e) => {
7244
+ if (e.key === "ArrowDown") setOpen(true);
7245
+ },
7246
+ title: open ? "Fechar lista de per\xEDodos" : "Abrir lista de per\xEDodos",
7247
+ children: [
7248
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_ssr3.DotsThreeIcon, { size: 18 }),
7249
+ periods.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "absolute -top-1 -right-1 bg-accent text-foreground text-xs rounded-full w-5 h-5 flex items-center justify-center", children: periods.length })
7250
+ ]
7251
+ }
7252
+ ),
7253
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_framer_motion7.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
7254
+ import_framer_motion7.motion.div,
7255
+ {
7256
+ initial: "hidden",
7257
+ animate: "visible",
7258
+ exit: "exit",
7259
+ variants: menuVariants,
7260
+ transition: { type: "spring", stiffness: 500, damping: 30 },
7261
+ className: "bg-card border border-border rounded-lg shadow-lg overflow-hidden",
7262
+ style: {
7263
+ minWidth: 180,
7264
+ maxHeight: 260,
7265
+ overflow: "hidden",
7266
+ position: "absolute",
7267
+ top: typeof topOffset === "number" ? topOffset : "calc(100% + 6px)",
7268
+ right: typeof rightOffset === "number" ? rightOffset : 0
7269
+ },
7270
+ role: "menu",
7271
+ "aria-orientation": "vertical",
7272
+ children: [
7273
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground", children: "Per\xEDodos" }),
7274
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "h-px bg-border" }),
7275
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
7276
+ "div",
7277
+ {
7278
+ ref: listRef,
7279
+ className: "flex flex-col p-2 gap-1",
7280
+ style: { maxHeight: 200, overflowY: "auto" },
7281
+ children: periods.map((p, idx) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
7282
+ import_framer_motion7.motion.button,
7283
+ {
7284
+ className: "flex items-center justify-between w-full text-left px-3 py-2 rounded focus:outline-none transition-colors " + (activePeriods && activePeriods.includes(p) || p === activePeriod ? "bg-accent/10" : "hover:bg-accent/5 focus:bg-accent/10"),
7285
+ variants: itemVariants,
7286
+ initial: "hidden",
7287
+ animate: "visible",
7288
+ whileTap: { scale: 0.98 },
7289
+ onClick: () => handleSelect(p),
7290
+ ref: idx === 0 ? firstItemRef : void 0,
7291
+ role: "menuitem",
7292
+ "aria-checked": activePeriods && activePeriods.includes(p) || p === activePeriod,
7293
+ children: [
7294
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "truncate", children: p }),
7295
+ (activePeriods && activePeriods.includes(p) || p === activePeriod) && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "ml-2 text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_ssr4.Check, { size: 16, weight: "bold" }) })
7296
+ ]
7297
+ },
7298
+ p
7299
+ ))
7300
+ }
7301
+ )
7302
+ ]
7303
+ }
7304
+ ) })
7305
+ ] });
7306
+ };
7307
+ var PeriodsDropdown_default = PeriodsDropdown;
7308
+
7309
+ // src/components/rechart/ShowOnly.tsx
7310
+ var import_framer_motion8 = require("framer-motion");
7311
+ var import_react36 = require("@phosphor-icons/react");
7312
+ var import_jsx_runtime55 = require("react/jsx-runtime");
7313
+ var ShowOnly = ({
7314
+ showOnlyHighlighted,
7315
+ setShowOnlyHighlighted,
7316
+ highlightedSeriesSize
7317
+ }) => {
7318
+ const hasHighlights = highlightedSeriesSize > 0;
7319
+ if (!hasHighlights) return null;
7320
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
7321
+ import_framer_motion8.motion.div,
7322
+ {
7323
+ whileTap: { scale: hasHighlights ? 0.985 : 1 },
7324
+ whileHover: { y: hasHighlights ? -2 : 0 },
7325
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
7326
+ ButtonBase,
7327
+ {
7328
+ variant: "secondary",
7329
+ onClick: () => hasHighlights && setShowOnlyHighlighted((v) => !v),
7330
+ "aria-pressed": showOnlyHighlighted,
7331
+ "aria-label": showOnlyHighlighted ? "Exibir todos" : "Mostrar somente destacados",
7332
+ title: showOnlyHighlighted ? "Exibir todos" : "Mostrar somente destacados",
7333
+ disabled: !hasHighlights,
7334
+ className: cn(
7335
+ "flex items-center gap-2 text-sm px-3 py-1 rounded-md transition-shadow",
7336
+ !hasHighlights ? "opacity-60 cursor-not-allowed" : showOnlyHighlighted ? "bg-primary/10 text-primary shadow-sm border" : "bg-transparent text-muted-foreground border border-transparent hover:bg-muted/5"
7337
+ ),
7338
+ children: showOnlyHighlighted ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_jsx_runtime55.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react36.EyeSlash, { size: 16, weight: "regular" }) }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_jsx_runtime55.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react36.Eye, { size: 16, weight: "bold" }) })
7339
+ }
7340
+ )
7341
+ }
7342
+ ) });
7343
+ };
7344
+ var ShowOnly_default = ShowOnly;
7345
+
7346
+ // src/components/rechart/Highlights.tsx
7347
+ var import_framer_motion9 = require("framer-motion");
7348
+ var import_jsx_runtime56 = require("react/jsx-runtime");
7349
+ var Highlights = ({
7350
+ allKeys,
7351
+ mapperConfig,
7352
+ finalColors,
7353
+ highlightedSeries,
7354
+ toggleHighlight,
7355
+ containerWidth
7356
+ }) => {
7357
+ const count = allKeys.length || 1;
7358
+ const available = containerWidth && containerWidth > 0 ? containerWidth : 600;
7359
+ const perPill = Math.floor(available / count);
7360
+ const showFullLabel = perPill >= 96;
7361
+ const showShortLabel = perPill >= 64;
7362
+ const containerVariants = {
7363
+ hidden: { opacity: 0 },
7364
+ visible: { opacity: 1, transition: { staggerChildren: 0.03 } }
7365
+ };
7366
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7367
+ import_framer_motion9.motion.div,
7368
+ {
7369
+ className: "flex-1 flex items-center gap-2 flex-wrap",
7370
+ initial: "hidden",
7371
+ animate: "visible",
7372
+ variants: containerVariants,
7373
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_framer_motion9.AnimatePresence, { initial: false, mode: "popLayout", children: allKeys.map((k) => {
7374
+ const isHighlighted = highlightedSeries.has(k);
7375
+ const label = mapperConfig[k]?.label ?? k;
7376
+ const color = finalColors[k];
7377
+ const pillClasses = cn(
7378
+ "inline-flex items-center gap-2 px-3 py-1 rounded-full text-sm border transition-all select-none",
7379
+ isHighlighted ? "bg-card/95 border-2 text-foreground shadow-[0_6px_18px_rgba(0,0,0,0.12)]" : "bg-muted/10 border-border text-muted-foreground"
7380
+ );
7381
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7382
+ import_framer_motion9.motion.div,
7383
+ {
7384
+ layout: true,
7385
+ initial: "hidden",
7386
+ animate: "visible",
7387
+ exit: "exit",
7388
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7389
+ ButtonBase,
7390
+ {
7391
+ asChild: true,
7392
+ variant: "ghost",
7393
+ onClick: () => toggleHighlight(k),
7394
+ title: isHighlighted ? `Desativar ${label}` : `Ativar ${label}`,
7395
+ className: pillClasses,
7396
+ style: { minWidth: showFullLabel ? void 0 : 36 },
7397
+ "aria-pressed": isHighlighted,
7398
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7399
+ import_framer_motion9.motion.button,
7400
+ {
7401
+ whileHover: { scale: isHighlighted ? 1.04 : 1.03 },
7402
+ whileTap: { scale: 0.96 },
7403
+ animate: isHighlighted ? { scale: 1.02 } : { scale: 1 },
7404
+ className: "flex items-center gap-2",
7405
+ children: [
7406
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7407
+ import_framer_motion9.motion.span,
7408
+ {
7409
+ className: cn("w-3 h-3 rounded-sm flex-shrink-0 border"),
7410
+ style: {
7411
+ backgroundColor: color,
7412
+ borderColor: isHighlighted ? color : "transparent",
7413
+ boxShadow: isHighlighted ? `0 6px 20px ${color}33` : void 0
7414
+ },
7415
+ layout: true,
7416
+ initial: { scale: 0.8, opacity: 0.9 },
7417
+ animate: { scale: 1, opacity: 1 },
7418
+ transition: { type: "spring", stiffness: 400, damping: 30 }
7419
+ }
7420
+ ),
7421
+ showFullLabel ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_framer_motion9.motion.span, { className: "truncate max-w-[10rem]", layout: true, children: label }) : showShortLabel ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7422
+ import_framer_motion9.motion.span,
7423
+ {
7424
+ className: "truncate max-w-[6rem] text-xs",
7425
+ layout: true,
7426
+ children: label
7427
+ }
7428
+ ) : null,
7429
+ isHighlighted ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7430
+ import_framer_motion9.motion.span,
7431
+ {
7432
+ initial: { opacity: 0, scale: 0.6 },
7433
+ animate: { opacity: 1, scale: 1 },
7434
+ transition: {
7435
+ type: "spring",
7436
+ stiffness: 450,
7437
+ damping: 28
7438
+ },
7439
+ className: "ml-1 text-xs text-foreground",
7440
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7441
+ "svg",
7442
+ {
7443
+ width: "12",
7444
+ height: "12",
7445
+ viewBox: "0 0 24 24",
7446
+ fill: "none",
7447
+ xmlns: "http://www.w3.org/2000/svg",
7448
+ "aria-hidden": true,
7449
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7450
+ "path",
7451
+ {
7452
+ d: "M20 6L9 17l-5-5",
7453
+ stroke: "currentColor",
7454
+ strokeWidth: "2",
7455
+ strokeLinecap: "round",
7456
+ strokeLinejoin: "round"
7457
+ }
7458
+ )
7459
+ }
7460
+ )
7461
+ }
7462
+ ) : null
7463
+ ]
7464
+ }
7465
+ )
7466
+ }
7467
+ )
7468
+ },
7469
+ `pill-${k}`
7470
+ );
7471
+ }) })
7472
+ }
7473
+ );
7474
+ };
7475
+ var Highlights_default = Highlights;
7476
+
7477
+ // src/components/rechart/Chart.tsx
7478
+ var import_jsx_runtime57 = require("react/jsx-runtime");
7479
+ var DEFAULT_COLORS4 = ["#55af7d", "#8e68ff", "#2273e1"];
7480
+ var Chart = ({
7481
+ data,
7482
+ series,
7483
+ className,
7484
+ height = 350,
7485
+ width = 900,
7486
+ colors: colors2 = DEFAULT_COLORS4,
7487
+ gridColor,
7488
+ showGrid = true,
7489
+ showTooltip = true,
7490
+ showLegend = true,
7491
+ title,
7492
+ titlePosition = "left",
7493
+ showLabels = false,
7494
+ xAxis,
7495
+ labelMap,
7496
+ enableHighlights = false,
7497
+ enableShowOnly = false,
7498
+ enablePeriodsDropdown = false,
7499
+ enableDraggableTooltips = false
7500
+ }) => {
7501
+ const smartConfig = (0, import_react37.useMemo)(() => {
7502
+ const xAxisConfig2 = typeof xAxis === "string" ? { dataKey: xAxis, label: formatFieldName2(xAxis), autoLabel: true } : xAxis;
7503
+ const detectedFields = detectDataFields2(data, xAxisConfig2.dataKey);
7504
+ const mapperConfig2 = detectedFields.reduce((acc, field) => {
7505
+ acc[field] = {
7506
+ label: labelMap?.[field] ?? formatFieldName2(field),
7507
+ type: "number",
7508
+ visible: true
7509
+ };
7510
+ return acc;
7511
+ }, {});
7512
+ return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
7513
+ }, [data, xAxis, labelMap]);
7514
+ const { xAxisConfig, mapperConfig } = smartConfig;
7515
+ const [activeTooltips, setActiveTooltips] = (0, import_react37.useState)([]);
7516
+ const [highlightedSeries, setHighlightedSeries] = (0, import_react37.useState)(
7517
+ /* @__PURE__ */ new Set()
7518
+ );
7519
+ const [showOnlyHighlighted, setShowOnlyHighlighted] = (0, import_react37.useState)(false);
7520
+ (0, import_react37.useEffect)(() => {
7521
+ if (highlightedSeries.size === 0 && showOnlyHighlighted) {
7522
+ setShowOnlyHighlighted(false);
7523
+ }
7524
+ }, [highlightedSeries, showOnlyHighlighted]);
7525
+ const processedData = data.map((item) => ({
7526
+ ...item,
7527
+ name: String(item[xAxisConfig.dataKey] || "N/A")
7528
+ }));
7529
+ const wrapperRef = (0, import_react37.useRef)(null);
7530
+ const [measuredWidth, setMeasuredWidth] = (0, import_react37.useState)(null);
7531
+ (0, import_react37.useLayoutEffect)(() => {
7532
+ const el = wrapperRef.current;
7533
+ if (!el) return;
7534
+ const ro = new ResizeObserver((entries) => {
7535
+ const r = entries[0];
7536
+ if (r && typeof r.contentRect.width === "number") {
7537
+ setMeasuredWidth(Math.round(r.contentRect.width));
7538
+ }
7539
+ });
7540
+ ro.observe(el);
7541
+ setMeasuredWidth(Math.round(el.getBoundingClientRect().width));
7542
+ return () => ro.disconnect();
7543
+ }, []);
7544
+ const seriesOrder = [];
7545
+ if (series) {
7546
+ if (series.bar)
7547
+ series.bar.forEach((k) => seriesOrder.push({ type: "bar", key: k }));
7548
+ if (series.line)
7549
+ series.line.forEach((k) => seriesOrder.push({ type: "line", key: k }));
7550
+ if (series.area)
7551
+ series.area.forEach((k) => seriesOrder.push({ type: "area", key: k }));
7552
+ } else {
7553
+ Object.keys(mapperConfig).forEach(
7554
+ (k) => seriesOrder.push({ type: "bar", key: k })
7555
+ );
7556
+ }
7557
+ const allKeys = seriesOrder.map((s) => s.key).filter(Boolean);
7558
+ const generateColors = (dataKeys) => {
7559
+ const colorMap = {};
7560
+ const allColors = generateAdditionalColors3(colors2, dataKeys.length);
7561
+ dataKeys.forEach((key, index) => {
7562
+ colorMap[key] = mapperConfig[key] && mapperConfig[key].color || allColors[index] || colors2[index % colors2.length];
7563
+ });
7564
+ return colorMap;
7565
+ };
7566
+ const finalColors = generateColors(allKeys);
7567
+ const adaptDataForTooltip = (0, import_react37.useCallback)(
7568
+ (universalData) => ({
7569
+ ...universalData,
7570
+ name: String(universalData[xAxisConfig.dataKey] || "N/A")
7571
+ }),
7572
+ [xAxisConfig.dataKey]
7573
+ );
7574
+ const activePeriods = (0, import_react37.useMemo)(
7575
+ () => activeTooltips.map((t) => adaptDataForTooltip(t.data).name),
7576
+ [activeTooltips, adaptDataForTooltip]
7577
+ );
7578
+ const openTooltipForPeriod = (periodName) => {
7579
+ if (!enableDraggableTooltips) return;
7580
+ const row = processedData.find((r) => String(r.name) === periodName);
7581
+ if (!row) return;
7582
+ const tooltipId = `${periodName}`;
7583
+ const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
7584
+ if (existingIndex !== -1) {
7585
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
7586
+ return;
7587
+ }
7588
+ const offsetIndex = activeTooltips.length;
7589
+ const availableWidth = typeof width === "number" ? width : measuredWidth ? Math.max(0, measuredWidth - 32) : computedWidth;
7590
+ const newTooltip = {
7591
+ id: tooltipId,
7592
+ data: row,
7593
+ position: {
7594
+ top: 48 + offsetIndex * 28,
7595
+ left: Math.max(120, availableWidth - 260 - offsetIndex * 28)
7596
+ }
7597
+ };
7598
+ setActiveTooltips((prev) => [...prev, newTooltip]);
7599
+ };
7600
+ (0, import_react37.useEffect)(() => {
7601
+ window.dispatchEvent(new Event("recountTooltips"));
7602
+ }, [activeTooltips.length]);
7603
+ const toggleHighlight = (0, import_react37.useCallback)((key) => {
7604
+ setHighlightedSeries((prev) => {
7605
+ const next = new Set(prev);
7606
+ if (next.has(key)) next.delete(key);
7607
+ else next.add(key);
7608
+ return next;
7609
+ });
7610
+ }, []);
7611
+ const niceCeil = (value) => {
7612
+ if (!isFinite(value) || value <= 0) return 1;
7613
+ const pow = Math.pow(10, Math.floor(Math.log10(value)));
7614
+ const normalized = value / pow;
7615
+ const multipliers = [
7616
+ 1,
7617
+ 1.25,
7618
+ 1.5,
7619
+ 2,
7620
+ 2.5,
7621
+ 3,
7622
+ 4,
7623
+ 5,
7624
+ 7.5,
7625
+ 10,
7626
+ 15,
7627
+ 20,
7628
+ 25,
7629
+ 50,
7630
+ 100
7631
+ ];
7632
+ for (const m of multipliers) {
7633
+ if (m >= normalized) return Math.ceil(m * pow);
7634
+ }
7635
+ return Math.ceil(100 * pow);
7636
+ };
7637
+ const maxDataValue = (0, import_react37.useMemo)(() => {
7638
+ let max = 0;
7639
+ const numericKeys = allKeys;
7640
+ for (const row of processedData) {
7641
+ const r = row;
7642
+ for (const key of numericKeys) {
7643
+ const v = r[key];
7644
+ if (typeof v === "number" && Number.isFinite(v) && v > max) max = v;
7645
+ }
7646
+ }
7647
+ return max;
7648
+ }, [processedData, allKeys]);
7649
+ const niceMax = (0, import_react37.useMemo)(() => {
7650
+ let padding = 0.08;
7651
+ if (maxDataValue > 1e6) padding = 0.05;
7652
+ if (maxDataValue > 1e7) padding = 0.03;
7653
+ if (maxDataValue === 0) padding = 0.12;
7654
+ const padded = maxDataValue * (1 + padding);
7655
+ return niceCeil(padded);
7656
+ }, [maxDataValue]);
7657
+ const computedWidth = (0, import_react37.useMemo)(() => {
7658
+ if (typeof width === "number") return width;
7659
+ const points = processedData.length || 1;
7660
+ const barCount = series?.bar?.length ?? 0;
7661
+ const lineCount = series?.line?.length ?? 0;
7662
+ const areaCount = series?.area?.length ?? 0;
7663
+ const basePerPoint = 84;
7664
+ const perBarExtra = Math.max(0, barCount - 1) * 10;
7665
+ const perOtherExtra = (lineCount + areaCount) * 6;
7666
+ let sizeFactor = 1;
7667
+ if (niceMax > 1e5) sizeFactor = 1.18;
7668
+ if (niceMax > 1e6) sizeFactor = 1.36;
7669
+ if (niceMax > 1e7) sizeFactor = 1.6;
7670
+ const perPoint = Math.round(
7671
+ (basePerPoint + perBarExtra + perOtherExtra) * sizeFactor
7672
+ );
7673
+ const marginExtra = 140;
7674
+ const raw = Math.round(points * perPoint + marginExtra);
7675
+ const min = 380;
7676
+ const max = 2200;
7677
+ return Math.max(min, Math.min(max, raw));
7678
+ }, [
7679
+ width,
7680
+ processedData.length,
7681
+ series?.bar?.length,
7682
+ series?.line?.length,
7683
+ series?.area?.length,
7684
+ niceMax
7685
+ ]);
7686
+ const handleBarClick = (data2, index, event) => {
7687
+ if (!enableDraggableTooltips) return;
7688
+ event.stopPropagation();
7689
+ const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
7690
+ const tooltipId = `${xAxisValue}`;
7691
+ const rect = event.target.getBoundingClientRect();
7692
+ const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
7693
+ if (existingIndex !== -1) {
7694
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
7695
+ } else {
7696
+ const newTooltip = {
7697
+ id: tooltipId,
7698
+ data: data2,
7699
+ position: { top: rect.top - 10, left: rect.right + 10 }
7700
+ };
7701
+ setActiveTooltips((prev) => [...prev, newTooltip]);
7702
+ }
7703
+ };
7704
+ const handleChartClick = (e) => {
7705
+ if (!enableDraggableTooltips) return;
7706
+ const ev = e;
7707
+ if (ev && ev.activePayload && ev.activePayload.length > 0) {
7708
+ const clickedData = ev.activePayload[0].payload;
7709
+ const xAxisValue = clickedData[xAxisConfig.dataKey] || clickedData.name || "N/A";
7710
+ const tooltipId = `${xAxisValue}`;
7711
+ const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
7712
+ if (existingIndex !== -1) {
7713
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
7714
+ } else {
7715
+ const newTooltip = {
7716
+ id: tooltipId,
7717
+ data: clickedData,
7718
+ position: {
7719
+ top: (ev?.chartY || 100) - 10,
7720
+ left: (ev?.chartX || 100) - 100
7721
+ }
7722
+ };
7723
+ setActiveTooltips((prev) => [...prev, newTooltip]);
7724
+ }
7725
+ return;
7726
+ }
7727
+ setActiveTooltips([]);
7728
+ };
7729
+ const handleSeriesClick = (...args) => {
7730
+ if (args.length >= 3) {
7731
+ const [data2, index, event] = args;
7732
+ handleBarClick(data2, index, event);
7733
+ return;
7734
+ }
7735
+ handleChartClick(args[0]);
7736
+ };
7737
+ const onTooltipPositionChange = (id, position) => {
7738
+ setActiveTooltips(
7739
+ (prev) => prev.map((t) => t.id === id ? { ...t, position } : t)
7740
+ );
7741
+ };
7742
+ const CustomTooltip = ({
7743
+ active,
7744
+ payload,
7745
+ label
7746
+ }) => {
7747
+ if (!active || !payload) return null;
7748
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "bg-card border border-border rounded-lg p-3 shadow-lg", children: [
7749
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "font-medium text-foreground mb-2", children: label }),
7750
+ payload.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex items-center gap-2 text-sm", children: [
7751
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7752
+ "div",
7753
+ {
7754
+ className: "w-3 h-3 rounded-sm",
7755
+ style: {
7756
+ backgroundColor: finalColors[entry.dataKey] || entry.color
7757
+ }
7758
+ }
7759
+ ),
7760
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "text-muted-foreground", children: [
7761
+ entry.name,
7762
+ ":"
7763
+ ] }),
7764
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "text-foreground font-medium", children: entry.value?.toLocaleString("pt-BR") })
7765
+ ] }, index)),
7766
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "text-xs text-muted-foreground mt-1", children: "Clique para fixar este tooltip" })
7767
+ ] });
7768
+ };
7769
+ const getTitleClassName = () => {
7770
+ return "text-xl font-semibold text-foreground mb-3";
7771
+ };
7772
+ const finalEnableHighlights = enableHighlights;
7773
+ const finalEnableShowOnly = enableShowOnly;
7774
+ const finalEnablePeriodsDropdown = enablePeriodsDropdown && enableDraggableTooltips;
7775
+ const chartRightMargin = 30;
7776
+ const containerPaddingLeft = 16;
7777
+ const chartLeftMargin = 20;
7778
+ const measuredInner = measuredWidth ? Math.max(0, measuredWidth - 32) : void 0;
7779
+ const effectiveChartWidth = typeof width === "number" ? width : measuredInner ?? computedWidth;
7780
+ const chartInnerWidth = effectiveChartWidth - chartLeftMargin - chartRightMargin;
7781
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7782
+ "div",
7783
+ {
7784
+ ref: wrapperRef,
7785
+ style: {
7786
+ width: "100%",
7787
+ overflowX: typeof width === "number" ? "auto" : "visible",
7788
+ overflowY: "hidden"
7789
+ },
7790
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7791
+ "div",
7792
+ {
7793
+ className: cn("rounded-lg bg-card p-4 relative", className),
7794
+ style: typeof width === "number" ? { width: `${width + 32}px` } : { width: "100%", maxWidth: "100%" },
7795
+ children: [
7796
+ title && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7797
+ "div",
7798
+ {
7799
+ style: {
7800
+ paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
7801
+ width: "100%",
7802
+ maxWidth: `${chartInnerWidth}px`,
7803
+ display: "flex",
7804
+ justifyContent: titlePosition === "center" ? "center" : titlePosition === "right" ? "flex-end" : "flex-start",
7805
+ alignItems: "center"
7806
+ },
7807
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("h3", { className: getTitleClassName(), children: title })
7808
+ }
7809
+ ),
7810
+ allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly) && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7811
+ "div",
7812
+ {
7813
+ className: "flex items-center w-full",
7814
+ style: {
7815
+ paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
7816
+ width: "98%",
7817
+ display: "flex",
7818
+ alignItems: "center",
7819
+ gap: "0.5rem"
7820
+ },
7821
+ children: [
7822
+ finalEnableHighlights && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7823
+ Highlights_default,
7824
+ {
7825
+ allKeys,
7826
+ mapperConfig,
7827
+ finalColors,
7828
+ highlightedSeries,
7829
+ toggleHighlight,
7830
+ containerWidth: chartInnerWidth
7831
+ }
7832
+ ),
7833
+ finalEnableShowOnly && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7834
+ ShowOnly_default,
7835
+ {
7836
+ showOnlyHighlighted,
7837
+ setShowOnlyHighlighted,
7838
+ highlightedSeriesSize: highlightedSeries.size,
7839
+ clearHighlights: () => setHighlightedSeries(/* @__PURE__ */ new Set())
7840
+ }
7841
+ ),
7842
+ finalEnablePeriodsDropdown && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7843
+ "div",
7844
+ {
7845
+ style: {
7846
+ marginLeft: "auto",
7847
+ display: "flex",
7848
+ alignItems: "center"
7849
+ },
7850
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7851
+ PeriodsDropdown_default,
7852
+ {
7853
+ processedData,
7854
+ onOpenPeriod: openTooltipForPeriod,
7855
+ rightOffset: chartRightMargin,
7856
+ activePeriods
7857
+ }
7858
+ )
7859
+ }
7860
+ )
7861
+ ]
7862
+ }
7863
+ ),
7864
+ !(allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly)) && finalEnablePeriodsDropdown && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7865
+ "div",
7866
+ {
7867
+ style: {
7868
+ paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
7869
+ paddingRight: `${chartRightMargin}px`,
7870
+ width: "100%",
7871
+ maxWidth: `${chartInnerWidth}px`,
7872
+ display: "flex",
7873
+ justifyContent: "flex-end"
7874
+ },
7875
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7876
+ PeriodsDropdown_default,
7877
+ {
7878
+ processedData,
7879
+ onOpenPeriod: openTooltipForPeriod,
7880
+ rightOffset: chartRightMargin
7881
+ }
7882
+ )
7883
+ }
7884
+ ),
7885
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_recharts4.ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7886
+ import_recharts4.ComposedChart,
7887
+ {
7888
+ data: processedData,
7889
+ height,
7890
+ margin: {
7891
+ top: showLabels ? 48 : 20,
7892
+ right: 30,
7893
+ left: 20,
7894
+ bottom: 5
7895
+ },
7896
+ onClick: handleChartClick,
7897
+ children: [
7898
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7899
+ import_recharts4.CartesianGrid,
7900
+ {
7901
+ strokeDasharray: "3 3",
7902
+ stroke: gridColor || "hsl(var(--muted-foreground))",
7903
+ opacity: 0.5
7904
+ }
7905
+ ),
7906
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7907
+ import_recharts4.XAxis,
7908
+ {
7909
+ dataKey: xAxisConfig.dataKey,
7910
+ stroke: "hsl(var(--muted-foreground))",
7911
+ fontSize: 12,
7912
+ tickLine: false,
7913
+ axisLine: false,
7914
+ tickFormatter: xAxisConfig.formatter
7915
+ }
7916
+ ),
7917
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7918
+ import_recharts4.YAxis,
7919
+ {
7920
+ stroke: "hsl(var(--muted-foreground))",
7921
+ fontSize: 12,
7922
+ tickLine: false,
7923
+ axisLine: false,
7924
+ tickFormatter: (value) => Number(value).toLocaleString("pt-BR"),
7925
+ domain: [0, niceMax],
7926
+ tickCount: 6
7927
+ }
7928
+ ),
7929
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7930
+ import_recharts4.Tooltip,
7931
+ {
7932
+ content: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(CustomTooltip, {}),
7933
+ cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
7934
+ }
7935
+ ),
7936
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7937
+ import_recharts4.Legend,
7938
+ {
7939
+ wrapperStyle: {
7940
+ color: "hsl(var(--foreground))",
7941
+ fontSize: "14px"
7942
+ }
7943
+ }
7944
+ ),
7945
+ seriesOrder.map((s) => {
7946
+ const key = s.key;
7947
+ if (showOnlyHighlighted && !highlightedSeries.has(key))
7948
+ return null;
7949
+ const label = mapperConfig[key]?.label ?? labelMap?.[key] ?? formatFieldName2(key);
7950
+ const color = finalColors[key];
7951
+ if (s.type === "bar") {
7952
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7953
+ import_recharts4.Bar,
7954
+ {
7955
+ dataKey: key,
7956
+ name: label,
7957
+ fill: color,
7958
+ radius: [4, 4, 0, 0],
7959
+ onClick: handleBarClick,
7960
+ style: {
7961
+ cursor: "pointer",
7962
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
7963
+ },
7964
+ activeBar: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7965
+ import_recharts4.Rectangle,
7966
+ {
7967
+ fill: color,
7968
+ stroke: color,
7969
+ strokeWidth: 2,
7970
+ opacity: 0.8
7971
+ }
7972
+ ),
7973
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7974
+ import_recharts4.LabelList,
7975
+ {
7976
+ dataKey: key,
7977
+ position: "top",
7978
+ content: pillLabelRenderer_default(color, "filled"),
7979
+ offset: 8
7980
+ }
7981
+ ) : null
7982
+ },
7983
+ `bar-${key}`
7984
+ );
7985
+ }
7986
+ if (s.type === "line") {
7987
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7988
+ import_recharts4.Line,
7989
+ {
7990
+ dataKey: key,
7991
+ name: label,
7992
+ stroke: color,
7993
+ strokeWidth: 2,
7994
+ dot: { r: 3 },
7995
+ activeDot: { r: 6 },
7996
+ onClick: handleSeriesClick,
7997
+ style: {
7998
+ cursor: "pointer",
7999
+ pointerEvents: "all",
8000
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
8001
+ },
8002
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
8003
+ import_recharts4.LabelList,
8004
+ {
8005
+ dataKey: key,
8006
+ position: "top",
8007
+ content: pillLabelRenderer_default(color, "filled"),
8008
+ offset: 14
8009
+ }
8010
+ ) : null
8011
+ },
8012
+ `line-${key}`
8013
+ );
8014
+ }
8015
+ if (s.type === "area") {
8016
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
8017
+ import_recharts4.Area,
8018
+ {
8019
+ dataKey: key,
8020
+ name: label,
8021
+ stroke: color,
8022
+ fill: color,
8023
+ fillOpacity: 0.15,
8024
+ onClick: handleSeriesClick,
8025
+ style: {
8026
+ cursor: "pointer",
8027
+ pointerEvents: "all",
8028
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
8029
+ },
8030
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
8031
+ import_recharts4.LabelList,
8032
+ {
8033
+ dataKey: key,
8034
+ position: "top",
8035
+ content: pillLabelRenderer_default(color, "soft"),
8036
+ offset: 12
8037
+ }
8038
+ ) : null
8039
+ },
8040
+ `area-${key}`
8041
+ );
8042
+ }
8043
+ return null;
8044
+ })
8045
+ ]
8046
+ }
8047
+ ) }),
8048
+ enableDraggableTooltips && activeTooltips.map((tooltip) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
8049
+ DraggableTooltip_default,
8050
+ {
8051
+ id: tooltip.id,
8052
+ data: adaptDataForTooltip(tooltip.data),
8053
+ position: tooltip.position,
8054
+ title,
8055
+ dataKeys: allKeys,
8056
+ finalColors,
8057
+ onClose: (id) => setActiveTooltips((prev) => prev.filter((t) => t.id !== id)),
8058
+ onPositionChange: onTooltipPositionChange,
8059
+ periodLabel: "Per\xEDodo Selecionado",
8060
+ dataLabel: "Dados do Per\xEDodo",
8061
+ globalTooltipCount: activeTooltips.length,
8062
+ onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
8063
+ closeAllButtonPosition: "top-center",
8064
+ closeAllButtonVariant: "floating"
8065
+ },
8066
+ tooltip.id
8067
+ )),
8068
+ enableDraggableTooltips && activeTooltips.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
8069
+ CloseAllButton_default,
8070
+ {
8071
+ count: activeTooltips.length,
8072
+ onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
8073
+ position: "top-center",
8074
+ variant: "floating"
8075
+ }
8076
+ )
8077
+ ]
8078
+ }
8079
+ )
8080
+ }
8081
+ );
8082
+ };
8083
+ var Chart_default = Chart;
8084
+
8085
+ // src/hooks/use-drag.tsx
8086
+ var import_react38 = require("react");
8087
+ var useDrag = (options = {}) => {
8088
+ const [isDragging, setIsDragging] = (0, import_react38.useState)(null);
8089
+ const [positions, setPositions] = (0, import_react38.useState)({});
8090
+ const dragStartPos = (0, import_react38.useRef)(null);
8091
+ const dragId = (0, import_react38.useRef)(null);
8092
+ const handleMouseDown = (0, import_react38.useCallback)((id, e) => {
8093
+ e.preventDefault();
8094
+ const currentPosition = positions[id] || { top: 0, left: 0 };
8095
+ dragStartPos.current = {
8096
+ x: e.clientX,
8097
+ y: e.clientY,
8098
+ elementX: currentPosition.left,
8099
+ elementY: currentPosition.top
8100
+ };
8101
+ dragId.current = id;
8102
+ setIsDragging(id);
8103
+ options.onDragStart?.(id);
8104
+ }, [positions, options]);
8105
+ const handleMouseMove = (0, import_react38.useCallback)((e) => {
8106
+ if (!isDragging || !dragStartPos.current || !dragId.current) return;
8107
+ const deltaX = e.clientX - dragStartPos.current.x;
8108
+ const deltaY = e.clientY - dragStartPos.current.y;
8109
+ const newPosition = {
8110
+ left: dragStartPos.current.elementX + deltaX,
8111
+ top: dragStartPos.current.elementY + deltaY
8112
+ };
8113
+ newPosition.left = Math.max(0, Math.min(window.innerWidth - 300, newPosition.left));
8114
+ newPosition.top = Math.max(0, Math.min(window.innerHeight - 200, newPosition.top));
8115
+ setPositions((prev) => ({
8116
+ ...prev,
8117
+ [dragId.current]: newPosition
8118
+ }));
8119
+ options.onDrag?.(dragId.current, newPosition);
8120
+ }, [isDragging, options]);
8121
+ const handleMouseUp = (0, import_react38.useCallback)(() => {
8122
+ if (dragId.current) {
8123
+ options.onDragEnd?.(dragId.current);
8124
+ }
8125
+ setIsDragging(null);
8126
+ dragStartPos.current = null;
8127
+ dragId.current = null;
8128
+ }, [options]);
8129
+ (0, import_react38.useEffect)(() => {
8130
+ if (isDragging) {
8131
+ document.addEventListener("mousemove", handleMouseMove);
8132
+ document.addEventListener("mouseup", handleMouseUp);
8133
+ document.body.style.userSelect = "none";
8134
+ return () => {
8135
+ document.removeEventListener("mousemove", handleMouseMove);
8136
+ document.removeEventListener("mouseup", handleMouseUp);
8137
+ document.body.style.userSelect = "";
8138
+ };
8139
+ }
8140
+ }, [isDragging, handleMouseMove, handleMouseUp]);
8141
+ const setPosition = (0, import_react38.useCallback)((id, position) => {
8142
+ setPositions((prev) => ({
8143
+ ...prev,
8144
+ [id]: position
8145
+ }));
8146
+ }, []);
8147
+ const getPosition = (0, import_react38.useCallback)((id) => {
8148
+ return positions[id] || { top: 0, left: 0 };
8149
+ }, [positions]);
8150
+ const isElementDragging = (0, import_react38.useCallback)((id) => {
8151
+ return isDragging === id;
8152
+ }, [isDragging]);
8153
+ return {
8154
+ handleMouseDown,
8155
+ getPosition,
8156
+ setPosition,
8157
+ isElementDragging,
8158
+ isDragging: isDragging !== null
8159
+ };
8160
+ };