@lv-x-software-house/x_view 1.2.2-dev.12 → 1.2.2-dev.14

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.
Files changed (3) hide show
  1. package/dist/index.js +969 -817
  2. package/dist/index.mjs +405 -253
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/XViewScene.jsx
2
- import React23, { useCallback as useCallback3, useEffect as useEffect21, useRef as useRef17, useState as useState22, useMemo as useMemo12 } from "react";
2
+ import React23, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef17, useState as useState23, useMemo as useMemo12 } from "react";
3
3
  import { useRouter, useSearchParams } from "next/navigation";
4
4
  import { useSession } from "next-auth/react";
5
5
  import CryptoJS from "crypto-js";
@@ -735,7 +735,7 @@ function XViewSidebar({
735
735
  }
736
736
 
737
737
  // src/components/AncestryRelationshipPanel.jsx
738
- import React8, { useState as useState8, useEffect as useEffect8, useRef as useRef7 } from "react";
738
+ import React8, { useState as useState9, useEffect as useEffect8, useRef as useRef7 } from "react";
739
739
 
740
740
  // node_modules/uuid/dist/esm-node/rng.js
741
741
  import crypto from "crypto";
@@ -785,6 +785,7 @@ function v4(options, buf, offset) {
785
785
  var v4_default = v4;
786
786
 
787
787
  // src/logic/x_view_utils.js
788
+ import { useState as useState3, useCallback } from "react";
788
789
  import * as THREE2 from "three";
789
790
 
790
791
  // src/logic/x_view_config.js
@@ -2999,9 +3000,36 @@ var extractFileUrlsFromProperties = (dataObject) => {
2999
3000
  });
3000
3001
  return urlsToDelete;
3001
3002
  };
3003
+ function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
3004
+ const [width, setWidth] = useState3(initialWidth);
3005
+ const [isResizing, setIsResizing] = useState3(false);
3006
+ const handlePointerDown = useCallback((e) => {
3007
+ e.preventDefault();
3008
+ e.stopPropagation();
3009
+ setIsResizing(true);
3010
+ const startX = e.clientX;
3011
+ const startWidth = width;
3012
+ const originalUserSelect = document.body.style.userSelect;
3013
+ document.body.style.userSelect = "none";
3014
+ const handlePointerMove = (moveEvent) => {
3015
+ const deltaX = startX - moveEvent.clientX;
3016
+ const newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);
3017
+ setWidth(newWidth);
3018
+ };
3019
+ const handlePointerUp = () => {
3020
+ setIsResizing(false);
3021
+ document.body.style.userSelect = originalUserSelect;
3022
+ document.removeEventListener("pointermove", handlePointerMove);
3023
+ document.removeEventListener("pointerup", handlePointerUp);
3024
+ };
3025
+ document.addEventListener("pointermove", handlePointerMove);
3026
+ document.addEventListener("pointerup", handlePointerUp);
3027
+ }, [width, minWidth, maxWidth]);
3028
+ return { width, isResizing, handlePointerDown, setWidth };
3029
+ }
3002
3030
 
3003
3031
  // src/components/CustomPropertyDisplay.jsx
3004
- import React3, { useState as useState3, useRef as useRef3, useEffect as useEffect3 } from "react";
3032
+ import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
3005
3033
  import { FiCheck, FiX, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
3006
3034
  function CustomPropertyDisplay({
3007
3035
  prop,
@@ -3016,12 +3044,12 @@ function CustomPropertyDisplay({
3016
3044
  },
3017
3045
  onUploadFile
3018
3046
  }) {
3019
- const [isEditing, setIsEditing] = useState3(prop.isEditing ?? false);
3020
- const [tempProp, setTempProp] = useState3(prop);
3021
- const [isHovered, setIsHovered] = useState3(false);
3022
- const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState3(false);
3047
+ const [isEditing, setIsEditing] = useState4(prop.isEditing ?? false);
3048
+ const [tempProp, setTempProp] = useState4(prop);
3049
+ const [isHovered, setIsHovered] = useState4(false);
3050
+ const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState4(false);
3023
3051
  const dropdownRef = useRef3(null);
3024
- const [uploadingItemIndex, setUploadingItemIndex] = useState3(null);
3052
+ const [uploadingItemIndex, setUploadingItemIndex] = useState4(null);
3025
3053
  const fileInputRef = useRef3(null);
3026
3054
  const currentUploadTargetRef = useRef3(null);
3027
3055
  useEffect3(() => {
@@ -3367,15 +3395,15 @@ function CustomPropertyDisplay({
3367
3395
  import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
3368
3396
 
3369
3397
  // src/components/DescriptionEditModal.jsx
3370
- import React5, { useState as useState5, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
3398
+ import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
3371
3399
  import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage } from "react-icons/fi";
3372
3400
 
3373
3401
  // src/components/SectionImportModal.jsx
3374
- import React4, { useState as useState4, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
3402
+ import React4, { useState as useState5, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
3375
3403
  import { FiSearch, FiLayers as FiLayers2, FiHexagon, FiClock, FiCheck as FiCheck2, FiCopy, FiTerminal, FiChevronDown as FiChevronDown2, FiChevronRight, FiDownload, FiLink } from "react-icons/fi";
3376
3404
  var CodeBlock = ({ content, isActive, onClick }) => {
3377
- const [isExpanded, setIsExpanded] = useState4(false);
3378
- const [copied, setCopied] = useState4(false);
3405
+ const [isExpanded, setIsExpanded] = useState5(false);
3406
+ const [copied, setCopied] = useState5(false);
3379
3407
  const cleanContent = content.replace(/^```|```$/g, "").trim();
3380
3408
  const isLongCode = cleanContent.split("\n").length > 4;
3381
3409
  const handleCopy = (e) => {
@@ -3438,12 +3466,14 @@ var formatLineContent = (line) => {
3438
3466
  return /* @__PURE__ */ React4.createElement("span", { className: "break-words" }, line);
3439
3467
  };
3440
3468
  function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], availableAncestries = [] }) {
3441
- const [searchTerm, setSearchTerm] = useState4("");
3442
- const [selectedItem, setSelectedItem] = useState4(null);
3443
- const [searchHistory, setSearchHistory] = useState4([]);
3444
- const [activeIndex, setActiveIndex] = useState4(0);
3469
+ const [searchTerm, setSearchTerm] = useState5("");
3470
+ const [selectedItem, setSelectedItem] = useState5(null);
3471
+ const [searchHistory, setSearchHistory] = useState5([]);
3472
+ const [activeIndex, setActiveIndex] = useState5(0);
3473
+ const [selectedIndices, setSelectedIndices] = useState5(/* @__PURE__ */ new Set([0]));
3474
+ const [lastSelectedIndex, setLastSelectedIndex] = useState5(0);
3445
3475
  const sectionRefs = useRef4([]);
3446
- const [isDropdownOpen, setIsDropdownOpen] = useState4(false);
3476
+ const [isDropdownOpen, setIsDropdownOpen] = useState5(false);
3447
3477
  const inputRef = useRef4(null);
3448
3478
  useEffect4(() => {
3449
3479
  if (!selectedItem) return;
@@ -3490,6 +3520,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3490
3520
  }, [selectedItem]);
3491
3521
  useEffect4(() => {
3492
3522
  setActiveIndex(0);
3523
+ setSelectedIndices(/* @__PURE__ */ new Set([0]));
3524
+ setLastSelectedIndex(0);
3493
3525
  }, [selectedItem]);
3494
3526
  useEffect4(() => {
3495
3527
  if (selectedItem && sectionRefs.current[activeIndex]) {
@@ -3506,22 +3538,64 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3506
3538
  if (document.activeElement === inputRef.current) return;
3507
3539
  if (e.key === "ArrowDown" || e.key === "ArrowRight") {
3508
3540
  e.preventDefault();
3509
- setActiveIndex((prev) => Math.min(prev + 1, itemSections.length - 1));
3541
+ setActiveIndex((prev) => {
3542
+ const next = Math.min(prev + 1, itemSections.length - 1);
3543
+ if (e.shiftKey) {
3544
+ setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
3545
+ } else if (!e.ctrlKey && !e.metaKey) {
3546
+ setSelectedIndices(/* @__PURE__ */ new Set([next]));
3547
+ setLastSelectedIndex(next);
3548
+ }
3549
+ return next;
3550
+ });
3510
3551
  }
3511
3552
  if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
3512
3553
  e.preventDefault();
3513
- setActiveIndex((prev) => Math.max(prev - 1, 0));
3554
+ setActiveIndex((prev) => {
3555
+ const next = Math.max(prev - 1, 0);
3556
+ if (e.shiftKey) {
3557
+ setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
3558
+ } else if (!e.ctrlKey && !e.metaKey) {
3559
+ setSelectedIndices(/* @__PURE__ */ new Set([next]));
3560
+ setLastSelectedIndex(next);
3561
+ }
3562
+ return next;
3563
+ });
3514
3564
  }
3515
3565
  if (e.key === "Enter") {
3516
3566
  e.preventDefault();
3517
- if (itemSections[activeIndex]) {
3518
- handleConfirmImport(itemSections[activeIndex]);
3519
- }
3567
+ handleConfirmImport();
3520
3568
  }
3521
3569
  };
3522
3570
  window.addEventListener("keydown", handleKeyDown);
3523
3571
  return () => window.removeEventListener("keydown", handleKeyDown);
3524
- }, [itemSections, activeIndex, selectedItem]);
3572
+ }, [itemSections, selectedItem]);
3573
+ const handleSectionClick = (index, e) => {
3574
+ e.stopPropagation();
3575
+ if (e.shiftKey && lastSelectedIndex !== null) {
3576
+ const start = Math.min(lastSelectedIndex, index);
3577
+ const end = Math.max(lastSelectedIndex, index);
3578
+ const newSelection = new Set(selectedIndices);
3579
+ for (let i = start; i <= end; i++) {
3580
+ newSelection.add(i);
3581
+ }
3582
+ setSelectedIndices(newSelection);
3583
+ } else if (e.ctrlKey || e.metaKey) {
3584
+ const newSelection = new Set(selectedIndices);
3585
+ if (newSelection.has(index)) {
3586
+ newSelection.delete(index);
3587
+ if (newSelection.size === 0) newSelection.add(index);
3588
+ } else {
3589
+ newSelection.add(index);
3590
+ }
3591
+ setSelectedIndices(newSelection);
3592
+ setLastSelectedIndex(index);
3593
+ } else {
3594
+ setSelectedIndices(/* @__PURE__ */ new Set([index]));
3595
+ setLastSelectedIndex(index);
3596
+ }
3597
+ setActiveIndex(index);
3598
+ };
3525
3599
  const handleSelectItem = (item) => {
3526
3600
  setSelectedItem(item);
3527
3601
  setSearchHistory((prev) => {
@@ -3535,16 +3609,22 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3535
3609
  setSearchTerm("");
3536
3610
  setIsDropdownOpen(false);
3537
3611
  };
3538
- const handleConfirmImport = (sectionToImport = null) => {
3539
- const section = sectionToImport || itemSections[activeIndex];
3540
- if (!section) return;
3612
+ const handleConfirmImport = () => {
3613
+ if (selectedIndices.size === 0) return;
3541
3614
  const type = selectedItem._type;
3542
3615
  const itemId = selectedItem.id || selectedItem.ancestry_id;
3543
- if (section.id) {
3544
- const tag = `[[REF:${type}:${itemId}:${section.id}]]`;
3545
- onSelect(tag);
3616
+ const indicesToImport = Array.from(selectedIndices).sort((a, b) => a - b);
3617
+ const tagsToImport = [];
3618
+ indicesToImport.forEach((idx) => {
3619
+ const section = itemSections[idx];
3620
+ if (section && section.id) {
3621
+ tagsToImport.push(`[[REF:${type}:${itemId}:${section.id}]]`);
3622
+ }
3623
+ });
3624
+ if (tagsToImport.length > 0) {
3625
+ onSelect(tagsToImport);
3546
3626
  } else {
3547
- alert("Esta se\xE7\xE3o n\xE3o possui um ID \xFAnico salvo. Salve o node de origem primeiro.");
3627
+ alert("Nenhuma se\xE7\xE3o v\xE1lida selecionada.");
3548
3628
  }
3549
3629
  };
3550
3630
  const renderSectionContent = (content) => {
@@ -3615,7 +3695,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3615
3695
  /* @__PURE__ */ React4.createElement("div", { className: "truncate" }, /* @__PURE__ */ React4.createElement("div", { className: "text-sm font-medium text-slate-200 truncate" }, item.name), /* @__PURE__ */ React4.createElement("div", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, isNode ? ((_a = item.version_node) == null ? void 0 : _a.is_version) ? "Vers\xE3o" : "Node" : "Ancestralidade"))
3616
3696
  );
3617
3697
  }))), /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col bg-black/20 relative z-10" }, selectedItem ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 pr-8" }, /* @__PURE__ */ React4.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap" }, itemSections.map((section, index) => {
3618
- const isActive = index === activeIndex;
3698
+ const isSelected = selectedIndices.has(index);
3699
+ const isFocused = index === activeIndex;
3619
3700
  const match = section.content.match(/^(\s*)([\s\S]*?)(\s*)$/);
3620
3701
  let leadingSpace = match ? match[1] : "";
3621
3702
  const bodyText = match ? match[2] : section.content;
@@ -3633,10 +3714,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3633
3714
  refAssigned = true;
3634
3715
  }
3635
3716
  },
3636
- onClick: () => setActiveIndex(index),
3717
+ onClick: (e) => handleSectionClick(index, e),
3637
3718
  className: `
3638
3719
  transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
3639
- ${isActive ? "bg-indigo-500/20 ring-1 ring-indigo-500/30" : "hover:bg-white/5"}
3720
+ ${isSelected ? "bg-indigo-500/30 ring-1 ring-indigo-500/50" : "hover:bg-white/5"}
3721
+ ${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
3640
3722
  `
3641
3723
  },
3642
3724
  renderSectionContent(bodyText)
@@ -3657,8 +3739,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3657
3739
  CodeBlock,
3658
3740
  {
3659
3741
  content: part,
3660
- isActive,
3661
- onClick: () => setActiveIndex(index)
3742
+ isActive: isSelected,
3743
+ onClick: (e) => handleSectionClick(index, e)
3662
3744
  }
3663
3745
  )
3664
3746
  );
