@mlw-packages/react-components 1.10.19 → 1.10.21

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
@@ -3485,58 +3485,100 @@ var ThemeIcon = ({ theme }) => {
3485
3485
  }
3486
3486
  ) });
3487
3487
  };
3488
+ function resolveOrigin(origin, buttonRef, cursorPos) {
3489
+ if (origin === "cursor" && cursorPos) {
3490
+ return cursorPos;
3491
+ }
3492
+ if (!buttonRef.current) {
3493
+ return { x: window.innerWidth / 2, y: window.innerHeight / 2 };
3494
+ }
3495
+ const rect = buttonRef.current.getBoundingClientRect();
3496
+ switch (origin) {
3497
+ case "top-left":
3498
+ return { x: rect.left, y: rect.top };
3499
+ case "top-right":
3500
+ return { x: rect.right, y: rect.top };
3501
+ case "center":
3502
+ default:
3503
+ return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
3504
+ }
3505
+ }
3488
3506
  function ModeToggleBase({
3489
3507
  themes = ["light", "dark", "system"],
3490
3508
  className,
3491
3509
  directToggle = false,
3492
- variant = "ghost"
3510
+ variant = "ghost",
3511
+ showLabel = false,
3512
+ tooltip = false,
3513
+ animationOrigin = "center",
3514
+ transitionDuration = 400,
3515
+ storageKey,
3516
+ defaultTheme,
3517
+ onThemeChange
3493
3518
  }) {
3494
3519
  const [mounted, setMounted] = React32.useState(false);
3520
+ const [isTransitioning, setIsTransitioning] = React32.useState(false);
3521
+ const cursorPos = React32.useRef(null);
3495
3522
  const { setTheme, theme: currentTheme } = useTheme();
3496
3523
  const buttonRef = React32.useRef(null);
3497
3524
  React32.useEffect(() => {
3525
+ if (storageKey && defaultTheme) {
3526
+ const stored = localStorage.getItem(storageKey);
3527
+ if (!stored) setTheme(defaultTheme);
3528
+ } else if (defaultTheme && !localStorage.getItem("theme")) {
3529
+ setTheme(defaultTheme);
3530
+ }
3498
3531
  setMounted(true);
3499
- }, []);
3532
+ }, [defaultTheme, setTheme, storageKey]);
3500
3533
  const isDark = mounted && (currentTheme?.includes("dark") || currentTheme === "system" && typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches);
3534
+ const activeTheme = mounted ? currentTheme : defaultTheme;
3535
+ const tooltipText = tooltip === true ? themeLabels[activeTheme] ?? "Toggle theme" : typeof tooltip === "string" ? tooltip : null;
3501
3536
  const toggleTheme = async (newTheme) => {
3537
+ if (isTransitioning) return;
3502
3538
  if (!buttonRef.current) {
3503
3539
  setTheme(newTheme);
3540
+ onThemeChange?.(newTheme);
3504
3541
  return;
3505
3542
  }
3506
3543
  const supportsViewTransition = typeof document !== "undefined" && "startViewTransition" in document && typeof document.startViewTransition === "function";
3507
3544
  if (!supportsViewTransition) {
3508
3545
  setTheme(newTheme);
3546
+ onThemeChange?.(newTheme);
3509
3547
  return;
3510
3548
  }
3511
3549
  try {
3512
- const rect = buttonRef.current.getBoundingClientRect();
3513
- const x = rect.left + rect.width / 2;
3514
- const y = rect.top + rect.height / 2;
3550
+ setIsTransitioning(true);
3551
+ const { x, y } = resolveOrigin(
3552
+ animationOrigin,
3553
+ buttonRef,
3554
+ cursorPos.current
3555
+ );
3515
3556
  const endRadius = Math.hypot(
3516
3557
  Math.max(x, window.innerWidth - x),
3517
3558
  Math.max(y, window.innerHeight - y)
3518
3559
  );
3519
3560
  const transition = document.startViewTransition(async () => {
3520
3561
  setTheme(newTheme);
3562
+ onThemeChange?.(newTheme);
3521
3563
  });
3522
3564
  await transition.ready;
3523
- document.documentElement.animate(
3565
+ const animation = document.documentElement.animate(
3524
3566
  [
3525
- {
3526
- clipPath: `circle(0px at ${x}px ${y}px)`
3527
- },
3528
- {
3529
- clipPath: `circle(${Math.ceil(endRadius)}px at ${x}px ${y}px)`
3530
- }
3567
+ { clipPath: `circle(0px at ${x}px ${y}px)` },
3568
+ { clipPath: `circle(${Math.ceil(endRadius)}px at ${x}px ${y}px)` }
3531
3569
  ],
3532
3570
  {
3533
- duration: 400,
3571
+ duration: transitionDuration,
3534
3572
  easing: "cubic-bezier(0.4, 0, 0.2, 1)",
3535
3573
  pseudoElement: "::view-transition-new(root)"
3536
3574
  }
3537
3575
  );
3576
+ animation.onfinish = () => setIsTransitioning(false);
3577
+ animation.oncancel = () => setIsTransitioning(false);
3538
3578
  } catch {
3539
3579
  setTheme(newTheme);
3580
+ onThemeChange?.(newTheme);
3581
+ setIsTransitioning(false);
3540
3582
  }
3541
3583
  };
3542
3584
  const handleDirectToggle = () => {
@@ -3544,67 +3586,72 @@ function ModeToggleBase({
3544
3586
  const nextIndex = (currentIndex + 1) % themes.length;
3545
3587
  toggleTheme(themes[nextIndex]);
3546
3588
  };
3547
- if (directToggle) {
3548
- return /* @__PURE__ */ jsxRuntime.jsxs(
3549
- ButtonBase,
3589
+ const handleMouseMove = (e) => {
3590
+ cursorPos.current = { x: e.clientX, y: e.clientY };
3591
+ };
3592
+ const buttonContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3593
+ /* @__PURE__ */ jsxRuntime.jsx(
3594
+ react.SunIcon,
3550
3595
  {
3551
- ref: buttonRef,
3552
- variant,
3553
- size: "icon",
3554
- className: cn("relative overflow-hidden group", className),
3555
- onClick: handleDirectToggle,
3556
- children: [
3557
- /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3558
- /* @__PURE__ */ jsxRuntime.jsx(
3559
- react.SunIcon,
3560
- {
3561
- className: `h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-90 scale-0 opacity-0" : "rotate-0 scale-100 opacity-100 group-hover:rotate-12"}`
3562
- }
3563
- ),
3564
- /* @__PURE__ */ jsxRuntime.jsx(
3565
- react.MoonIcon,
3566
- {
3567
- className: `absolute h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-0 scale-100 opacity-100 group-hover:-rotate-12" : "rotate-90 scale-0 opacity-0"}`
3568
- }
3569
- )
3570
- ] }),
3571
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Toggle theme" })
3572
- ]
3596
+ className: `h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-90 scale-0 opacity-0" : "rotate-0 scale-100 opacity-100 group-hover:rotate-12"}`
3573
3597
  }
3598
+ ),
3599
+ /* @__PURE__ */ jsxRuntime.jsx(
3600
+ react.MoonIcon,
3601
+ {
3602
+ className: `absolute h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-0 scale-100 opacity-100 group-hover:-rotate-12" : "rotate-90 scale-0 opacity-0"}`
3603
+ }
3604
+ ),
3605
+ showLabel && mounted && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-5 text-sm font-medium", children: themeLabels[activeTheme] }),
3606
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Toggle theme" })
3607
+ ] });
3608
+ const wrapWithTooltip = (node) => {
3609
+ if (!tooltipText) return node;
3610
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProviderBase, { children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipBase, { children: [
3611
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTriggerBase, { asChild: true, children: node }),
3612
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContentBase, { children: tooltipText })
3613
+ ] }) });
3614
+ };
3615
+ if (directToggle) {
3616
+ return wrapWithTooltip(
3617
+ /* @__PURE__ */ jsxRuntime.jsx(
3618
+ ButtonBase,
3619
+ {
3620
+ ref: buttonRef,
3621
+ variant,
3622
+ size: showLabel ? "default" : "icon",
3623
+ className: cn("relative overflow-hidden group", className),
3624
+ onClick: handleDirectToggle,
3625
+ onMouseMove: handleMouseMove,
3626
+ onKeyDown: (e) => {
3627
+ if (e.repeat && (e.key === "Enter" || e.key === " ")) {
3628
+ e.preventDefault();
3629
+ }
3630
+ },
3631
+ children: buttonContent
3632
+ }
3633
+ )
3574
3634
  );
3575
3635
  }
