@mlw-packages/react-components 1.5.7 → 1.5.8

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
  CloseAllButton: () => CloseAllButton_default,
526
528
  CollapsibleBase: () => CollapsibleBase,
@@ -599,6 +601,7 @@ __export(index_exports, {
599
601
  InputOTPSeparatorBase: () => InputOTPSeparatorBase,
600
602
  InputOTPSlotBase: () => InputOTPSlotBase,
601
603
  LabelBase: () => LabelBase_default,
604
+ LineChart: () => LineChart_default,
602
605
  LoadingBase: () => LoadingBase,
603
606
  ModeToggleBase: () => ModeToggleBase,
604
607
  MultiCombobox: () => MultiCombobox,
@@ -611,6 +614,7 @@ __export(index_exports, {
611
614
  NavigationMenuTriggerBase: () => NavigationMenuTriggerBase,
612
615
  NavigationMenuViewportBase: () => NavigationMenuViewportBase,
613
616
  PeriodsDropdown: () => PeriodsDropdown_default,
617
+ PieChart: () => PieChart_default,
614
618
  PopoverAnchorBase: () => PopoverAnchorBase,
615
619
  PopoverBase: () => PopoverBase,
616
620
  PopoverContentBase: () => PopoverContentBase,
@@ -706,6 +710,7 @@ __export(index_exports, {
706
710
  resolveChartMargins: () => resolveChartMargins,
707
711
  resolveContainerPaddingLeft: () => resolveContainerPaddingLeft,
708
712
  toast: () => toast,
713
+ useChartHighlights: () => useChartHighlights,
709
714
  useDrag: () => useDrag,
710
715
  useIsMobile: () => useIsMobile,
711
716
  useTheme: () => useTheme
@@ -4623,43 +4628,119 @@ function ModeToggleBase({
4623
4628
  ] });
4624
4629
  }
4625
4630
 
4631
+ // src/components/ui/DestructiveDialog.tsx
4632
+ var React29 = __toESM(require("react"));
4633
+ var import_react25 = require("@phosphor-icons/react");
4634
+ var import_jsx_runtime43 = require("react/jsx-runtime");
4635
+ var DestructiveDialog = ({
4636
+ title,
4637
+ description,
4638
+ onConfirm,
4639
+ onCancel,
4640
+ children,
4641
+ triggerContent
4642
+ }) => {
4643
+ const titleId = "destructive-dialog-title";
4644
+ const descriptionId = "destructive-dialog-description";
4645
+ const triggerEl = React29.isValidElement(children) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AlertDialogTriggerBase, { asChild: true, children }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AlertDialogTriggerBase, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ButtonBase, { variant: "destructive", children: triggerContent ?? "Excluir" }) });
4646
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(AlertDialogBase, { children: [
4647
+ triggerEl,
4648
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
4649
+ AlertDialogContentBase,
4650
+ {
4651
+ role: "alertdialog",
4652
+ "aria-modal": "true",
4653
+ "aria-labelledby": titleId,
4654
+ "aria-describedby": descriptionId,
4655
+ className: cn("border border-destructive bg-background"),
4656
+ children: [
4657
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-start gap-4", children: [
4658
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex items-center justify-center w-10 h-10 rounded-full ring-1 ring-destructive/30", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react25.XCircleIcon, { className: "w-6 h-6 text-destructive" }) }),
4659
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex-1", children: [
4660
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4661
+ AlertDialogTitleBase,
4662
+ {
4663
+ id: titleId,
4664
+ className: "text-lg sm:text-xl font-semibold text-destructive",
4665
+ children: title
4666
+ }
4667
+ ),
4668
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4669
+ AlertDialogDescriptionBase,
4670
+ {
4671
+ id: descriptionId,
4672
+ className: "mt-2 text-sm text-muted-foreground",
4673
+ children: description
4674
+ }
4675
+ )
4676
+ ] })
4677
+ ] }),
4678
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(AlertDialogFooterBase, { className: "mt-2 flex justify-end gap-3", children: [
4679
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4680
+ AlertDialogCancelBase,
4681
+ {
4682
+ onClick: onCancel,
4683
+ className: cn(
4684
+ buttonVariantsBase({ variant: "outline", size: "default" }),
4685
+ "hover:bg-foreground/5 hover:text-primary hover:opacity-90 hover:shadow-none"
4686
+ ),
4687
+ children: "Cancelar"
4688
+ }
4689
+ ),
4690
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4691
+ AlertDialogActionBase,
4692
+ {
4693
+ onClick: onConfirm,
4694
+ className: cn(
4695
+ buttonVariantsBase({ variant: "destructive", size: "default" })
4696
+ ),
4697
+ children: "Confirmar"
4698
+ }
4699
+ )
4700
+ ] })
4701
+ ]
4702
+ }
4703
+ )
4704
+ ] });
4705
+ };
4706
+
4626
4707
  // src/components/date-time-picker/DateTimePicker.tsx
4627
4708
  var import_date_fns = require("date-fns");
4628
4709
 
4629
4710
  // src/components/date-time-picker/calendar.tsx
4630
- var React29 = __toESM(require("react"));
4711
+ var React30 = __toESM(require("react"));
4631
4712
  var import_react_day_picker2 = require("react-day-picker");
4632
- var import_react25 = require("@phosphor-icons/react");
4713
+ var import_react26 = require("@phosphor-icons/react");
4633
4714
  var import_framer_motion6 = require("framer-motion");