@@ -3668,7 +3750,7 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3668
3750
  const isLastLine = lineIndex === lines.length - 1;
3669
3751
  const isEmptyLine = line.trim() === "";
3670
3752
  if (isEmptyLine) {
3671
- return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: `${index}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React4.createElement("br", null));
3753
+ return /* @__PURE__ */ React4.createElement("br", { key: `${index}-${partIndex}-${lineIndex}` });
3672
3754
  }
3673
3755
  return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: `${index}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React4.createElement(
3674
3756
  "span",
@@ -3679,10 +3761,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3679
3761
  refAssigned = true;
3680
3762
  }
3681
3763
  },
3682
- onClick: () => setActiveIndex(index),
3764
+ onClick: (e) => handleSectionClick(index, e),
3683
3765
  className: `
3684
- transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
3685
- ${isActive ? "bg-indigo-500/20 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
3766
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone select-none
3767
+ ${isSelected ? "bg-indigo-500/30 text-white ring-1 ring-indigo-500/50 shadow-sm" : "hover:bg-white/5 hover:text-slate-200"}
3768
+ ${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
3686
3769
  `
3687
3770
  },
3688
3771
  formatLineContent(line)
@@ -3696,7 +3779,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3696
3779
  className: "flex items-center gap-2 px-6 py-2.5 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-semibold rounded-lg shadow-lg shadow-indigo-500/20 transition-all transform active:scale-95"
3697
3780
  },
3698
3781
  /* @__PURE__ */ React4.createElement(FiDownload, { className: "text-indigo-200" }),
3699
- "Importar Se\xE7\xE3o"
3782
+ "Importar ",
3783
+ selectedIndices.size > 1 ? `${selectedIndices.size} Se\xE7\xF5es` : "Se\xE7\xE3o"
3700
3784
  ))) : /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col items-center justify-center text-slate-500" }, /* @__PURE__ */ React4.createElement("div", { className: "w-16 h-16 rounded-full bg-white/5 flex items-center justify-center mb-4" }, /* @__PURE__ */ React4.createElement(FiSearch, { size: 24, className: "opacity-50" })), /* @__PURE__ */ React4.createElement("p", null, "Selecione um item \xE0 esquerda para visualizar suas se\xE7\xF5es."))))
3701
3785
  ));
3702
3786
  }
@@ -3728,16 +3812,22 @@ function DescriptionEditModal({
3728
3812
  availableAncestries = [],
3729
3813
  availableImages = []
3730
3814
  }) {
3731
- const [text, setText] = useState5(initialValue || "");
3815
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.9 : 1200;
3816
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize } = useResizablePanel({
3817
+ initialWidth: 700,
3818
+ minWidth: 400,
3819
+ maxWidth: maxPanelW
3820
+ });
3821
+ const [text, setText] = useState6(initialValue || "");
3732
3822
  const textareaRef = useRef5(null);
3733
- const [isImportModalOpen, setIsImportModalOpen] = useState5(false);
3734
- const [isMentionModalOpen, setIsMentionModalOpen] = useState5(false);
3735
- const [mentionSearch, setMentionSearch] = useState5("");
3736
- const [mentionTriggerIndex, setMentionTriggerIndex] = useState5(null);
3737
- const [isImageModalOpen, setIsImageModalOpen] = useState5(false);
3738
- const [manualImageUrl, setManualImageUrl] = useState5("");
3823
+ const [isImportModalOpen, setIsImportModalOpen] = useState6(false);
3824
+ const [isMentionModalOpen, setIsMentionModalOpen] = useState6(false);
3825
+ const [mentionSearch, setMentionSearch] = useState6("");
3826
+ const [mentionTriggerIndex, setMentionTriggerIndex] = useState6(null);
3827
+ const [isImageModalOpen, setIsImageModalOpen] = useState6(false);
3828
+ const [manualImageUrl, setManualImageUrl] = useState6("");
3739
3829
  const hoverTimeoutRef = useRef5(null);