3576
3636
  return /* @__PURE__ */ jsxRuntime.jsxs(DropDownMenuBase, { children: [
3577
- /* @__PURE__ */ jsxRuntime.jsx(DropDownMenuTriggerBase, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
3578
- ButtonBase,
3579
- {
3580
- ref: buttonRef,
3581
- variant,
3582
- size: "icon",
3583
- className: cn("relative overflow-hidden group", className),
3584
- children: [
3585
- /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3586
- /* @__PURE__ */ jsxRuntime.jsx(
3587
- react.SunIcon,
3588
- {
3589
- className: `h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-90 scale-0 opacity-0" : "rotate-0 scale-100 opacity-100 group-hover:rotate-12"}`
3590
- }
3591
- ),
3592
- /* @__PURE__ */ jsxRuntime.jsx(
3593
- react.MoonIcon,
3594
- {
3595
- className: `absolute h-[1.2rem] w-[1.2rem] transition-all duration-500 ${isDark ? "rotate-0 scale-100 opacity-100 group-hover:-rotate-12" : "rotate-90 scale-0 opacity-0"}`
3596
- }
3597
- )
3598
- ] }),
3599
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Toggle theme" })
3600
- ]
3601
- }
3637
+ /* @__PURE__ */ jsxRuntime.jsx(DropDownMenuTriggerBase, { asChild: true, children: wrapWithTooltip(
3638
+ /* @__PURE__ */ jsxRuntime.jsx(
3639
+ ButtonBase,
3640
+ {
3641
+ ref: buttonRef,
3642
+ variant,
3643
+ size: showLabel ? "default" : "icon",
3644
+ className: cn("relative overflow-hidden group", className),
3645
+ onMouseMove: handleMouseMove,
3646
+ children: buttonContent
3647
+ }
3648
+ )
3602
3649
  ) }),
3603
3650
  /* @__PURE__ */ jsxRuntime.jsx(
3604
3651
  DropDownMenuContentBase,
3605
3652
  {
3606
3653
  align: "end",
3607
- className: "border-border bg-popover text-popover-foreground min-w-[140px] ",
3654
+ className: "border-border bg-popover text-popover-foreground min-w-[140px]",
3608
3655
  children: themes.map((theme) => {
3609
3656
  const isActive = currentTheme === theme;
3610
3657
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3858,7 +3905,7 @@ var FileUploader = React32__namespace.forwardRef(
3858
3905
  showPreview = true,
3859
3906
  dropzoneText = "Arraste arquivos aqui ou clique para selecionar",
3860
3907
  dropzoneSubtext,
3861
- animate: animate2 = true,
3908
+ animate: animate3 = true,
3862
3909
  ...props
3863
3910
  }, ref) => {
3864
3911
  const [isDragging, setIsDragging] = React32__namespace.useState(false);
@@ -4011,7 +4058,7 @@ var FileUploader = React32__namespace.forwardRef(
4011
4058
  framerMotion.motion.p,
4012
4059
  {
4013
4060
  className: "mb-2 text-xs font-semibold text-foreground",
4014
- initial: animate2 ? { opacity: 0, y: -10 } : false,
4061
+ initial: animate3 ? { opacity: 0, y: -10 } : false,
4015
4062
  animate: { opacity: 1, y: 0 },
4016
4063
  transition: { delay: 0.1 },
4017
4064
  children: dropzoneText
@@ -4021,7 +4068,7 @@ var FileUploader = React32__namespace.forwardRef(
4021
4068
  framerMotion.motion.p,
4022
4069
  {
4023
4070
  className: "text-xs text-muted-foreground",
4024
- initial: animate2 ? { opacity: 0, y: -10 } : false,
4071
+ initial: animate3 ? { opacity: 0, y: -10 } : false,
4025
4072
  animate: { opacity: 1, y: 0 },
4026
4073
  transition: { delay: 0.2 },
4027
4074
  children: defaultSubtext
@@ -4031,7 +4078,7 @@ var FileUploader = React32__namespace.forwardRef(
4031
4078
  framerMotion.motion.div,
4032
4079
  {
4033
4080
  className: "py-2 w-full",
4034
- initial: animate2 ? { opacity: 0, y: 10 } : false,
4081
+ initial: animate3 ? { opacity: 0, y: 10 } : false,
4035
4082
  animate: { opacity: 1, y: 0 },
4036
4083
  transition: { delay: 0.3 },
4037
4084
  children: [
@@ -4046,7 +4093,7 @@ var FileUploader = React32__namespace.forwardRef(
4046
4093
  framerMotion.motion.div,
4047
4094
  {
4048
4095
  layout: true,
4049
- initial: animate2 ? { opacity: 0, x: -20 } : false,
4096
+ initial: animate3 ? { opacity: 0, x: -20 } : false,
4050
4097
  animate: { opacity: 1, x: 0 },
4051
4098
  exit: {
4052
4099
  opacity: 0,
@@ -4054,7 +4101,7 @@ var FileUploader = React32__namespace.forwardRef(
4054
4101
  transition: { duration: 0.2 }
4055
4102
  },
4056
4103
  transition: {
4057
- delay: animate2 ? index * 0.05 : 0,
4104
+ delay: animate3 ? index * 0.05 : 0,
4058
4105
  layout: { duration: 0.2 }
4059
4106
  },
4060
4107
  className: cn(
@@ -9669,7 +9716,8 @@ function DayViewAgenda({
9669
9716
  events,
9670
9717
  onEventSelect,
9671
9718
  showUndatedEvents,
9672
- noTime = false
9719
+ noTime = false,
9720
+ onEventCreate
9673
9721
  }) {
9674
9722
  const hours = React32.useMemo(() => {
9675
9723
  const dayStart = dateFns.startOfDay(currentDate);
@@ -9919,6 +9967,7 @@ function DayViewAgenda({
9919
9967
  const startTime = new Date(currentDate);
9920
9968
  startTime.setHours(hourValue);
9921
9969
  startTime.setMinutes(quarter * 15);
9970
+ if (onEventCreate) onEventCreate(startTime);
9922
9971
  },
9923
9972
  time: quarterHourTime
9924
9973
  },
@@ -10181,7 +10230,8 @@ function EventAgenda({
10181
10230
  onlyMonth,
10182
10231
  onlyWeek,
10183
10232
  onlyAgenda,
10184
- onlyYear
10233
+ onlyYear,
10234
+ allowCellClick = false
10185
10235
  }) {
10186
10236
  const lockedView = onlyDay ? "day" : onlyMonth ? "month" : onlyWeek ? "week" : onlyAgenda ? "agenda" : onlyYear ? "year" : void 0;
10187
10237
  const [currentDate, setCurrentDate] = React32.useState(
@@ -10344,7 +10394,13 @@ function EventAgenda({
10344
10394
  currentDate,
10345
10395
  events,
10346
10396
  onEventSelect: handleEventSelect,
10347
- noTime
10397
+ noTime,
10398
+ onEventCreate: allowCellClick ? (d) => onEventUpdate?.({
10399
+ start: d,
10400
+ end: d,
10401
+ title: "Novo Evento",
10402
+ id: crypto.randomUUID()
10403
+ }) : void 0
10348
10404
  }
10349
10405
  ),
10350
10406
  activeView === "week" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -10353,7 +10409,13 @@ function EventAgenda({
10353
10409
  currentDate,
10354
10410
  events,
10355
10411
  onEventSelect: handleEventSelect,
10356
- noTime
10412
+ noTime,
10413
+ onEventCreate: allowCellClick ? (d) => onEventUpdate?.({
10414
+ start: d,
10415
+ end: d,
10416
+ title: "Novo Evento",
10417
+ id: crypto.randomUUID()
10418
+ }) : void 0
10357
10419
  }
10358
10420
  ),
10359
10421
  activeView === "day" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -10362,7 +10424,13 @@ function EventAgenda({
10362
10424
  currentDate,
10363
10425
  events,
10364
10426
  onEventSelect: handleEventSelect,
10365
- noTime
10427
+ noTime,
10428
+ onEventCreate: allowCellClick ? (d) => onEventUpdate?.({
10429
+ start: d,
10430
+ end: d,
10431
+ title: "Novo Evento",
10432
+ id: crypto.randomUUID()
10433
+ }) : void 0
10366
10434
  }
10367
10435
  ),
10368
10436
  activeView === "agenda" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -10371,7 +10439,13 @@ function EventAgenda({
10371
10439
  currentDate,
10372
10440
  events,
10373
10441
  onEventSelect: handleEventSelect,
10374
- noTime
10442
+ noTime,
10443
+ onEventCreate: allowCellClick ? (d) => onEventUpdate?.({
10444
+ start: d,
10445
+ end: d,
10446
+ title: "Novo Evento",
10447
+ id: crypto.randomUUID()
10448
+ }) : void 0
10375
10449
  }
10376
10450
  ),
10377
10451
  activeView === "year" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -10634,7 +10708,8 @@ function MonthViewAgenda({
10634
10708
  events,
10635
10709
  onEventSelect,
10636
10710
  showUndatedEvents,
10637
- noTime = false
10711
+ noTime = false,
10712
+ onEventCreate
10638
10713
  }) {
10639
10714
  const days = React32.useMemo(() => {
10640
10715
  const monthStart = dateFns.startOfMonth(currentDate);
@@ -10777,6 +10852,7 @@ function MonthViewAgenda({
10777
10852
  onClick: () => {
10778
10853
  const t = new Date(day);
10779
10854
  t.setHours(DefaultStartHourAgenda, 0, 0);
10855
+ if (onEventCreate) onEventCreate(t);
10780
10856
  },
10781
10857
  children: [
10782
10858
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -16115,7 +16191,8 @@ var DraggableTooltipComponent = ({
16115
16191
  highlightedSeries,
16116
16192
  toggleHighlight,
16117
16193
  finalColors,
16118
- valueFormatter
16194
+ valueFormatter,
16195
+ seriesTypeMap
16119
16196
  ]
16120
16197
  ),
16121
16198
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-2 border-t", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
@@ -16409,74 +16486,106 @@ var SystemTooltip = ({
16409
16486
  const [localPos, setLocalPos] = React32.useState(position);
16410
16487
  const [dragging, setDragging] = React32.useState(false);
16411
16488
  const offsetRef = React32.useRef({ x: 0, y: 0 });
16412
- const lastMouse = React32.useRef({ x: 0, y: 0 });
16413
- React32.useEffect(() => setLocalPos(position), [position]);
16489
+ const lastPos = React32.useRef({ x: 0, y: 0 });
16490
+ const tooltipRef = React32.useRef(null);
16491
+ const currentPosRef = React32.useRef(position);
16492
+ React32.useEffect(() => {
16493
+ currentPosRef.current = position;
16494
+ setLocalPos(position);
16495
+ }, [position]);
16414
16496
  React32.useEffect(() => {
16415
16497
  let rafId = null;
16416
- const handleMouseMove = (e) => {
16417
- if (!dragging) return;
16418
- lastMouse.current = { x: e.clientX, y: e.clientY };
16498
+ const applyMove = (clientX, clientY) => {
16499
+ lastPos.current = { x: clientX, y: clientY };
16419
16500
  if (rafId) cancelAnimationFrame(rafId);
16420
16501
  rafId = requestAnimationFrame(() => {
16421
- const newLeft = lastMouse.current.x - offsetRef.current.x;
16422
- const newTop = lastMouse.current.y - offsetRef.current.y;
16423
- const rawPosition = {
16424
- top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
16425
- left: Math.max(0, Math.min(newLeft, window.innerWidth - 320))
16502
+ const p = {
16503
+ top: Math.max(
16504
+ 0,
16505
+ Math.min(
16506
+ lastPos.current.y - offsetRef.current.y,
16507
+ window.innerHeight - 200
16508
+ )
16509
+ ),
16510
+ left: Math.max(
16511
+ 0,
16512
+ Math.min(
16513
+ lastPos.current.x - offsetRef.current.x,
16514
+ window.innerWidth - 320
16515
+ )
16516
+ )
16426
16517
  };
16427
- setLocalPos(rawPosition);
16428
- if (onPositionChange) onPositionChange(id, rawPosition);
16518
+ currentPosRef.current = p;
16519
+ if (tooltipRef.current) {
16520
+ tooltipRef.current.style.top = `${p.top}px`;
16521
+ tooltipRef.current.style.left = `${p.left}px`;
16522
+ }
16523
+ onPositionChange?.(id, p);
16429
16524
  });
16430
16525
  };
16431
- const handleMouseUp = () => {
16432
- if (dragging) {
16433
- setDragging(false);
16434
- if (rafId) cancelAnimationFrame(rafId);
16435
- }
16526
+ const stopDrag = () => {
16527
+ if (!dragging) return;
16528
+ setDragging(false);
16529
+ setLocalPos(currentPosRef.current);
16530
+ if (rafId) cancelAnimationFrame(rafId);
16531
+ };
16532
+ const handleMouseMove = (e) => {
16533
+ if (dragging) applyMove(e.clientX, e.clientY);
16534
+ };
16535
+ const handleTouchMove = (e) => {
16536
+ if (!dragging || !e.touches[0]) return;
16537
+ applyMove(e.touches[0].clientX, e.touches[0].clientY);
16436
16538
  };
16437
16539
  if (dragging) {
16438
16540
  document.addEventListener("mousemove", handleMouseMove, {
16439
16541
  passive: true
16440
16542
  });
16441
- document.addEventListener("mouseup", handleMouseUp);
16543
+ document.addEventListener("mouseup", stopDrag);
16544
+ document.addEventListener("touchmove", handleTouchMove, {
16545
+ passive: true
16546
+ });
16547
+ document.addEventListener("touchend", stopDrag);
16548
+ document.addEventListener("touchcancel", stopDrag);
16442
16549
  document.body.style.cursor = "grabbing";
16443
16550
  document.body.style.userSelect = "none";
16444
16551
  }
16445
16552
  return () => {
16446
16553
  if (rafId) cancelAnimationFrame(rafId);
16447
16554
  document.removeEventListener("mousemove", handleMouseMove);
16448
- document.removeEventListener("mouseup", handleMouseUp);
16555
+ document.removeEventListener("mouseup", stopDrag);
16556
+ document.removeEventListener("touchmove", handleTouchMove);
16557
+ document.removeEventListener("touchend", stopDrag);
16558
+ document.removeEventListener("touchcancel", stopDrag);
16449
16559
  document.body.style.cursor = "";
16450
16560
  document.body.style.userSelect = "";
16451
16561
  };
16452
16562
  }, [dragging, id, onPositionChange]);
16453
- const handleMouseDownLocal = React32.useCallback(
16454
- (e) => {
16455
- e.preventDefault();
16456
- e.stopPropagation();
16457
- const rect = e.currentTarget.closest(".fixed")?.getBoundingClientRect();
16563
+ const startDrag = React32.useCallback(
16564
+ (clientX, clientY, e) => {
16565
+ const rect = tooltipRef.current?.getBoundingClientRect();
16458
16566
  if (!rect) return;
16459
- offsetRef.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };
16567
+ offsetRef.current = { x: clientX - rect.left, y: clientY - rect.top };
16460
16568
  setDragging(true);
16461
16569
  onMouseDown?.(id, e);
16462
16570
  },
16463
16571
  [id, onMouseDown]
16464
16572
  );
16573
+ const handleMouseDownLocal = React32.useCallback(
16574
+ (e) => {
16575
+ e.preventDefault();
16576
+ e.stopPropagation();
16577
+ startDrag(e.clientX, e.clientY, e);
16578
+ },
16579
+ [startDrag]
16580
+ );
16465
16581
  const handleTouchStartLocal = React32.useCallback(
16466
16582
  (e) => {
16467
16583
  e.stopPropagation();
16468
16584
  const touch = e.touches[0];
16469
16585
  if (!touch) return;
16470
- const rect = e.currentTarget.closest(".fixed")?.getBoundingClientRect();
16471
- if (!rect) return;
16472
- offsetRef.current = {
16473
- x: touch.clientX - rect.left,
16474
- y: touch.clientY - rect.top
16475
- };
16476
- setDragging(true);
16477
- onMouseDown?.(id, e);
16586
+ startDrag(touch.clientX, touch.clientY, e);
16478
16587
  },
16479
- [id, onMouseDown]
16588
+ [startDrag]
16480
16589
  );
16481
16590
  const handleConnClick = React32.useCallback(
16482
16591
  (e, conn) => {
@@ -16524,15 +16633,13 @@ var SystemTooltip = ({
16524
16633
  return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsxs(
16525
16634
  framerMotion.motion.div,
16526
16635
  {
16636
+ ref: tooltipRef,
16527
16637
  className: "fixed bg-card/95 backdrop-blur-md border border-border/50 rounded-xl shadow-2xl z-[10000] w-80 overflow-hidden",
16528
16638
  variants: tooltipVariants2,
16529
16639
  initial: "hidden",
16530
16640
  animate: "visible",
16531
16641
  exit: "exit",
16532
- style: {
16533
- top: localPos.top,
16534
- left: localPos.left
16535
- },
16642
+ style: { top: localPos.top, left: localPos.left },
16536
16643
  onClick: (e) => e.stopPropagation(),
16537
16644
  children: [
16538
16645
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -16547,7 +16654,7 @@ var SystemTooltip = ({
16547
16654
  },
16548
16655
  children: [
16549
16656
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3", children: [
16550
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded", children: /* @__PURE__ */ jsxRuntime.jsx(react.DotsSixVerticalIcon, { size: 16, className: "text-primary" }) }),
16657
+ /* @__PURE__ */ jsxRuntime.jsx(react.DotsSixVerticalIcon, { size: 16, className: "text-primary" }),
16551
16658
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: title })
16552
16659
  ] }),
16553
16660
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -16573,22 +16680,19 @@ var SystemTooltip = ({
16573
16680
  ] }) }),
16574
16681
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pb-4 space-y-4 max-h-[300px] overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/40 transition-colors", children: [
16575
16682
  /* @__PURE__ */ jsxRuntime.jsx(SeparatorBase, { className: "w-full" }),
16576
- isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16577
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
16578
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-1", children: [
16579
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-1.5 h-1.5 rounded-full" }),
16580
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-3 w-16" })
16581
- ] }),
16582
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-10 w-full rounded-lg" }, i)) })
16683
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: [1, 2].map((g) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
16684
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-1", children: [
16685
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-1.5 h-1.5 rounded-full" }),
16686
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-3 w-16" })
16583
16687
  ] }),
16584
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
16585
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-1", children: [
16586
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-1.5 h-1.5 rounded-full" }),
16587
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-3 w-16" })
16588
- ] }),
16589
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: [1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-10 w-full rounded-lg" }, i)) })
16590
- ] })
16591
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16688
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx(
16689
+ SkeletonBase,
16690
+ {
16691
+ className: "h-10 w-full rounded-lg"
16692
+ },
16693
+ i
16694
+ )) })
16695
+ ] }, g)) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16592
16696
  entries.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
16593
16697
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-1", children: [
16594
16698
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500" }),
@@ -16603,7 +16707,7 @@ var SystemTooltip = ({
16603
16707
  ] }),
16604
16708
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: renderConnections(exits, "blue") })
16605
16709
  ] }),
16606
- data.connections.length === 0 && !isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Nenhuma conex\xE3o encontrada" }) })
16710
+ data.connections.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Nenhuma conex\xE3o encontrada" }) })
16607
16711
  ] })
16608
16712
  ] })
16609
16713
  ]
@@ -16625,6 +16729,13 @@ var useIsTruncated = (ref) => {
16625
16729
  }, [ref]);
16626
16730
  return truncated;
16627
16731
  };
16732
+ var SNAP_HEIGHTS = {
16733
+ collapsed: "80px",
16734
+ peek: "42dvh",
16735
+ full: "85dvh"
16736
+ };
16737
+ var VELOCITY_THRESHOLD = 500;
16738
+ var CLOSE_THRESHOLD = 50;
16628
16739
  var CopyData = ({ value }) => {
16629
16740
  const [copied, setCopied] = React32.useState(false);
16630
16741
  const handleCopy = React32.useCallback(() => {
@@ -16658,26 +16769,56 @@ var propertyLabels = {
16658
16769
  Destino: "Destino",
16659
16770
  Origem: "Origem"
16660
16771
  };
16661
- var IntegrationCard = ({ title, details }) => {
16772
+ var LongPressTooltip = ({ content, isMobile, children }) => {
16773
+ const [open, setOpen] = React32.useState(false);
16774
+ const timerRef = React32.useRef(null);
16775
+ const handleTouchStart = React32.useCallback(() => {
16776
+ timerRef.current = setTimeout(() => setOpen(true), 1e3);
16777
+ }, []);
16778
+ const handleTouchEnd = React32.useCallback(() => {
16779
+ if (timerRef.current) clearTimeout(timerRef.current);
16780
+ setTimeout(() => setOpen(false), 1500);
16781
+ }, []);
16782
+ React32.useEffect(
16783
+ () => () => {
16784
+ if (timerRef.current) clearTimeout(timerRef.current);
16785
+ },
16786
+ []
16787
+ );
16788
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProviderBase, { children: /* @__PURE__ */ jsxRuntime.jsxs(
16789
+ TooltipBase,
16790
+ {
16791
+ open: isMobile ? open : void 0,
16792
+ onOpenChange: isMobile ? setOpen : void 0,
16793
+ children: [
16794
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTriggerBase, { asChild: true, children: isMobile ? React32__namespace.default.cloneElement(children, {
16795
+ onTouchStart: handleTouchStart,
16796
+ onTouchEnd: handleTouchEnd,
16797
+ onTouchCancel: handleTouchEnd
16798
+ }) : children }),
16799
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContentBase, { sideOffset: 6, className: "z-[10001]", children: content })
16800
+ ]
16801
+ }
16802
+ ) });
16803
+ };
16804
+ var IntegrationCard = ({ title, details, isMobile }) => {
16662
16805
  const titleRef = React32.useRef(null);
16663
16806
  const isTitleTruncated = useIsTruncated(titleRef);
16664
16807
  const blackList = ["id", "elementId", "identity"];
16665
16808
  const entries = details ? Object.entries(details).filter(
16666
16809
  ([key, value]) => value !== void 0 && value !== null && value !== "" && !blackList.includes(key)
16667
16810
  ) : [];
16811
+ const titleSpan = /* @__PURE__ */ jsxRuntime.jsx(
16812
+ "span",
16813
+ {
16814
+ ref: titleRef,
16815
+ className: "text-sm font-bold text-foreground truncate flex-1 min-w-0 cursor-default",
16816
+ children: title
16817
+ }
16818
+ );
16668
16819
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-border/40 bg-muted/20 overflow-hidden", children: [
16669
16820
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border/30", children: [
16670
- /* @__PURE__ */ jsxRuntime.jsx(TooltipProviderBase, { children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipBase, { children: [
16671
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTriggerBase, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
16672
- "span",
16673
- {
16674
- ref: titleRef,
16675
- className: "text-sm font-bold text-foreground truncate flex-1 min-w-0 cursor-default",
16676
- children: title
16677
- }
16678
- ) }),
16679
- isTitleTruncated && /* @__PURE__ */ jsxRuntime.jsx(TooltipContentBase, { sideOffset: 6, className: "z-[10001]", children: title })
16680
- ] }) }),
16821
+ isTitleTruncated ? /* @__PURE__ */ jsxRuntime.jsx(LongPressTooltip, { content: title, isMobile, children: titleSpan }) : titleSpan,
16681
16822
  entries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