4634
- var import_jsx_runtime43 = require("react/jsx-runtime");
4715
+ var import_jsx_runtime44 = require("react/jsx-runtime");
4635
4716
  function CalendarBase2({
4636
4717
  className,
4637
4718
  classNames,
4638
4719
  showOutsideDays = true,
4639
4720
  ...props
4640
4721
  }) {
4641
- const [month, setMonth] = React29.useState(
4722
+ const [month, setMonth] = React30.useState(
4642
4723
  props.month || props.defaultMonth || /* @__PURE__ */ new Date()
4643
4724
  );
4644
- const [direction, setDirection] = React29.useState(1);
4725
+ const [direction, setDirection] = React30.useState(1);
4645
4726
  const handleMonthChange = (newMonth) => {
4646
4727
  const isNext = newMonth > month ? 1 : -1;
4647
4728
  setDirection(isNext);
4648
4729
  setMonth(newMonth);
4649
4730
  props.onMonthChange?.(newMonth);
4650
4731
  };
4651
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4732
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4652
4733
  "div",
4653
4734
  {
4654
4735
  className: cn(
4655
4736
  "rounded-2xl border bg-background p-4 shadow-lg overflow-hidden w-full h-full flex flex-col",
4656
4737
  className
4657
4738
  ),
4658
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "relative flex-1 flex flex-col min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_framer_motion6.AnimatePresence, { initial: false, mode: "wait", custom: direction, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4739
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "relative flex-1 flex flex-col min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_framer_motion6.AnimatePresence, { initial: false, mode: "wait", custom: direction, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4659
4740
  "div",
4660
4741
  {
4661
4742
  className: "w-full h-full flex flex-col",
4662
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4743
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4663
4744
  import_react_day_picker2.DayPicker,
4664
4745
  {
4665
4746
  showOutsideDays,
@@ -4708,8 +4789,8 @@ function CalendarBase2({
4708
4789
  ...classNames
4709
4790
  },
4710
4791
  components: {
4711
- IconLeft: () => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react25.CaretLeftIcon, { className: "h-4 w-4" }),
4712
- IconRight: () => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react25.CaretRightIcon, { className: "h-4 w-4" })
4792
+ IconLeft: () => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react26.CaretLeftIcon, { className: "h-4 w-4" }),
4793
+ IconRight: () => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react26.CaretRightIcon, { className: "h-4 w-4" })
4713
4794
  },
4714
4795
  ...props
4715
4796
  }
@@ -4724,15 +4805,15 @@ CalendarBase2.displayName = "CalendarBase";
4724
4805
 
4725
4806
  // src/components/date-time-picker/DateTimePicker.tsx
4726
4807
  var import_locale = require("date-fns/locale");
4727
- var import_react28 = require("react");
4808
+ var import_react29 = require("react");
4728
4809
 
4729
4810
  // src/components/date-time-picker/TimePicker.tsx
4730
4811
  var import_framer_motion7 = require("framer-motion");
4731
- var React31 = __toESM(require("react"));
4812
+ var React32 = __toESM(require("react"));
4732
4813
 
4733
4814
  // src/components/date-time-picker/TimePickerInput.tsx
4734
- var import_react26 = require("@phosphor-icons/react");
4735
- var import_react27 = __toESM(require("react"));
4815
+ var import_react27 = require("@phosphor-icons/react");
4816
+ var import_react28 = __toESM(require("react"));
4736
4817
 
4737
4818
  // src/components/date-time-picker/time-picker-utils.ts
4738
4819
  function isValidHour(value) {
@@ -4874,8 +4955,8 @@ function display12HourValue(hours) {
4874
4955
  }
4875
4956
 
4876
4957
  // src/components/date-time-picker/TimePickerInput.tsx
4877
- var import_jsx_runtime44 = require("react/jsx-runtime");
4878
- var TimePickerInput = import_react27.default.forwardRef(
4958
+ var import_jsx_runtime45 = require("react/jsx-runtime");
4959
+ var TimePickerInput = import_react28.default.forwardRef(
4879
4960
  ({
4880
4961
  className,
4881
4962
  type = "tel",
@@ -4894,10 +4975,10 @@ var TimePickerInput = import_react27.default.forwardRef(
4894
4975
  label,
4895
4976
  ...props
4896
4977
  }, ref) => {
4897
- const [flag, setFlag] = import_react27.default.useState(false);
4898
- const [prevIntKey, setPrevIntKey] = import_react27.default.useState("0");
4899
- const [isFocused, setIsFocused] = import_react27.default.useState(false);
4900
- import_react27.default.useEffect(() => {
4978
+ const [flag, setFlag] = import_react28.default.useState(false);
4979
+ const [prevIntKey, setPrevIntKey] = import_react28.default.useState("0");
4980
+ const [isFocused, setIsFocused] = import_react28.default.useState(false);
4981
+ import_react28.default.useEffect(() => {
4901
4982
  if (flag) {
4902
4983
  const timer = setTimeout(() => {
4903
4984
  setFlag(false);
@@ -4905,7 +4986,7 @@ var TimePickerInput = import_react27.default.forwardRef(
4905
4986
  return () => clearTimeout(timer);
4906
4987
  }
4907
4988
  }, [flag]);
4908
- const calculatedValue = import_react27.default.useMemo(() => {
4989
+ const calculatedValue = import_react28.default.useMemo(() => {
4909
4990
  return getDateByType(date, picker);
4910
4991
  }, [date, picker]);
4911
4992
  const calculateNewValue = (key) => {
@@ -4961,8 +5042,8 @@ var TimePickerInput = import_react27.default.forwardRef(
4961
5042
  const baseLabel = getPickerLabel();
4962
5043
  return `${baseLabel}, valor atual: ${calculatedValue}.`;
4963
5044
  };
4964
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "relative group flex flex-col items-center", children: [
4965
- getPickerLabel() && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5045
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "relative group flex flex-col items-center", children: [
5046
+ getPickerLabel() && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4966
5047
  "label",
4967
5048
  {
4968
5049
  htmlFor: id || picker,
@@ -4970,7 +5051,7 @@ var TimePickerInput = import_react27.default.forwardRef(
4970
5051
  children: getPickerLabel()
4971
5052
  }
4972
5053
  ),
4973
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
5054
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
4974
5055
  "div",
4975
5056
  {
4976
5057
  className: cn(
@@ -4978,7 +5059,7 @@ var TimePickerInput = import_react27.default.forwardRef(
4978
5059
  "transition-all duration-200"
4979
5060
  ),
4980
5061
  children: [
4981
- showArrows && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5062
+ showArrows && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4982
5063
  "button",
4983
5064
  {
4984
5065
  type: "button",
@@ -4994,11 +5075,11 @@ var TimePickerInput = import_react27.default.forwardRef(
4994
5075
  ),
4995
5076
  tabIndex: -1,
4996
5077
  "aria-label": `Incrementar ${getPickerLabel().toLowerCase()}`,
4997
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react26.CaretUpIcon, { size: 14, className: "sm:w-4 sm:h-4" })
5078
+ children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_react27.CaretUpIcon, { size: 14, className: "sm:w-4 sm:h-4" })
4998
5079
  }
4999
5080
  ),
5000
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "relative", children: [
5001
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5081
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "relative", children: [
5082
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5002
5083
  "input",
5003
5084
  {
5004
5085
  ref,
@@ -5043,9 +5124,9 @@ var TimePickerInput = import_react27.default.forwardRef(
5043
5124
  ...props
5044
5125
  }
5045
5126
  ),
5046
- isFocused && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "absolute inset-0 rounded-lg ring-2 ring-primary/20 pointer-events-none animate-pulse" })
5127
+ isFocused && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "absolute inset-0 rounded-lg ring-2 ring-primary/20 pointer-events-none animate-pulse" })
5047
5128
  ] }),
5048
- showArrows && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5129
+ showArrows && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5049
5130
  "button",
5050
5131
  {
5051
5132
  type: "button",
@@ -5061,7 +5142,7 @@ var TimePickerInput = import_react27.default.forwardRef(
5061
5142
  ),
5062
5143
  tabIndex: -1,
5063
5144
  "aria-label": `Decrementar ${getPickerLabel().toLowerCase()}`,
5064
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react26.CaretDownIcon, { size: 14, className: "sm:w-4 sm:h-4" })
5145
+ children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_react27.CaretDownIcon, { size: 14, className: "sm:w-4 sm:h-4" })
5065
5146
  }
5066
5147
  )
5067
5148
  ]
@@ -5073,16 +5154,16 @@ var TimePickerInput = import_react27.default.forwardRef(
5073
5154
  TimePickerInput.displayName = "TimePickerInput";
5074
5155
 
5075
5156
  // src/components/date-time-picker/TimePicker.tsx
5076
- var import_jsx_runtime45 = require("react/jsx-runtime");
5157
+ var import_jsx_runtime46 = require("react/jsx-runtime");
5077
5158
  function TimePicker({
5078
5159
  date,
5079
5160
  setDate,
5080
5161
  hideSeconds,
5081
5162
  enableButton
5082
5163
  }) {
5083
- const minuteRef = React31.useRef(null);
5084
- const hourRef = React31.useRef(null);
5085
- const secondRef = React31.useRef(null);
5164
+ const minuteRef = React32.useRef(null);
5165
+ const hourRef = React32.useRef(null);
5166
+ const secondRef = React32.useRef(null);
5086
5167
  const containerVariants = {
5087
5168
  hidden: { opacity: 0, y: 10 },
5088
5169
  visible: {
@@ -5098,7 +5179,7 @@ function TimePicker({
5098
5179
  hidden: { opacity: 0, y: 10 },
5099
5180
  visible: { opacity: 1, y: 0 }
5100
5181
  };
5101
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
5182
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
5102
5183
  import_framer_motion7.motion.div,
5103
5184
  {
5104
5185
  variants: containerVariants,
@@ -5106,12 +5187,12 @@ function TimePicker({
5106
5187
  animate: "visible",
5107
5188
  className: "flex items-end justify-center gap-2 sm:gap-3 p-2 sm:p-3 md:p-4 rounded-lg bg-muted/20 border border-border/50 w-full max-w-full overflow-hidden",
5108
5189
  children: [
5109
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5190
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5110
5191
  import_framer_motion7.motion.div,
5111
5192
  {
5112
5193
  variants: itemVariants2,
5113
5194
  className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
5114
- children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5195
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5115
5196
  TimePickerInput,
5116
5197
  {
5117
5198
  picker: "hours",
@@ -5124,12 +5205,12 @@ function TimePicker({
5124
5205
  )
5125
5206
  }
5126
5207
  ),
5127
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5208
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5128
5209
  import_framer_motion7.motion.div,
5129
5210
  {
5130
5211
  variants: itemVariants2,
5131
5212
  className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
5132
- children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5213
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5133
5214
  TimePickerInput,
5134
5215
  {
5135
5216
  picker: "minutes",
@@ -5143,7 +5224,7 @@ function TimePicker({
5143
5224
  )
5144
5225
  }
5145
5226
  ),
5146
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_framer_motion7.AnimatePresence, { children: !hideSeconds && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_jsx_runtime45.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5227
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_framer_motion7.AnimatePresence, { children: !hideSeconds && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_jsx_runtime46.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5147
5228
  import_framer_motion7.motion.div,
5148
5229
  {
5149
5230
  variants: itemVariants2,
@@ -5151,7 +5232,7 @@ function TimePicker({
5151
5232
  animate: "visible",
5152
5233
  exit: "hidden",
5153
5234
  className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
5154
- children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5235
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5155
5236
  TimePickerInput,
5156
5237
  {
5157
5238
  picker: "seconds",
@@ -5170,8 +5251,8 @@ function TimePicker({
5170
5251
  }
5171
5252
 
5172
5253
  // src/components/date-time-picker/DateTimePicker.tsx
5173
- var import_react29 = require("@phosphor-icons/react");
5174
- var import_jsx_runtime46 = require("react/jsx-runtime");
5254
+ var import_react30 = require("@phosphor-icons/react");
5255
+ var import_jsx_runtime47 = require("react/jsx-runtime");
5175
5256
  function DateTimePicker({
5176
5257
  label,
5177
5258
  date,
@@ -5184,9 +5265,9 @@ function DateTimePicker({
5184
5265
  disabled,
5185
5266
  className
5186
5267
  }) {
5187
- const [internalDate, setInternalDate] = (0, import_react28.useState)(date);
5188
- const [open, setOpen] = (0, import_react28.useState)(false);
5189
- const [timePickerOpen, setTimePickerOpen] = (0, import_react28.useState)(false);
5268
+ const [internalDate, setInternalDate] = (0, import_react29.useState)(date);
5269
+ const [open, setOpen] = (0, import_react29.useState)(false);
5270
+ const [timePickerOpen, setTimePickerOpen] = (0, import_react29.useState)(false);
5190
5271
  const handleSelect = (newDay) => {
5191
5272
  if (!newDay) return;
5192
5273
  if (!internalDate) {
@@ -5215,15 +5296,15 @@ function DateTimePicker({
5215
5296
  if (!timeFormat) return "PPP";
5216
5297
  return `PPP - ${timeFormat}`;
5217
5298
  };
5218
- (0, import_react28.useEffect)(() => {
5299
+ (0, import_react29.useEffect)(() => {
5219
5300
  if (date) {
5220
5301
  setInternalDate(date);
5221
5302
  }
5222
5303
  }, [date, open]);
5223
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cn("space-y-2 w-full sm:w-auto", className), children: [
5224
- label && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(LabelBase_default, { children: label }),
5225
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(PopoverBase, { open, onOpenChange: setOpen, children: [
5226
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PopoverTriggerBase, { disabled, asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
5304
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: cn("space-y-2 w-full sm:w-auto", className), children: [
5305
+ label && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(LabelBase_default, { children: label }),
5306
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(PopoverBase, { open, onOpenChange: setOpen, children: [
5307
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverTriggerBase, { disabled, asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
5227
5308
  ButtonBase,
5228
5309
  {
5229
5310
  variant: "outline",
@@ -5235,12 +5316,12 @@ function DateTimePicker({
5235
5316
  !date && "text-muted-foreground"
5236
5317
  ),
5237
5318
  children: [
5238
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "truncate flex-1", children: date ? (0, import_date_fns.format)(date, getDisplayFormat(), { locale: import_locale.ptBR }) : "Pick a date" }),
5239
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react29.CalendarBlankIcon, { className: "flex-shrink-0 w-5 h-5 sm:w-6 sm:h-6" })
5319
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "truncate flex-1", children: date ? (0, import_date_fns.format)(date, getDisplayFormat(), { locale: import_locale.ptBR }) : "Pick a date" }),
5320
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react30.CalendarBlankIcon, { className: "flex-shrink-0 w-5 h-5 sm:w-6 sm:h-6" })
5240
5321
  ]
5241
5322
  }
5242
5323
  ) }),
5243
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5324
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5244
5325
  PopoverContentBase,
5245
5326
  {
5246
5327
  className: "w-full p-0",
@@ -5249,8 +5330,8 @@ function DateTimePicker({
5249
5330
  side: "bottom",
5250
5331
  avoidCollisions: true,
5251
5332
  collisionPadding: 8,
5252
- children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-col space-y-2 sm:space-y-3 p-2 sm:p-3 md:p-4 max-h-[calc(100vh-4rem)] overflow-y-auto", children: [
5253
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5333
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex flex-col space-y-2 sm:space-y-3 p-2 sm:p-3 md:p-4 max-h-[calc(100vh-4rem)] overflow-y-auto", children: [
5334
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5254
5335
  CalendarBase2,
5255
5336
  {
5256
5337
  mode: "single",
@@ -5263,13 +5344,13 @@ function DateTimePicker({
5263
5344
  className: "w-full"
5264
5345
  }
5265
5346
  ),
5266
- !(hideHour && hideMinute) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex justify-center w-full px-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
5347
+ !(hideHour && hideMinute) && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex justify-center w-full px-2", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
5267
5348
  PopoverBase,
5268
5349
  {
5269
5350
  open: timePickerOpen,
5270
5351
  onOpenChange: setTimePickerOpen,
5271
5352
  children: [
5272
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PopoverTriggerBase, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
5353
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverTriggerBase, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
5273
5354
  ButtonBase,
5274
5355
  {
5275
5356
  variant: "outline",
@@ -5285,14 +5366,14 @@ function DateTimePicker({
5285
5366
  "min-h-[36px] sm:min-h-[40px]"
5286
5367
  ),
5287
5368
  children: [
5288
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react29.ClockIcon, { className: "text-primary/70 flex-shrink-0 w-4 h-4 sm:w-5 sm:h-5" }),
5289
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-foreground truncate", children: internalDate ? (0, import_date_fns.format)(internalDate, getTimeFormat() || "HH:mm", {
5369
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react30.ClockIcon, { className: "text-primary/70 flex-shrink-0 w-4 h-4 sm:w-5 sm:h-5" }),
5370
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-foreground truncate", children: internalDate ? (0, import_date_fns.format)(internalDate, getTimeFormat() || "HH:mm", {
5290
5371
  locale: import_locale.ptBR
5291
5372
  }) : "00:00" })
5292
5373
  ]
5293
5374
  }
5294
5375
  ) }),
5295
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5376
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5296
5377
  PopoverContentBase,
5297
5378
  {
5298
5379
  className: "w-[calc(100vw-2rem)] max-w-sm p-3 sm:p-3 rounded-md",
@@ -5301,9 +5382,9 @@ function DateTimePicker({
5301
5382
  sideOffset: 8,
5302
5383
  avoidCollisions: true,
5303
5384
  collisionPadding: 8,
5304
- children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-col items-center space-y-2 sm:space-y-3", children: [
5305
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h4", { className: "text-sm sm:text-base font-medium text-center", children: "Alterar Hor\xE1rio" }),
5306
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5385
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex flex-col items-center space-y-2 sm:space-y-3", children: [
5386
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h4", { className: "text-sm sm:text-base font-medium text-center", children: "Alterar Hor\xE1rio" }),
5387
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5307
5388
  TimePicker,
5308
5389
  {
5309
5390
  setDate: handleTimeChange,
@@ -5311,7 +5392,7 @@ function DateTimePicker({
5311
5392
  hideSeconds
5312
5393
  }
5313
5394
  ),
5314
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5395
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5315
5396
  ButtonBase,
5316
5397
  {
5317
5398
  size: "sm",
@@ -5335,7 +5416,7 @@ function DateTimePicker({
5335
5416
  }
5336
5417
 
5337
5418
  // src/components/selects/Select.tsx
5338
- var import_jsx_runtime47 = require("react/jsx-runtime");
5419
+ var import_jsx_runtime48 = require("react/jsx-runtime");
5339
5420
  function Select({
5340
5421
  items,
5341
5422
  groupItems,
@@ -5344,9 +5425,9 @@ function Select({
5344
5425
  errorMessage,
5345
5426
  testIds = {}
5346
5427
  }) {
5347
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { "data-testid": testIds.root ?? "select-root", children: [
5348
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(SelectBase, { onValueChange: onChange, "data-testid": testIds.base ?? "select-base", children: [
5349
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5428
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { "data-testid": testIds.root ?? "select-root", children: [
5429
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(SelectBase, { onValueChange: onChange, "data-testid": testIds.base ?? "select-base", children: [
5430
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5350
5431
  SelectTriggerBase,
5351
5432
  {
5352
5433
  className: cn(
@@ -5354,7 +5435,7 @@ function Select({
5354
5435
  errorMessage && "border-red-500"
5355
5436
  ),
5356
5437
  "data-testid": testIds.trigger ?? "select-trigger",
5357
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5438
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5358
5439
  SelectValueBase,
5359
5440
  {
5360
5441
  placeholder,
@@ -5363,9 +5444,9 @@ function Select({
5363
5444
  )
5364
5445
  }
5365
5446
  ),
5366
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScrollAreaBase, { "data-testid": testIds.scrollarea ?? "select-scrollarea", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(SelectContentBase, { "data-testid": testIds.content ?? "select-content", children: groupItems ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_jsx_runtime47.Fragment, { children: Object.keys(groupItems).map((key) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(SelectGroupBase, { "data-testid": testIds.group ?? "select-group", children: [
5367
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(SelectLabelBase, { "data-testid": testIds.label ?? "select-label", children: key }),
5368
- groupItems[key].map((item) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5447
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ScrollAreaBase, { "data-testid": testIds.scrollarea ?? "select-scrollarea", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SelectContentBase, { "data-testid": testIds.content ?? "select-content", children: groupItems ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_jsx_runtime48.Fragment, { children: Object.keys(groupItems).map((key) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(SelectGroupBase, { "data-testid": testIds.group ?? "select-group", children: [
5448
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SelectLabelBase, { "data-testid": testIds.label ?? "select-label", children: key }),
5449
+ groupItems[key].map((item) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5369
5450
  SelectItemBase,
5370
5451
  {
5371
5452
  value: item.value,
@@ -5374,7 +5455,7 @@ function Select({
5374
5455
  },
5375
5456
  item.value
5376
5457
  ))
5377
- ] }, key)) }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(SelectGroupBase, { "data-testid": testIds.group ?? "select-group", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5458
+ ] }, key)) }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SelectGroupBase, { "data-testid": testIds.group ?? "select-group", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5378
5459
  SelectItemBase,
5379
5460
  {
5380
5461
  value: item.value,
@@ -5384,7 +5465,7 @@ function Select({
5384
5465
  item.value
5385
5466
  )) }) }) })
5386
5467
  ] }),
5387
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5468
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5388
5469
  "p",
5389
5470
  {
5390
5471
  className: "text-sm text-red-500",
@@ -5395,131 +5476,202 @@ function Select({
5395
5476
  ] });
5396
5477
  }
5397
5478
 
5398
- // src/components/ui/DestructiveDialog.tsx
5399
- var React32 = __toESM(require("react"));
5400
- var import_react30 = require("@phosphor-icons/react");
5401
- var import_jsx_runtime48 = require("react/jsx-runtime");
5402
- var DestructiveDialog = ({
5403
- title,
5404
- description,
5405
- onConfirm,
5406
- onCancel,
5407
- children,
5408
- triggerContent
5409
- }) => {
5410
- const titleId = "destructive-dialog-title";
5411
- const descriptionId = "destructive-dialog-description";
5412
- const triggerEl = React32.isValidElement(children) ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AlertDialogTriggerBase, { asChild: true, children }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AlertDialogTriggerBase, { children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ButtonBase, { variant: "destructive", children: triggerContent ?? "Excluir" }) });
5413
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(AlertDialogBase, { children: [
5414
- triggerEl,
5415
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
5416
- AlertDialogContentBase,
5417
- {
5418
- role: "alertdialog",
5419
- "aria-modal": "true",
5420
- "aria-labelledby": titleId,
5421
- "aria-describedby": descriptionId,
5422
- className: cn("border border-destructive bg-background"),
5423
- children: [
5424
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-start gap-4", children: [
5425
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex items-center justify-center w-10 h-10 rounded-full ring-1 ring-destructive/30", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_react30.XCircleIcon, { className: "w-6 h-6 text-destructive" }) }),
5426
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex-1", children: [
5427
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5428
- AlertDialogTitleBase,
5429
- {
5430
- id: titleId,
5431
- className: "text-lg sm:text-xl font-semibold text-destructive",
5432
- children: title
5433
- }
5434
- ),
5435
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5436
- AlertDialogDescriptionBase,
5437
- {
5438
- id: descriptionId,
5439
- className: "mt-2 text-sm text-muted-foreground",
5440
- children: description
5441
- }
5442
- )
5443
- ] })
5444
- ] }),
5445
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(AlertDialogFooterBase, { className: "mt-2 flex justify-end gap-3", children: [
5446
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5447
- AlertDialogCancelBase,
5448
- {
5449
- onClick: onCancel,
5450
- className: cn(
5451
- buttonVariantsBase({ variant: "outline", size: "default" }),
5452
- "hover:bg-foreground/5 hover:text-primary hover:opacity-90 hover:shadow-none"
5453
- ),
5454
- children: "Cancelar"
5455
- }
5456
- ),
5457
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5458
- AlertDialogActionBase,
5459
- {
5460
- onClick: onConfirm,
5461
- className: cn(
5462
- buttonVariantsBase({ variant: "destructive", size: "default" })
5463
- ),
5464
- children: "Confirmar"
5465
- }
5466
- )
5467
- ] })
5468
- ]
5469
- }
5470
- )
5471
- ] });
5472
- };
5479
+ // src/components/charts/Chart.tsx
5480
+ var import_react35 = require("react");
5481
+ var import_recharts = require("recharts");
5473
5482
 
5474
- // src/components/charts/components/controls/PeriodsDropdown.tsx
5475
- var import_react31 = require("react");
5476
- var import_framer_motion8 = require("framer-motion");
5477
- var import_ssr = require("@phosphor-icons/react/dist/ssr");
5478
- var import_ssr2 = require("@phosphor-icons/react/dist/ssr");
5479
- var import_jsx_runtime49 = require("react/jsx-runtime");
5480
- var menuVariants = {
5481
- hidden: { opacity: 0, y: -6, scale: 0.98 },
5482
- visible: { opacity: 1, y: 0, scale: 1 },
5483
- exit: { opacity: 0, y: -6, scale: 0.98 }
5483
+ // src/components/charts/utils/helpers.ts
5484
+ var formatFieldName = (fieldName) => {
5485
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
5484
5486
  };
5485
- var itemVariants = {
5486
- hidden: { opacity: 0, x: -6 },
5487
- visible: { opacity: 1, x: 0 }
5487
+ var detectDataFields = (data, xAxisKey) => {
5488
+ if (!data || data.length === 0) return [];
5489
+ const firstItem = data[0];
5490
+ return Object.keys(firstItem).filter(
5491
+ (key) => key !== xAxisKey && typeof firstItem[key] === "number"
5492
+ );
5488
5493
  };
5489
- function PeriodsDropdown({
5490
- processedData,
5491
- onOpenPeriod,
5492
- rightOffset,
5493
- topOffset,
5494
- activePeriod,
5495
- activePeriods
5496
- }) {
5497
- const periods = processedData.map((d) => String(d.name));
5498
- const [open, setOpen] = (0, import_react31.useState)(false);
5499
- const wrapperRef = (0, import_react31.useRef)(null);
5500
- const firstItemRef = (0, import_react31.useRef)(null);
5501
- const listRef = (0, import_react31.useRef)(null);
5502
- (0, import_react31.useEffect)(() => {
5503
- const handleClickOutside = (e) => {
5504
- if (!wrapperRef.current) return;
5505
- if (!wrapperRef.current.contains(e.target)) setOpen(false);
5506
- };
5507
- const handleEscape = (e) => {
5508
- if (e.key === "Escape") setOpen(false);
5494
+ var detectXAxis = (data) => {
5495
+ if (!data || data.length === 0) return "name";
5496
+ const firstItem = data[0];
5497
+ const stringFields = Object.keys(firstItem).filter(
5498
+ (key) => typeof firstItem[key] === "string" || typeof firstItem[key] === "number" && String(firstItem[key]).length <= 4
5499
+ );
5500
+ return stringFields[0] || Object.keys(firstItem)[0] || "name";
5501
+ };
5502
+ var generateAdditionalColors = (baseColors, count) => {
5503
+ const hexToRgb = (hex) => {
5504
+ const clean = hex.replace("#", "");
5505
+ const bigint = parseInt(
5506
+ clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean,
5507
+ 16
5508
+ );
5509
+ return { r: bigint >> 16 & 255, g: bigint >> 8 & 255, b: bigint & 255 };
5510
+ };
5511
+ const rgbToHsl = ({ r, g, b }) => {
5512
+ r /= 255;
5513
+ g /= 255;
5514
+ b /= 255;
5515
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
5516
+ let h = 0;
5517
+ let s = 0;
5518
+ const l = (max + min) / 2;
5519
+ if (max !== min) {
5520
+ const d = max - min;
5521
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
5522
+ switch (max) {
5523
+ case r:
5524
+ h = (g - b) / d + (g < b ? 6 : 0);
5525
+ break;
5526
+ case g:
5527
+ h = (b - r) / d + 2;
5528
+ break;
5529
+ case b:
5530
+ h = (r - g) / d + 4;
5531
+ break;
5532
+ }
5533
+ h /= 6;
5534
+ }
5535
+ return {
5536
+ h: Math.round(h * 360),
5537
+ s: Math.round(s * 100),
5538
+ l: Math.round(l * 100)
5509
5539
  };
5510
- document.addEventListener("mousedown", handleClickOutside);
5511
- document.addEventListener("keydown", handleEscape);
5512
- return () => {
5513
- document.removeEventListener("mousedown", handleClickOutside);
5514
- document.removeEventListener("keydown", handleEscape);
5540
+ };
5541
+ const hslToHex = (h, s, l) => {
5542
+ s /= 100;
5543
+ l /= 100;
5544
+ const k = (n) => (n + h / 30) % 5;
5545
+ const a = s * Math.min(l, 1 - l);
5546
+ const f = (n) => {
5547
+ const color = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
5548
+ return Math.round(255 * color).toString(16).padStart(2, "0");
5515
5549
  };
5516
- }, []);
5517
- (0, import_react31.useEffect)(() => {
5518
- if (open && firstItemRef.current) {
5519
- firstItemRef.current.focus();
5520
- }
5521
- }, [open]);
5522
- function handleSelect(p) {
5550
+ return `#${f(0)}${f(8)}${f(4)}`;
5551
+ };
5552
+ const anchors = baseColors.map((c) => rgbToHsl(hexToRgb(c)));
5553
+ const colors2 = [...baseColors];
5554
+ let i = 0;
5555
+ while (colors2.length < count) {
5556
+ const anchor = anchors[i % anchors.length];
5557
+ const step = Math.floor(i / anchors.length + 1);
5558
+ const hueOffset = step * 25 * (i % 2 === 0 ? 1 : -1);
5559
+ const satOffset = i % 3 === 0 ? -6 : 6;
5560
+ const lightOffset = i % 4 === 0 ? 6 : -4;
5561
+ const newH = (anchor.h + hueOffset + 360) % 360;
5562
+ const newS = Math.max(30, Math.min(95, anchor.s + satOffset));
5563
+ const newL = Math.max(25, Math.min(45, anchor.l + lightOffset));
5564
+ colors2.push(hslToHex(newH, newS, newL));
5565
+ i += 1;
5566
+ }
5567
+ return colors2.slice(0, count);
5568
+ };
5569
+ var niceCeil = (value) => {
5570
+ if (!isFinite(value) || value <= 0) return 1;
5571
+ const pow = Math.pow(10, Math.floor(Math.log10(value)));
5572
+ const normalized = value / pow;
5573
+ const multipliers = [
5574
+ 1,
5575
+ 1.25,
5576
+ 1.5,
5577
+ 2,
5578
+ 2.5,
5579
+ 3,
5580
+ 4,
5581
+ 5,
5582
+ 7.5,
5583
+ 10,
5584
+ 15,
5585
+ 20,
5586
+ 25,
5587
+ 50,
5588
+ 100
5589
+ ];
5590
+ for (const m of multipliers) {
5591
+ if (m >= normalized) return Math.ceil(m * pow);
5592
+ }
5593
+ return Math.ceil(100 * pow);
5594
+ };
5595
+ var compactTick = (value) => {
5596
+ if (value >= 1e9)
5597
+ return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
5598
+ if (value >= 1e6)
5599
+ return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
5600
+ if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
5601
+ return String(value);
5602
+ };
5603
+ var resolveContainerPaddingLeft = (padding, containerPaddingLeft, defaultLeft = 16) => {
5604
+ if (typeof padding === "number") return padding;
5605
+ if (padding && typeof padding === "object" && padding.left != null)
5606
+ return padding.left;
5607
+ if (typeof containerPaddingLeft === "number") return containerPaddingLeft;
5608
+ return defaultLeft;
5609
+ };
5610
+ var resolveChartMargins = (margins, chartMargins, showLabels) => {
5611
+ const defaultRight = 30;
5612
+ const defaultLeft = 20;
5613
+ const topDefault = showLabels ? 48 : 20;
5614
+ const bottomDefault = 5;
5615
+ return {
5616
+ top: margins?.top ?? chartMargins?.top ?? topDefault,
5617
+ right: margins?.right ?? chartMargins?.right ?? defaultRight,
5618
+ left: margins?.left ?? chartMargins?.left ?? defaultLeft,
5619
+ bottom: margins?.bottom ?? chartMargins?.bottom ?? bottomDefault
5620
+ };
5621
+ };
5622
+
5623
+ // src/components/charts/Chart.tsx
5624
+ var import_sonner2 = require("sonner");
5625
+
5626
+ // src/components/charts/components/controls/PeriodsDropdown.tsx
5627
+ var import_react31 = require("react");
5628
+ var import_framer_motion8 = require("framer-motion");
5629
+ var import_ssr = require("@phosphor-icons/react/dist/ssr");
5630
+ var import_ssr2 = require("@phosphor-icons/react/dist/ssr");
5631
+ var import_jsx_runtime49 = require("react/jsx-runtime");
5632
+ var menuVariants = {
5633
+ hidden: { opacity: 0, y: -6, scale: 0.98 },
5634
+ visible: { opacity: 1, y: 0, scale: 1 },
5635
+ exit: { opacity: 0, y: -6, scale: 0.98 }
5636
+ };
5637
+ var itemVariants = {
5638
+ hidden: { opacity: 0, x: -6 },
5639
+ visible: { opacity: 1, x: 0 }
5640
+ };
5641
+ function PeriodsDropdown({
5642
+ processedData,
5643
+ onOpenPeriod,
5644
+ rightOffset,
5645
+ topOffset,
5646
+ activePeriod,
5647
+ activePeriods
5648
+ }) {
5649
+ const periods = processedData.map((d) => String(d.name));
5650
+ const [open, setOpen] = (0, import_react31.useState)(false);
5651
+ const wrapperRef = (0, import_react31.useRef)(null);
5652
+ const firstItemRef = (0, import_react31.useRef)(null);
5653
+ const listRef = (0, import_react31.useRef)(null);
5654
+ (0, import_react31.useEffect)(() => {
5655
+ const handleClickOutside = (e) => {
5656
+ if (!wrapperRef.current) return;
5657
+ if (!wrapperRef.current.contains(e.target)) setOpen(false);
5658
+ };
5659
+ const handleEscape = (e) => {
5660
+ if (e.key === "Escape") setOpen(false);
5661
+ };
5662
+ document.addEventListener("mousedown", handleClickOutside);
5663
+ document.addEventListener("keydown", handleEscape);
5664
+ return () => {
5665
+ document.removeEventListener("mousedown", handleClickOutside);
5666
+ document.removeEventListener("keydown", handleEscape);
5667
+ };
5668
+ }, []);
5669
+ (0, import_react31.useEffect)(() => {
5670
+ if (open && firstItemRef.current) {
5671
+ firstItemRef.current.focus();
5672
+ }
5673
+ }, [open]);
5674
+ function handleSelect(p) {
5523
5675
  onOpenPeriod(p);
5524
5676
  setOpen(false);
5525
5677
  }
@@ -6594,269 +6746,2217 @@ var TooltipSimple = ({
6594
6746
  };
6595
6747
  var TooltipSimple_default = TooltipSimple;
6596
6748
 
6597
- // src/components/charts/utils/helpers.ts
6598
- var formatFieldName = (fieldName) => {
6599
- return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
6600
- };
6601
- var detectDataFields = (data, xAxisKey) => {
6602
- if (!data || data.length === 0) return [];
6603
- const firstItem = data[0];
6604
- return Object.keys(firstItem).filter(
6605
- (key) => key !== xAxisKey && typeof firstItem[key] === "number"
6606
- );
6749
+ // src/components/charts/utils/pillLabelRenderer.tsx
6750
+ var import_jsx_runtime56 = require("react/jsx-runtime");
6751
+ var formatCompactNumber = (value) => {
6752
+ const isNegative = value < 0;
6753
+ const absValue = Math.abs(value);
6754
+ let formatted;
6755
+ if (absValue >= 1e9) {
6756
+ formatted = (absValue / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
6757
+ } else if (absValue >= 1e6) {
6758
+ formatted = (absValue / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
6759
+ } else if (absValue >= 1e3) {
6760
+ formatted = (absValue / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
6761
+ } else {
6762
+ formatted = absValue.toString();
6763
+ }
6764
+ return isNegative ? `-${formatted}` : formatted;
6607
6765
  };
6608
- var detectXAxis = (data) => {
6609
- if (!data || data.length === 0) return "name";
6610
- const firstItem = data[0];
6611
- const stringFields = Object.keys(firstItem).filter(
6612
- (key) => typeof firstItem[key] === "string" || typeof firstItem[key] === "number" && String(firstItem[key]).length <= 4
6613
- );
6614
- return stringFields[0] || Object.keys(firstItem)[0] || "name";
6766
+ var parseNumber = (v) => {
6767
+ if (typeof v === "number") return v;
6768
+ if (typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v)))
6769
+ return Number(v);
6770
+ return void 0;
6615
6771
  };
6616
- var generateAdditionalColors = (baseColors, count) => {
6617
- const hexToRgb = (hex) => {
6618
- const clean = hex.replace("#", "");
6619
- const bigint = parseInt(
6620
- clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean,
6621
- 16
6772
+ var renderPillLabel = (color, variant) => {
6773
+ return (props) => {
6774
+ const { x, y, value } = props;
6775
+ const text = typeof value === "number" ? formatCompactNumber(value) : String(value ?? "");
6776
+ const paddingX = 8;
6777
+ const approxCharWidth = 7;
6778
+ const pillWidth = Math.max(
6779
+ 40,
6780
+ String(text).length * approxCharWidth + paddingX * 2
6622
6781
  );
6623
- return { r: bigint >> 16 & 255, g: bigint >> 8 & 255, b: bigint & 255 };
6624
- };
6625
- const rgbToHsl = ({ r, g, b }) => {
6626
- r /= 255;
6627
- g /= 255;
6628
- b /= 255;
6629
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
6630
- let h = 0;
6631
- let s = 0;
6632
- const l = (max + min) / 2;
6633
- if (max !== min) {
6634
- const d = max - min;
6635
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
6636
- switch (max) {
6637
- case r:
6638
- h = (g - b) / d + (g < b ? 6 : 0);
6639
- break;
6640
- case g:
6641
- h = (b - r) / d + 2;
6642
- break;
6643
- case b:
6644
- h = (r - g) / d + 4;
6645
- break;
6782
+ const pillHeight = 20;
6783
+ const xNum = parseNumber(x);
6784
+ const px = parseNumber(props.x);
6785
+ const pWidth = parseNumber(props.width);
6786
+ const vb = props.viewBox;
6787
+ const cxNum = parseNumber(props.cx);
6788
+ let centerX;
6789
+ if (typeof px === "number" && typeof pWidth === "number") {
6790
+ centerX = px + pWidth / 2;
6791
+ } else if (typeof xNum === "number" && typeof pWidth === "number") {
6792
+ centerX = xNum + pWidth / 2;
6793
+ } else if (typeof cxNum === "number") {
6794
+ centerX = cxNum;
6795
+ } else if (vb && typeof vb.x === "number" && typeof vb.width === "number" && typeof props.index === "number") {
6796
+ const approxCols = Math.max(1, props.index + 1);
6797
+ const colWidth = vb.width / approxCols;
6798
+ centerX = vb.x + colWidth * (props.index + 0.5);
6799
+ } else if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
6800
+ centerX = vb.x + vb.width / 2;
6801
+ } else {
6802
+ centerX = typeof props.index === "number" ? props.index * 40 + 24 : 0;
6803
+ }
6804
+ if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
6805
+ const minX = vb.x + 0 + pillWidth / 22;
6806
+ const maxX = vb.x + vb.width - 2 - pillWidth / 2;
6807
+ centerX = Math.max(minX, Math.min(maxX, centerX));
6808
+ }
6809
+ const yNum = parseNumber(y);
6810
+ const py = parseNumber(props.y);
6811
+ const cyNum = parseNumber(props.cy);
6812
+ 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);
6813
+ const rectX = centerX - pillWidth / 2;
6814
+ const rectY = centerY - pillHeight - 6;
6815
+ const textX = centerX;
6816
+ const textY = rectY + pillHeight / 2 + 3;
6817
+ const rectFill = variant === "filled" ? color : variant === "soft" ? `${color}20` : "#ffffff";
6818
+ const rectStroke = variant === "outline" ? `${color}CC` : void 0;
6819
+ const numValue = parseNumber(value);
6820
+ const isNegative = typeof numValue === "number" && numValue < 0;
6821
+ let textColor;
6822
+ if (isNegative) {
6823
+ textColor = "#dc2626";
6824
+ } else {
6825
+ if (variant === "filled") {
6826
+ textColor = "#ffffff";
6827
+ } else {
6828
+ textColor = "#374151";
6646
6829
  }
6647
- h /= 6;
6648
6830
  }
6649
- return {
6650
- h: Math.round(h * 360),
6651
- s: Math.round(s * 100),
6652
- l: Math.round(l * 100)
6653
- };
6654
- };
6655
- const hslToHex = (h, s, l) => {
6656
- s /= 100;
6657
- l /= 100;
6658
- const k = (n) => (n + h / 30) % 5;
6659
- const a = s * Math.min(l, 1 - l);
6660
- const f = (n) => {
6661
- const color = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
6662
- return Math.round(255 * color).toString(16).padStart(2, "0");
6831
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("g", { children: [
6832
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6833
+ "rect",
6834
+ {
6835
+ x: rectX,
6836
+ y: rectY,
6837
+ rx: pillHeight / 2,
6838
+ width: pillWidth,
6839
+ height: pillHeight,
6840
+ fill: rectFill,
6841
+ stroke: rectStroke,
6842
+ strokeWidth: rectStroke ? 1 : 0
6843
+ }
6844
+ ),
6845
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6846
+ "text",
6847
+ {
6848
+ x: textX,
6849
+ y: textY - 3,
6850
+ fill: textColor,
6851
+ fontSize: 13,
6852
+ fontWeight: 700,
6853
+ textAnchor: "middle",
6854
+ dominantBaseline: "central",
6855
+ letterSpacing: 0.2,
6856
+ children: text
6857
+ }
6858
+ )
6859
+ ] });
6860
+ };
6861
+ };
6862
+ var pillLabelRenderer_default = renderPillLabel;
6863
+
6864
+ // src/components/charts/Chart.tsx
6865
+ var import_jsx_runtime57 = require("react/jsx-runtime");
6866
+ var DEFAULT_COLORS = ["#55af7d", "#8e68ff", "#2273e1"];
6867
+ var Chart = ({
6868
+ data,
6869
+ series,
6870
+ className,
6871
+ height = 350,
6872
+ width = "100%",
6873
+ colors: colors2 = DEFAULT_COLORS,
6874
+ gridColor,
6875
+ showGrid = true,
6876
+ showTooltip = true,
6877
+ showLegend = true,
6878
+ title,
6879
+ titlePosition = "left",
6880
+ showLabels = false,
6881
+ xAxis,
6882
+ labelMap,
6883
+ enableHighlights = false,
6884
+ enableShowOnly = false,
6885
+ enablePeriodsDropdown = false,
6886
+ enableDraggableTooltips = false,
6887
+ showTooltipTotal = false,
6888
+ maxTooltips = 5,
6889
+ chartMargin
6890
+ }) => {
6891
+ const smartConfig = (0, import_react35.useMemo)(() => {
6892
+ const resolvedXAxisKey = typeof xAxis === "string" ? xAxis : xAxis && xAxis.dataKey || detectXAxis(data);
6893
+ const xAxisConfig2 = typeof xAxis === "string" ? {
6894
+ dataKey: resolvedXAxisKey,
6895
+ label: formatFieldName(resolvedXAxisKey),
6896
+ autoLabel: true
6897
+ } : {
6898
+ dataKey: resolvedXAxisKey,
6899
+ label: xAxis?.label ?? formatFieldName(resolvedXAxisKey),
6900
+ formatter: xAxis?.formatter,
6901
+ autoLabel: xAxis?.autoLabel ?? true
6902
+ };
6903
+ const detectedFields = detectDataFields(data, xAxisConfig2.dataKey);
6904
+ const mapperConfig2 = detectedFields.reduce((acc, field) => {
6905
+ acc[field] = {
6906
+ label: labelMap?.[field] ?? formatFieldName(field),
6907
+ type: "number",
6908
+ visible: true
6909
+ };
6910
+ return acc;
6911
+ }, {});
6912
+ return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
6913
+ }, [data, xAxis, labelMap]);
6914
+ const { xAxisConfig, mapperConfig } = smartConfig;
6915
+ const [activeTooltips, setActiveTooltips] = (0, import_react35.useState)([]);
6916
+ const [highlightedSeries, setHighlightedSeries] = (0, import_react35.useState)(
6917
+ /* @__PURE__ */ new Set()
6918
+ );
6919
+ const [showOnlyHighlighted, setShowOnlyHighlighted] = (0, import_react35.useState)(false);
6920
+ (0, import_react35.useEffect)(() => {
6921
+ if (highlightedSeries.size === 0 && showOnlyHighlighted) {
6922
+ setShowOnlyHighlighted(false);
6923
+ }
6924
+ }, [highlightedSeries, showOnlyHighlighted]);
6925
+ const processedData = data.map((item) => ({
6926
+ ...item,
6927
+ name: String(item[xAxisConfig.dataKey] || "N/A")
6928
+ }));
6929
+ const wrapperRef = (0, import_react35.useRef)(null);
6930
+ const [measuredWidth, setMeasuredWidth] = (0, import_react35.useState)(null);
6931
+ (0, import_react35.useLayoutEffect)(() => {
6932
+ const el = wrapperRef.current;
6933
+ if (!el) return;
6934
+ const ro = new ResizeObserver((entries) => {
6935
+ const r = entries[0];
6936
+ if (r && typeof r.contentRect.width === "number") {
6937
+ setMeasuredWidth(Math.round(r.contentRect.width));
6938
+ }
6939
+ });
6940
+ ro.observe(el);
6941
+ setMeasuredWidth(Math.round(el.getBoundingClientRect().width));
6942
+ return () => ro.disconnect();
6943
+ }, []);
6944
+ const seriesOrder = [];
6945
+ if (series) {
6946
+ if (series.bar)
6947
+ series.bar.forEach((k) => seriesOrder.push({ type: "bar", key: k }));
6948
+ if (series.line)
6949
+ series.line.forEach((k) => seriesOrder.push({ type: "line", key: k }));
6950
+ if (series.area)
6951
+ series.area.forEach((k) => seriesOrder.push({ type: "area", key: k }));
6952
+ } else {
6953
+ Object.keys(mapperConfig).forEach(
6954
+ (k) => seriesOrder.push({ type: "bar", key: k })
6955
+ );
6956
+ }
6957
+ const allKeys = seriesOrder.map((s) => s.key).filter(Boolean);
6958
+ const generateColors = (0, import_react35.useCallback)(
6959
+ (dataKeys) => {
6960
+ const colorMap = {};
6961
+ const allColors = generateAdditionalColors(colors2, dataKeys.length);
6962
+ dataKeys.forEach((key, index) => {
6963
+ colorMap[key] = mapperConfig[key]?.color || allColors[index] || colors2[index % colors2.length];
6964
+ });
6965
+ return colorMap;
6966
+ },
6967
+ [colors2, mapperConfig]
6968
+ );
6969
+ const finalColors = (0, import_react35.useMemo)(
6970
+ () => generateColors(allKeys),
6971
+ [generateColors, allKeys]
6972
+ );
6973
+ const adaptDataForTooltip = (0, import_react35.useCallback)(
6974
+ (universalData) => ({
6975
+ ...universalData,
6976
+ name: String(universalData[xAxisConfig.dataKey] || "N/A")
6977
+ }),
6978
+ [xAxisConfig.dataKey]
6979
+ );
6980
+ const activePeriods = (0, import_react35.useMemo)(
6981
+ () => activeTooltips.map((t) => adaptDataForTooltip(t.data).name),
6982
+ [activeTooltips, adaptDataForTooltip]
6983
+ );
6984
+ (0, import_react35.useEffect)(() => {
6985
+ window.dispatchEvent(new Event("recountTooltips"));
6986
+ }, [activeTooltips.length]);
6987
+ const toggleHighlight = (0, import_react35.useCallback)((key) => {
6988
+ setHighlightedSeries((prev) => {
6989
+ const next = new Set(prev);
6990
+ if (next.has(key)) next.delete(key);
6991
+ else next.add(key);
6992
+ return next;
6993
+ });
6994
+ }, []);
6995
+ const maxDataValue = (0, import_react35.useMemo)(() => {
6996
+ let max = 0;
6997
+ const numericKeys = allKeys;
6998
+ for (const row of processedData) {
6999
+ const r = row;
7000
+ for (const key of numericKeys) {
7001
+ const v = r[key];
7002
+ if (typeof v === "number" && Number.isFinite(v) && v > max) max = v;
7003
+ }
7004
+ }
7005
+ return max;
7006
+ }, [processedData, allKeys]);
7007
+ const minDataValue = (0, import_react35.useMemo)(() => {
7008
+ let min = 0;
7009
+ const numericKeys = allKeys;
7010
+ for (const row of processedData) {
7011
+ const r = row;
7012
+ for (const key of numericKeys) {
7013
+ const v = r[key];
7014
+ if (typeof v === "number" && Number.isFinite(v) && v < min)
7015
+ min = v;
7016
+ }
7017
+ }
7018
+ return min;
7019
+ }, [processedData, allKeys]);
7020
+ const niceMax = (0, import_react35.useMemo)(() => {
7021
+ let padding = 0.08;
7022
+ if (maxDataValue > 1e6) padding = 0.05;
7023
+ if (maxDataValue > 1e7) padding = 0.03;
7024
+ if (maxDataValue === 0) padding = 0.12;
7025
+ const padded = maxDataValue * (1 + padding);
7026
+ return niceCeil(padded);
7027
+ }, [maxDataValue]);
7028
+ const computedWidth = (0, import_react35.useMemo)(() => {
7029
+ if (typeof width === "number") return width;
7030
+ const points = Math.max(1, processedData.length);
7031
+ const barCount = series?.bar?.length ?? 0;
7032
+ const lineCount = series?.line?.length ?? 0;
7033
+ const areaCount = series?.area?.length ?? 0;
7034
+ const basePerPoint = 60;
7035
+ const perBarExtra = barCount > 0 ? Math.max(0, barCount - 1) * 8 : 0;
7036
+ const perOtherExtra = (lineCount + areaCount) * 4;
7037
+ let sizeFactor = 1;
7038
+ if (niceMax > 1e5) sizeFactor = 1.1;
7039
+ if (niceMax > 1e6) sizeFactor = 1.2;
7040
+ if (niceMax > 1e7) sizeFactor = 1.3;
7041
+ const perPoint = Math.round(
7042
+ (basePerPoint + perBarExtra + perOtherExtra) * sizeFactor
7043
+ );
7044
+ const marginExtra = 120;
7045
+ const calculated = points * perPoint + marginExtra;
7046
+ const minWidth = 300;
7047
+ const maxWidth = 1800;
7048
+ return Math.max(minWidth, Math.min(maxWidth, calculated));
7049
+ }, [
7050
+ width,
7051
+ processedData.length,
7052
+ series?.bar?.length,
7053
+ series?.line?.length,
7054
+ series?.area?.length,
7055
+ niceMax
7056
+ ]);
7057
+ const toggleTooltip = (0, import_react35.useCallback)(
7058
+ (tooltipId, data2, basePosition) => {
7059
+ const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
7060
+ if (existingIndex !== -1) {
7061
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
7062
+ } else {
7063
+ if (activeTooltips.length >= maxTooltips) {
7064
+ import_sonner2.toast.warning(
7065
+ `Limite de ${maxTooltips} janelas de informa\xE7\xE3o atingido. A mais antiga ser\xE1 substitu\xEDda.`
7066
+ );
7067
+ }
7068
+ const offsetIndex = activeTooltips.length;
7069
+ const gap = 28;
7070
+ const newTooltip = {
7071
+ id: tooltipId,
7072
+ data: data2,
7073
+ position: {
7074
+ top: basePosition.top + offsetIndex * gap,
7075
+ left: basePosition.left + offsetIndex * gap
7076
+ }
7077
+ };
7078
+ setActiveTooltips((prev) => {
7079
+ const next = [...prev, newTooltip];
7080
+ return next.length > maxTooltips ? next.slice(1) : next;
7081
+ });
7082
+ }
7083
+ },
7084
+ [activeTooltips, maxTooltips]
7085
+ );
7086
+ const handleChartClick = (0, import_react35.useCallback)(
7087
+ (e) => {
7088
+ if (!enableDraggableTooltips) return;
7089
+ const ev = e;
7090
+ if (ev?.activePayload?.length) {
7091
+ const clickedData = ev.activePayload[0].payload;
7092
+ const xAxisValue = clickedData[xAxisConfig.dataKey] || clickedData.name || "N/A";
7093
+ const tooltipId = String(xAxisValue);
7094
+ toggleTooltip(tooltipId, clickedData, {
7095
+ top: (ev.chartY || 100) - 10,
7096
+ left: (ev.chartX || 100) - 100
7097
+ });
7098
+ } else {
7099
+ setActiveTooltips([]);
7100
+ }
7101
+ },
7102
+ [enableDraggableTooltips, xAxisConfig.dataKey, toggleTooltip]
7103
+ );
7104
+ const handleBarClick = (0, import_react35.useCallback)(
7105
+ (data2, index, event) => {
7106
+ if (!enableDraggableTooltips) return;
7107
+ event.stopPropagation();
7108
+ const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
7109
+ const tooltipId = String(xAxisValue);
7110
+ const rect = event.target.getBoundingClientRect();
7111
+ toggleTooltip(tooltipId, data2, {
7112
+ top: Math.max(8, rect.top - 10),
7113
+ left: rect.right + 10
7114
+ });
7115
+ },
7116
+ [enableDraggableTooltips, xAxisConfig.dataKey, toggleTooltip]
7117
+ );
7118
+ const handleSeriesClick = (0, import_react35.useCallback)(
7119
+ (...args) => {
7120
+ if (args.length >= 3) {
7121
+ const [data2, index, event] = args;
7122
+ handleBarClick(data2, index, event);
7123
+ return;
7124
+ }
7125
+ handleChartClick(args[0]);
7126
+ },
7127
+ [handleBarClick, handleChartClick]
7128
+ );
7129
+ const onTooltipPositionChange = (0, import_react35.useCallback)(
7130
+ (id, position) => {
7131
+ setActiveTooltips(
7132
+ (prev) => prev.map((t) => t.id === id ? { ...t, position } : t)
7133
+ );
7134
+ },
7135
+ []
7136
+ );
7137
+ const titleClassName = (0, import_react35.useMemo)(
7138
+ () => "text-xl font-semibold text-foreground mb-3",
7139
+ []
7140
+ );
7141
+ const finalEnableHighlights = enableHighlights;
7142
+ const finalEnableShowOnly = enableShowOnly;
7143
+ const finalEnablePeriodsDropdown = enablePeriodsDropdown && enableDraggableTooltips;
7144
+ const defaultChartRightMargin = 30;
7145
+ const defaultChartLeftMargin = 0;
7146
+ const containerPaddingLeft = 16;
7147
+ const finalChartRightMargin = chartMargin?.right ?? defaultChartRightMargin;
7148
+ const finalChartLeftMargin = chartMargin?.left ?? defaultChartLeftMargin;
7149
+ const finalChartTopMargin = chartMargin?.top ?? (showLabels ? 48 : 20);
7150
+ const finalChartBottomMargin = chartMargin?.bottom ?? 5;
7151
+ const measuredInner = measuredWidth ? Math.max(0, measuredWidth - 32) : void 0;
7152
+ const effectiveChartWidth = typeof width === "number" ? width : measuredInner ?? computedWidth;
7153
+ const chartInnerWidth = effectiveChartWidth - finalChartLeftMargin - finalChartRightMargin;
7154
+ const openTooltipForPeriod = (0, import_react35.useCallback)(
7155
+ (periodName) => {
7156
+ if (!enableDraggableTooltips) return;
7157
+ const row = processedData.find((r) => String(r.name) === periodName);
7158
+ if (!row) return;
7159
+ const tooltipId = String(periodName);
7160
+ const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
7161
+ if (existingIndex !== -1) {
7162
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
7163
+ return;
7164
+ }
7165
+ if (activeTooltips.length >= maxTooltips) {
7166
+ import_sonner2.toast.warning(
7167
+ `Limite de ${maxTooltips} janelas de informa\xE7\xE3o atingido. A mais antiga ser\xE1 substitu\xEDda.`
7168
+ );
7169
+ }
7170
+ const offsetIndex = activeTooltips.length;
7171
+ const availableWidth = typeof width === "number" ? width : measuredInner ?? computedWidth;
7172
+ const gap = 28;
7173
+ const leftGap = 28;
7174
+ const newTooltip = {
7175
+ id: tooltipId,
7176
+ data: row,
7177
+ position: {
7178
+ top: 48 + offsetIndex * gap,
7179
+ left: Math.max(120, availableWidth - 280 - offsetIndex * leftGap)
7180
+ }
7181
+ };
7182
+ setActiveTooltips((prev) => {
7183
+ const next = [...prev, newTooltip];
7184
+ return next.length > maxTooltips ? next.slice(1) : next;
7185
+ });
7186
+ },
7187
+ [
7188
+ enableDraggableTooltips,
7189
+ processedData,
7190
+ activeTooltips,
7191
+ width,
7192
+ measuredInner,
7193
+ computedWidth,
7194
+ maxTooltips
7195
+ ]
7196
+ );
7197
+ if (!data) return null;
7198
+ if (Array.isArray(data) && data.length === 0) {
7199
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7200
+ "div",
7201
+ {
7202
+ className: cn(
7203
+ "rounded-lg bg-card p-4 relative w-full text-muted-foreground"
7204
+ ),
7205
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7206
+ "div",
7207
+ {
7208
+ style: {
7209
+ paddingLeft: `${containerPaddingLeft + finalChartLeftMargin}px`
7210
+ },
7211
+ children: "Sem dados para exibir"
7212
+ }
7213
+ )
7214
+ }
7215
+ );
7216
+ }
7217
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7218
+ "div",
7219
+ {
7220
+ ref: wrapperRef,
7221
+ style: {
7222
+ width: "100%",
7223
+ overflowX: "hidden",
7224
+ overflowY: "hidden",
7225
+ minWidth: 0
7226
+ },
7227
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7228
+ "div",
7229
+ {
7230
+ className: cn("rounded-lg bg-card p-2 relative", className),
7231
+ style: { width: "100%", maxWidth: "100%", minWidth: 0 },
7232
+ children: [
7233
+ title && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7234
+ "div",
7235
+ {
7236
+ style: {
7237
+ paddingLeft: `${containerPaddingLeft + finalChartLeftMargin}px`,
7238
+ width: "100%",
7239
+ maxWidth: `${chartInnerWidth}px`,
7240
+ display: "flex",
7241
+ justifyContent: titlePosition === "center" ? "center" : titlePosition === "right" ? "flex-end" : "flex-start",
7242
+ alignItems: "center",
7243
+ marginTop: 4
7244
+ },
7245
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("h3", { className: titleClassName, children: title })
7246
+ }
7247
+ ),
7248
+ allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly) && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7249
+ "div",
7250
+ {
7251
+ className: "flex items-center w-full",
7252
+ style: {
7253
+ paddingLeft: `${containerPaddingLeft + finalChartLeftMargin}px`,
7254
+ width: "98%",
7255
+ display: "flex",
7256
+ alignItems: "center",
7257
+ gap: "0.5rem"
7258
+ },
7259
+ children: [
7260
+ finalEnableHighlights && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7261
+ Highlights_default,
7262
+ {
7263
+ allKeys,
7264
+ mapperConfig,
7265
+ finalColors,
7266
+ highlightedSeries,
7267
+ toggleHighlight,
7268
+ containerWidth: chartInnerWidth
7269
+ }
7270
+ ),
7271
+ finalEnableShowOnly && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7272
+ ShowOnly_default,
7273
+ {
7274
+ showOnlyHighlighted,
7275
+ setShowOnlyHighlighted,
7276
+ highlightedSeriesSize: highlightedSeries.size,
7277
+ clearHighlights: () => setHighlightedSeries(/* @__PURE__ */ new Set())
7278
+ }
7279
+ ),
7280
+ finalEnablePeriodsDropdown && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7281
+ "div",
7282
+ {
7283
+ style: {
7284
+ marginLeft: "auto",
7285
+ display: "flex",
7286
+ alignItems: "center"
7287
+ },
7288
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7289
+ PeriodsDropdown_default,
7290
+ {
7291
+ processedData,
7292
+ onOpenPeriod: openTooltipForPeriod,
7293
+ rightOffset: finalChartRightMargin,
7294
+ activePeriods
7295
+ }
7296
+ )
7297
+ }
7298
+ )
7299
+ ]
7300
+ }
7301
+ ),
7302
+ !(allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly)) && finalEnablePeriodsDropdown && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7303
+ "div",
7304
+ {
7305
+ style: {
7306
+ paddingLeft: `${containerPaddingLeft + finalChartLeftMargin}px`,
7307
+ paddingRight: `${finalChartRightMargin}px`,
7308
+ width: "100%",
7309
+ maxWidth: `${chartInnerWidth}px`,
7310
+ display: "flex",
7311
+ justifyContent: "flex-end"
7312
+ },
7313
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7314
+ PeriodsDropdown_default,
7315
+ {
7316
+ processedData,
7317
+ onOpenPeriod: openTooltipForPeriod,
7318
+ rightOffset: finalChartRightMargin
7319
+ }
7320
+ )
7321
+ }
7322
+ ),
7323
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
7324
+ import_recharts.ComposedChart,
7325
+ {
7326
+ data: processedData,
7327
+ height,
7328
+ margin: {
7329
+ top: finalChartTopMargin,
7330
+ right: finalChartRightMargin,
7331
+ left: finalChartLeftMargin,
7332
+ bottom: finalChartBottomMargin
7333
+ },
7334
+ onClick: handleChartClick,
7335
+ children: [
7336
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7337
+ import_recharts.CartesianGrid,
7338
+ {
7339
+ strokeDasharray: "3 3",
7340
+ stroke: gridColor || "hsl(var(--muted-foreground))",
7341
+ opacity: 0.5
7342
+ }
7343
+ ),
7344
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7345
+ import_recharts.XAxis,
7346
+ {
7347
+ dataKey: xAxisConfig.dataKey,
7348
+ stroke: "hsl(var(--muted-foreground))",
7349
+ fontSize: 12,
7350
+ tickLine: false,
7351
+ axisLine: false,
7352
+ tickFormatter: xAxisConfig.formatter
7353
+ }
7354
+ ),
7355
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7356
+ import_recharts.YAxis,
7357
+ {
7358
+ stroke: "hsl(var(--muted-foreground))",
7359
+ fontSize: 12,
7360
+ tickLine: false,
7361
+ axisLine: false,
7362
+ tickFormatter: (value) => Number(value).toLocaleString("pt-BR"),
7363
+ domain: [Math.min(minDataValue, 0), niceMax],
7364
+ tickCount: 6
7365
+ }
7366
+ ),
7367
+ minDataValue < 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7368
+ import_recharts.ReferenceLine,
7369
+ {
7370
+ y: 0,
7371
+ stroke: "hsl(var(--muted-foreground))",
7372
+ strokeWidth: 1,
7373
+ strokeDasharray: "4 4"
7374
+ }
7375
+ ),
7376
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7377
+ import_recharts.Tooltip,
7378
+ {
7379
+ content: showTooltipTotal ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TooltipWithTotal_default, { finalColors }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TooltipSimple_default, { finalColors }),
7380
+ cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
7381
+ }
7382
+ ),
7383
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7384
+ import_recharts.Legend,
7385
+ {
7386
+ wrapperStyle: {
7387
+ color: "hsl(var(--foreground))",
7388
+ fontSize: "14px"
7389
+ }
7390
+ }
7391
+ ),
7392
+ seriesOrder.map((s) => {
7393
+ const key = s.key;
7394
+ if (showOnlyHighlighted && !highlightedSeries.has(key))
7395
+ return null;
7396
+ const label = mapperConfig[key]?.label ?? labelMap?.[key] ?? formatFieldName(key);
7397
+ const color = finalColors[key];
7398
+ if (s.type === "bar") {
7399
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7400
+ import_recharts.Bar,
7401
+ {
7402
+ dataKey: key,
7403
+ name: label,
7404
+ fill: color,
7405
+ radius: [4, 4, 0, 0],
7406
+ onClick: handleBarClick,
7407
+ style: {
7408
+ cursor: "pointer",
7409
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
7410
+ },
7411
+ activeBar: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7412
+ import_recharts.Rectangle,
7413
+ {
7414
+ fill: color,
7415
+ stroke: color,
7416
+ strokeWidth: 2,
7417
+ opacity: 0.8
7418
+ }
7419
+ ),
7420
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7421
+ import_recharts.LabelList,
7422
+ {
7423
+ dataKey: key,
7424
+ position: "top",
7425
+ content: pillLabelRenderer_default(color, "filled"),
7426
+ offset: 8
7427
+ }
7428
+ ) : null
7429
+ },
7430
+ `bar-${key}`
7431
+ );
7432
+ }
7433
+ if (s.type === "line") {
7434
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7435
+ import_recharts.Line,
7436
+ {
7437
+ dataKey: key,
7438
+ name: label,
7439
+ stroke: color,
7440
+ strokeWidth: 2,
7441
+ dot: { r: 3 },
7442
+ activeDot: { r: 6 },
7443
+ onClick: handleSeriesClick,
7444
+ style: {
7445
+ cursor: "pointer",
7446
+ pointerEvents: "all",
7447
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
7448
+ },
7449
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7450
+ import_recharts.LabelList,
7451
+ {
7452
+ dataKey: key,
7453
+ position: "top",
7454
+ content: pillLabelRenderer_default(color, "filled"),
7455
+ offset: 14
7456
+ }
7457
+ ) : null
7458
+ },
7459
+ `line-${key}`
7460
+ );
7461
+ }
7462
+ if (s.type === "area") {
7463
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7464
+ import_recharts.Area,
7465
+ {
7466
+ dataKey: key,
7467
+ name: label,
7468
+ stroke: color,
7469
+ fill: color,
7470
+ fillOpacity: 0.35,
7471
+ strokeWidth: 2,
7472
+ onClick: handleSeriesClick,
7473
+ style: {
7474
+ cursor: "pointer",
7475
+ pointerEvents: "all",
7476
+ opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
7477
+ },
7478
+ children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7479
+ import_recharts.LabelList,
7480
+ {
7481
+ dataKey: key,
7482
+ position: "top",
7483
+ content: pillLabelRenderer_default(color, "soft"),
7484
+ offset: 12
7485
+ }
7486
+ ) : null
7487
+ },
7488
+ `area-${key}`
7489
+ );
7490
+ }
7491
+ return null;
7492
+ })
7493
+ ]
7494
+ }
7495
+ ) }),
7496
+ enableDraggableTooltips && activeTooltips.map((tooltip) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7497
+ DraggableTooltip_default,
7498
+ {
7499
+ id: tooltip.id,
7500
+ data: adaptDataForTooltip(tooltip.data),
7501
+ position: tooltip.position,
7502
+ title,
7503
+ dataKeys: allKeys,
7504
+ finalColors,
7505
+ highlightedSeries,
7506
+ toggleHighlight,
7507
+ showOnlyHighlighted,
7508
+ onClose: (id) => setActiveTooltips((prev) => prev.filter((t) => t.id !== id)),
7509
+ onPositionChange: onTooltipPositionChange,
7510
+ periodLabel: "Per\xEDodo Selecionado",
7511
+ dataLabel: "Dados do Per\xEDodo",
7512
+ globalTooltipCount: activeTooltips.length,
7513
+ onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
7514
+ closeAllButtonPosition: "top-center",
7515
+ closeAllButtonVariant: "floating"
7516
+ },
7517
+ tooltip.id
7518
+ )),
7519
+ enableDraggableTooltips && activeTooltips.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
7520
+ CloseAllButton_default,
7521
+ {
7522
+ count: activeTooltips.length,
7523
+ onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
7524
+ position: "top-center",
7525
+ variant: "floating"
7526
+ }
7527
+ )
7528
+ ]
7529
+ }
7530
+ )
7531
+ }
7532
+ );
7533
+ };
7534
+ var Chart_default = Chart;
7535
+
7536
+ // src/components/charts/BarChart.tsx
7537
+ var import_react36 = require("react");
7538
+ var import_recharts2 = require("recharts");
7539
+ var import_jsx_runtime58 = require("react/jsx-runtime");
7540
+ var DEFAULT_COLORS2 = ["#55af7d", "#8e68ff", "#2273e1"];
7541
+ var BarChart = ({
7542
+ data,
7543
+ className,
7544
+ height = 350,
7545
+ width = 900,
7546
+ colors: colors2 = DEFAULT_COLORS2,
7547
+ gridColor,
7548
+ showGrid = true,
7549
+ showTooltip = true,
7550
+ showLegend = true,
7551
+ title,
7552
+ titlePosition = "left",
7553
+ showLabels = false,
7554
+ xAxis,
7555
+ mapper,
7556
+ yAxis,
7557
+ labelMap,
7558
+ autoDetect = false,
7559
+ padding,
7560
+ margins,
7561
+ containerPaddingLeft,
7562
+ chartMargins
7563
+ }) => {
7564
+ const resolvedContainerPaddingLeft = resolveContainerPaddingLeft(
7565
+ padding,
7566
+ containerPaddingLeft,
7567
+ 16
7568
+ );
7569
+ const smartConfig = (0, import_react36.useMemo)(() => {
7570
+ const providedMapper = yAxis ?? mapper;
7571
+ if (autoDetect === true || xAxis == null || providedMapper == null) {
7572
+ const detectedXAxis = detectXAxis(data);
7573
+ const detectedFields = detectDataFields(data, detectedXAxis);
7574
+ return {
7575
+ xAxisConfig: {
7576
+ dataKey: detectedXAxis,
7577
+ label: labelMap?.[detectedXAxis] ?? formatFieldName(detectedXAxis),
7578
+ autoLabel: true
7579
+ },
7580
+ mapperConfig: detectedFields.reduce((acc, field) => {
7581
+ acc[field] = {
7582
+ label: labelMap?.[field] ?? formatFieldName(field),
7583
+ type: "number",
7584
+ visible: true
7585
+ };
7586
+ return acc;
7587
+ }, {})
7588
+ };
7589
+ }
7590
+ const xAxisConfig2 = typeof xAxis === "string" ? { dataKey: xAxis, label: formatFieldName(xAxis), autoLabel: true } : xAxis;
7591
+ let mapperConfig2;
7592
+ if (Array.isArray(providedMapper)) {
7593
+ mapperConfig2 = providedMapper.reduce((acc, field) => {
7594
+ acc[field] = {
7595
+ label: labelMap?.[field] ?? formatFieldName(field),
7596
+ type: "auto",
7597
+ visible: true
7598
+ };
7599
+ return acc;
7600
+ }, {});
7601
+ } else {
7602
+ mapperConfig2 = Object.keys(providedMapper).reduce(
7603
+ (acc, key) => {
7604
+ acc[key] = {
7605
+ label: providedMapper[key]?.label ?? labelMap?.[key] ?? formatFieldName(key),
7606
+ type: "auto",
7607
+ visible: true,
7608
+ ...providedMapper[key]
7609
+ // Sobrescreve com configurações do usuário
7610
+ };
7611
+ return acc;
7612
+ },
7613
+ {}
7614
+ );
7615
+ }
7616
+ return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
7617
+ }, [data, xAxis, mapper, yAxis, autoDetect, labelMap]);
7618
+ const { xAxisConfig, mapperConfig } = smartConfig;
7619
+ const [activeTooltips, setActiveTooltips] = (0, import_react36.useState)([]);
7620
+ const [isDragging, setIsDragging] = (0, import_react36.useState)(null);
7621
+ const [dragOffset, setDragOffset] = (0, import_react36.useState)({
7622
+ x: 0,
7623
+ y: 0
7624
+ });
7625
+ const [globalTooltipCount, setGlobalTooltipCount] = (0, import_react36.useState)(0);
7626
+ const [alignmentGuides, setAlignmentGuides] = (0, import_react36.useState)([]);
7627
+ const processedData = data.map((item) => ({
7628
+ ...item,
7629
+ name: String(item[xAxisConfig.dataKey] || "N/A")
7630
+ // Garantir propriedade 'name' para tooltip
7631
+ }));
7632
+ const generateColors = (dataKeys2) => {
7633
+ const colorMap = {};
7634
+ const allColors = generateAdditionalColors(colors2, dataKeys2.length);
7635
+ dataKeys2.forEach((key, index) => {
7636
+ colorMap[key] = allColors[index] || colors2[index % colors2.length];
7637
+ });
7638
+ return colorMap;
7639
+ };
7640
+ const dataKeys = Object.keys(mapperConfig);
7641
+ const finalColors = generateColors(dataKeys);
7642
+ const adaptDataForTooltip = (universalData) => {
7643
+ return {
7644
+ ...universalData,
7645
+ name: String(universalData[xAxisConfig.dataKey] || "N/A")
7646
+ // Garantir que tem a propriedade 'name'
7647
+ };
7648
+ };
7649
+ const maxDataValue = (0, import_react36.useMemo)(() => {
7650
+ let max = 0;
7651
+ const keys = Object.keys(mapperConfig);
7652
+ for (const row of processedData) {
7653
+ const r = row;
7654
+ for (const key of keys) {
7655
+ const v = r[key];
7656
+ if (typeof v === "number" && Number.isFinite(v) && v > max)
7657
+ max = v;
7658
+ }
7659
+ }
7660
+ return max;
7661
+ }, [processedData, mapperConfig]);
7662
+ const niceMax = (0, import_react36.useMemo)(() => {
7663
+ let padding2 = 0.08;
7664
+ if (maxDataValue > 1e6) padding2 = 0.05;
7665
+ if (maxDataValue > 1e7) padding2 = 0.03;
7666
+ if (maxDataValue === 0) padding2 = 0.12;
7667
+ const padded = maxDataValue * (1 + padding2);
7668
+ return niceCeil(padded);
7669
+ }, [maxDataValue]);
7670
+ const handleBarClick = (data2, index, event) => {
7671
+ event.stopPropagation();
7672
+ const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
7673
+ const tooltipId = `${xAxisValue}`;
7674
+ const rect = event.target.getBoundingClientRect();
7675
+ const existingIndex = activeTooltips.findIndex(
7676
+ (tooltip) => tooltip.id === tooltipId
7677
+ );
7678
+ if (existingIndex !== -1) {
7679
+ setActiveTooltips(
7680
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
7681
+ );
7682
+ } else {
7683
+ const newTooltip = {
7684
+ id: tooltipId,
7685
+ data: data2,
7686
+ position: {
7687
+ top: rect.top - 10,
7688
+ // Posição fixa da viewport
7689
+ left: rect.right + 10
7690
+ // À direita da barra clicada
7691
+ }
7692
+ };
7693
+ setActiveTooltips((prev) => [...prev, newTooltip]);
7694
+ }
7695
+ };
7696
+ const handleChartClick = () => {
7697
+ setActiveTooltips([]);
7698
+ };
7699
+ const ALIGNMENT_THRESHOLD2 = 25;
7700
+ const GUIDE_THRESHOLD2 = 60;
7701
+ const STRONG_SNAP_THRESHOLD2 = 35;
7702
+ const PRECISION_SNAP_THRESHOLD2 = 8;
7703
+ const updateAlignmentGuides = (0, import_react36.useCallback)(
7704
+ (draggedTooltipId, currentPosition) => {
7705
+ if (!isDragging) return;
7706
+ const getAllTooltips = () => {
7707
+ const allTooltips2 = [];
7708
+ allTooltips2.push(...activeTooltips);
7709
+ const globalEvent = new CustomEvent("requestGlobalTooltips", {
7710
+ detail: { requesterId: draggedTooltipId, response: allTooltips2 }
7711
+ });
7712
+ window.dispatchEvent(globalEvent);
7713
+ return allTooltips2;
7714
+ };
7715
+ const allTooltips = getAllTooltips();
7716
+ const otherTooltips = allTooltips.filter(
7717
+ (t) => t.id !== draggedTooltipId
7718
+ );
7719
+ const guides = [];
7720
+ const tooltipDimensions = { width: 224, height: 120 };
7721
+ otherTooltips.forEach((tooltip) => {
7722
+ const topDiff = Math.abs(currentPosition.top - tooltip.position.top);
7723
+ if (topDiff <= GUIDE_THRESHOLD2) {
7724
+ guides.push({
7725
+ type: "horizontal",
7726
+ position: tooltip.position.top,
7727
+ visible: true,
7728
+ sourceTooltip: {
7729
+ top: currentPosition.top,
7730
+ left: currentPosition.left,
7731
+ width: tooltipDimensions.width,
7732
+ height: tooltipDimensions.height
7733
+ },
7734
+ targetTooltip: {
7735
+ top: tooltip.position.top,
7736
+ left: tooltip.position.left,
7737
+ width: tooltipDimensions.width,
7738
+ height: tooltipDimensions.height
7739
+ }
7740
+ });
7741
+ }
7742
+ const leftDiff = Math.abs(currentPosition.left - tooltip.position.left);
7743
+ if (leftDiff <= GUIDE_THRESHOLD2) {
7744
+ guides.push({
7745
+ type: "vertical",
7746
+ position: tooltip.position.left,
7747
+ visible: true,
7748
+ sourceTooltip: {
7749
+ top: currentPosition.top,
7750
+ left: currentPosition.left,
7751
+ width: tooltipDimensions.width,
7752
+ height: tooltipDimensions.height
7753
+ },
7754
+ targetTooltip: {
7755
+ top: tooltip.position.top,
7756
+ left: tooltip.position.left,
7757
+ width: tooltipDimensions.width,
7758
+ height: tooltipDimensions.height
7759
+ }
7760
+ });
7761
+ }
7762
+ });
7763
+ setAlignmentGuides(guides);
7764
+ },
7765
+ [isDragging, activeTooltips]
7766
+ );
7767
+ const snapToGuides = (0, import_react36.useCallback)(
7768
+ (position) => {
7769
+ const snappedPosition = { ...position };
7770
+ let hasSnapped = false;
7771
+ alignmentGuides.forEach((guide) => {
7772
+ if (guide.type === "horizontal") {
7773
+ const diff = Math.abs(position.top - guide.position);
7774
+ if (diff <= PRECISION_SNAP_THRESHOLD2) {
7775
+ snappedPosition.top = guide.position;
7776
+ hasSnapped = true;
7777
+ }
7778
+ } else if (guide.type === "vertical") {
7779
+ const diff = Math.abs(position.left - guide.position);
7780
+ if (diff <= PRECISION_SNAP_THRESHOLD2) {
7781
+ snappedPosition.left = guide.position;
7782
+ hasSnapped = true;
7783
+ }
7784
+ }
7785
+ });
7786
+ if (!hasSnapped) {
7787
+ alignmentGuides.forEach((guide) => {
7788
+ if (guide.type === "horizontal") {
7789
+ const diff = Math.abs(position.top - guide.position);
7790
+ if (diff <= STRONG_SNAP_THRESHOLD2) {
7791
+ snappedPosition.top = guide.position;
7792
+ }
7793
+ } else if (guide.type === "vertical") {
7794
+ const diff = Math.abs(position.left - guide.position);
7795
+ if (diff <= STRONG_SNAP_THRESHOLD2) {
7796
+ snappedPosition.left = guide.position;
7797
+ }
7798
+ }
7799
+ });
7800
+ }
7801
+ alignmentGuides.forEach((guide) => {
7802
+ if (guide.type === "horizontal") {
7803
+ const diff = Math.abs(position.top - guide.position);
7804
+ if (diff <= ALIGNMENT_THRESHOLD2 && snappedPosition.top === position.top) {
7805
+ snappedPosition.top = guide.position;
7806
+ }
7807
+ } else if (guide.type === "vertical") {
7808
+ const diff = Math.abs(position.left - guide.position);
7809
+ if (diff <= ALIGNMENT_THRESHOLD2 && snappedPosition.left === position.left) {
7810
+ snappedPosition.left = guide.position;
7811
+ }
7812
+ }
7813
+ });
7814
+ return snappedPosition;
7815
+ },
7816
+ [alignmentGuides]
7817
+ );
7818
+ const handleMouseDown = (e, tooltipId) => {
7819
+ e.preventDefault();
7820
+ e.stopPropagation();
7821
+ const tooltip = activeTooltips.find((t) => t.id === tooltipId);
7822
+ if (!tooltip) return;
7823
+ const rect = e.currentTarget.getBoundingClientRect();
7824
+ const offsetX = e.clientX - rect.left;
7825
+ const offsetY = e.clientY - rect.top;
7826
+ setIsDragging(tooltipId);
7827
+ setDragOffset({ x: offsetX, y: offsetY });
7828
+ };
7829
+ (0, import_react36.useEffect)(() => {
7830
+ let rafId;
7831
+ let lastMousePosition = { x: 0, y: 0 };
7832
+ const handleGlobalMouseMove = (e) => {
7833
+ if (!isDragging) return;
7834
+ lastMousePosition = { x: e.clientX, y: e.clientY };
7835
+ if (rafId) cancelAnimationFrame(rafId);
7836
+ rafId = requestAnimationFrame(() => {
7837
+ const newLeft = lastMousePosition.x - dragOffset.x;
7838
+ const newTop = lastMousePosition.y - dragOffset.y;
7839
+ const rawPosition = {
7840
+ top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
7841
+ left: Math.max(0, Math.min(newLeft, window.innerWidth - 250))
7842
+ };
7843
+ updateAlignmentGuides(isDragging, rawPosition);
7844
+ const snappedPosition = snapToGuides(rawPosition);
7845
+ setActiveTooltips(
7846
+ (prev) => prev.map((tooltip) => {
7847
+ if (tooltip.id === isDragging) {
7848
+ return {
7849
+ ...tooltip,
7850
+ position: snappedPosition
7851
+ };
7852
+ }
7853
+ return tooltip;
7854
+ })
7855
+ );
7856
+ });
6663
7857
  };
6664
- return `#${f(0)}${f(8)}${f(4)}`;
7858
+ const handleGlobalMouseUp = () => {
7859
+ if (isDragging) {
7860
+ setIsDragging(null);
7861
+ setAlignmentGuides([]);
7862
+ if (rafId) cancelAnimationFrame(rafId);
7863
+ }
7864
+ };
7865
+ if (isDragging) {
7866
+ document.addEventListener("mousemove", handleGlobalMouseMove, {
7867
+ passive: true
7868
+ });
7869
+ document.addEventListener("mouseup", handleGlobalMouseUp);
7870
+ document.body.style.cursor = "grabbing";
7871
+ document.body.style.userSelect = "none";
7872
+ }
7873
+ return () => {
7874
+ if (rafId) cancelAnimationFrame(rafId);
7875
+ document.removeEventListener("mousemove", handleGlobalMouseMove);
7876
+ document.removeEventListener("mouseup", handleGlobalMouseUp);
7877
+ document.body.style.cursor = "";
7878
+ document.body.style.userSelect = "";
7879
+ };
7880
+ }, [
7881
+ isDragging,
7882
+ dragOffset,
7883
+ alignmentGuides,
7884
+ updateAlignmentGuides,
7885
+ snapToGuides
7886
+ ]);
7887
+ (0, import_react36.useEffect)(() => {
7888
+ const handleCloseAllTooltips = () => {
7889
+ setActiveTooltips([]);
7890
+ setGlobalTooltipCount(0);
7891
+ };
7892
+ window.addEventListener("closeAllTooltips", handleCloseAllTooltips);
7893
+ return () => {
7894
+ window.removeEventListener("closeAllTooltips", handleCloseAllTooltips);
7895
+ };
7896
+ }, []);
7897
+ (0, import_react36.useEffect)(() => {
7898
+ const handleTooltipCountRequest = () => {
7899
+ window.dispatchEvent(
7900
+ new CustomEvent("tooltipCountResponse", {
7901
+ detail: { count: activeTooltips.length }
7902
+ })
7903
+ );
7904
+ };
7905
+ const handleGlobalTooltipsRequest = (event) => {
7906
+ const { detail } = event;
7907
+ if (detail && detail.response && detail.requesterId) {
7908
+ activeTooltips.forEach((tooltip) => {
7909
+ if (!detail.response.find(
7910
+ (t) => t.id === tooltip.id
7911
+ )) {
7912
+ detail.response.push({
7913
+ id: tooltip.id,
7914
+ position: tooltip.position
7915
+ });
7916
+ }
7917
+ });
7918
+ }
7919
+ };
7920
+ window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
7921
+ window.addEventListener(
7922
+ "requestGlobalTooltips",
7923
+ handleGlobalTooltipsRequest
7924
+ );
7925
+ return () => {
7926
+ window.removeEventListener(
7927
+ "requestTooltipCount",
7928
+ handleTooltipCountRequest
7929
+ );
7930
+ window.removeEventListener(
7931
+ "requestGlobalTooltips",
7932
+ handleGlobalTooltipsRequest
7933
+ );
7934
+ };
7935
+ }, [activeTooltips]);
7936
+ (0, import_react36.useEffect)(() => {
7937
+ if (isDragging) return;
7938
+ let totalCount = 0;
7939
+ const handleCountResponse = (event) => {
7940
+ const customEvent = event;
7941
+ totalCount += customEvent.detail.count;
7942
+ };
7943
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
7944
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
7945
+ const timeoutId = setTimeout(() => {
7946
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
7947
+ setGlobalTooltipCount(totalCount);
7948
+ }, 5);
7949
+ return () => {
7950
+ clearTimeout(timeoutId);
7951
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
7952
+ };
7953
+ }, [activeTooltips.length, isDragging]);
7954
+ const CustomTooltip = ({
7955
+ active,
7956
+ payload,
7957
+ label
7958
+ }) => {
7959
+ if (!active || !payload) return null;
7960
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "bg-card border border-border rounded-lg p-3 shadow-lg", children: [
7961
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "font-medium text-foreground mb-2", children: label }),
7962
+ payload.map(
7963
+ (entry, index) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex items-center gap-2 text-sm", children: [
7964
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
7965
+ "div",
7966
+ {
7967
+ className: "w-3 h-3 rounded-sm",
7968
+ style: { backgroundColor: entry.color }
7969
+ }
7970
+ ),
7971
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "text-muted-foreground", children: [
7972
+ entry.name,
7973
+ ":"
7974
+ ] }),
7975
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "text-foreground font-medium", children: entry.value?.toLocaleString("pt-BR") })
7976
+ ] }, index)
7977
+ ),
7978
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "text-xs text-muted-foreground mt-1", children: "Clique para fixar este tooltip" })
7979
+ ] });
6665
7980
  };
6666
- const anchors = baseColors.map((c) => rgbToHsl(hexToRgb(c)));
6667
- const colors2 = [...baseColors];
6668
- let i = 0;
6669
- while (colors2.length < count) {
6670
- const anchor = anchors[i % anchors.length];
6671
- const step = Math.floor(i / anchors.length + 1);
6672
- const hueOffset = step * 25 * (i % 2 === 0 ? 1 : -1);
6673
- const satOffset = i % 3 === 0 ? -6 : 6;
6674
- const lightOffset = i % 4 === 0 ? 6 : -4;
6675
- const newH = (anchor.h + hueOffset + 360) % 360;
6676
- const newS = Math.max(30, Math.min(95, anchor.s + satOffset));
6677
- const newL = Math.max(25, Math.min(45, anchor.l + lightOffset));
6678
- colors2.push(hslToHex(newH, newS, newL));
6679
- i += 1;
6680
- }
6681
- return colors2.slice(0, count);
6682
- };
6683
- var niceCeil = (value) => {
6684
- if (!isFinite(value) || value <= 0) return 1;
6685
- const pow = Math.pow(10, Math.floor(Math.log10(value)));
6686
- const normalized = value / pow;
6687
- const multipliers = [
6688
- 1,
6689
- 1.25,
6690
- 1.5,
6691
- 2,
6692
- 2.5,
6693
- 3,
6694
- 4,
6695
- 5,
6696
- 7.5,
6697
- 10,
6698
- 15,
6699
- 20,
6700
- 25,
6701
- 50,
6702
- 100
6703
- ];
6704
- for (const m of multipliers) {
6705
- if (m >= normalized) return Math.ceil(m * pow);
6706
- }
6707
- return Math.ceil(100 * pow);
6708
- };
6709
- var compactTick = (value) => {
6710
- if (value >= 1e9)
6711
- return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
6712
- if (value >= 1e6)
6713
- return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
6714
- if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
6715
- return String(value);
6716
- };
6717
- var resolveContainerPaddingLeft = (padding, containerPaddingLeft, defaultLeft = 16) => {
6718
- if (typeof padding === "number") return padding;
6719
- if (padding && typeof padding === "object" && padding.left != null)
6720
- return padding.left;
6721
- if (typeof containerPaddingLeft === "number") return containerPaddingLeft;
6722
- return defaultLeft;
7981
+ const getTitleClassName = (position) => {
7982
+ const baseClasses = "text-xl font-semibold text-foreground mb-3";
7983
+ switch (position) {
7984
+ case "center":
7985
+ return `${baseClasses} text-center`;
7986
+ case "right":
7987
+ return `${baseClasses} text-right`;
7988
+ default:
7989
+ return `${baseClasses} text-left`;
7990
+ }
7991
+ };
7992
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
7993
+ "div",
7994
+ {
7995
+ className: cn("rounded-lg bg-card p-4 relative", className),
7996
+ style: {
7997
+ width: typeof width === "number" ? `${width + 32}px` : "fit-content",
7998
+ maxWidth: "100%"
7999
+ },
8000
+ children: [
8001
+ title && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { style: { paddingLeft: `${resolvedContainerPaddingLeft}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { className: getTitleClassName(titlePosition), children: title }) }),
8002
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
8003
+ import_recharts2.BarChart,
8004
+ {
8005
+ data: processedData,
8006
+ width: typeof width === "number" ? width : 900,
8007
+ height,
8008
+ margin: resolveChartMargins(margins, chartMargins, showLabels),
8009
+ onClick: handleChartClick,
8010
+ children: [
8011
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8012
+ import_recharts2.CartesianGrid,
8013
+ {
8014
+ strokeDasharray: "3 3",
8015
+ stroke: gridColor || "hsl(var(--muted-foreground))",
8016
+ opacity: 0.5
8017
+ }
8018
+ ),
8019
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8020
+ import_recharts2.XAxis,
8021
+ {
8022
+ dataKey: xAxisConfig.dataKey,
8023
+ stroke: "hsl(var(--muted-foreground))",
8024
+ fontSize: 12,
8025
+ tickLine: false,
8026
+ axisLine: false,
8027
+ tickFormatter: xAxisConfig.formatter
8028
+ }
8029
+ ),
8030
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8031
+ import_recharts2.YAxis,
8032
+ {
8033
+ stroke: "hsl(var(--muted-foreground))",
8034
+ fontSize: 12,
8035
+ tickLine: false,
8036
+ axisLine: false,
8037
+ tickFormatter: (value) => value.toLocaleString("pt-BR"),
8038
+ domain: [0, niceMax],
8039
+ tickCount: 6
8040
+ }
8041
+ ),
8042
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8043
+ import_recharts2.Tooltip,
8044
+ {
8045
+ content: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(CustomTooltip, {}),
8046
+ cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
8047
+ }
8048
+ ),
8049
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8050
+ import_recharts2.Legend,
8051
+ {
8052
+ wrapperStyle: {
8053
+ color: "hsl(var(--foreground))",
8054
+ fontSize: "14px"
8055
+ }
8056
+ }
8057
+ ),
8058
+ dataKeys.map((key) => {
8059
+ const fieldConfig = mapperConfig[key];
8060
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8061
+ import_recharts2.Bar,
8062
+ {
8063
+ dataKey: key,
8064
+ name: fieldConfig?.label || key,
8065
+ fill: fieldConfig?.color || finalColors[key],
8066
+ radius: [4, 4, 0, 0],
8067
+ onClick: handleBarClick,
8068
+ style: { cursor: "pointer" },
8069
+ activeBar: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8070
+ import_recharts2.Rectangle,
8071
+ {
8072
+ fill: finalColors[key],
8073
+ stroke: finalColors[key],
8074
+ strokeWidth: 2,
8075
+ opacity: 0.8
8076
+ }
8077
+ ),
8078
+ children: showLabels && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8079
+ import_recharts2.LabelList,
8080
+ {
8081
+ dataKey: key,
8082
+ position: "top",
8083
+ content: pillLabelRenderer_default(
8084
+ finalColors[key] || "#000",
8085
+ "filled"
8086
+ )
8087
+ }
8088
+ )
8089
+ },
8090
+ key
8091
+ );
8092
+ })
8093
+ ]
8094
+ }
8095
+ ),
8096
+ alignmentGuides.map((guide, index) => {
8097
+ const isHorizontal = guide.type === "horizontal";
8098
+ const color = isHorizontal ? "#3b82f6" : "#ef4444";
8099
+ const startX = isHorizontal ? Math.min(
8100
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
8101
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
8102
+ ) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
8103
+ const endX = isHorizontal ? Math.max(
8104
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
8105
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
8106
+ ) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
8107
+ const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
8108
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
8109
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
8110
+ );
8111
+ const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
8112
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
8113
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
8114
+ );
8115
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
8116
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8117
+ "div",
8118
+ {
8119
+ className: "fixed pointer-events-none z-30",
8120
+ style: {
8121
+ left: startX,
8122
+ top: startY,
8123
+ width: isHorizontal ? endX - startX : "2px",
8124
+ height: isHorizontal ? "2px" : endY - startY,
8125
+ backgroundColor: color,
8126
+ boxShadow: `0 0 8px ${color}60`,
8127
+ opacity: 0.9,
8128
+ borderStyle: "dashed",
8129
+ borderWidth: "1px",
8130
+ borderColor: color,
8131
+ transform: "translateZ(0)"
8132
+ }
8133
+ }
8134
+ ),
8135
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8136
+ "div",
8137
+ {
8138
+ className: "fixed pointer-events-none z-31",
8139
+ style: {
8140
+ left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
8141
+ top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
8142
+ width: "8px",
8143
+ height: "8px",
8144
+ backgroundColor: color,
8145
+ borderRadius: "50%",
8146
+ boxShadow: `0 0 4px ${color}80`,
8147
+ opacity: 0.8
8148
+ }
8149
+ }
8150
+ ),
8151
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8152
+ "div",
8153
+ {
8154
+ className: "fixed pointer-events-none z-31",
8155
+ style: {
8156
+ left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
8157
+ top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
8158
+ width: "8px",
8159
+ height: "8px",
8160
+ backgroundColor: color,
8161
+ borderRadius: "50%",
8162
+ boxShadow: `0 0 4px ${color}80`,
8163
+ opacity: 0.8
8164
+ }
8165
+ }
8166
+ )
8167
+ ] }, index);
8168
+ }),
8169
+ activeTooltips.map((tooltip, index) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
8170
+ DraggableTooltip_default,
8171
+ {
8172
+ id: tooltip.id,
8173
+ data: adaptDataForTooltip(tooltip.data),
8174
+ position: tooltip.position,
8175
+ isDragging: isDragging === tooltip.id,
8176
+ title,
8177
+ dataKeys,
8178
+ finalColors,
8179
+ onMouseDown: (id, e) => handleMouseDown(e, id),
8180
+ onClose: (id) => {
8181
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
8182
+ },
8183
+ periodLabel: "Per\xEDodo Selecionado",
8184
+ dataLabel: "Dados do Per\xEDodo",
8185
+ showCloseAllButton: index === 0,
8186
+ globalTooltipCount,
8187
+ onCloseAll: () => {
8188
+ window.dispatchEvent(new Event("closeAllTooltips"));
8189
+ },
8190
+ closeAllButtonPosition: "top-center",
8191
+ closeAllButtonVariant: "floating"
8192
+ },
8193
+ tooltip.id
8194
+ ))
8195
+ ]
8196
+ }
8197
+ );
6723
8198
  };
6724
- var resolveChartMargins = (margins, chartMargins, showLabels) => {
6725
- const defaultRight = 30;
6726
- const defaultLeft = 20;
6727
- const topDefault = showLabels ? 48 : 20;
6728
- const bottomDefault = 5;
6729
- return {
6730
- top: margins?.top ?? chartMargins?.top ?? topDefault,
6731
- right: margins?.right ?? chartMargins?.right ?? defaultRight,
6732
- left: margins?.left ?? chartMargins?.left ?? defaultLeft,
6733
- bottom: margins?.bottom ?? chartMargins?.bottom ?? bottomDefault
8199
+ var BarChart_default = BarChart;
8200
+
8201
+ // src/components/charts/LineChart.tsx
8202
+ var import_react37 = require("react");
8203
+ var import_recharts3 = require("recharts");
8204
+ var import_jsx_runtime59 = require("react/jsx-runtime");
8205
+ var defaultData = [
8206
+ { name: "A", value: 100 },
8207
+ { name: "B", value: 200 },
8208
+ { name: "C", value: 150 }
8209
+ ];
8210
+ var DEFAULT_COLORS3 = ["#55af7d", "#8e68ff", "#2273e1"];
8211
+ var CustomLineChart = ({
8212
+ data = defaultData,
8213
+ className,
8214
+ height = 300,
8215
+ width = "100%",
8216
+ colors: colors2 = DEFAULT_COLORS3,
8217
+ gridColor,
8218
+ showGrid = true,
8219
+ showTooltip = true,
8220
+ showLegend = true,
8221
+ title,
8222
+ titlePosition = "left",
8223
+ strokeWidth = 2,
8224
+ showDots = true,
8225
+ showLabels = false,
8226
+ padding,
8227
+ margins,
8228
+ containerPaddingLeft,
8229
+ chartMargins
8230
+ }) => {
8231
+ const resolvedContainerPaddingLeft = resolveContainerPaddingLeft(
8232
+ padding,
8233
+ containerPaddingLeft,
8234
+ 16
8235
+ );
8236
+ const [activeTooltips, setActiveTooltips] = (0, import_react37.useState)([]);
8237
+ const [isDragging, setIsDragging] = (0, import_react37.useState)(null);
8238
+ const [dragOffset, setDragOffset] = (0, import_react37.useState)({
8239
+ x: 0,
8240
+ y: 0
8241
+ });
8242
+ const [globalTooltipCount, setGlobalTooltipCount] = (0, import_react37.useState)(0);
8243
+ const [alignmentGuides, setAlignmentGuides] = (0, import_react37.useState)([]);
8244
+ const generateColors = (dataKeys2) => {
8245
+ const colorMap = {};
8246
+ const allColors = generateAdditionalColors(colors2, dataKeys2.length);
8247
+ dataKeys2.forEach((key, index) => {
8248
+ colorMap[key] = allColors[index] || colors2[index % colors2.length];
8249
+ });
8250
+ return colorMap;
8251
+ };
8252
+ const dataKeys = (0, import_react37.useMemo)(
8253
+ () => data.length > 0 ? Object.keys(data[0]).filter((key) => key !== "name") : [],
8254
+ [data]
8255
+ );
8256
+ const finalColors = generateColors(dataKeys);
8257
+ const maxDataValue = (0, import_react37.useMemo)(() => {
8258
+ let max = 0;
8259
+ for (const row of data) {
8260
+ const r = row;
8261
+ for (const key of dataKeys) {
8262
+ const v = r[key];
8263
+ if (typeof v === "number" && Number.isFinite(v) && v > max)
8264
+ max = v;
8265
+ }
8266
+ }
8267
+ return max;
8268
+ }, [data, dataKeys]);
8269
+ const niceMax = (0, import_react37.useMemo)(() => {
8270
+ let padding2 = 0.08;
8271
+ if (maxDataValue > 1e6) padding2 = 0.05;
8272
+ if (maxDataValue > 1e7) padding2 = 0.03;
8273
+ if (maxDataValue === 0) padding2 = 0.12;
8274
+ const padded = maxDataValue * (1 + padding2);
8275
+ return niceCeil(padded);
8276
+ }, [maxDataValue]);
8277
+ const ClickableDot = (props) => {
8278
+ const { cx, cy, payload, dataKey } = props;
8279
+ const handleDotClick = (e) => {
8280
+ e.stopPropagation();
8281
+ if (!payload || !cx || !cy) return;
8282
+ const tooltipId = `${payload.name}`;
8283
+ const existingIndex = activeTooltips.findIndex(
8284
+ (tooltip) => tooltip.id === tooltipId
8285
+ );
8286
+ if (existingIndex !== -1) {
8287
+ setActiveTooltips(
8288
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
8289
+ );
8290
+ } else {
8291
+ const newTooltip = {
8292
+ id: tooltipId,
8293
+ data: payload,
8294
+ position: {
8295
+ top: cy - 50,
8296
+ // Posição relativa ao SVG
8297
+ left: cx - 100
8298
+ }
8299
+ };
8300
+ setActiveTooltips((prev) => [...prev, newTooltip]);
8301
+ }
8302
+ };
8303
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8304
+ "circle",
8305
+ {
8306
+ cx,
8307
+ cy,
8308
+ r: 6,
8309
+ fill: finalColors[dataKey || ""] || colors2[0],
8310
+ stroke: finalColors[dataKey || ""] || colors2[0],
8311
+ strokeWidth: 2,
8312
+ style: { cursor: "pointer" },
8313
+ onClick: handleDotClick
8314
+ }
8315
+ );
8316
+ };
8317
+ const handleChartClick = (e) => {
8318
+ if (e && e.activePayload && e.activePayload.length > 0) {
8319
+ const clickedData = e.activePayload[0].payload;
8320
+ const tooltipId = `${clickedData.name}`;
8321
+ const existingIndex = activeTooltips.findIndex(
8322
+ (tooltip) => tooltip.id === tooltipId
8323
+ );
8324
+ if (existingIndex !== -1) {
8325
+ setActiveTooltips(
8326
+ (prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
8327
+ );
8328
+ } else {
8329
+ const newTooltip = {
8330
+ id: tooltipId,
8331
+ data: clickedData,
8332
+ position: {
8333
+ top: (e.chartY || 100) - 10,
8334
+ left: (e.chartX || 100) - 100
8335
+ }
8336
+ };
8337
+ setActiveTooltips((prev) => [...prev, newTooltip]);
8338
+ }
8339
+ } else {
8340
+ }
8341
+ };
8342
+ const handleChartBackgroundClick = () => {
8343
+ setActiveTooltips([]);
8344
+ };
8345
+ const handleCloseAllTooltips = (0, import_react37.useCallback)(() => {
8346
+ window.dispatchEvent(new CustomEvent("closeAllTooltips"));
8347
+ }, []);
8348
+ const updateAlignmentGuides = (0, import_react37.useCallback)(
8349
+ (draggedTooltipId, draggedPosition) => {
8350
+ const SNAP_THRESHOLD = 15;
8351
+ const draggedTooltip = activeTooltips.find(
8352
+ (t) => t.id === draggedTooltipId
8353
+ );
8354
+ if (!draggedTooltip) return;
8355
+ const tooltipWidth = 200;
8356
+ const tooltipHeight = 80;
8357
+ const globalTooltips = [];
8358
+ window.dispatchEvent(
8359
+ new CustomEvent("requestGlobalTooltips", {
8360
+ detail: { requesterId: draggedTooltipId }
8361
+ })
8362
+ );
8363
+ activeTooltips.forEach((tooltip) => {
8364
+ if (tooltip.id !== draggedTooltipId) {
8365
+ globalTooltips.push({
8366
+ top: tooltip.position.top,
8367
+ left: tooltip.position.left,
8368
+ width: tooltipWidth,
8369
+ height: tooltipHeight,
8370
+ id: tooltip.id
8371
+ });
8372
+ }
8373
+ });
8374
+ const newGuides = [];
8375
+ globalTooltips.forEach((otherTooltip) => {
8376
+ const draggedCenter = {
8377
+ x: draggedPosition.left + tooltipWidth / 2,
8378
+ y: draggedPosition.top + tooltipHeight / 2
8379
+ };
8380
+ const otherCenter = {
8381
+ x: otherTooltip.left + otherTooltip.width / 2,
8382
+ y: otherTooltip.top + otherTooltip.height / 2
8383
+ };
8384
+ const horizontalDistance = Math.abs(draggedCenter.y - otherCenter.y);
8385
+ if (horizontalDistance <= SNAP_THRESHOLD) {
8386
+ newGuides.push({
8387
+ type: "horizontal",
8388
+ position: otherCenter.y,
8389
+ visible: true,
8390
+ sourceTooltip: {
8391
+ top: draggedPosition.top,
8392
+ left: draggedPosition.left,
8393
+ width: tooltipWidth,
8394
+ height: tooltipHeight
8395
+ },
8396
+ targetTooltip: {
8397
+ top: otherTooltip.top,
8398
+ left: otherTooltip.left,
8399
+ width: otherTooltip.width,
8400
+ height: otherTooltip.height
8401
+ }
8402
+ });
8403
+ }
8404
+ const verticalDistance = Math.abs(draggedCenter.x - otherCenter.x);
8405
+ if (verticalDistance <= SNAP_THRESHOLD) {
8406
+ newGuides.push({
8407
+ type: "vertical",
8408
+ position: otherCenter.x,
8409
+ visible: true,
8410
+ sourceTooltip: {
8411
+ top: draggedPosition.top,
8412
+ left: draggedPosition.left,
8413
+ width: tooltipWidth,
8414
+ height: tooltipHeight
8415
+ },
8416
+ targetTooltip: {
8417
+ top: otherTooltip.top,
8418
+ left: otherTooltip.left,
8419
+ width: otherTooltip.width,
8420
+ height: otherTooltip.height
8421
+ }
8422
+ });
8423
+ }
8424
+ });
8425
+ setAlignmentGuides(newGuides);
8426
+ },
8427
+ [activeTooltips]
8428
+ );
8429
+ const snapToGuides = (0, import_react37.useCallback)(
8430
+ (position) => {
8431
+ const SNAP_DISTANCE = 10;
8432
+ const snappedPosition = { ...position };
8433
+ alignmentGuides.forEach((guide) => {
8434
+ if (guide.type === "horizontal") {
8435
+ const tooltipCenter = position.top + 40;
8436
+ if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
8437
+ snappedPosition.top = guide.position - 40;
8438
+ }
8439
+ } else if (guide.type === "vertical") {
8440
+ const tooltipCenter = position.left + 100;
8441
+ if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
8442
+ snappedPosition.left = guide.position - 100;
8443
+ }
8444
+ }
8445
+ });
8446
+ return snappedPosition;
8447
+ },
8448
+ [alignmentGuides]
8449
+ );
8450
+ const handleMouseDown = (tooltipId, e) => {
8451
+ const rect = e.target.getBoundingClientRect();
8452
+ const offsetX = e.clientX - rect.left;
8453
+ const offsetY = e.clientY - rect.top;
8454
+ setIsDragging(tooltipId);
8455
+ setDragOffset({ x: offsetX, y: offsetY });
8456
+ };
8457
+ (0, import_react37.useEffect)(() => {
8458
+ let rafId;
8459
+ let lastMousePosition = { x: 0, y: 0 };
8460
+ const handleGlobalMouseMove = (e) => {
8461
+ if (!isDragging) return;
8462
+ lastMousePosition = { x: e.clientX, y: e.clientY };
8463
+ if (rafId) cancelAnimationFrame(rafId);
8464
+ rafId = requestAnimationFrame(() => {
8465
+ const newLeft = lastMousePosition.x - dragOffset.x;
8466
+ const newTop = lastMousePosition.y - dragOffset.y;
8467
+ let finalPosition = { top: newTop, left: newLeft };
8468
+ finalPosition = snapToGuides(finalPosition);
8469
+ setActiveTooltips(
8470
+ (prev) => prev.map(
8471
+ (tooltip) => tooltip.id === isDragging ? { ...tooltip, position: finalPosition } : tooltip
8472
+ )
8473
+ );
8474
+ updateAlignmentGuides(isDragging, finalPosition);
8475
+ });
8476
+ };
8477
+ const handleGlobalMouseUp = () => {
8478
+ if (rafId) cancelAnimationFrame(rafId);
8479
+ setIsDragging(null);
8480
+ setAlignmentGuides([]);
8481
+ document.body.style.cursor = "";
8482
+ document.body.style.userSelect = "";
8483
+ };
8484
+ if (isDragging) {
8485
+ document.body.style.cursor = "grabbing";
8486
+ document.body.style.userSelect = "none";
8487
+ window.addEventListener("mousemove", handleGlobalMouseMove);
8488
+ window.addEventListener("mouseup", handleGlobalMouseUp);
8489
+ }
8490
+ return () => {
8491
+ if (rafId) cancelAnimationFrame(rafId);
8492
+ window.removeEventListener("mousemove", handleGlobalMouseMove);
8493
+ window.removeEventListener("mouseup", handleGlobalMouseUp);
8494
+ document.body.style.cursor = "";
8495
+ document.body.style.userSelect = "";
8496
+ };
8497
+ }, [
8498
+ isDragging,
8499
+ dragOffset,
8500
+ alignmentGuides,
8501
+ updateAlignmentGuides,
8502
+ snapToGuides
8503
+ ]);
8504
+ (0, import_react37.useEffect)(() => {
8505
+ const handleCloseAllTooltips2 = () => {
8506
+ setActiveTooltips([]);
8507
+ setGlobalTooltipCount(0);
8508
+ };
8509
+ window.addEventListener("closeAllTooltips", handleCloseAllTooltips2);
8510
+ return () => {
8511
+ window.removeEventListener("closeAllTooltips", handleCloseAllTooltips2);
8512
+ };
8513
+ }, []);
8514
+ (0, import_react37.useEffect)(() => {
8515
+ const handleTooltipCountRequest = () => {
8516
+ window.dispatchEvent(
8517
+ new CustomEvent("tooltipCountResponse", {
8518
+ detail: { count: activeTooltips.length }
8519
+ })
8520
+ );
8521
+ };
8522
+ const handleGlobalTooltipsRequest = (event) => {
8523
+ const requesterId = event.detail?.requesterId;
8524
+ activeTooltips.forEach((tooltip) => {
8525
+ if (tooltip.id !== requesterId) {
8526
+ window.dispatchEvent(
8527
+ new CustomEvent("globalTooltipResponse", {
8528
+ detail: {
8529
+ tooltip: {
8530
+ top: tooltip.position.top,
8531
+ left: tooltip.position.left,
8532
+ width: 200,
8533
+ height: 80,
8534
+ id: tooltip.id
8535
+ }
8536
+ }
8537
+ })
8538
+ );
8539
+ }
8540
+ });
8541
+ };
8542
+ window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
8543
+ window.addEventListener(
8544
+ "requestGlobalTooltips",
8545
+ handleGlobalTooltipsRequest
8546
+ );
8547
+ return () => {
8548
+ window.removeEventListener(
8549
+ "requestTooltipCount",
8550
+ handleTooltipCountRequest
8551
+ );
8552
+ window.removeEventListener(
8553
+ "requestGlobalTooltips",
8554
+ handleGlobalTooltipsRequest
8555
+ );
8556
+ };
8557
+ }, [activeTooltips]);
8558
+ (0, import_react37.useEffect)(() => {
8559
+ if (isDragging) return;
8560
+ let totalCount = 0;
8561
+ const handleCountResponse = (event) => {
8562
+ const customEvent = event;
8563
+ totalCount += customEvent.detail.count;
8564
+ };
8565
+ window.addEventListener("tooltipCountResponse", handleCountResponse);
8566
+ window.dispatchEvent(new CustomEvent("requestTooltipCount"));
8567
+ const timeoutId = setTimeout(() => {
8568
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
8569
+ setGlobalTooltipCount(totalCount);
8570
+ }, 5);
8571
+ return () => {
8572
+ clearTimeout(timeoutId);
8573
+ window.removeEventListener("tooltipCountResponse", handleCountResponse);
8574
+ };
8575
+ }, [activeTooltips.length, isDragging]);
8576
+ const getTitleClass = () => {
8577
+ switch (titlePosition) {
8578
+ case "center":
8579
+ return "text-center";
8580
+ case "right":
8581
+ return "text-right";
8582
+ default:
8583
+ return "text-left";
8584
+ }
6734
8585
  };
8586
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: cn("relative", className), children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
8587
+ "div",
8588
+ {
8589
+ className: "rounded-lg bg-card p-4 relative border border-border",
8590
+ style: {
8591
+ width: typeof width === "number" ? `${width + 32}px` : "fit-content",
8592
+ maxWidth: "100%"
8593
+ },
8594
+ onClick: handleChartBackgroundClick,
8595
+ children: [
8596
+ title && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { style: { paddingLeft: `${resolvedContainerPaddingLeft}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: cn("mb-4", getTitleClass()), children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: title }) }) }),
8597
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
8598
+ import_recharts3.LineChart,
8599
+ {
8600
+ data,
8601
+ width: typeof width === "number" ? width : 900,
8602
+ height,
8603
+ margin: resolveChartMargins(margins, chartMargins, showLabels),
8604
+ onClick: handleChartClick,
8605
+ children: [
8606
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8607
+ import_recharts3.CartesianGrid,
8608
+ {
8609
+ strokeDasharray: "3 3",
8610
+ stroke: gridColor || "hsl(var(--muted-foreground))",
8611
+ opacity: 0.3
8612
+ }
8613
+ ),
8614
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8615
+ import_recharts3.XAxis,
8616
+ {
8617
+ dataKey: "name",
8618
+ className: "fill-muted-foreground text-xs",
8619
+ fontSize: 12
8620
+ }
8621
+ ),
8622
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8623
+ import_recharts3.YAxis,
8624
+ {
8625
+ className: "fill-muted-foreground text-xs",
8626
+ fontSize: 12,
8627
+ tickFormatter: (value) => compactTick(Number(value)),
8628
+ domain: [0, niceMax],
8629
+ tickCount: 6
8630
+ }
8631
+ ),
8632
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(import_recharts3.Tooltip, { content: () => null }),
8633
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8634
+ import_recharts3.Legend,
8635
+ {
8636
+ wrapperStyle: {
8637
+ fontSize: "12px",
8638
+ color: "hsl(var(--muted-foreground))"
8639
+ }
8640
+ }
8641
+ ),
8642
+ dataKeys.map((key) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8643
+ import_recharts3.Line,
8644
+ {
8645
+ type: "monotone",
8646
+ dataKey: key,
8647
+ stroke: finalColors[key],
8648
+ strokeWidth,
8649
+ dot: showDots ? { r: 4, cursor: "pointer" } : false,
8650
+ activeDot: (props) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(ClickableDot, { ...props, dataKey: key }),
8651
+ children: showLabels && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8652
+ import_recharts3.LabelList,
8653
+ {
8654
+ dataKey: key,
8655
+ position: "top",
8656
+ content: pillLabelRenderer_default(
8657
+ finalColors[key] || "#000",
8658
+ "filled"
8659
+ ),
8660
+ offset: 14
8661
+ }
8662
+ )
8663
+ },
8664
+ key
8665
+ ))
8666
+ ]
8667
+ }
8668
+ ),
8669
+ alignmentGuides.map((guide, index) => {
8670
+ const isHorizontal = guide.type === "horizontal";
8671
+ const color = isHorizontal ? "#3b82f6" : "#ef4444";
8672
+ const startX = isHorizontal ? Math.min(
8673
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
8674
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
8675
+ ) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
8676
+ const endX = isHorizontal ? Math.max(
8677
+ guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
8678
+ guide.targetTooltip.left + guide.targetTooltip.width / 2
8679
+ ) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
8680
+ const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
8681
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
8682
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
8683
+ );
8684
+ const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
8685
+ guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
8686
+ guide.targetTooltip.top + guide.targetTooltip.height / 2
8687
+ );
8688
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
8689
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8690
+ "div",
8691
+ {
8692
+ className: "fixed pointer-events-none z-30",
8693
+ style: {
8694
+ left: startX,
8695
+ top: startY,
8696
+ width: isHorizontal ? endX - startX : "2px",
8697
+ height: isHorizontal ? "2px" : endY - startY,
8698
+ backgroundColor: color,
8699
+ boxShadow: `0 0 8px ${color}60`,
8700
+ opacity: 0.9,
8701
+ borderStyle: "dashed",
8702
+ borderWidth: "1px",
8703
+ borderColor: color,
8704
+ transform: "translateZ(0)"
8705
+ }
8706
+ }
8707
+ ),
8708
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8709
+ "div",
8710
+ {
8711
+ className: "fixed pointer-events-none z-31",
8712
+ style: {
8713
+ left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
8714
+ top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
8715
+ width: "8px",
8716
+ height: "8px",
8717
+ backgroundColor: color,
8718
+ borderRadius: "50%",
8719
+ boxShadow: `0 0 4px ${color}80`,
8720
+ opacity: 0.8
8721
+ }
8722
+ }
8723
+ ),
8724
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8725
+ "div",
8726
+ {
8727
+ className: "fixed pointer-events-none z-31",
8728
+ style: {
8729
+ left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
8730
+ top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
8731
+ width: "8px",
8732
+ height: "8px",
8733
+ backgroundColor: color,
8734
+ borderRadius: "50%",
8735
+ boxShadow: `0 0 4px ${color}80`,
8736
+ opacity: 0.8
8737
+ }
8738
+ }
8739
+ )
8740
+ ] }, index);
8741
+ }),
8742
+ activeTooltips.map((tooltip, index) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
8743
+ DraggableTooltip_default,
8744
+ {
8745
+ id: tooltip.id,
8746
+ data: tooltip.data,
8747
+ position: tooltip.position,
8748
+ isDragging: isDragging === tooltip.id,
8749
+ title,
8750
+ dataKeys,
8751
+ finalColors,
8752
+ onMouseDown: (id, e) => handleMouseDown(id, e),
8753
+ onClose: (id) => {
8754
+ setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
8755
+ },
8756
+ periodLabel: "Ponto Selecionado",
8757
+ dataLabel: "Dados do Ponto",
8758
+ showCloseAllButton: index === 0,
8759
+ globalTooltipCount,
8760
+ onCloseAll: handleCloseAllTooltips,
8761
+ closeAllButtonPosition: "top-center",
8762
+ closeAllButtonVariant: "floating"
8763
+ },
8764
+ tooltip.id
8765
+ ))
8766
+ ]
8767
+ }
8768
+ ) });
6735
8769
  };