3740
- const [tooltipData, setTooltipData] = useState5(null);
3830
+ const [tooltipData, setTooltipData] = useState6(null);
3741
3831
  useEffect5(() => {
3742
3832
  const handleKeyDown = (e) => {
3743
3833
  if (e.key === "Escape") {
@@ -3830,12 +3920,28 @@ function DescriptionEditModal({
3830
3920
  const uniqueSuffix = v4_default().slice(0, 4);
3831
3921
  insertAtCursor(`*/${nextNum}:${uniqueSuffix}/ `);
3832
3922
  };
3833
- const handleImportSelect = (tag) => {
3834
- const nextNum = getNextSectionNumber(text);
3835
- const uniqueSuffix = v4_default().slice(0, 4);
3836
- insertAtCursor(`
3837
- */${nextNum}:${uniqueSuffix}/ ${tag}
3838
- `);
3923
+ const handleImportSelect = (tags) => {
3924
+ const tagsArray = Array.isArray(tags) ? tags : [tags];
3925
+ const el = textareaRef.current;
3926
+ if (!el) return;
3927
+ let currentText = text;
3928
+ let currentNum = getNextSectionNumber(currentText);
3929
+ let blockToInsert = "";
3930
+ tagsArray.forEach((tag) => {
3931
+ const uniqueSuffix = v4_default().slice(0, 4);
3932
+ blockToInsert += `
3933
+ */${currentNum}:${uniqueSuffix}/ ${tag}
3934
+ `;
3935
+ currentNum++;
3936
+ });
3937
+ const start = el.selectionStart;
3938
+ const end = el.selectionEnd;
3939
+ const newText = currentText.substring(0, start) + blockToInsert + currentText.substring(end);
3940
+ el.value = newText;
3941
+ el.setSelectionRange(start + blockToInsert.length, start + blockToInsert.length);
3942
+ el.dispatchEvent(new Event("input", { bubbles: true }));
3943
+ el.focus();
3944
+ setText(newText);
3839
3945
  setIsImportModalOpen(false);
3840
3946
  };
3841
3947
  const handleMentionSelect = (node) => {
@@ -3880,7 +3986,8 @@ function DescriptionEditModal({
3880
3986
  return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement("div", { className: "fixed inset-0 z-[2000] flex justify-end pointer-events-none bg-transparent" }, /* @__PURE__ */ React5.createElement(
3881
3987
  "div",
3882
3988
  {
3883
- className: "ui-overlay pointer-events-auto relative group h-full w-[min(90vw,700px)] border-l border-white/10 bg-slate-950/95 shadow-2xl text-white flex flex-col",
3989
+ className: `ui-overlay pointer-events-auto relative group h-full border-l border-white/10 bg-slate-950/95 shadow-2xl text-white flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
3990
+ style: { width: `${panelWidth}px`, maxWidth: "90vw" },
3884
3991
  onClick: swallow,
3885
3992
  onPointerDown: swallow,
3886
3993
  onPointerMove: swallow,
@@ -3889,6 +3996,17 @@ function DescriptionEditModal({
3889
3996
  onContextMenu: swallow,
3890
3997
  onDoubleClick: swallow
3891
3998
  },
3999
+ /* @__PURE__ */ React5.createElement(
4000
+ "div",
4001
+ {
4002
+ onPointerDown: (e) => {
4003
+ e.stopPropagation();
4004
+ handleResize(e);
4005
+ },
4006
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
4007
+ title: "Arraste para redimensionar"
4008
+ }
4009
+ ),
3892
4010
  /* @__PURE__ */ React5.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 shrink-0" }),
3893
4011
  /* @__PURE__ */ React5.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React5.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80" }), /* @__PURE__ */ React5.createElement("p", { className: "text-sm font-medium text-slate-200" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ React5.createElement("button", { onClick: handleClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
3894
4012
  /* @__PURE__ */ React5.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 overflow-x-auto custom-scrollbar" }, /* @__PURE__ */ React5.createElement(
@@ -4080,11 +4198,11 @@ function DescriptionEditModal({
4080
4198
  }
4081
4199
 
4082
4200
  // src/components/DescriptionDisplay.jsx
4083
- import React6, { useMemo as useMemo5, useState as useState6, useEffect as useEffect6, useRef as useRef6 } from "react";
4201
+ import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
4084
4202
  import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2 } from "react-icons/fi";
4085
4203
  var CodeBlock2 = ({ content, isActive, onClick }) => {
4086
- const [isExpanded, setIsExpanded] = useState6(false);
4087
- const [copied, setCopied] = useState6(false);
4204
+ const [isExpanded, setIsExpanded] = useState7(false);
4205
+ const [copied, setCopied] = useState7(false);
4088
4206
  const cleanContent = content.replace(/^```|```$/g, "").trim();
4089
4207
  const isLongCode = cleanContent.split("\n").length > 4;
4090
4208
  const handleCopy = (e) => {
@@ -4283,7 +4401,7 @@ function DescriptionDisplay({
4283
4401
  });
4284
4402
  return navItems;
4285
4403
  }, [sections]);
4286
- const [currentStepIndex, setCurrentStepIndex] = useState6(0);
4404
+ const [currentStepIndex, setCurrentStepIndex] = useState7(0);
4287
4405
  const activeRef = useRef6(null);
4288
4406
  const lastNotifiedSectionId = useRef6(null);
4289
4407
  const isInitialMount = useRef6(true);
@@ -4464,7 +4582,7 @@ function DescriptionDisplay({
4464
4582
  }
4465
4583
 
4466
4584
  // src/components/DescriptionReadModePanel.jsx
4467
- import React7, { useState as useState7, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4585
+ import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4468
4586
  import {
4469
4587
  FiArrowLeft,
4470
4588
  FiEdit2,
@@ -4566,10 +4684,10 @@ function DescriptionReadModePanel({
4566
4684
  onRenderAbstractionTree = null,
4567
4685
  initialShowAbstraction = false
4568
4686
  }) {
4569
- const [showProperties, setShowProperties] = useState7(false);
4570
- const [showAbstraction, setShowAbstraction] = useState7(false);
4571
- const [targetRenderNodeId, setTargetRenderNodeId] = useState7(null);
4572
- const [isLinkCopied, setIsLinkCopied] = useState7(false);
4687
+ const [showProperties, setShowProperties] = useState8(false);
4688
+ const [showAbstraction, setShowAbstraction] = useState8(false);
4689
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
4690
+ const [isLinkCopied, setIsLinkCopied] = useState8(false);
4573
4691
  const handleCopyLink = (e) => {
4574
4692
  e.stopPropagation();
4575
4693
  if (!ancestryId) return;
@@ -4824,11 +4942,11 @@ function AncestryRelationshipPanel({
4824
4942
  onMentionClick,
4825
4943
  onUploadFile
4826
4944
  }) {
4827
- const [description, setDescription] = useState8((data == null ? void 0 : data.description) ?? "");
4828
- const [customProps, setCustomProps] = useState8(() => extractCustomPropsFromNode(data || {}));
4829
- const [existingSections, setExistingSections] = useState8((data == null ? void 0 : data.description_sections) || []);
4830
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState8(false);
4831
- const [isReadMode, setIsReadMode] = useState8(false);
4945
+ const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
4946
+ const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
4947
+ const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
4948
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
4949
+ const [isReadMode, setIsReadMode] = useState9(false);
4832
4950
  const propsEndRef = useRef7(null);
4833
4951
  useEffect8(() => {
4834
4952
  setDescription((data == null ? void 0 : data.description) ?? "");
@@ -4970,7 +5088,7 @@ function AncestryRelationshipPanel({
4970
5088
  }
4971
5089
 
4972
5090
  // src/components/CreateAncestryPanel.jsx
4973
- import React10, { useState as useState10, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback } from "react";
5091
+ import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
4974
5092
  import {
4975
5093
  FiEdit2 as FiEdit23,
4976
5094
  FiBookOpen as FiBookOpen2,
@@ -4990,7 +5108,7 @@ import {
4990
5108
  } from "react-icons/fi";
4991
5109
 
4992
5110
  // src/components/AncestryPickerModal.jsx
4993
- import React9, { useState as useState9, useMemo as useMemo7, useEffect as useEffect9 } from "react";
5111
+ import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
4994
5112
  import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
4995
5113
  function AncestryPickerModal({
4996
5114
  isOpen,
@@ -5000,7 +5118,7 @@ function AncestryPickerModal({
5000
5118
  availableNodes = [],
5001
5119
  currentAncestryId
5002
5120
  }) {
5003
- const [searchTerm, setSearchTerm] = useState9("");
5121
+ const [searchTerm, setSearchTerm] = useState10("");
5004
5122
  useEffect9(() => {
5005
5123
  if (!isOpen) return;
5006
5124
  const handleKeyDown = (e) => {
@@ -5085,7 +5203,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
5085
5203
  var _a, _b;
5086
5204
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
5087
5205
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
5088
- const [isDragOver, setIsDragOver] = useState10(false);
5206
+ const [isDragOver, setIsDragOver] = useState11(false);
5089
5207
  const isSelectedParent = String(selectedParentId) === String(itemId);
5090
5208
  const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
5091
5209
  const isHighlightedPath = highlightedPathIds.includes(String(itemId));
@@ -5221,8 +5339,8 @@ function CreateAncestryPanel({
5221
5339
  isAddingNodes,
5222
5340
  currentAncestryId
5223
5341
  } = ancestryMode;
5224
- const [isSaving, setIsSaving] = useState10(false);
5225
- const [isLinkCopied, setIsLinkCopied] = useState10(false);
5342
+ const [isSaving, setIsSaving] = useState11(false);
5343
+ const [isLinkCopied, setIsLinkCopied] = useState11(false);
5226
5344
  const handleCopyLink = (e) => {
5227
5345
  e.stopPropagation();
5228
5346
  if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
@@ -5236,11 +5354,11 @@ function CreateAncestryPanel({
5236
5354
  setTimeout(() => setIsLinkCopied(false), 2e3);
5237
5355
  }).catch((err) => console.error("Erro ao copiar link:", err));
5238
5356
  };
5239
- const [isPickerOpen, setIsPickerOpen] = useState10(false);
5240
- const [customProps, setCustomProps] = useState10([]);
5357
+ const [isPickerOpen, setIsPickerOpen] = useState11(false);
5358
+ const [customProps, setCustomProps] = useState11([]);
5241
5359
  const propsEndRef = useRef8(null);
5242
- const [branchStack, setBranchStack] = useState10([]);
5243
- const [targetRenderNodeId, setTargetRenderNodeId] = useState10(null);
5360
+ const [branchStack, setBranchStack] = useState11([]);
5361
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
5244
5362
  const highlightedPathIds = useMemo8(() => {
5245
5363
  var _a, _b;
5246
5364
  if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
@@ -5254,17 +5372,26 @@ function CreateAncestryPanel({
5254
5372
  }
5255
5373
  return ids;
5256
5374
  }, [targetRenderNodeId, ancestryMode.abstraction_tree]);
5257
- const [targetScrollSectionId, setTargetScrollSectionId] = useState10(null);
5258
- const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState10(null);
5259
- const [ancestryName, setAncestryName] = useState10(initialName);
5260
- const [description, setDescription] = useState10(initialDescription || "");
5261
- const [existingSections, setExistingSections] = useState10(initialSections || []);
5262
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState10(false);
5263
- const [isReadMode, setIsReadMode] = useState10(false);
5375
+ const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
5376
+ const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
5377
+ const [ancestryName, setAncestryName] = useState11(initialName);
5378
+ const [description, setDescription] = useState11(initialDescription || "");
5379
+ const [existingSections, setExistingSections] = useState11(initialSections || []);
5380
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
5381
+ const [isReadMode, setIsReadMode] = useState11(false);
5382
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
5383
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
5384
+ initialWidth: isReadMode ? 700 : 440,
5385
+ minWidth: 320,
5386
+ maxWidth: maxPanelW
5387
+ });
5388
+ useEffect10(() => {
5389
+ setWidth(isReadMode ? 700 : 440);
5390
+ }, [isReadMode, setWidth]);
5264
5391
  const currentMaxRenderIndexRef = useRef8(0);
5265
5392
  const branchProgressMapRef = useRef8({});
5266
- const [lastSavedSnapshot, setLastSavedSnapshot] = useState10(null);
5267
- const [isPrivate, setIsPrivate] = useState10(ancestryMode.is_private || false);
5393
+ const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
5394
+ const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
5268
5395
  const initializedContextIdRef = useRef8(null);
5269
5396
  const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
5270
5397
  const handleImageClickFromText = (url, name) => {
@@ -5283,7 +5410,7 @@ function CreateAncestryPanel({
5283
5410
  }
5284
5411
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5285
5412
  };
5286
- const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
5413
+ const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
5287
5414
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
5288
5415
  const treeKey = isAbstraction ? "abstraction_tree" : "tree";
5289
5416
  setAncestryMode((prev) => {
@@ -6239,10 +6366,8 @@ function CreateAncestryPanel({
6239
6366
  return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
6240
6367
  "div",
6241
6368
  {
6242
- className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col transition-all duration-300 ease-out
6243
- ${isReadMode ? "w-[min(92vw,700px)]" : "w-[min(92vw,440px)]"}
6244
- `,
6245
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" },
6369
+ className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
6370
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
6246
6371
  onPointerDown: swallow,
6247
6372
  onPointerMove: swallow,
6248
6373
  onPointerUp: swallow,
@@ -6251,6 +6376,17 @@ function CreateAncestryPanel({
6251
6376
  onContextMenu: swallow,
6252
6377
  onDoubleClick: swallow
6253
6378
  },
6379
+ /* @__PURE__ */ React10.createElement(
6380
+ "div",
6381
+ {
6382
+ onPointerDown: (e) => {
6383
+ e.stopPropagation();
6384
+ handleResize(e);
6385
+ },
6386
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
6387
+ title: "Arraste para redimensionar"
6388
+ }
6389
+ ),
6254
6390
  isReadMode ? /* @__PURE__ */ React10.createElement(
6255
6391
  DescriptionReadModePanel,
6256
6392
  {
@@ -6547,25 +6683,25 @@ function CreateAncestryPanel({
6547
6683
  }
6548
6684
 
6549
6685
  // src/components/ImageViewer.jsx
6550
- import React11, { useState as useState11, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback2 } from "react";
6686
+ import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
6551
6687
  import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
6552
6688
  function ImageViewer({ data, onClose }) {
6553
6689
  var _a;
6554
6690
  const { images = [], startIndex = 0, visible } = data;
6555
- const [currentIndex, setCurrentIndex] = useState11(startIndex);
6556
- const [isLoading, setIsLoading] = useState11(false);
6557
- const [loadedSrc, setLoadedSrc] = useState11(null);
6691
+ const [currentIndex, setCurrentIndex] = useState12(startIndex);
6692
+ const [isLoading, setIsLoading] = useState12(false);
6693
+ const [loadedSrc, setLoadedSrc] = useState12(null);
6558
6694
  useLayoutEffect2(() => {
6559
6695
  if (visible) {
6560
6696
  setCurrentIndex(startIndex);
6561
6697
  }
6562
6698
  }, [visible, startIndex]);
6563
- const handleNext = useCallback2(() => {
6699
+ const handleNext = useCallback3(() => {
6564
6700
  if (images.length > 1) {
6565
6701
  setCurrentIndex((prev) => (prev + 1) % images.length);
6566
6702
  }
6567
6703
  }, [images.length]);
6568
- const handlePrev = useCallback2(() => {
6704
+ const handlePrev = useCallback3(() => {
6569
6705
  if (images.length > 1) {
6570
6706
  setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
6571
6707
  }
@@ -6670,10 +6806,10 @@ function ImageViewer({ data, onClose }) {
6670
6806
  }
6671
6807
 
6672
6808
  // src/components/InSceneCreationForm.jsx
6673
- import React13, { useState as useState13, useEffect as useEffect13, useRef as useRef10 } from "react";
6809
+ import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
6674
6810
 
6675
6811
  // src/components/ColorPicker.jsx
6676
- import React12, { useState as useState12, useEffect as useEffect12, useRef as useRef9 } from "react";
6812
+ import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
6677
6813
  import { HexColorPicker } from "react-colorful";
6678
6814
  import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
6679
6815
  var PRESET_COLORS = [
@@ -6694,7 +6830,7 @@ var PRESET_COLORS = [
6694
6830
  "#000000"
6695
6831
  ];
6696
6832
  function ColorPicker({ color, onChange, disabled }) {
6697
- const [isOpen, setIsOpen] = useState12(false);
6833
+ const [isOpen, setIsOpen] = useState13(false);
6698
6834
  const popoverRef = useRef9(null);
6699
6835
  useEffect12(() => {
6700
6836
  const handleClickOutside = (event) => {
@@ -6793,21 +6929,21 @@ function InSceneCreationForm({
6793
6929
  viewType
6794
6930
  }) {
6795
6931
  var _a;
6796
- const [name, setName] = useState13("");
6797
- const [types, setTypes] = useState13([]);
6798
- const [typeInput, setTypeInput] = useState13("");
6799
- const [color, setColor] = useState13(initialColor || "#cccccc");
6800
- const [size, setSize] = useState13("medium");
6801
- const [intensity, setIntensity] = useState13(0);
6802
- const [description, setDescription] = useState13("");
6803
- const [customProps, setCustomProps] = useState13([]);
6804
- const [showTypeSuggestions, setShowTypeSuggestions] = useState13(false);
6805
- const [filteredTypes, setFilteredTypes] = useState13([]);
6806
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState13(false);
6807
- const [useImageAsTexture, setUseImageAsTexture] = useState13(false);
6808
- const [selectedImageUrl, setSelectedImageUrl] = useState13(null);
6809
- const [targetDatasetId, setTargetDatasetId] = useState13(sourceNodeDatasetId || "");
6810
- const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState13(false);
6932
+ const [name, setName] = useState14("");
6933
+ const [types, setTypes] = useState14([]);
6934
+ const [typeInput, setTypeInput] = useState14("");
6935
+ const [color, setColor] = useState14(initialColor || "#cccccc");
6936
+ const [size, setSize] = useState14("medium");
6937
+ const [intensity, setIntensity] = useState14(0);
6938
+ const [description, setDescription] = useState14("");
6939
+ const [customProps, setCustomProps] = useState14([]);
6940
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
6941
+ const [filteredTypes, setFilteredTypes] = useState14([]);
6942
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
6943
+ const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
6944
+ const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
6945
+ const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
6946
+ const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
6811
6947
  const datasetDropdownRef = useRef10(null);
6812
6948
  useEffect13(() => {
6813
6949
  if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
@@ -7140,7 +7276,7 @@ function InSceneCreationForm({
7140
7276
  }
7141
7277
 
7142
7278
  // src/components/InSceneVersionForm.jsx
7143
- import React14, { useState as useState14, useEffect as useEffect14, useRef as useRef11 } from "react";
7279
+ import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
7144
7280
  import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
7145
7281
  function InSceneVersionForm({
7146
7282
  onSave,
@@ -7158,14 +7294,14 @@ function InSceneVersionForm({
7158
7294
  onMentionClick,
7159
7295
  onUploadFile
7160
7296
  }) {
7161
- const [name, setName] = useState14("");
7162
- const [size, setSize] = useState14("medium");
7163
- const [description, setDescription] = useState14("");
7164
- const [customProps, setCustomProps] = useState14([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
7165
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
7297
+ const [name, setName] = useState15("");
7298
+ const [size, setSize] = useState15("medium");
7299
+ const [description, setDescription] = useState15("");
7300
+ const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
7301
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
7166
7302
  const propsEndRef = useRef11(null);
7167
- const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
7168
- const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
7303
+ const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
7304
+ const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
7169
7305
  const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
7170
7306
  useEffect14(() => {
7171
7307
  if (!hasImages && useImageAsTexture) {
@@ -7358,7 +7494,7 @@ function InSceneVersionForm({
7358
7494
  }
7359
7495
 
7360
7496
  // src/components/NodeDetailsPanel.jsx
7361
- import React15, { useState as useState15, useEffect as useEffect15, useRef as useRef12 } from "react";
7497
+ import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
7362
7498
  import { FiPlus as FiPlus5, FiMaximize2 as FiMaximize23, FiX as FiX4, FiCheck as FiCheck9, FiImage as FiImage3, FiEdit2 as FiEdit26, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
7363
7499
  function NodeDetailsPanel({
7364
7500
  node,
@@ -7380,27 +7516,36 @@ function NodeDetailsPanel({
7380
7516
  userRole,
7381
7517
  currentDatasetName
7382
7518
  }) {
7383
- const [name, setName] = useState15((node == null ? void 0 : node.name) ?? "");
7384
- const [types, setTypes] = useState15([]);
7385
- const [typeInput, setTypeInput] = useState15("");
7386
- const [color, setColor] = useState15((node == null ? void 0 : node.color) ?? "#8b5cf6");
7387
- const [size, setSize] = useState15((node == null ? void 0 : node.size) ?? "medium");
7388
- const [description, setDescription] = useState15((node == null ? void 0 : node.description) ?? "");
7389
- const [intensity, setIntensity] = useState15((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
7390
- const [customProps, setCustomProps] = useState15(() => extractCustomPropsFromNode(node || {}));
7391
- const [showTypeSuggestions, setShowTypeSuggestions] = useState15(false);
7392
- const [filteredTypes, setFilteredTypes] = useState15([]);
7393
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
7394
- const [isReadMode, setIsReadMode] = useState15(false);
7395
- const [existingSections, setExistingSections] = useState15((node == null ? void 0 : node.description_sections) || []);
7396
- const [isSaving, setIsSaving] = useState15(false);
7397
- const [isLinkCopied, setIsLinkCopied] = useState15(false);
7398
- const [useImageAsTexture, setUseImageAsTexture] = useState15(() => {
7519
+ const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
7520
+ const [types, setTypes] = useState16([]);
7521
+ const [typeInput, setTypeInput] = useState16("");
7522
+ const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
7523
+ const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
7524
+ const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
7525
+ const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
7526
+ const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
7527
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
7528
+ const [filteredTypes, setFilteredTypes] = useState16([]);
7529
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
7530
+ const [isReadMode, setIsReadMode] = useState16(false);
7531
+ const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
7532
+ const [isSaving, setIsSaving] = useState16(false);
7533
+ const [isLinkCopied, setIsLinkCopied] = useState16(false);
7534
+ const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
7399
7535
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
7400
7536
  if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
7401
7537
  return !!(node == null ? void 0 : node.useImageAsTexture);
7402
7538
  });
7403
- const [selectedImageUrl, setSelectedImageUrl] = useState15((node == null ? void 0 : node.textureImageUrl) ?? null);
7539
+ const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
7540
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
7541
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
7542
+ initialWidth: isReadMode ? 700 : 440,
7543
+ minWidth: 320,
7544
+ maxWidth: maxPanelW
7545
+ });
7546
+ useEffect15(() => {
7547
+ setWidth(isReadMode ? 700 : 440);
7548
+ }, [isReadMode, setWidth]);
7404
7549
  const prevNodeIdRef = useRef12(null);
7405
7550
  const propsEndRef = useRef12(null);
7406
7551
  const canEdit = userRole !== "viewer";
@@ -7608,10 +7753,8 @@ function NodeDetailsPanel({
7608
7753
  return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
7609
7754
  "div",
7610
7755
  {
7611
- className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col transition-all duration-300 ease-out
7612
- ${isReadMode ? "w-[min(92vw,700px)]" : "w-[min(92vw,440px)]"}
7613
- `,
7614
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" },
7756
+ className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
7757
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
7615
7758
  onPointerDown: swallow,
7616
7759
  onPointerMove: swallow,
7617
7760
  onPointerUp: swallow,
@@ -7620,6 +7763,17 @@ function NodeDetailsPanel({
7620
7763
  onContextMenu: swallow,
7621
7764
  onDoubleClick: swallow
7622
7765
  },
7766
+ /* @__PURE__ */ React15.createElement(
7767
+ "div",
7768
+ {
7769
+ onPointerDown: (e) => {
7770
+ e.stopPropagation();
7771
+ handleResize(e);
7772
+ },
7773
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
7774
+ title: "Arraste para redimensionar"
7775
+ }
7776
+ ),
7623
7777
  isReadMode ? /* @__PURE__ */ React15.createElement(
7624
7778
  DescriptionReadModePanel,
7625
7779
  {
@@ -7821,7 +7975,7 @@ function NodeDetailsPanel({
7821
7975
  }
7822
7976
 
7823
7977
  // src/components/MultiNodeContextMenu.jsx
7824
- import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState16, useEffect as useEffect16 } from "react";
7978
+ import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
7825
7979
  function MultiNodeContextMenu({
7826
7980
  data,
7827
7981
  userRole,
@@ -7832,7 +7986,7 @@ function MultiNodeContextMenu({
7832
7986
  onDeleteNodes
7833
7987
  }) {
7834
7988
  const menuRef = useRef13(null);
7835
- const [menuPos, setMenuPos] = useState16({ left: 0, top: 0 });
7989
+ const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
7836
7990
  const ability = defineAbilityFor(userRole);
7837
7991
  const canDelete = ability.can("delete", "Node");
7838
7992
  useLayoutEffect3(() => {
@@ -7881,7 +8035,7 @@ function MultiNodeContextMenu({
7881
8035
  }
7882
8036
 
7883
8037
  // src/components/RelationshipDetailsPanel.jsx
7884
- import React17, { useState as useState17, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
8038
+ import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
7885
8039
  import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
7886
8040
  function RelationshipDetailsPanel({
7887
8041
  link,
@@ -7897,13 +8051,13 @@ function RelationshipDetailsPanel({
7897
8051
  userRole
7898
8052
  // Recebendo userRole via props
7899
8053
  }) {
7900
- const [name, setName] = useState17((link == null ? void 0 : link.name) ?? "");
7901
- const [description, setDescription] = useState17((link == null ? void 0 : link.description) ?? "");
7902
- const [customProps, setCustomProps] = useState17(() => extractCustomPropsFromNode(link || {}));
7903
- const [existingSections, setExistingSections] = useState17((link == null ? void 0 : link.description_sections) || []);
7904
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
7905
- const [isSaving, setIsSaving] = useState17(false);
7906
- const [isReadMode, setIsReadMode] = useState17(false);
8054
+ const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
8055
+ const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
8056
+ const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
8057
+ const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
8058
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
8059
+ const [isSaving, setIsSaving] = useState18(false);
8060
+ const [isReadMode, setIsReadMode] = useState18(false);
7907
8061
  const propsEndRef = useRef14(null);
7908
8062
  const canEdit = useMemo9(() => {
7909
8063
  const ability = defineAbilityFor(userRole);
@@ -8106,7 +8260,7 @@ function RelationshipDetailsPanel({
8106
8260
  }
8107
8261
 
8108
8262
  // src/components/RelationshipContextMenu.jsx
8109
- import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState18, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8263
+ import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8110
8264
  function RelationshipContextMenu({
8111
8265
  data,
8112
8266
  userRole,
@@ -8118,7 +8272,7 @@ function RelationshipContextMenu({
8118
8272
  onClose
8119
8273
  }) {
8120
8274
  const menuRef = useRef15(null);
8121
- const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
8275
+ const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
8122
8276
  const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
8123
8277
  const sourceName = useMemo10(
8124
8278
  () => {
@@ -8320,7 +8474,7 @@ function LoadingScreen() {
8320
8474
  }
8321
8475
 
8322
8476
  // src/components/ImportParentFileModal.jsx
8323
- import React20, { useEffect as useEffect19, useState as useState19 } from "react";
8477
+ import React20, { useEffect as useEffect19, useState as useState20 } from "react";
8324
8478
  function ImportParentFileModal({
8325
8479
  isOpen,
8326
8480
  onClose,
@@ -8331,11 +8485,11 @@ function ImportParentFileModal({
8331
8485
  onFetchAvailableFiles,
8332
8486
  currentViewName
8333
8487
  }) {
8334
- const [activeTab, setActiveTab] = useState19("databases");
8335
- const [availableDbs, setAvailableDbs] = useState19([]);
8336
- const [availableViews, setAvailableViews] = useState19([]);
8337
- const [selectedItem, setSelectedItem] = useState19(null);
8338
- const [isLoading, setIsLoading] = useState19(false);
8488
+ const [activeTab, setActiveTab] = useState20("databases");
8489
+ const [availableDbs, setAvailableDbs] = useState20([]);
8490
+ const [availableViews, setAvailableViews] = useState20([]);
8491
+ const [selectedItem, setSelectedItem] = useState20(null);
8492
+ const [isLoading, setIsLoading] = useState20(false);
8339
8493
  useEffect19(() => {
8340
8494
  if (isOpen && session && onFetchAvailableFiles) {
8341
8495
  const fetchData = async () => {
@@ -8481,7 +8635,7 @@ function ImportParentFileModal({
8481
8635
  }
8482
8636
 
8483
8637
  // src/components/AncestryLinkDetailsPanel.jsx
8484
- import React21, { useState as useState20 } from "react";
8638
+ import React21, { useState as useState21 } from "react";
8485
8639
  import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
8486
8640
  function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
8487
8641
  var _a, _b, _c, _d;
@@ -8491,7 +8645,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8491
8645
  const customProps = extractCustomPropsFromNode(relationshipData);
8492
8646
  const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
8493
8647
  const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
8494
- const [isReadMode, setIsReadMode] = useState20(false);
8648
+ const [isReadMode, setIsReadMode] = useState21(false);
8495
8649
  const swallow = (e) => e.stopPropagation();
8496
8650
  const handleImageClickFromText = (url, name) => {
8497
8651
  if (onOpenImageViewer) {
@@ -8557,7 +8711,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8557
8711
  }
8558
8712
 
8559
8713
  // src/components/AncestryBoard.jsx
8560
- import React22, { useState as useState21, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8714
+ import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8561
8715
  import {
8562
8716
  FiSearch as FiSearch4,
8563
8717
  FiLayers as FiLayers6,
@@ -8734,11 +8888,11 @@ function AncestryBoard({
8734
8888
  userRole
8735
8889
  // [NOVO] Recebe a role do usuário
8736
8890
  }) {
8737
- const [searchTerm, setSearchTerm] = useState21("");
8738
- const [groups, setGroups] = useState21([]);
8739
- const [isLoaded, setIsLoaded] = useState21(false);
8740
- const [pickingGroupId, setPickingGroupId] = useState21(null);
8741
- const [saveStatus, setSaveStatus] = useState21("idle");
8891
+ const [searchTerm, setSearchTerm] = useState22("");
8892
+ const [groups, setGroups] = useState22([]);
8893
+ const [isLoaded, setIsLoaded] = useState22(false);
8894
+ const [pickingGroupId, setPickingGroupId] = useState22(null);
8895
+ const [saveStatus, setSaveStatus] = useState22("idle");
8742
8896
  const canEdit = useMemo11(() => {
8743
8897
  return userRole !== "viewer";
8744
8898
  }, [userRole]);
@@ -9188,37 +9342,37 @@ function XViewScene({
9188
9342
  const sceneDataRef = useRef17(null);
9189
9343
  const parentDataRef = useRef17(null);
9190
9344
  const ancestryDataRef = useRef17(null);
9191
- const [isLoading, setIsLoading] = useState22(true);
9192
- const [permissionStatus, setPermissionStatus] = useState22("loading");
9193
- const [userPermissionRole, setUserPermissionRole] = useState22(null);
9194
- const [isInitialized, setIsInitialized] = useState22(false);
9195
- const [sceneVersion, setSceneVersion] = useState22(0);
9196
- const [contextMenu, setContextMenu] = useState22({ visible: false, x: 0, y: 0, nodeData: null });
9197
- const [multiContextMenu, setMultiContextMenu] = useState22({ visible: false, x: 0, y: 0, nodeIds: null });
9198
- const [relationshipMenu, setRelationshipMenu] = useState22({ visible: false, x: 0, y: 0, linkObject: null });
9199
- const [creationMode, setCreationMode] = useState22({ isActive: false, sourceNodeData: null });
9200
- const [versionMode, setVersionMode] = useState22({ isActive: false, sourceNodeData: null });
9201
- const [hasFocusedInitial, setHasFocusedInitial] = useState22(false);
9202
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState22(false);
9203
- const [ancestryMode, setAncestryMode] = useState22({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9204
- const [readingMode, setReadingMode] = useState22({
9345
+ const [isLoading, setIsLoading] = useState23(true);
9346
+ const [permissionStatus, setPermissionStatus] = useState23("loading");
9347
+ const [userPermissionRole, setUserPermissionRole] = useState23(null);
9348
+ const [isInitialized, setIsInitialized] = useState23(false);
9349
+ const [sceneVersion, setSceneVersion] = useState23(0);
9350
+ const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
9351
+ const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
9352
+ const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
9353
+ const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
9354
+ const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
9355
+ const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
9356
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
9357
+ const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9358
+ const [readingMode, setReadingMode] = useState23({
9205
9359
  isActive: false,
9206
9360
  ancestry: null,
9207
9361
  branchStack: [],
9208
9362
  autoAbstraction: false
9209
9363
  });
9210
- const [formPosition, setFormPosition] = useState22({ left: 16, top: 16, opacity: 0 });
9211
- const [detailsNode, setDetailsNode] = useState22(null);
9212
- const [detailsLink, setDetailsLink] = useState22(null);
9213
- const [ancestryLinkDetails, setAncestryLinkDetails] = useState22(null);
9214
- const [imageViewer, setImageViewer] = useState22({ visible: false, images: [], startIndex: 0 });
9215
- const [editingAncestryRel, setEditingAncestryRel] = useState22({ visible: false, data: null, path: null });
9216
- const [isImportModalOpen, setIsImportModalOpen] = useState22(false);
9217
- const [importSuccessMessage, setImportSuccessMessage] = useState22("");
9218
- const [highlightedNodeId, setHighlightedNodeId] = useState22(null);
9219
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState22(false);
9220
- const [ancestryBoardData, setAncestryBoardData] = useState22([]);
9221
- const [isSidebarOpen, setIsSidebarOpen] = useState22(false);
9364
+ const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
9365
+ const [detailsNode, setDetailsNode] = useState23(null);
9366
+ const [detailsLink, setDetailsLink] = useState23(null);
9367
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
9368
+ const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
9369
+ const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
9370
+ const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
9371
+ const [importSuccessMessage, setImportSuccessMessage] = useState23("");
9372
+ const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
9373
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
9374
+ const [ancestryBoardData, setAncestryBoardData] = useState23([]);
9375
+ const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
9222
9376
  const mountRef = useRef17(null);
9223
9377
  const tooltipRef = useRef17(null);
9224
9378
  const formRef = useRef17(null);
@@ -9261,6 +9415,12 @@ function XViewScene({
9261
9415
  lastDescriptionLength: 0,
9262
9416
  highlightedNodeId: null
9263
9417
  });
9418
+ const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
9419
+ const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
9420
+ initialWidth: 700,
9421
+ minWidth: 320,
9422
+ maxWidth: maxReadPanelW
9423
+ });
9264
9424
  useEffect21(() => {
9265
9425
  stateRef.current.ancestry = ancestryMode;
9266
9426
  }, [ancestryMode]);
@@ -9285,10 +9445,10 @@ function XViewScene({
9285
9445
  }
9286
9446
  stateRef.current.nodeIdToParentFileMap = map;
9287
9447
  }, [isInitialized, sceneVersion]);
9288
- const handleNavigateBack = useCallback3(() => {
9448
+ const handleNavigateBack = useCallback4(() => {
9289
9449
  router.push("/dashboard/scenes");
9290
9450
  }, [router]);
9291
- const handleConfirmImport = useCallback3(
9451
+ const handleConfirmImport = useCallback4(
9292
9452
  async (importPayload) => {
9293
9453
  var _a2, _b2;
9294
9454
  let files = [];
@@ -9336,7 +9496,6 @@ function XViewScene({
9336
9496
  if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
9337
9497
  const viewSpecificAncestries = ancestryResponse.data.filter(
9338
9498
  (anc) => anc._source_file_id === viewToImport.id && !anc.is_private
9339
- // <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
9340
9499
  );
9341
9500
  const processedAncestries = viewSpecificAncestries.map((anc) => ({
9342
9501
  ...anc,
@@ -9387,7 +9546,7 @@ function XViewScene({
9387
9546
  const handleOpenImageViewer = (images, startIndex) => {
9388
9547
  setImageViewer({ visible: true, images, startIndex });
9389
9548
  };
9390
- const tweenToTarget = useCallback3((target, zoomFactor = 1, forcedDirection = null) => {
9549
+ const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
9391
9550
  const { camera, controls, tweenGroup } = stateRef.current;
9392
9551
  if (!camera || !controls || !tweenGroup) return;
9393
9552
  const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
@@ -9410,7 +9569,7 @@ function XViewScene({
9410
9569
  if (!t || typeof t.closest !== "function") return false;
9411
9570
  return !!t.closest(".ui-overlay");
9412
9571
  };
9413
- const buildFullAncestryTree = useCallback3((idTree, nodes, ancestries = []) => {
9572
+ const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
9414
9573
  if (!idTree) return null;
9415
9574
  const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
9416
9575
  const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
@@ -9436,14 +9595,10 @@ function XViewScene({
9436
9595
  return {
9437
9596
  ...branch,
9438
9597
  name: linkedAncestry.name,
9439
- // Sobrescreve nome para exibição
9440
9598
  description: linkedAncestry.description,
9441
- // Sobrescreve descrição
9442
9599
  description_sections: linkedAncestry.description_sections,
9443
9600
  tree: graftedTree,
9444
- // ENXERTA A ÁRVORE AQUI
9445
9601
  isLinked: true
9446
- // Flag útil
9447
9602
  };
9448
9603
  }
9449
9604
  }
@@ -9490,7 +9645,7 @@ function XViewScene({
9490
9645
  }
9491
9646
  return recursiveBuild(idTree);
9492
9647
  }, []);
9493
- const handleActivateTimeline = useCallback3(() => {
9648
+ const handleActivateTimeline = useCallback4(() => {
9494
9649
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
9495
9650
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
9496
9651
  while (timelineIntervalsGroup.children.length > 0) {
@@ -9643,7 +9798,7 @@ function XViewScene({
9643
9798
  }
9644
9799
  });
9645
9800
  }, []);
9646
- const handleVersionTimeline = useCallback3((sourceMesh, versionMeshes) => {
9801
+ const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
9647
9802
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
9648
9803
  if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
9649
9804
  versionMeshes.forEach((mesh) => {
@@ -9836,16 +9991,14 @@ function XViewScene({
9836
9991
  isInitialized,
9837
9992
  permissionStatus,
9838
9993
  focusNodeId,
9839
- // <-- MANTIDO
9840
9994
  focusAncestryId
9841
- // <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
9842
9995
  ]);
9843
- const isNodeInView = useCallback3((id) => {
9996
+ const isNodeInView = useCallback4((id) => {
9844
9997
  const key = String(id);
9845
9998
  const objs = stateRef.current.nodeObjects || {};
9846
9999
  return !!objs[key];
9847
10000
  }, []);
9848
- const addOrUpdateNodeMesh = useCallback3((nodeData, position, suppressVersionUpdate = false) => {
10001
+ const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
9849
10002
  const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
9850
10003
  const nodeId = String(nodeData.id);
9851
10004
  if (nodeObjects[nodeId]) {
@@ -10494,7 +10647,7 @@ function XViewScene({
10494
10647
  }
10495
10648
  };
10496
10649
  }, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
10497
- const handleGhostNodeImageChange = useCallback3((useImage, imageUrl) => {
10650
+ const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
10498
10651
  const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
10499
10652
  const { graphGroup, glowTexture } = stateRef.current;
10500
10653
  if (!ghostNode || !graphGroup) return;
@@ -10536,7 +10689,7 @@ function XViewScene({
10536
10689
  aura: newGhostNode.getObjectByName("aura")
10537
10690
  };
10538
10691
  }, []);
10539
- const handleGhostNodeIntensityChange = useCallback3((newIntensity) => {
10692
+ const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
10540
10693
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
10541
10694
  if (!ghostNode) return;
10542
10695
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10557,7 +10710,7 @@ function XViewScene({
10557
10710
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
10558
10711
  }
10559
10712
  }, []);
10560
- const handleDetailNodeIntensityChange = useCallback3((nodeId, newIntensity) => {
10713
+ const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
10561
10714
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
10562
10715
  if (!mesh) return;
10563
10716
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10703,7 +10856,7 @@ function XViewScene({
10703
10856
  mountRef.current.style.cursor = "default";
10704
10857
  }
10705
10858
  };
10706
- const handleAncestryTreeUpdate = useCallback3((newTree, extraData = null) => {
10859
+ const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
10707
10860
  setAncestryMode((prev) => {
10708
10861
  const prevTreeStr = JSON.stringify(prev.tree);
10709
10862
  const newTreeStr = JSON.stringify(newTree);
@@ -10773,7 +10926,7 @@ function XViewScene({
10773
10926
  const handleStartVersioning = (nodeData) => {
10774
10927
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
10775
10928
  };
10776
- const handleClearAncestryVisuals = useCallback3((ancestryId) => {
10929
+ const handleClearAncestryVisuals = useCallback4((ancestryId) => {
10777
10930
  const { renderedAncestries, ancestryGroup } = stateRef.current;
10778
10931
  const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
10779
10932
  if (renderIndex !== -1) {
@@ -10787,7 +10940,7 @@ function XViewScene({
10787
10940
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
10788
10941
  }
10789
10942
  }, []);
10790
- const handleRenderAncestry = useCallback3(
10943
+ const handleRenderAncestry = useCallback4(
10791
10944
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
10792
10945
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10793
10946
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11203,7 +11356,7 @@ function XViewScene({
11203
11356
  },
11204
11357
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
11205
11358
  );
11206
- const handleRenderAbstractionTree = useCallback3((ancestryObject, targetNodeId = null) => {
11359
+ const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
11207
11360
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11208
11361
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
11209
11362
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
@@ -11264,7 +11417,7 @@ function XViewScene({
11264
11417
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
11265
11418
  tweenToTarget(rootTargetPos, 0.7);
11266
11419
  }, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
11267
- const handleReadModeBranchNav = useCallback3((nodeId, action, direction = "right") => {
11420
+ const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
11268
11421
  const { ancestry, branchStack } = readingMode;
11269
11422
  if (!ancestry || !ancestry.tree) return;
11270
11423
  const allAncestries = ancestryDataRef.current || [];
@@ -11302,9 +11455,7 @@ function XViewScene({
11302
11455
  description_sections: branchToOpen.description_sections,
11303
11456
  tree: branchToOpen.tree,
11304
11457
  _originNodeId: nodeId,
11305
- // <--- ID do node pai (link visual)
11306
11458
  _branchDirection: direction
11307
- // <--- Direção para cálculo de posição
11308
11459
  };
11309
11460
  const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
11310
11461
  const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
@@ -11360,7 +11511,6 @@ function XViewScene({
11360
11511
  const parentAncestryObj = {
11361
11512
  ...targetAncestryInfo,
11362
11513
  tree: targetTreeToRender,
11363
- // Re-injeta a origem se o pai também for uma branch aninhada
11364
11514
  _originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
11365
11515
  _branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
11366
11516
  };
@@ -11408,7 +11558,7 @@ function XViewScene({
11408
11558
  }));
11409
11559
  }
11410
11560
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
11411
- const handleReadModeHighlight = useCallback3((nodeId) => {
11561
+ const handleReadModeHighlight = useCallback4((nodeId) => {
11412
11562
  if (stateRef.current.highlightedNodeId !== nodeId) {
11413
11563
  stateRef.current.highlightedNodeId = nodeId;
11414
11564
  }
@@ -11420,7 +11570,6 @@ function XViewScene({
11420
11570
  readingMode.ancestry.tree,
11421
11571
  Object.values(parentDataRef.current).flatMap((f) => f.nodes),
11422
11572
  ancestryDataRef.current
11423
- // <--- Adicionar
11424
11573
  );
11425
11574
  const findNodeInTree = (tree, targetId) => {
11426
11575
  if (!tree) return null;
@@ -11474,7 +11623,6 @@ function XViewScene({
11474
11623
  description_sections: ancestry.description_sections,
11475
11624
  direction: null,
11476
11625
  customProperties: rootProps
11477
- // <--- ADICIONADO
11478
11626
  };
11479
11627
  }
11480
11628
  const fullTree = buildFullAncestryTree(
@@ -11503,7 +11651,6 @@ function XViewScene({
11503
11651
  description_sections: currentMeta.description_sections,
11504
11652
  direction: currentDirection,
11505
11653
  customProperties: branchProps
11506
- // <--- ADICIONADO
11507
11654
  };
11508
11655
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
11509
11656
  const readModeAbstractionTree = useMemo12(() => {
@@ -11518,7 +11665,7 @@ function XViewScene({
11518
11665
  allAncestries
11519
11666
  );
11520
11667
  }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
11521
- const handleStartReadingAncestry = useCallback3(
11668
+ const handleStartReadingAncestry = useCallback4(
11522
11669
  async (ancestryObject) => {
11523
11670
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11524
11671
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11539,7 +11686,6 @@ function XViewScene({
11539
11686
  ancestry: ancestryObject,
11540
11687
  branchStack: [],
11541
11688
  autoAbstraction: shouldAutoRenderAbstraction
11542
- // <--- FLAG ENVIADA PARA A UI
11543
11689
  });
11544
11690
  if (shouldAutoRenderAbstraction) {
11545
11691
  handleRenderAbstractionTree(ancestryObject, null);
@@ -11553,9 +11699,8 @@ function XViewScene({
11553
11699
  }
11554
11700
  },
11555
11701
  [handleRenderAncestry, handleRenderAbstractionTree]
11556
- // <--- DEPENDÊNCIA ADICIONADA
11557
11702
  );
11558
- const handleReadModeSectionChange = useCallback3((activeSectionId) => {
11703
+ const handleReadModeSectionChange = useCallback4((activeSectionId) => {
11559
11704
  const { ancestry, branchStack } = readingMode;
11560
11705
  if (!ancestry || !readingMode.isActive) return;
11561
11706
  let targetObj = ancestry;
@@ -11624,10 +11769,10 @@ function XViewScene({
11624
11769
  }, 0);
11625
11770
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11626
11771
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
11627
- const handleCloseReadMode = useCallback3(() => {
11772
+ const handleCloseReadMode = useCallback4(() => {
11628
11773
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
11629
11774
  }, []);
11630
- const handleAncestrySectionChange = useCallback3((activeSectionId, ancestryOverride = null, rotation = 0) => {
11775
+ const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
11631
11776
  var _a2, _b2;
11632
11777
  const currentMode = stateRef.current.ancestry;
11633
11778
  let targetObj = ancestryOverride;
@@ -11679,7 +11824,7 @@ function XViewScene({
11679
11824
  const renderPayload = { ...targetObj, tree: treeToRender };
11680
11825
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11681
11826
  }, [handleRenderAncestry]);
11682
- const handleEditAncestry = useCallback3(
11827
+ const handleEditAncestry = useCallback4(
11683
11828
  async (ancestryObject) => {
11684
11829
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11685
11830
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11702,10 +11847,8 @@ function XViewScene({
11702
11847
  ...ancestryObject,
11703
11848
  tree: fullTree,
11704
11849
  abstraction_tree: fullAbstractionTree,
11705
- // NOVO
11706
11850
  selectedParentId: ancestryObject.ancestral_node,
11707
11851
  selectedAbstractionParentId: ancestryObject.ancestral_node,
11708
- // NOVO
11709
11852
  isEditMode: true,
11710
11853
  currentAncestryId: ancestryObject.ancestry_id,
11711
11854
  ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
@@ -11713,7 +11856,6 @@ function XViewScene({
11713
11856
  ancestryDescriptionSections: ancestryObject.description_sections || [],
11714
11857
  isAddingNodes: false,
11715
11858
  isAddingAbstractionNodes: false
11716
- // NOVO
11717
11859
  });
11718
11860
  },
11719
11861
  [handleRenderAncestry, buildFullAncestryTree]
@@ -11721,7 +11863,7 @@ function XViewScene({
11721
11863
  const handleSelectAncestryParent = (nodeId) => {
11722
11864
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
11723
11865
  };
11724
- const handleRemoveFromAncestry = useCallback3((pathToRemove) => {
11866
+ const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
11725
11867
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
11726
11868
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
11727
11869
  return;
@@ -11746,7 +11888,7 @@ function XViewScene({
11746
11888
  return { ...prev, tree: newTree };
11747
11889
  });
11748
11890
  }, []);
11749
- const handleSaveAncestry = useCallback3(
11891
+ const handleSaveAncestry = useCallback4(
11750
11892
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
11751
11893
  const treeToUse = treeOverride || ancestryMode.tree;
11752
11894
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -11950,7 +12092,7 @@ function XViewScene({
11950
12092
  });
11951
12093
  setEditingAncestryRel({ visible: false, data: null, path: null });
11952
12094
  };
11953
- const handleDeleteAncestry = useCallback3(
12095
+ const handleDeleteAncestry = useCallback4(
11954
12096
  async (ancestryIdToDelete) => {
11955
12097
  if (!ancestryIdToDelete) {
11956
12098
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -12012,15 +12154,15 @@ function XViewScene({
12012
12154
  },
12013
12155
  [save_view_data, delete_file_action]
12014
12156
  );
12015
- const handleOpenAncestryBoard = useCallback3(() => {
12157
+ const handleOpenAncestryBoard = useCallback4(() => {
12016
12158
  setIsAncestryBoardOpen(true);
12017
12159
  }, []);
12018
- const handleSelectAncestryFromBoard = useCallback3((ancestry) => {
12160
+ const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
12019
12161
  setIsAncestryBoardOpen(false);
12020
12162
  setIsSidebarOpen(false);
12021
12163
  handleStartReadingAncestry(ancestry);
12022
12164
  }, [handleStartReadingAncestry]);
12023
- const handleSaveAncestryBoard = useCallback3(async (groups) => {
12165
+ const handleSaveAncestryBoard = useCallback4(async (groups) => {
12024
12166
  if (!sceneConfigId || !viewParams || !session) return;
12025
12167
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
12026
12168
  await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
@@ -12044,13 +12186,13 @@ function XViewScene({
12044
12186
  return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
12045
12187
  });
12046
12188
  }, [parentDataRef.current, sceneVersion]);
12047
- const handleAddExistingNode = useCallback3(
12189
+ const handleAddExistingNode = useCallback4(
12048
12190
  (nodeId) => {
12049
12191
  return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
12050
12192
  },
12051
12193
  [actionHandlerContext]
12052
12194
  );
12053
- const handleSaveCurrentView = useCallback3(async () => {
12195
+ const handleSaveCurrentView = useCallback4(async () => {
12054
12196
  const { nodeObjects, allLinks } = stateRef.current;
12055
12197
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
12056
12198
  console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
@@ -12090,7 +12232,7 @@ function XViewScene({
12090
12232
  const allAvailableAncestries = useMemo12(() => {
12091
12233
  return ancestryDataRef.current || [];
12092
12234
  }, [sceneVersion, isInitialized]);
12093
- const handleOpenReference = useCallback3((referenceData) => {
12235
+ const handleOpenReference = useCallback4((referenceData) => {
12094
12236
  const { type, id } = referenceData;
12095
12237
  if (type === "node") {
12096
12238
  const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
@@ -12117,10 +12259,10 @@ function XViewScene({
12117
12259
  }
12118
12260
  }
12119
12261
  }, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
12120
- const handleToggleAncestryAddMode = useCallback3(() => {
12262
+ const handleToggleAncestryAddMode = useCallback4(() => {
12121
12263
  setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
12122
12264
  }, []);
12123
- const handleFocusNode = useCallback3((nodeData) => {
12265
+ const handleFocusNode = useCallback4((nodeData) => {
12124
12266
  if (!nodeData) return;
12125
12267
  const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
12126
12268
  if (nodeMesh) {
@@ -12190,7 +12332,6 @@ function XViewScene({
12190
12332
  height: "100vh",
12191
12333
  position: "relative",
12192
12334
  overflow: "hidden",
12193
- // <--- ADICIONE ESTA LINHA
12194
12335
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
12195
12336
  }
12196
12337
  },
@@ -12257,9 +12398,20 @@ function XViewScene({
12257
12398
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
12258
12399
  "div",
12259
12400
  {
12260
- className: "ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col transition-all duration-300 ease-out w-[min(92vw,700px)]",
12261
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
12401
+ className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
12402
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
12262
12403
  },
12404
+ /* @__PURE__ */ React23.createElement(
12405
+ "div",
12406
+ {
12407
+ onPointerDown: (e) => {
12408
+ e.stopPropagation();
12409
+ handleReadModeResize(e);
12410
+ },
12411
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
12412
+ title: "Arraste para redimensionar"
12413
+ }
12414
+ ),
12263
12415
  /* @__PURE__ */ React23.createElement(
12264
12416
  DescriptionReadModePanel,
12265
12417
  {