16682
16823
  CopyData,
16683
16824
  {
@@ -16697,69 +16838,59 @@ var IntegrationCard = ({ title, details }) => {
16697
16838
  }) })
16698
16839
  ] });
16699
16840
  };
16700
- var Name = ({
16701
- name,
16702
- description
16703
- }) => {
16841
+ var Name = ({ name, description, isMobile }) => {
16704
16842
  const nameRef = React32.useRef(null);
16705
16843
  const descRef = React32.useRef(null);
16706
16844
  const isNameTruncated = useIsTruncated(nameRef);
16707
16845
  const isDescTruncated = useIsTruncated(descRef);
16708
16846
  const showTooltip = isNameTruncated || isDescTruncated;
16709
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipProviderBase, { children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipBase, { children: [
16710
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTriggerBase, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cursor-default min-w-0", children: [
16711
- /* @__PURE__ */ jsxRuntime.jsx(
16712
- "h3",
16713
- {
16714
- ref: nameRef,
16715
- className: "text-xl font-bold text-foreground tracking-tight truncate",
16716
- children: name
16717
- }
16718
- ),
16719
- description && /* @__PURE__ */ jsxRuntime.jsx(
16720
- "p",
16721
- {
16722
- ref: descRef,
16723
- className: "text-xs text-foreground/70 truncate mt-0.5",
16724
- children: description
16725
- }
16726
- )
16727
- ] }) }),
16728
- showTooltip && /* @__PURE__ */ jsxRuntime.jsxs(TooltipContentBase, { sideOffset: 8, className: "z-[10001]", children: [
16729
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold", children: name }),
16730
- description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-foreground/70 mt-0.5", children: description })
16731
- ] })
16732
- ] }) });
16847
+ const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cursor-default min-w-0", children: [
16848
+ /* @__PURE__ */ jsxRuntime.jsx(
16849
+ "h3",
16850
+ {
16851
+ ref: nameRef,
16852
+ className: "text-xl font-bold text-foreground tracking-tight truncate",
16853
+ children: name
16854
+ }
16855
+ ),
16856
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { ref: descRef, className: "text-xs text-foreground/70 truncate mt-0.5", children: description })
16857
+ ] });
16858
+ if (!showTooltip) return content;
16859
+ return /* @__PURE__ */ jsxRuntime.jsx(
16860
+ LongPressTooltip,
16861
+ {
16862
+ content: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16863
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold", children: name }),
16864
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-foreground/70 mt-0.5", children: description })
16865
+ ] }),
16866
+ isMobile,
16867
+ children: content
16868
+ }
16869
+ );
16733
16870
  };