8770
+ var LineChart_default = CustomLineChart;
6736
8771
 
6737
- // src/components/charts/utils/pillLabelRenderer.tsx
6738
- var import_jsx_runtime56 = require("react/jsx-runtime");
6739
- var formatCompactNumber = (value) => {
6740
- const isNegative = value < 0;
6741
- const absValue = Math.abs(value);
6742
- let formatted;
6743
- if (absValue >= 1e9) {
6744
- formatted = (absValue / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
6745
- } else if (absValue >= 1e6) {
6746
- formatted = (absValue / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
6747
- } else if (absValue >= 1e3) {
6748
- formatted = (absValue / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
6749
- } else {
6750
- formatted = absValue.toString();
6751
- }
6752
- return isNegative ? `-${formatted}` : formatted;
8772
+ // src/components/charts/PieChart.tsx
8773
+ var import_recharts4 = require("recharts");
8774
+ var import_jsx_runtime60 = require("react/jsx-runtime");
8775
+ var defaultData2 = [
8776
+ { name: "Vendas", value: 4e3 },
8777
+ { name: "Marketing", value: 3e3 },
8778
+ { name: "Desenvolvimento", value: 2e3 },
8779
+ { name: "Suporte", value: 1e3 },
8780
+ { name: "Outros", value: 800 }
8781
+ ];
8782
+ var DEFAULT_COLORS4 = [
8783
+ "#55af7d",
8784
+ // verde do projeto
8785
+ "#8e68ff",
8786
+ // roxo do projeto
8787
+ "#2273e1",
8788
+ // azul do projeto
8789
+ "#f59e0b",
8790
+ // amarelo complementar
8791
+ "#ef4444",
8792
+ // vermelho complementar
8793
+ "#8b5cf6",
8794
+ // roxo claro
8795
+ "#06b6d4",
8796
+ // ciano
8797
+ "#84cc16"
8798
+ // verde lima
8799
+ ];
8800
+ var RADIAN = Math.PI / 180;
8801
+ var renderCustomizedLabel = ({
8802
+ cx = 0,
8803
+ cy = 0,
8804
+ midAngle = 0,
8805
+ innerRadius = 0,
8806
+ outerRadius = 0,
8807
+ percent = 0
8808
+ }) => {
8809
+ const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
8810
+ const x = cx + radius * Math.cos(-midAngle * RADIAN);
8811
+ const y = cy + radius * Math.sin(-midAngle * RADIAN);
8812
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8813
+ "text",
8814
+ {
8815
+ x,
8816
+ y,
8817
+ fill: "white",
8818
+ textAnchor: x > cx ? "start" : "end",
8819
+ dominantBaseline: "central",
8820
+ fontSize: 12,
8821
+ fontWeight: "600",
8822
+ children: `${(percent * 100).toFixed(0)}%`
8823
+ }
8824
+ );
6753
8825
  };
6754
- var parseNumber = (v) => {
6755
- if (typeof v === "number") return v;
6756
- if (typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v)))
6757
- return Number(v);
6758
- return void 0;
8826
+ var CustomPieChart = ({
8827
+ data = defaultData2,
8828
+ className,
8829
+ height = 400,
8830
+ width = "100%",
8831
+ colors: colors2,
8832
+ showTooltip = true,
8833
+ showLegend = true,
8834
+ showLabels = true,
8835
+ innerRadius = 0,
8836
+ outerRadius = 120,
8837
+ centerX = "50%",
8838
+ centerY = "50%"
8839
+ }) => {
8840
+ const finalColors = colors2 || DEFAULT_COLORS4;
8841
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: cn("w-full rounded-lg bg-card p-4", className), children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_recharts4.ResponsiveContainer, { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_recharts4.PieChart, { children: [
8842
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8843
+ import_recharts4.Pie,
8844
+ {
8845
+ data,
8846
+ cx: centerX,
8847
+ cy: centerY,
8848
+ labelLine: false,
8849
+ label: showLabels ? renderCustomizedLabel : false,
8850
+ outerRadius,
8851
+ innerRadius,
8852
+ fill: "#8884d8",
8853
+ dataKey: "value",
8854
+ children: data.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8855
+ import_recharts4.Cell,
8856
+ {
8857
+ fill: finalColors[index % finalColors.length]
8858
+ },
8859
+ `cell-${entry.name}-${index}`
8860
+ ))
8861
+ }
8862
+ ),
8863
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8864
+ import_recharts4.Tooltip,
8865
+ {
8866
+ contentStyle: {
8867
+ backgroundColor: "hsl(var(--popover))",
8868
+ border: "1px solid hsl(var(--border))",
8869
+ borderRadius: "6px",
8870
+ color: "hsl(var(--popover-foreground))"
8871
+ }
8872
+ }
8873
+ ),
8874
+ showLegend && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_recharts4.Legend, {})
8875
+ ] }) }) });
6759
8876
  };