16734
- var SystemNode = React32__namespace.default.forwardRef(
16735
- ({ label }, ref) => {
16736
- const innerRef = React32.useRef(null);
16737
- const truncated = label.length > 9 ? label.substring(0, 9) + "\u2026" : label;
16738
- const needsTooltip = label.length > 9;
16739
- const setRefs = React32.useCallback(
16740
- (node) => {
16741
- innerRef.current = node;
16742
- if (typeof ref === "function") ref(node);
16743
- else if (ref)
16744
- ref.current = node;
16745
- },
16746
- [ref]
16747
- );
16748
- const circle = /* @__PURE__ */ jsxRuntime.jsx(
16871
+ function SystemNodeInner({ label, isMobile }, ref) {
16872
+ const truncated = label.length > 9 ? label.substring(0, 9) + "\u2026" : label;
16873
+ const needsTooltip = label.length > 9;
16874
+ if (!needsTooltip) {
16875
+ return /* @__PURE__ */ jsxRuntime.jsx(
16749
16876
  "div",
16750
16877
  {
16751
- ref: setRefs,
16878
+ ref,
16752
16879
  className: "w-[76px] h-[76px] rounded-full bg-primary flex items-center justify-center shrink-0 z-10 cursor-default",
16753
16880
  children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-primary-foreground text-center px-2 leading-tight select-none", children: truncated })
16754
16881
  }
16755
16882
  );
16756
- if (!needsTooltip) return circle;
16757
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipProviderBase, { children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipBase, { children: [
16758
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTriggerBase, { asChild: true, children: circle }),
16759
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContentBase, { sideOffset: 8, className: "z-[10001]", children: label })
16760
- ] }) });
16761
16883
  }
16762
- );
16884
+ return /* @__PURE__ */ jsxRuntime.jsx(LongPressTooltip, { content: label, isMobile, children: /* @__PURE__ */ jsxRuntime.jsx(
16885
+ "div",
16886
+ {
16887
+ ref,
16888
+ className: "w-[76px] h-[76px] rounded-full bg-primary flex items-center justify-center shrink-0 z-10 cursor-default",
16889
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-primary-foreground text-center px-2 leading-tight select-none", children: truncated })
16890
+ }
16891
+ ) });
16892
+ }
16893
+ var SystemNode = React32__namespace.default.forwardRef(SystemNodeInner);
16763
16894
  SystemNode.displayName = "SystemNode";
16764
16895
  var Beam = ({ isInput, containerRef, leftRef, rightRef }) => {
16765
16896
  const gradientId = React32.useId();
@@ -16767,6 +16898,7 @@ var Beam = ({ isInput, containerRef, leftRef, rightRef }) => {
16767
16898
  const [svgSize, setSvgSize] = React32.useState({ w: 0, h: 0 });
16768
16899
  React32.useEffect(() => {
16769
16900
  let rafId;
16901
+ let running = true;
16770
16902
  const update = () => {
16771
16903
  const container = containerRef.current;
16772
16904
  const left = leftRef.current;
@@ -16779,39 +16911,31 @@ var Beam = ({ isInput, containerRef, leftRef, rightRef }) => {
16779
16911
  const cy1 = lr.top - cr.top + lr.height / 2;
16780
16912
  const cx2 = rr.left - cr.left + rr.width / 2;
16781
16913
  const cy2 = rr.top - cr.top + rr.height / 2;
16782
- const dx = cx2 - cx1, dy = cy2 - cy1;
16914
+ const dx = cx2 - cx1;
16915
+ const dy = cy2 - cy1;
16783
16916
  const dist = Math.sqrt(dx * dx + dy * dy);
16784
16917
  if (dist === 0) return;
16785
- const ux = dx / dist, uy = dy / dist;
16918
+ const ux = dx / dist;
16919
+ const uy = dy / dist;
16786
16920
  const r1 = lr.width / 2;
16787
16921
  const r2 = rr.width / 2;
16788
- setSvgSize({ w: cr.width, h: cr.height });
16789
- setPathD(
16790
- `M ${cx1 + ux * r1},${cy1 + uy * r1} L ${cx2 - ux * r2},${cy2 - uy * r2}`
16922
+ const newW = cr.width;
16923
+ const newH = cr.height;
16924
+ const newPath = `M ${cx1 + ux * r1},${cy1 + uy * r1} L ${cx2 - ux * r2},${cy2 - uy * r2}`;
16925
+ setSvgSize(
16926
+ (prev) => prev.w !== newW || prev.h !== newH ? { w: newW, h: newH } : prev
16791
16927
  );
16928
+ setPathD((prev) => prev !== newPath ? newPath : prev);
16792
16929
  };
16793
- const schedule = () => {
16794
- cancelAnimationFrame(rafId);
16795
- rafId = requestAnimationFrame(update);
16930
+ const loop = () => {
16931
+ if (!running) return;
16932
+ update();
16933
+ rafId = requestAnimationFrame(loop);
16796
16934
  };
16797
- requestAnimationFrame(() => requestAnimationFrame(update));
16798
- schedule();
16799
- const ro = new ResizeObserver(schedule);
16800
- if (containerRef.current) ro.observe(containerRef.current);
16801
- if (leftRef.current) ro.observe(leftRef.current);
16802
- if (rightRef.current) ro.observe(rightRef.current);
16803
- const mo = new MutationObserver(schedule);
16804
- if (containerRef.current) {
16805
- mo.observe(containerRef.current, {
16806
- attributes: true,
16807
- attributeFilter: ["class", "style"],
16808
- subtree: true
16809
- });
16810
- }
16935
+ rafId = requestAnimationFrame(loop);
16811
16936
  return () => {
16937
+ running = false;
16812
16938
  cancelAnimationFrame(rafId);
16813
- ro.disconnect();
16814
- mo.disconnect();
16815
16939
  };
16816
16940
  }, [containerRef, leftRef, rightRef]);
16817
16941
  const animX1 = isInput ? ["90%", "-10%"] : ["10%", "110%"];
@@ -16877,7 +17001,7 @@ var Beam = ({ isInput, containerRef, leftRef, rightRef }) => {
16877
17001
  }
16878
17002
  );
16879
17003
  };
16880
- var SystemsDiagram = ({ isInput, currentSystem, externalSystem }) => {
17004
+ var SystemsDiagram = ({ isInput, currentSystem, externalSystem, isMobile }) => {
16881
17005
  const containerRef = React32.useRef(null);
16882
17006
  const leftRef = React32.useRef(null);
16883
17007
  const rightRef = React32.useRef(null);
@@ -16891,14 +17015,16 @@ var SystemsDiagram = ({ isInput, currentSystem, externalSystem }) => {
16891
17015
  SystemNode,
16892
17016
  {
16893
17017
  ref: leftRef,
16894
- label: isInput ? externalSystem : currentSystem
17018
+ label: isInput ? externalSystem : currentSystem,
17019
+ isMobile
16895
17020
  }
16896
17021
  ),
16897
17022
  /* @__PURE__ */ jsxRuntime.jsx(
16898
17023
  SystemNode,
16899
17024
  {
16900
17025
  ref: rightRef,
16901
- label: isInput ? currentSystem : externalSystem
17026
+ label: isInput ? currentSystem : externalSystem,
17027
+ isMobile
16902
17028
  }
16903
17029
  ),
16904
17030
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -16914,47 +17040,84 @@ var SystemsDiagram = ({ isInput, currentSystem, externalSystem }) => {
16914
17040
  }
16915
17041
  );
16916
17042
  };
16917
- var BodyComponent = ({ data, isLoading, connections, isInput, externalSystem }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-3 space-y-3 max-h-[460px] overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/40 transition-colors", children: [
16918
- isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
16919
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-6 w-3/4" }),
16920
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-3.5 w-1/2" })
16921
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(Name, { name: data.name, description: data.description }),
16922
- isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
16923
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between py-1", children: [
16924
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-[76px] h-[76px] rounded-full" }),
16925
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-[76px] h-[76px] rounded-full" })
16926
- ] }),
16927
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border/20" }),
16928
- [1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsxs(
16929
- "div",
16930
- {
16931
- className: "rounded-lg border border-border/20 overflow-hidden",
16932
- children: [
16933
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-8 w-full" }),
16934
- [1, 2, 3].map((j) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-7 w-full mt-px" }, j))
16935
- ]
17043
+ var BodyComponent = ({
17044
+ data,
17045
+ isLoading,
17046
+ connections,
17047
+ isInput,
17048
+ externalSystem,
17049
+ isMobile,
17050
+ scrollable
17051
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: [
17052
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 h-5 bg-gradient-to-b from-card to-transparent z-10 pointer-events-none" }),
17053
+ /* @__PURE__ */ jsxRuntime.jsxs(
17054
+ "div",
17055
+ {
17056
+ className: [
17057
+ "px-3 py-3 space-y-3",
17058
+ scrollable ? "overflow-y-auto overscroll-contain [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-primary/20 [&::-webkit-scrollbar-thumb]:rounded-full" : "overflow-hidden",
17059
+ isMobile ? "max-h-[calc(85dvh-80px)]" : "max-h [&::-webkit-scrollbar]:hidden"
17060
+ ].join(" "),
17061
+ onPointerDownCapture: (e) => {
17062
+ if (scrollable) e.stopPropagation();
16936
17063
  },
16937
- i
16938
- ))
16939
- ] }) : connections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center", children: "Nenhuma conex\xE3o encontrada" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16940
- /* @__PURE__ */ jsxRuntime.jsx(
16941
- SystemsDiagram,
16942
- {
16943
- isInput,
16944
- currentSystem: data.name,
16945
- externalSystem
16946
- }
16947
- ),
16948
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-muted-foreground uppercase -mb-2", children: isInput ? "Informa\xE7\xF5es de Entrada" : "Informa\xE7\xF5es de Sa\xEDda" }) }),
16949
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: connections.map((conn) => /* @__PURE__ */ jsxRuntime.jsx(
16950
- IntegrationCard,
16951
- {
16952
- title: conn.name,
16953
- details: conn.integration
17064
+ onTouchStartCapture: (e) => {
17065
+ if (scrollable) e.stopPropagation();
16954
17066
  },
16955
- conn.id
16956
- )) })
16957
- ] })
17067
+ children: [
17068
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
17069
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-6 w-3/4" }),
17070
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-3.5 w-1/2" })
17071
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
17072
+ Name,
17073
+ {
17074
+ name: data.name,
17075
+ description: data.description,
17076
+ isMobile
17077
+ }
17078
+ ),
17079
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17080
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between py-1", children: [
17081
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-[76px] h-[76px] rounded-full" }),
17082
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "w-[76px] h-[76px] rounded-full" })
17083
+ ] }),
17084
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border/20" }),
17085
+ [1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsxs(
17086
+ "div",
17087
+ {
17088
+ className: "rounded-lg border border-border/20 overflow-hidden",
17089
+ children: [
17090
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-8 w-full" }),
17091
+ [1, 2, 3].map((j) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBase, { className: "h-7 w-full mt-px" }, j))
17092
+ ]
17093
+ },
17094
+ i
17095
+ ))
17096
+ ] }) : connections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center", children: "Nenhuma conex\xE3o encontrada" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17097
+ /* @__PURE__ */ jsxRuntime.jsx(
17098
+ SystemsDiagram,
17099
+ {
17100
+ isInput,
17101
+ currentSystem: data.name,
17102
+ externalSystem,
17103
+ isMobile
17104
+ }
17105
+ ),
17106
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-muted-foreground uppercase -mb-2", children: isInput ? "Informa\xE7\xF5es de Entrada" : "Informa\xE7\xF5es de Sa\xEDda" }) }),
17107
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: connections.map((conn) => /* @__PURE__ */ jsxRuntime.jsx(
17108
+ IntegrationCard,
17109
+ {
17110
+ title: conn.name,
17111
+ details: conn.integration,
17112
+ isMobile
17113
+ },
17114
+ conn.id
17115
+ )) })
17116
+ ] })
17117
+ ]
17118
+ }
17119
+ ),
17120
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-5 bg-gradient-to-t from-card to-transparent z-10 pointer-events-none" })
16958
17121
  ] });
16959
17122
  var Body = React32__namespace.default.memo(BodyComponent);
16960
17123
  var modalVariants = {
@@ -16974,6 +17137,25 @@ var modalVariants = {
16974
17137
  transition: { type: "spring", stiffness: 400, damping: 28 }
16975
17138
  }
16976
17139
  };