6760
- var renderPillLabel = (color, variant) => {
6761
- return (props) => {
6762
- const { x, y, value } = props;
6763
- const text = typeof value === "number" ? formatCompactNumber(value) : String(value ?? "");
6764
- const paddingX = 8;
6765
- const approxCharWidth = 7;
6766
- const pillWidth = Math.max(
6767
- 40,
6768
- String(text).length * approxCharWidth + paddingX * 2
6769
- );
6770
- const pillHeight = 20;
6771
- const xNum = parseNumber(x);
6772
- const px = parseNumber(props.x);
6773
- const pWidth = parseNumber(props.width);
6774
- const vb = props.viewBox;
6775
- const cxNum = parseNumber(props.cx);
6776
- let centerX;
6777
- if (typeof px === "number" && typeof pWidth === "number") {
6778
- centerX = px + pWidth / 2;
6779
- } else if (typeof xNum === "number" && typeof pWidth === "number") {
6780
- centerX = xNum + pWidth / 2;
6781
- } else if (typeof cxNum === "number") {
6782
- centerX = cxNum;
6783
- } else if (vb && typeof vb.x === "number" && typeof vb.width === "number" && typeof props.index === "number") {
6784
- const approxCols = Math.max(1, props.index + 1);
6785
- const colWidth = vb.width / approxCols;
6786
- centerX = vb.x + colWidth * (props.index + 0.5);
6787
- } else if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
6788
- centerX = vb.x + vb.width / 2;
6789
- } else {
6790
- centerX = typeof props.index === "number" ? props.index * 40 + 24 : 0;
6791
- }
6792
- if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
6793
- const minX = vb.x + 0 + pillWidth / 22;
6794
- const maxX = vb.x + vb.width - 2 - pillWidth / 2;
6795
- centerX = Math.max(minX, Math.min(maxX, centerX));
6796
- }
6797
- const yNum = parseNumber(y);
6798
- const py = parseNumber(props.y);
6799
- const cyNum = parseNumber(props.cy);
6800
- 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);
6801
- const rectX = centerX - pillWidth / 2;
6802
- const rectY = centerY - pillHeight - 6;
6803
- const textX = centerX;
6804
- const textY = rectY + pillHeight / 2 + 3;
6805
- const rectFill = variant === "filled" ? color : variant === "soft" ? `${color}20` : "#ffffff";
6806
- const rectStroke = variant === "outline" ? `${color}CC` : void 0;
6807
- const numValue = parseNumber(value);
6808
- const isNegative = typeof numValue === "number" && numValue < 0;
6809
- let textColor;
6810
- if (isNegative) {
6811
- textColor = "#dc2626";
6812
- } else {
6813
- if (variant === "filled") {
6814
- textColor = "#ffffff";
8877
+ var PieChart_default = CustomPieChart;
8878
+
8879
+ // src/components/charts/hooks/useChartHighlights.tsx
8880
+ var import_react38 = require("react");
8881
+ var useChartHighlights = () => {
8882
+ const [highlightedSeries, setHighlightedSeries] = (0, import_react38.useState)(
8883
+ /* @__PURE__ */ new Set()
8884
+ );
8885
+ const [showOnlyHighlighted, setShowOnlyHighlighted] = (0, import_react38.useState)(false);
8886
+ const toggleHighlight = (0, import_react38.useCallback)((key) => {
8887
+ setHighlightedSeries((prev) => {
8888
+ const next = new Set(prev);
8889
+ if (next.has(key)) {
8890
+ next.delete(key);
6815
8891
  } else {
6816
- textColor = "#374151";
8892
+ next.add(key);
6817
8893
  }
6818
- }
6819
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("g", { children: [
6820
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6821
- "rect",
6822
- {
6823
- x: rectX,
6824
- y: rectY,
6825
- rx: pillHeight / 2,
6826
- width: pillWidth,
6827
- height: pillHeight,
6828
- fill: rectFill,
6829
- stroke: rectStroke,
6830
- strokeWidth: rectStroke ? 1 : 0
6831
- }
6832
- ),
6833
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6834
- "text",
6835
- {
6836
- x: textX,
6837
- y: textY - 3,
6838
- fill: textColor,
6839
- fontSize: 13,
6840
- fontWeight: 700,
6841
- textAnchor: "middle",
6842
- dominantBaseline: "central",
6843
- letterSpacing: 0.2,
6844
- children: text
6845
- }
6846
- )
6847
- ] });
8894
+ return next;
8895
+ });
8896
+ }, []);
8897
+ const clearHighlights = (0, import_react38.useCallback)(() => {
8898
+ setHighlightedSeries(/* @__PURE__ */ new Set());
8899
+ setShowOnlyHighlighted(false);
8900
+ }, []);
8901
+ const isHighlighted = (0, import_react38.useCallback)(
8902
+ (key) => {
8903
+ return highlightedSeries.has(key);
8904
+ },
8905
+ [highlightedSeries]
8906
+ );
8907
+ const getSeriesStyle = (0, import_react38.useCallback)(
8908
+ (key) => {
8909
+ const hasHighlights = highlightedSeries.size > 0;
8910
+ const isSeriesHighlighted = highlightedSeries.has(key);
8911
+ if (showOnlyHighlighted && !isSeriesHighlighted) {
8912
+ return {
8913
+ opacity: 0,
8914
+ pointerEvents: "none",
8915
+ transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1)"
8916
+ };
8917
+ }
8918
+ if (!hasHighlights) {
8919
+ return {
8920
+ opacity: 1,
8921
+ transform: "scale(1)",
8922
+ transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1)"
8923
+ };
8924
+ }
8925
+ if (isSeriesHighlighted) {
8926
+ return {
8927
+ opacity: 1,
8928
+ transform: "scale(1.02)",
8929
+ filter: "drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15))",
8930
+ transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1)"
8931
+ };
8932
+ }
8933
+ return {
8934
+ opacity: 0.25,
8935
+ transform: "scale(0.98)",
8936
+ transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1)"
8937
+ };
8938
+ },
8939
+ [highlightedSeries, showOnlyHighlighted]
8940
+ );
8941
+ return {
8942
+ highlightedSeries,
8943
+ showOnlyHighlighted,
8944
+ toggleHighlight,
8945
+ setShowOnlyHighlighted,
8946
+ clearHighlights,
8947
+ getSeriesStyle,
8948
+ isHighlighted
6848
8949
  };