17140
+ function resolveSnapPx(snap) {
17141
+ const vh = typeof window !== "undefined" ? window.innerHeight : 800;
17142
+ if (snap === "collapsed") return 80;
17143
+ if (snap === "peek") return vh * 0.42;
17144
+ return vh * 0.85;
17145
+ }
17146
+ function nearestSnap(heightPx) {
17147
+ const snaps = ["collapsed", "peek", "full"];
17148
+ let best = "peek";
17149
+ let bestDist = Infinity;
17150
+ for (const s of snaps) {
17151
+ const dist = Math.abs(resolveSnapPx(s) - heightPx);
17152
+ if (dist < bestDist) {
17153
+ bestDist = dist;
17154
+ best = s;
17155
+ }
17156
+ }
17157
+ return best;
17158
+ }
16977
17159
  var IntegrationModal = ({
16978
17160
  id,
16979
17161
  data,
@@ -17068,6 +17250,66 @@ var IntegrationModal = ({
17068
17250
  },
17069
17251
  [id, onMouseDown]
17070
17252
  );
17253
+ const [snap, setSnap] = React32.useState("peek");
17254
+ const sheetHeight = framerMotion.useMotionValue(SNAP_HEIGHTS.peek);
17255
+ const snapTo = React32.useCallback(
17256
+ (target) => {
17257
+ setSnap(target);
17258
+ framerMotion.animate(sheetHeight, SNAP_HEIGHTS[target], {
17259
+ type: "spring",
17260
+ stiffness: 320,
17261
+ damping: 36
17262
+ });
17263
+ },
17264
+ [sheetHeight]
17265
+ );
17266
+ React32.useEffect(() => {
17267
+ if (isMobile) {
17268
+ sheetHeight.set("0px");
17269
+ framerMotion.animate(sheetHeight, SNAP_HEIGHTS.peek, {
17270
+ type: "spring",
17271
+ stiffness: 320,
17272
+ damping: 36
17273
+ });
17274
+ }
17275
+ }, [isMobile, sheetHeight]);
17276
+ const handleDragEnd = React32.useCallback(
17277
+ (_, info) => {
17278
+ const vy = info.velocity.y;
17279
+ const dy = info.offset.y;
17280
+ const currentHeightStr = sheetHeight.get();
17281
+ const currentHeightPx = typeof currentHeightStr === "string" && currentHeightStr.endsWith("dvh") ? parseFloat(currentHeightStr) / 100 * window.innerHeight : parseFloat(currentHeightStr);
17282
+ const draggedHeightPx = currentHeightPx - dy;
17283
+ const collapsedPx = resolveSnapPx("collapsed");
17284
+ if (draggedHeightPx < collapsedPx - CLOSE_THRESHOLD || snap === "collapsed" && vy > VELOCITY_THRESHOLD) {
17285
+ onClose(id);
17286
+ return;
17287
+ }
17288
+ if (vy < -VELOCITY_THRESHOLD) {
17289
+ if (snap === "collapsed") {
17290
+ snapTo("peek");
17291
+ return;
17292
+ }
17293
+ if (snap === "peek") {
17294
+ snapTo("full");
17295
+ return;
17296
+ }
17297
+ }
17298
+ if (vy > VELOCITY_THRESHOLD) {
17299
+ if (snap === "full") {
17300
+ snapTo("peek");
17301
+ return;
17302
+ }
17303
+ if (snap === "peek") {
17304
+ snapTo("collapsed");
17305
+ return;
17306
+ }
17307
+ }
17308
+ const nearest = nearestSnap(draggedHeightPx);
17309
+ snapTo(nearest);
17310
+ },
17311
+ [id, onClose, snap, snapTo, sheetHeight]
17312
+ );
17071
17313
  const inputConnections = React32.useMemo(
17072
17314
  () => data.connections.filter((c) => c.type === "entrada"),
17073
17315
  [data.connections]
@@ -17082,19 +17324,19 @@ var IntegrationModal = ({
17082
17324
  const header = /* @__PURE__ */ jsxRuntime.jsxs(
17083
17325
  "div",
17084
17326
  {
17085
- className: "flex items-center justify-between py-1 border-b border-border shrink-0 max-w-lg",
17086
- onMouseDown: handleMouseDownLocal,
17087
- onTouchStart: handleTouchStartLocal,
17327
+ className: "flex items-center justify-between py-1 border-b border-border shrink-0",
17328
+ onMouseDown: !isMobile ? handleMouseDownLocal : void 0,
17329
+ onTouchStart: !isMobile ? handleTouchStartLocal : void 0,
17088
17330
  style: {
17089
- touchAction: "none",
17090
- cursor: dragging ? "grabbing" : "grab"
17331
+ touchAction: isMobile ? "auto" : "none",
17332
+ cursor: isMobile ? "default" : dragging ? "grabbing" : "grab"
17091
17333
  },
17092
17334
  children: [
17093
17335
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3", children: [
17094
- /* @__PURE__ */ jsxRuntime.jsx(react.DotsSixVerticalIcon, { size: 16, className: "text-primary" }),
17336
+ !isMobile && /* @__PURE__ */ jsxRuntime.jsx(react.DotsSixVerticalIcon, { size: 16, className: "text-primary" }),
17095
17337
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: title })
17096
17338
  ] }),
17097
- /* @__PURE__ */ jsxRuntime.jsx(
17339
+ !isMobile && /* @__PURE__ */ jsxRuntime.jsx(
17098
17340
  ButtonBase,
17099
17341
  {
17100
17342
  variant: "ghost",
@@ -17108,7 +17350,15 @@ var IntegrationModal = ({
17108
17350
  ]
17109
17351
  }
17110
17352
  );
17111
- const bodyProps = { data, isLoading, connections, isInput, externalSystem };
17353
+ const bodyProps = {
17354
+ data,
17355
+ isLoading,
17356
+ connections,
17357
+ isInput,
17358
+ externalSystem,
17359
+ isMobile,
17360
+ scrollable: isMobile ? snap === "full" : true
17361
+ };
17112
17362
  if (isMobile) {
17113
17363
  return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17114
17364
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -17125,17 +17375,42 @@ var IntegrationModal = ({
17125
17375
  /* @__PURE__ */ jsxRuntime.jsxs(
17126
17376
  framerMotion.motion.div,
17127
17377
  {
17128
- className: "fixed bottom-0 left-0 right-0 z-[10000] bg-card border-t border-border/50 rounded-t-2xl shadow-2xl flex flex-col min-h-0",
17129
- style: { maxHeight: "85dvh" },
17130
- initial: { y: "100%" },
17131
- animate: { y: 0 },
17132
- exit: { y: "100%" },
17133
- transition: { type: "spring", stiffness: 320, damping: 36 },
17378
+ className: [
17379
+ "fixed bottom-0 left-0 right-0 z-[10000] bg-card border-t border-border/50 shadow-2xl flex flex-col",
17380
+ snap === "full" ? "rounded-t-[10px]" : "rounded-t-2xl"
17381
+ ].join(" "),
17382
+ style: {
17383
+ height: sheetHeight,
17384
+ touchAction: "none",
17385
+ overscrollBehavior: "none",
17386
+ boxShadow: snap === "full" ? "0 -8px 40px 0 rgba(0,0,0,0.32), 0 -1px 0 0 hsl(var(--border))" : void 0
17387
+ },
17388
+ drag: "y",
17389
+ dragConstraints: { top: 0, bottom: 0 },
17390
+ dragElastic: { top: 0.05, bottom: 0.25 },
17391
+ dragMomentum: false,
17392
+ onDragEnd: handleDragEnd,
17393
+ exit: { height: 0, opacity: 0, transition: { duration: 0.25 } },
17134
17394
  onClick: (e) => e.stopPropagation(),
17135
17395
  children: [
17136
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center pt-2.5 pb-1 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-1 rounded-full bg-border" }) }),
17396
+ snap !== "full" && /* @__PURE__ */ jsxRuntime.jsx(
17397
+ "div",
17398
+ {
17399
+ className: "flex justify-center pt-3 pb-1 shrink-0 touch-none",
17400
+ style: { touchAction: "none" },
17401
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-1 rounded-full bg-muted-foreground/30" })
17402
+ }
17403
+ ),
17404
+ snap === "full" && /* @__PURE__ */ jsxRuntime.jsx(
17405
+ "div",
17406
+ {
17407
+ className: "flex items-center justify-between px-4 pt-3 pb-2 shrink-0 touch-none",
17408
+ style: { touchAction: "none" },
17409
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-1 rounded-full bg-muted-foreground/30 mx-auto" })
17410
+ }
17411
+ ),
17137
17412
  header,
17138
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/40 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsx(Body, { ...bodyProps }) })
17413
+ /* @__PURE__ */ jsxRuntime.jsx(Body, { ...bodyProps })
17139
17414
  ]
17140
17415
  },
17141
17416
  `sheet-${id}`
@@ -21679,6 +21954,22 @@ function GroupLabel({ group }) {
21679
21954
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold text-muted-foreground uppercase tracking-widest", children: group.label })
21680
21955
  ] });
21681
21956
  }
21957
+ function HighlightText({ text, query }) {
21958
+ if (!query || !query.trim()) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: text });
21959
+ const terms = query.split(/[, ]+/).map((t) => t.trim()).filter((t) => t.length > 0);
21960
+ if (terms.length === 0) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: text });
21961
+ const escapedTerms = terms.map(
21962
+ (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
21963
+ );
21964
+ const regex = new RegExp(`(${escapedTerms.join("|")})`, "gi");
21965
+ const parts = text.split(regex);
21966
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts.map((part, i) => {
21967
+ const isMatch = terms.some(
21968
+ (t) => t.toLowerCase() === part.toLowerCase()
21969
+ );
21970
+ return isMatch ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary font-semibold", children: part }, i) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: part }, i);
21971
+ }) });
21972
+ }
21682
21973
  function mapBadgeVariantToColor(variant) {
21683
21974
  if (!variant) return void 0;
21684
21975
  switch (variant) {
@@ -21705,8 +21996,10 @@ function mapBadgeVariantToColor(variant) {
21705
21996
  function CommandItemRow({
21706
21997
  item,
21707
21998
  isActive,
21999
+ isSelected,
21708
22000
  onSelect,
21709
- onHover
22001
+ onHover,
22002
+ searchQuery
21710
22003
  }) {
21711
22004
  return /* @__PURE__ */ jsxRuntime.jsxs(
21712
22005
  framerMotion.motion.button,
@@ -21724,7 +22017,7 @@ function CommandItemRow({
21724
22017
  "span",
21725
22018
  {
21726
22019
  className: `relative flex-shrink-0 w-8 h-8 flex items-center justify-center rounded-md text-base
21727
- ${isActive ? "bg-primary/20 text-primary" : "bg-muted text-muted-foreground group-hover:text-foreground"}`,
22020
+ ${isSelected ? "bg-primary text-primary-foreground" : isActive ? "bg-primary/20 text-primary" : "bg-muted text-muted-foreground group-hover:text-foreground"}`,
21728
22021
  children: item.icon
21729
22022
  }
21730
22023
  ),
@@ -21734,15 +22027,22 @@ function CommandItemRow({
21734
22027
  "span",
21735
22028
  {
21736
22029
  className: `text-sm font-medium truncate ${isActive ? "text-foreground" : "text-foreground/80"}`,
21737
- children: item.label
22030
+ children: /* @__PURE__ */ jsxRuntime.jsx(HighlightText, { text: item.label, query: searchQuery })
21738
22031
  }
21739
22032
  ),
21740
22033
  item.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { color: mapBadgeVariantToColor(item.badgeVariant), children: item.badge.toUpperCase() })
21741
22034
  ] }),
21742
- item.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: item.description })
22035
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: /* @__PURE__ */ jsxRuntime.jsx(HighlightText, { text: item.description, query: searchQuery }) })
21743
22036
  ] }),
21744
22037
  item.shortcut && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative hidden sm:flex items-center gap-1 flex-shrink-0", children: item.shortcut.map((k, i) => /* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: k }, i)) }),
21745
- isActive && /* @__PURE__ */ jsxRuntime.jsx(
22038
+ isSelected && /* @__PURE__ */ jsxRuntime.jsx(
22039
+ framerMotion.motion.div,
22040
+ {
22041
+ layoutId: `selected-indicator-${item.id}`,
22042
+ className: "absolute left-0 top-1/2 -translate-y-1/2 w-1 h-2/3 bg-primary rounded-r-md"
22043
+ }
22044
+ ),
22045
+ isActive && !isSelected && /* @__PURE__ */ jsxRuntime.jsx(
21746
22046
  react.CaretRightIcon,
21747
22047
  {
21748
22048
  className: "relative w-4 h-4 text-primary flex-shrink-0",
@@ -21762,22 +22062,40 @@ function useCommandPalette({
21762
22062
  recentItems = [],
21763
22063
  onRecentItemsChange,
21764
22064
  maxRecentItems = 5,
21765
- multiSearch = false
22065
+ multiSearch = false,
22066
+ multiSelect = false,
22067
+ onSelectMultiple
21766
22068
  }) {
21767
22069
  const [query, setQuery] = React32__namespace.useState("");
21768
22070
  const [activeIndex, setActiveIndex] = React32__namespace.useState(0);
21769
22071
  const [page, setPage] = React32__namespace.useState(0);
22072
+ const [selectedItemIds, setSelectedItemIds] = React32__namespace.useState(
22073
+ /* @__PURE__ */ new Set()
22074
+ );
22075
+ const toggleSelection = React32__namespace.useCallback((id) => {
22076
+ setSelectedItemIds((prev) => {
22077
+ const next = new Set(prev);
22078
+ if (next.has(id)) next.delete(id);
22079
+ else next.add(id);
22080
+ return next;
22081
+ });
22082
+ }, []);
22083
+ const clearSelection = React32__namespace.useCallback(
22084
+ () => setSelectedItemIds(/* @__PURE__ */ new Set()),
22085
+ []
22086
+ );
21770
22087
  const baseGroups = React32__namespace.useMemo(
21771
22088
  () => normaliseGroups(items, groups),
21772
22089
  [items, groups]
21773
22090
  );
21774
- React32__namespace.useEffect(() => {
22091
+ React32.useEffect(() => {
21775
22092
  if (open) {
21776
22093
  setQuery("");
21777
22094
  setActiveIndex(0);
21778
22095
  setPage(0);
22096
+ clearSelection();
21779
22097
  }
21780
- }, [open]);
22098
+ }, [open, clearSelection]);
21781
22099
  const searchTerms = React32__namespace.useMemo(() => {
21782
22100
  const parts = query.split(",");
21783
22101
  if (parts.length <= 1 && !multiSearch) return [];
@@ -21840,12 +22158,35 @@ function useCommandPalette({
21840
22158
  () => displayedGroups.flatMap((g) => g.items),
21841
22159
  [displayedGroups]
21842
22160
  );
22161
+ const selectedItems = React32.useMemo(
22162
+ () => allFlatItems.filter((i) => selectedItemIds.has(i.id)),
22163
+ [allFlatItems, selectedItemIds]
22164
+ );
21843
22165
  const pageItemCount = flatItems.length;
21844
22166
  React32.useEffect(() => {
21845
22167
  setActiveIndex((i) => Math.min(i, Math.max(pageItemCount - 1, 0)));
21846
22168
  }, [pageItemCount]);
21847
- function handleSelect(item) {
22169
+ function executeBulkAction() {
22170
+ if (!onSelectMultiple || selectedItems.length === 0) return;
22171
+ onSelectMultiple(selectedItems);
22172
+ onOpenChange?.(false);
22173
+ }
22174
+ function handleSelect(item, event) {
21848
22175
  if (!item) return;
22176
+ if (multiSelect) {
22177
+ if (event && ("ctrlKey" in event || "metaKey" in event || "shiftKey" in event) && (event.ctrlKey || event.metaKey || event.shiftKey)) {
22178
+ toggleSelection(item.id);
22179
+ return;
22180
+ }
22181
+ if (selectedItems.length > 0) {
22182
+ const itemsToSubmit = selectedItemIds.has(item.id) ? selectedItems : [...selectedItems, item];
22183
+ if (onSelectMultiple) {
22184
+ onSelectMultiple(itemsToSubmit);
22185
+ }
22186
+ onOpenChange?.(false);
22187
+ return;
22188
+ }
22189
+ }
21849
22190
  item.onSelect();
21850
22191
  onOpenChange?.(false);
21851
22192
  if (onRecentItemsChange) {
@@ -21878,12 +22219,26 @@ function useCommandPalette({
21878
22219
  }
21879
22220
  } else if (e.key === "Enter") {
21880
22221
  e.preventDefault();
21881
- handleSelect(flatItems[activeIndex]);
22222
+ if (multiSelect && (e.ctrlKey || e.metaKey)) {
22223
+ executeBulkAction();
22224
+ return;
22225
+ }
22226
+ handleSelect(flatItems[activeIndex], e);
21882
22227
  }
21883
22228
  };
21884
22229
  document.addEventListener("keydown", handler);
21885
22230
  return () => document.removeEventListener("keydown", handler);
21886
- }, [open, flatItems, activeIndex, pageItemCount, page, totalPages]);
22231
+ }, [
22232
+ open,
22233
+ flatItems,
22234
+ activeIndex,
22235
+ pageItemCount,
22236
+ page,
22237
+ totalPages,
22238
+ executeBulkAction,
22239
+ handleSelect,
22240
+ multiSelect
22241
+ ]);
21887
22242
  return {
21888
22243
  query,
21889
22244
  setQuery,
@@ -21899,6 +22254,10 @@ function useCommandPalette({
21899
22254
  totalItems,
21900
22255
  totalPages,
21901
22256
  handleSelect,
22257
+ selectedItemIds,
22258
+ toggleSelection,
22259
+ selectedItems,
22260
+ executeBulkAction,
21902
22261
  isEmpty: totalItems === 0 && query.trim().length > 0,
21903
22262
  showList: query.trim() !== "" || recentItems.length > 0
21904
22263
  };
@@ -21958,8 +22317,12 @@ var VirtualResultList = React32.memo(
21958
22317
  displayedGroups,
21959
22318
  flatItems,
21960
22319
  activeIndex,
22320
+ multiSelect,
22321
+ selectedItemIds,
21961
22322
  onHover,
21962
- onSelect
22323
+ onSelect,
22324
+ onToggleSelection,
22325
+ searchQuery
21963
22326
  }) => {
21964
22327
  const rows = React32.useMemo(() => {
21965
22328
  const acc = [];
@@ -22015,8 +22378,12 @@ var VirtualResultList = React32.memo(
22015
22378
  {
22016
22379
  item: row.item,
22017
22380
  isActive: row.globalIdx === activeIndex,
22381
+ isSelected: selectedItemIds.has(row.item.id),
22382
+ multiSelect,
22018
22383
  onHover: () => onHover(row.globalIdx),
22019
- onSelect: () => onSelect(row.item)
22384
+ onSelect: (e) => onSelect(row.item, e),
22385
+ onToggleSelection: (e) => onToggleSelection(row.item.id, e),
22386
+ searchQuery
22020
22387
  }
22021
22388
  ) })
22022
22389
  },
@@ -22028,30 +22395,55 @@ var VirtualResultList = React32.memo(
22028
22395
  }
22029
22396
  );
22030
22397
  VirtualResultList.displayName = "VirtualResultList";
22031
- var FooterBar = React32.memo(({ footer, totalItems }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/30", children: [
22032
- footer ?? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-[11px] text-muted-foreground", children: [
22033
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22034
- /* @__PURE__ */ jsxRuntime.jsx(react.ArrowElbowDownRightIcon, { className: "w-3 h-3" }),
22035
- "Selecionar"
22036
- ] }),
22037
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22038
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: "\u2191\u2193" }),
22039
- "Navegar"
22040
- ] }),
22041
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22042
- /* @__PURE__ */ jsxRuntime.jsx(react.ArrowBendUpLeftIcon, { className: "w-3 h-3" }),
22043
- "Fechar"
22044
- ] })
22045
- ] }),
22046
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
22047
- /* @__PURE__ */ jsxRuntime.jsx(react.CommandIcon, { className: "w-3 h-3" }),
22048
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
22049
- totalItems,
22050
- " resultado",
22051
- totalItems !== 1 ? "s" : ""
22398
+ var FooterBar = React32.memo(
22399
+ ({
22400
+ footer,
22401
+ totalItems,
22402
+ selectedCount = 0,
22403
+ executeBulkAction
22404
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/30", children: [
22405
+ footer ?? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4 text-[11px] text-muted-foreground", children: selectedCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
22406
+ /* @__PURE__ */ jsxRuntime.jsxs(
22407
+ "button",
22408
+ {
22409
+ onClick: executeBulkAction,
22410
+ className: "flex items-center gap-1.5 text-primary hover:text-primary/80 transition-colors font-medium cursor-pointer",
22411
+ children: [
22412
+ /* @__PURE__ */ jsxRuntime.jsx(react.CommandIcon, { className: "w-3 h-3" }),
22413
+ " Confirmar (",
22414
+ selectedCount,
22415
+ ")"
22416
+ ]
22417
+ }
22418
+ ),
22419
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22420
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: "Ctrl+Enter" }),
22421
+ "Finalizar sele\xE7\xE3o"
22422
+ ] })
22423
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
22424
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22425
+ /* @__PURE__ */ jsxRuntime.jsx(react.ArrowElbowDownRightIcon, { className: "w-3 h-3" }),
22426
+ "Selecionar"
22427
+ ] }),
22428
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22429
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: "\u2191\u2193" }),
22430
+ "Navegar"
22431
+ ] }),
22432
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
22433
+ /* @__PURE__ */ jsxRuntime.jsx(react.ArrowBendUpLeftIcon, { className: "w-3 h-3" }),
22434
+ "Fechar"
22435
+ ] })
22436
+ ] }) }),
22437
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
22438
+ /* @__PURE__ */ jsxRuntime.jsx(react.CommandIcon, { className: "w-3 h-3" }),
22439
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
22440
+ totalItems,
22441
+ " resultado",
22442
+ totalItems !== 1 ? "s" : ""
22443
+ ] })
22052
22444
  ] })
22053
22445
  ] })
22054
- ] }));
22446
+ );
22055
22447
  FooterBar.displayName = "FooterBar";
22056
22448
  function CommandPalette(props) {
22057
22449
  const {
@@ -22061,6 +22453,7 @@ function CommandPalette(props) {
22061
22453
  footer,
22062
22454
  debounceDelay = 300,
22063
22455
  multiSearch = false,
22456
+ multiSelect = false,
22064
22457
  emptyMessage = "Nenhum resultado encontrado.",
22065
22458
  shortcut = { key: "k", ctrl: true }
22066
22459
  } = props;
@@ -22077,6 +22470,9 @@ function CommandPalette(props) {
22077
22470
  flatItems,
22078
22471
  totalItems,
22079
22472
  handleSelect,
22473
+ selectedItemIds,
22474
+ toggleSelection,
22475
+ executeBulkAction,
22080
22476
  isEmpty,
22081
22477
  showList
22082
22478
  } = useCommandPalette({
@@ -22133,8 +22529,12 @@ function CommandPalette(props) {
22133
22529
  displayedGroups,
22134
22530
  flatItems,
22135
22531
  activeIndex,
22532
+ multiSelect,
22533
+ selectedItemIds,
22136
22534
  onHover: setActiveIndex,
22137
- onSelect: handleSelect
22535
+ onSelect: handleSelect,
22536
+ onToggleSelection: toggleSelection,
22537
+ searchQuery: query
22138
22538
  };
22139
22539
  if (isMobile) {
22140
22540
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -22177,65 +22577,60 @@ function CommandPalette(props) {
22177
22577
  ] }) })
22178
22578
  ] });
22179
22579
  }
22180
- return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
22181
- /* @__PURE__ */ jsxRuntime.jsx(
22182
- framerMotion.motion.div,
22183
- {
22184
- initial: { opacity: 0 },
22185
- animate: { opacity: 1 },
22186
- exit: { opacity: 0 },
22187
- transition: ANIMATION.overlay,
22188
- className: "fixed inset-0 z-[100] bg-background/80 backdrop-blur-sm",
22189
- onClick: handleClose
22190
- }
22191
- ),
22192
- /* @__PURE__ */ jsxRuntime.jsxs(
22193
- framerMotion.motion.div,
22194
- {
22195
- initial: { opacity: 0, scale: 0.96, y: -8 },
22196
- animate: { opacity: 1, scale: 1, y: 0 },
22197
- exit: { opacity: 0, scale: 0.96, y: -8 },
22198
- transition: ANIMATION.panel,
22199
- className: "fixed z-[100] top-12 -translate-x-1/2 -translate-y-1/2 w-full max-w-xl rounded-xl border border-border overflow-hidden shadow-2xl shadow-black/20 dark:shadow-black/60 bg-popover/95 backdrop-blur-xl",
22200
- style: { maxHeight: "min(600px, 80vh)" },
22201
- children: [
22202
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 border-b border-border", children: [
22203
- /* @__PURE__ */ jsxRuntime.jsx(
22204
- react.MagnifyingGlassIcon,
22205
- {
22206
- className: "w-4 h-4 text-muted-foreground flex-shrink-0",
22207
- weight: "bold"
22208
- }
22209
- ),
22210
- /* @__PURE__ */ jsxRuntime.jsx(
22211
- DebouncedInput,
22212
- {
22213
- ref: inputRef,
22214
- value: query,
22215
- debounce: debounceDelay,
22216
- onChange: handleQueryChange,
22217
- placeholder: searchPlaceholder,
22218
- rightIcon: query ? /* @__PURE__ */ jsxRuntime.jsx(
22219
- ButtonBase,
22220
- {
22221
- variant: "ghost",
22222
- size: "icon",
22223
- onClick: handleClearQuery,
22224
- className: "text-muted-foreground hover:text-red-500 hover:bg-transparent transition-colors",
22225
- children: /* @__PURE__ */ jsxRuntime.jsx(react.XIcon, { className: "w-4 h-4" })
22226
- }
22227
- ) : void 0,
22228
- className: "flex-1 bg-transparent border-none focus-visible:ring-0 outline-none shadow-none px-0 h-7 text-sm caret-primary"
22229
- }
22230
- )
22231
- ] }),
22232
- /* @__PURE__ */ jsxRuntime.jsx(SearchBadges, { terms: searchTerms }),
22233
- showList && /* @__PURE__ */ jsxRuntime.jsx(VirtualResultList, { ...sharedListProps }),
22234
- /* @__PURE__ */ jsxRuntime.jsx(FooterBar, { footer, totalItems })
22235
- ]
22236
- }
22237
- )
22238
- ] }) });
22580
+ return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
22581
+ framerMotion.motion.div,
22582
+ {
22583
+ initial: { opacity: 0, scale: 0.96, y: -8 },
22584
+ animate: { opacity: 1, scale: 1, y: 0 },
22585
+ exit: { opacity: 0, scale: 0.96, y: -8 },
22586
+ transition: ANIMATION.panel,
22587
+ className: "fixed z-[100] top-4 -translate-x-1/2 w-full max-w-xl rounded-xl border border-border overflow-hidden shadow-2xl shadow-black/20 dark:shadow-black/60 bg-popover/95 backdrop-blur-xl",
22588
+ style: { maxHeight: "min(600px, 80vh)" },
22589
+ children: [
22590
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 border-b border-border", children: [
22591
+ /* @__PURE__ */ jsxRuntime.jsx(
22592
+ react.MagnifyingGlassIcon,
22593
+ {
22594
+ className: "w-4 h-4 text-muted-foreground flex-shrink-0",
22595
+ weight: "bold"
22596
+ }
22597
+ ),
22598
+ /* @__PURE__ */ jsxRuntime.jsx(
22599
+ DebouncedInput,
22600
+ {
22601
+ ref: inputRef,
22602
+ value: query,
22603
+ debounce: debounceDelay,
22604
+ onChange: handleQueryChange,
22605
+ placeholder: searchPlaceholder,
22606
+ rightIcon: query ? /* @__PURE__ */ jsxRuntime.jsx(
22607
+ ButtonBase,
22608
+ {
22609
+ variant: "ghost",
22610
+ size: "icon",
22611
+ onClick: handleClearQuery,
22612
+ className: "text-muted-foreground hover:text-red-500 hover:bg-transparent transition-colors",
22613
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.XIcon, { className: "w-4 h-4" })
22614
+ }
22615
+ ) : void 0,
22616
+ className: "flex-1 bg-transparent border-none focus-visible:ring-0 outline-none shadow-none px-0 h-7 text-sm caret-primary"
22617
+ }
22618
+ )
22619
+ ] }),
22620
+ /* @__PURE__ */ jsxRuntime.jsx(SearchBadges, { terms: searchTerms }),
22621
+ showList && /* @__PURE__ */ jsxRuntime.jsx(VirtualResultList, { ...sharedListProps }),
22622
+ /* @__PURE__ */ jsxRuntime.jsx(
22623
+ FooterBar,
22624
+ {
22625
+ footer,
22626
+ totalItems,
22627
+ selectedCount: selectedItemIds.size,
22628
+ executeBulkAction
22629
+ }
22630
+ )
22631
+ ]
22632
+ }
22633
+ ) }) });
22239
22634
  }
22240
22635
 
22241
22636
  exports.AddButton = AddButton;