6849
8950
  };
6850
- var pillLabelRenderer_default = renderPillLabel;
6851
8951
 
6852
8952
  // src/hooks/use-drag.tsx
6853
- var import_react35 = require("react");
8953
+ var import_react39 = require("react");
6854
8954
  var useDrag = (options = {}) => {
6855
- const [isDragging, setIsDragging] = (0, import_react35.useState)(null);
6856
- const [positions, setPositions] = (0, import_react35.useState)({});
6857
- const dragStartPos = (0, import_react35.useRef)(null);
6858
- const dragId = (0, import_react35.useRef)(null);
6859
- const handleMouseDown = (0, import_react35.useCallback)((id, e) => {
8955
+ const [isDragging, setIsDragging] = (0, import_react39.useState)(null);
8956
+ const [positions, setPositions] = (0, import_react39.useState)({});
8957
+ const dragStartPos = (0, import_react39.useRef)(null);
8958
+ const dragId = (0, import_react39.useRef)(null);
8959
+ const handleMouseDown = (0, import_react39.useCallback)((id, e) => {
6860
8960
  e.preventDefault();
6861
8961
  const currentPosition = positions[id] || { top: 0, left: 0 };
6862
8962
  dragStartPos.current = {
@@ -6869,7 +8969,7 @@ var useDrag = (options = {}) => {
6869
8969
  setIsDragging(id);
6870
8970
  options.onDragStart?.(id);
6871
8971
  }, [positions, options]);
6872
- const handleMouseMove = (0, import_react35.useCallback)((e) => {
8972
+ const handleMouseMove = (0, import_react39.useCallback)((e) => {
6873
8973
  if (!isDragging || !dragStartPos.current || !dragId.current) return;
6874
8974
  const deltaX = e.clientX - dragStartPos.current.x;
6875
8975
  const deltaY = e.clientY - dragStartPos.current.y;
@@ -6885,7 +8985,7 @@ var useDrag = (options = {}) => {
6885
8985
  }));
6886
8986
  options.onDrag?.(dragId.current, newPosition);
6887
8987
  }, [isDragging, options]);
6888
- const handleMouseUp = (0, import_react35.useCallback)(() => {
8988
+ const handleMouseUp = (0, import_react39.useCallback)(() => {
6889
8989
  if (dragId.current) {
6890
8990
  options.onDragEnd?.(dragId.current);
6891
8991
  }
@@ -6893,7 +8993,7 @@ var useDrag = (options = {}) => {
6893
8993
  dragStartPos.current = null;
6894
8994
  dragId.current = null;
6895
8995
  }, [options]);
6896
- (0, import_react35.useEffect)(() => {
8996
+ (0, import_react39.useEffect)(() => {
6897
8997
  if (isDragging) {
6898
8998
  document.addEventListener("mousemove", handleMouseMove);
6899
8999
  document.addEventListener("mouseup", handleMouseUp);
@@ -6905,16 +9005,16 @@ var useDrag = (options = {}) => {
6905
9005
  };
6906
9006
  }
6907
9007
  }, [isDragging, handleMouseMove, handleMouseUp]);
6908
- const setPosition = (0, import_react35.useCallback)((id, position) => {
9008
+ const setPosition = (0, import_react39.useCallback)((id, position) => {
6909
9009
  setPositions((prev) => ({
6910
9010
  ...prev,
6911
9011
  [id]: position
6912
9012
  }));
6913
9013
  }, []);
6914
- const getPosition = (0, import_react35.useCallback)((id) => {
9014
+ const getPosition = (0, import_react39.useCallback)((id) => {
6915
9015
  return positions[id] || { top: 0, left: 0 };
6916
9016
  }, [positions]);
6917
- const isElementDragging = (0, import_react35.useCallback)((id) => {
9017
+ const isElementDragging = (0, import_react39.useCallback)((id) => {
6918
9018
  return isDragging === id;
6919
9019
  }, [isDragging]);
6920
9020
  return {