@lv-x-software-house/x_view 1.2.2-dev.2 → 1.2.2-dev.20

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 +1263 -888
  2. package/dist/index.mjs +720 -345
  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
@@ -811,7 +812,6 @@ var x_view_config = {
811
812
  ANCESTOR_HIGHLIGHT_COLOR: "#FFD700",
812
813
  BLOOM_EFFECT: { strength: 1.35, radius: 0.6, threshold: 0.52 },
813
814
  EMISSIVE_MULTIPLIER: {
814
- // AJUSTE: Valores agora representam ADIÇÃO de intensidade, não multiplicação
815
815
  BASE: 0,
816
816
  HOVER: 2,
817
817
  SELECTED: 1.5,
@@ -863,7 +863,6 @@ var computeNodeMaterialProps = (colorHex) => {
863
863
  return {
864
864
  color: srgb,
865
865
  emissive: emissiveColor
866
- // Intensity é controlada externamente
867
866
  };
868
867
  };
869
868
  var createNodeMesh = (nodeData, position, glowTexture) => {
@@ -1154,6 +1153,7 @@ var createMultipleLinkLines = (linksArray, sourceNodeMesh, targetNodeMesh, resol
1154
1153
  resolution,
1155
1154
  isCurved,
1156
1155
  isCurved,
1156
+ isCurved,
1157
1157
  curveOffset
1158
1158
  );
1159
1159
  line.userData = {
@@ -1530,12 +1530,12 @@ var userActionHandlers = {
1530
1530
  stateRef.current.creation = { isActive: true, sourceNodeData };
1531
1531
  const ghostGeometry = new THREE.SphereGeometry(1.5, 32, 32);
1532
1532
  const sourceColor = sourceNodeData.color || "#cccccc";
1533
- const { emissiveIntensity } = computeNodeMaterialProps(sourceColor);
1534
- const ghostColor = new THREE.Color(sourceColor);
1533
+ const { color: ghostColor, emissive: ghostEmissive } = computeNodeMaterialProps(sourceColor);
1535
1534
  const ghostMaterial = new THREE.MeshStandardMaterial({
1536
1535
  color: ghostColor,
1537
- emissive: ghostColor,
1538
- emissiveIntensity,
1536
+ emissive: ghostEmissive,
1537
+ emissiveIntensity: MIN_VISIBILITY_INTENSITY,
1538
+ // <-- Forçamos o brilho mínimo
1539
1539
  roughness: 0.6,
1540
1540
  metalness: 0,
1541
1541
  transparent: true,
@@ -1606,27 +1606,50 @@ var userActionHandlers = {
1606
1606
  setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
1607
1607
  },
1608
1608
  handleSaveNode: async (context, newNodeData) => {
1609
- const { graphDataRef, sceneDataRef, stateRef, creationMode, setters } = context;
1609
+ const { graphDataRef, sceneDataRef, stateRef, creationMode, setters, actions } = context;
1610
1610
  if (!graphDataRef.current || !sceneDataRef.current) return;
1611
1611
  const { sourceNodeData } = creationMode;
1612
- const newNode = { id: short.generate(), ...newNodeData };
1612
+ const { targetDatasetId, ...nodeDataToSave } = newNodeData;
1613
+ const newNode = { id: short.generate(), ...nodeDataToSave };
1613
1614
  const newLink = { id: `link_${short.generate()}`, source: sourceNodeData.id, target: newNode.id };
1614
- const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, sourceNodeData.id);
1615
- if (!parentInfo || !parentInfo.ownerId) {
1616
- console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node de origem:", sourceNodeData.id);
1617
- alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio.");
1615
+ const sourceParentInfo = stateRef.current.nodeIdToParentFileMap.get(String(sourceNodeData.id));
1616
+ const finalTargetDatasetId = targetDatasetId || sourceParentInfo.parentFileId;
1617
+ const targetParentInfo = sceneDataRef.current.parent_dbs.find((db) => String(db.db_id) === String(finalTargetDatasetId));
1618
+ if (!sourceParentInfo || !targetParentInfo) {
1619
+ alert("Erro ao identificar os datasets de origem ou destino.");
1618
1620
  return;
1619
1621
  }
1620
- const { parentFileId, ownerId } = parentInfo;
1621
- const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
1622
- specificParentData.nodes.push(newNode);
1623
- specificParentData.links.push(newLink);
1624
- const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
1622
+ const isCrossDataset = String(sourceParentInfo.parentFileId) !== String(finalTargetDatasetId);
1623
+ const sourceDataToUpdate = JSON.parse(JSON.stringify(graphDataRef.current[sourceParentInfo.parentFileId]));
1624
+ let targetDataToUpdate = isCrossDataset ? JSON.parse(JSON.stringify(graphDataRef.current[finalTargetDatasetId])) : sourceDataToUpdate;
1625
+ targetDataToUpdate.nodes.push(newNode);
1626
+ sourceDataToUpdate.links.push(newLink);
1627
+ const savePromises = [];
1628
+ if (isCrossDataset) {
1629
+ savePromises.push(
1630
+ actions.save_view_data(`x_view_dbs/${sourceParentInfo.ownerId}/${sourceParentInfo.parentFileId}`, sourceDataToUpdate)
1631
+ );
1632
+ savePromises.push(
1633
+ actions.save_view_data(`x_view_dbs/${targetParentInfo.owner_id}/${finalTargetDatasetId}`, targetDataToUpdate)
1634
+ );
1635
+ } else {
1636
+ savePromises.push(
1637
+ actions.save_view_data(`x_view_dbs/${sourceParentInfo.ownerId}/${sourceParentInfo.parentFileId}`, sourceDataToUpdate)
1638
+ );
1639
+ }
1625
1640
  try {
1626
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
1627
- graphDataRef.current[parentFileId] = specificParentData;
1641
+ await Promise.all(savePromises);
1642
+ graphDataRef.current[sourceParentInfo.parentFileId] = sourceDataToUpdate;
1643
+ if (isCrossDataset) {
1644
+ graphDataRef.current[finalTargetDatasetId] = targetDataToUpdate;
1645
+ }
1628
1646
  const finalPosition = stateRef.current.ghostElements.node.position.clone();
1629
1647
  addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
1648
+ stateRef.current.nodeIdToParentFileMap.set(String(newNode.id), {
1649
+ parentFileId: finalTargetDatasetId,
1650
+ ownerId: targetParentInfo.owner_id,
1651
+ datasetName: targetDataToUpdate.dataset_name || "Dataset Desconhecido"
1652
+ });
1630
1653
  setters.setSceneVersion((v) => v + 1);
1631
1654
  } catch (error) {
1632
1655
  console.error("Falha ao salvar os dados do grafo:", error);
@@ -1664,12 +1687,12 @@ var userActionHandlers = {
1664
1687
  stateRef.current.creation = { isActive: true, sourceNodeData };
1665
1688
  const ghostGeometry = new THREE.SphereGeometry(1.5, 32, 32);
1666
1689
  const sourceColor = sourceNodeData.color || "#cccccc";
1667
- const { emissiveIntensity } = computeNodeMaterialProps(sourceColor);
1668
- const ghostColor = new THREE.Color(sourceColor);
1690
+ const { color: ghostColor, emissive: ghostEmissive } = computeNodeMaterialProps(sourceColor);
1669
1691
  const ghostMaterial = new THREE.MeshStandardMaterial({
1670
1692
  color: ghostColor,
1671
- emissive: ghostColor,
1672
- emissiveIntensity,
1693
+ emissive: ghostEmissive,
1694
+ emissiveIntensity: MIN_VISIBILITY_INTENSITY,
1695
+ // <-- Forçamos o brilho mínimo
1673
1696
  roughness: 0.6,
1674
1697
  metalness: 0,
1675
1698
  transparent: true,
@@ -2977,9 +3000,36 @@ var extractFileUrlsFromProperties = (dataObject) => {
2977
3000
  });
2978
3001
  return urlsToDelete;
2979
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
+ }
2980
3030
 
2981
3031
  // src/components/CustomPropertyDisplay.jsx
2982
- 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";
2983
3033
  import { FiCheck, FiX, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
2984
3034
  function CustomPropertyDisplay({
2985
3035
  prop,
@@ -2994,12 +3044,12 @@ function CustomPropertyDisplay({
2994
3044
  },
2995
3045
  onUploadFile
2996
3046
  }) {
2997
- const [isEditing, setIsEditing] = useState3(prop.isEditing ?? false);
2998
- const [tempProp, setTempProp] = useState3(prop);
2999
- const [isHovered, setIsHovered] = useState3(false);
3000
- 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);
3001
3051
  const dropdownRef = useRef3(null);
3002
- const [uploadingItemIndex, setUploadingItemIndex] = useState3(null);
3052
+ const [uploadingItemIndex, setUploadingItemIndex] = useState4(null);
3003
3053
  const fileInputRef = useRef3(null);
3004
3054
  const currentUploadTargetRef = useRef3(null);
3005
3055
  useEffect3(() => {
@@ -3122,8 +3172,8 @@ function CustomPropertyDisplay({
3122
3172
  const availableOptions = [
3123
3173
  { value: "links", label: "Links", unique: true },
3124
3174
  { value: "images", label: "Images", unique: true },
3125
- { value: "documents", label: "Documents", unique: true },
3126
3175
  { value: "date", label: "Data", unique: true },
3176
+ { value: "documents", label: "Documents", unique: true },
3127
3177
  { value: "text", label: "Texto", unique: false },
3128
3178
  { value: "number", label: "N\xFAmero", unique: false },
3129
3179
  { value: "list", label: "Lista", unique: false }
@@ -3345,15 +3395,15 @@ function CustomPropertyDisplay({
3345
3395
  import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
3346
3396
 
3347
3397
  // src/components/DescriptionEditModal.jsx
3348
- import React5, { useState as useState5, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
3349
- import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage } from "react-icons/fi";
3398
+ import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
3399
+ import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage, FiCheckSquare } from "react-icons/fi";
3350
3400
 
3351
3401
  // src/components/SectionImportModal.jsx
3352
- 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";
3353
3403
  import { FiSearch, FiLayers as FiLayers2, FiHexagon, FiClock, FiCheck as FiCheck2, FiCopy, FiTerminal, FiChevronDown as FiChevronDown2, FiChevronRight, FiDownload, FiLink } from "react-icons/fi";
3354
3404
  var CodeBlock = ({ content, isActive, onClick }) => {
3355
- const [isExpanded, setIsExpanded] = useState4(false);
3356
- const [copied, setCopied] = useState4(false);
3405
+ const [isExpanded, setIsExpanded] = useState5(false);
3406
+ const [copied, setCopied] = useState5(false);
3357
3407
  const cleanContent = content.replace(/^```|```$/g, "").trim();
3358
3408
  const isLongCode = cleanContent.split("\n").length > 4;
3359
3409
  const handleCopy = (e) => {
@@ -3416,12 +3466,14 @@ var formatLineContent = (line) => {
3416
3466
  return /* @__PURE__ */ React4.createElement("span", { className: "break-words" }, line);
3417
3467
  };
3418
3468
  function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], availableAncestries = [] }) {
3419
- const [searchTerm, setSearchTerm] = useState4("");
3420
- const [selectedItem, setSelectedItem] = useState4(null);
3421
- const [searchHistory, setSearchHistory] = useState4([]);
3422
- 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);
3423
3475
  const sectionRefs = useRef4([]);
3424
- const [isDropdownOpen, setIsDropdownOpen] = useState4(false);
3476
+ const [isDropdownOpen, setIsDropdownOpen] = useState5(false);
3425
3477
  const inputRef = useRef4(null);
3426
3478
  useEffect4(() => {
3427
3479
  if (!selectedItem) return;
@@ -3468,6 +3520,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3468
3520
  }, [selectedItem]);
3469
3521
  useEffect4(() => {
3470
3522
  setActiveIndex(0);
3523
+ setSelectedIndices(/* @__PURE__ */ new Set([0]));
3524
+ setLastSelectedIndex(0);
3471
3525
  }, [selectedItem]);
3472
3526
  useEffect4(() => {
3473
3527
  if (selectedItem && sectionRefs.current[activeIndex]) {
@@ -3484,22 +3538,64 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3484
3538
  if (document.activeElement === inputRef.current) return;
3485
3539
  if (e.key === "ArrowDown" || e.key === "ArrowRight") {
3486
3540
  e.preventDefault();
3487
- 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
+ });
3488
3551
  }
3489
3552
  if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
3490
3553
  e.preventDefault();
3491
- 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
+ });
3492
3564
  }
3493
3565
  if (e.key === "Enter") {
3494
3566
  e.preventDefault();
3495
- if (itemSections[activeIndex]) {
3496
- handleConfirmImport(itemSections[activeIndex]);
3497
- }
3567
+ handleConfirmImport();
3498
3568
  }
3499
3569
  };
3500
3570
  window.addEventListener("keydown", handleKeyDown);
3501
3571
  return () => window.removeEventListener("keydown", handleKeyDown);
3502
- }, [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
+ };
3503
3599
  const handleSelectItem = (item) => {
3504
3600
  setSelectedItem(item);
3505
3601
  setSearchHistory((prev) => {
@@ -3513,16 +3609,22 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3513
3609
  setSearchTerm("");
3514
3610
  setIsDropdownOpen(false);
3515
3611
  };
3516
- const handleConfirmImport = (sectionToImport = null) => {
3517
- const section = sectionToImport || itemSections[activeIndex];
3518
- if (!section) return;
3612
+ const handleConfirmImport = () => {
3613
+ if (selectedIndices.size === 0) return;
3519
3614
  const type = selectedItem._type;
3520
3615
  const itemId = selectedItem.id || selectedItem.ancestry_id;
3521
- if (section.id) {
3522
- const tag = `[[REF:${type}:${itemId}:${section.id}]]`;
3523
- 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);
3524
3626
  } else {
3525
- 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.");
3526
3628
  }
3527
3629
  };
3528
3630
  const renderSectionContent = (content) => {
@@ -3593,7 +3695,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3593
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"))
3594
3696
  );
3595
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) => {
3596
- const isActive = index === activeIndex;
3698
+ const isSelected = selectedIndices.has(index);
3699
+ const isFocused = index === activeIndex;
3597
3700
  const match = section.content.match(/^(\s*)([\s\S]*?)(\s*)$/);
3598
3701
  let leadingSpace = match ? match[1] : "";
3599
3702
  const bodyText = match ? match[2] : section.content;
@@ -3611,10 +3714,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3611
3714
  refAssigned = true;
3612
3715
  }
3613
3716
  },
3614
- onClick: () => setActiveIndex(index),
3717
+ onClick: (e) => handleSectionClick(index, e),
3615
3718
  className: `
3616
3719
  transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
3617
- ${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" : ""}
3618
3722
  `
3619
3723
  },
3620
3724
  renderSectionContent(bodyText)
@@ -3635,8 +3739,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3635
3739
  CodeBlock,
3636
3740
  {
3637
3741
  content: part,
3638
- isActive,
3639
- onClick: () => setActiveIndex(index)
3742
+ isActive: isSelected,
3743
+ onClick: (e) => handleSectionClick(index, e)
3640
3744
  }
3641
3745
  )
3642
3746
  );
@@ -3646,7 +3750,7 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3646
3750
  const isLastLine = lineIndex === lines.length - 1;
3647
3751
  const isEmptyLine = line.trim() === "";
3648
3752
  if (isEmptyLine) {
3649
- 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}` });
3650
3754
  }
3651
3755
  return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: `${index}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React4.createElement(
3652
3756
  "span",
@@ -3657,10 +3761,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3657
3761
  refAssigned = true;
3658
3762
  }
3659
3763
  },
3660
- onClick: () => setActiveIndex(index),
3764
+ onClick: (e) => handleSectionClick(index, e),
3661
3765
  className: `
3662
- transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
3663
- ${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" : ""}
3664
3769
  `
3665
3770
  },
3666
3771
  formatLineContent(line)
@@ -3674,7 +3779,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
3674
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"
3675
3780
  },
3676
3781
  /* @__PURE__ */ React4.createElement(FiDownload, { className: "text-indigo-200" }),
3677
- "Importar Se\xE7\xE3o"
3782
+ "Importar ",
3783
+ selectedIndices.size > 1 ? `${selectedIndices.size} Se\xE7\xF5es` : "Se\xE7\xE3o"
3678
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."))))
3679
3785
  ));
3680
3786
  }
@@ -3706,16 +3812,22 @@ function DescriptionEditModal({
3706
3812
  availableAncestries = [],
3707
3813
  availableImages = []
3708
3814
  }) {
3709
- 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 || "");
3710
3822
  const textareaRef = useRef5(null);
3711
- const [isImportModalOpen, setIsImportModalOpen] = useState5(false);
3712
- const [isMentionModalOpen, setIsMentionModalOpen] = useState5(false);
3713
- const [mentionSearch, setMentionSearch] = useState5("");
3714
- const [mentionTriggerIndex, setMentionTriggerIndex] = useState5(null);
3715
- const [isImageModalOpen, setIsImageModalOpen] = useState5(false);
3716
- 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("");
3717
3829
  const hoverTimeoutRef = useRef5(null);
3718
- const [tooltipData, setTooltipData] = useState5(null);
3830
+ const [tooltipData, setTooltipData] = useState6(null);
3719
3831
  useEffect5(() => {
3720
3832
  const handleKeyDown = (e) => {
3721
3833
  if (e.key === "Escape") {
@@ -3723,6 +3835,7 @@ function DescriptionEditModal({
3723
3835
  e.preventDefault();
3724
3836
  e.stopPropagation();
3725
3837
  e.stopImmediatePropagation();
3838
+ if (hoverTimeoutRef.current) clearTimeout(hoverTimeoutRef.current);
3726
3839
  setIsMentionModalOpen(false);
3727
3840
  setMentionTriggerIndex(null);
3728
3841
  setTooltipData(null);
@@ -3807,15 +3920,32 @@ function DescriptionEditModal({
3807
3920
  const uniqueSuffix = v4_default().slice(0, 4);
3808
3921
  insertAtCursor(`*/${nextNum}:${uniqueSuffix}/ `);
3809
3922
  };
3810
- const handleImportSelect = (tag) => {
3811
- const nextNum = getNextSectionNumber(text);
3812
- const uniqueSuffix = v4_default().slice(0, 4);
3813
- insertAtCursor(`
3814
- */${nextNum}:${uniqueSuffix}/ ${tag}
3815
- `);
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);
3816
3945
  setIsImportModalOpen(false);
3817
3946
  };
3818
3947
  const handleMentionSelect = (node) => {
3948
+ if (hoverTimeoutRef.current) clearTimeout(hoverTimeoutRef.current);
3819
3949
  const tag = `[[MENTION:node:${node.id}]]`;
3820
3950
  const el = textareaRef.current;
3821
3951
  if (mentionTriggerIndex !== null && el) {
@@ -3856,7 +3986,8 @@ function DescriptionEditModal({
3856
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(
3857
3987
  "div",
3858
3988
  {
3859
- 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" },
3860
3991
  onClick: swallow,
3861
3992
  onPointerDown: swallow,
3862
3993
  onPointerMove: swallow,
@@ -3865,6 +3996,17 @@ function DescriptionEditModal({
3865
3996
  onContextMenu: swallow,
3866
3997
  onDoubleClick: swallow
3867
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
+ ),
3868
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" }),
3869
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")),
3870
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(
@@ -3894,6 +4036,24 @@ function DescriptionEditModal({
3894
4036
  },
3895
4037
  /* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
3896
4038
  " Lista"
4039
+ ), /* @__PURE__ */ React5.createElement(
4040
+ "button",
4041
+ {
4042
+ onClick: () => insertAtCursor("1. "),
4043
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4044
+ title: "Lista Numerada"
4045
+ },
4046
+ /* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
4047
+ " Numerada"
4048
+ ), /* @__PURE__ */ React5.createElement(
4049
+ "button",
4050
+ {
4051
+ onClick: () => insertAtCursor("- [ ] "),
4052
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4053
+ title: "Checklist (Checkbox)"
4054
+ },
4055
+ /* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
4056
+ " Checklist"
3897
4057
  ), /* @__PURE__ */ React5.createElement(
3898
4058
  "button",
3899
4059
  {
@@ -4029,7 +4189,7 @@ function DescriptionEditModal({
4029
4189
  className: "px-3 py-1.5 bg-indigo-600/30 hover:bg-indigo-600 text-indigo-200 text-xs rounded-lg transition-colors disabled:opacity-50"
4030
4190
  },
4031
4191
  "OK"
4032
- ))), /* @__PURE__ */ React5.createElement("div", { className: "p-2 border-t border-white/10 bg-slate-950/50 flex justify-end" }, /* @__PURE__ */ React5.createElement("button", { onClick: () => setIsImageModalOpen(false), className: "px-3 py-1.5 text-xs text-slate-400 hover:text-white transition-colors" }, "Cancelar")))), /* @__PURE__ */ React5.createElement("p", { className: "mt-2 text-xs text-slate-500 shrink-0" }, "Dica: Tags agora incluem ID (ex: ", /* @__PURE__ */ React5.createElement("b", null, "*/1:a9f2/"), ") para garantir que refer\xEAncias n\xE3o quebrem se voc\xEA reordenar o texto.")),
4192
+ ))), /* @__PURE__ */ React5.createElement("div", { className: "p-2 border-t border-white/10 bg-slate-950/50 flex justify-end" }, /* @__PURE__ */ React5.createElement("button", { onClick: () => setIsImageModalOpen(false), className: "px-3 py-1.5 text-xs text-slate-400 hover:text-white transition-colors" }, "Cancelar"))))),
4033
4193
  /* @__PURE__ */ React5.createElement("div", { className: "sticky bottom-0 z-10 bg-slate-950/95 border-t border-white/10 px-6 py-4 flex justify-end gap-3 shrink-0" }, /* @__PURE__ */ React5.createElement("button", { onClick: handleSave, className: "px-6 py-2 rounded-lg bg-gradient-to-tr from-indigo-600 to-indigo-400 hover:from-indigo-500 hover:to-indigo-300 transition-colors font-semibold text-sm shadow-[0_8px_24px_rgba(99,102,241,0.35)]" }, "Salvar"))
4034
4194
  )), tooltipData && /* @__PURE__ */ React5.createElement(
4035
4195
  "div",
@@ -4056,11 +4216,11 @@ function DescriptionEditModal({
4056
4216
  }
4057
4217
 
4058
4218
  // src/components/DescriptionDisplay.jsx
4059
- import React6, { useMemo as useMemo5, useState as useState6, useEffect as useEffect6, useRef as useRef6 } from "react";
4060
- 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";
4219
+ import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
4220
+ import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2, FiSave } from "react-icons/fi";
4061
4221
  var CodeBlock2 = ({ content, isActive, onClick }) => {
4062
- const [isExpanded, setIsExpanded] = useState6(false);
4063
- const [copied, setCopied] = useState6(false);
4222
+ const [isExpanded, setIsExpanded] = useState7(false);
4223
+ const [copied, setCopied] = useState7(false);
4064
4224
  const cleanContent = content.replace(/^```|```$/g, "").trim();
4065
4225
  const isLongCode = cleanContent.split("\n").length > 4;
4066
4226
  const handleCopy = (e) => {
@@ -4200,7 +4360,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
4200
4360
  );
4201
4361
  });
4202
4362
  };
4203
- var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
4363
+ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
4204
4364
  const trimmedLine = line.replace(/\r$/, "");
4205
4365
  const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
4206
4366
  if (line.startsWith("# ")) {
@@ -4211,9 +4371,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
4211
4371
  const content = line.replace("## ", "");
4212
4372
  return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
4213
4373
  }
4374
+ const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
4375
+ if (checkboxMatch) {
4376
+ const [_, space, state, content] = checkboxMatch;
4377
+ const isChecked = state.toLowerCase() === "x";
4378
+ const currentIdx = globalCheckboxCounterRef.current;
4379
+ globalCheckboxCounterRef.current += 1;
4380
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
4381
+ "div",
4382
+ {
4383
+ onClick: (e) => {
4384
+ e.stopPropagation();
4385
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4386
+ },
4387
+ className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
4388
+ ${isChecked ? "bg-indigo-500 border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-slate-500 bg-slate-900/50 hover:border-slate-400 group-hover/checkbox:border-slate-400"}
4389
+ `
4390
+ },
4391
+ isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
4392
+ ), /* @__PURE__ */ React6.createElement(
4393
+ "span",
4394
+ {
4395
+ className: `transition-all duration-200 cursor-pointer pt-[1px]
4396
+ ${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
4397
+ `,
4398
+ onClick: (e) => {
4399
+ e.stopPropagation();
4400
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4401
+ }
4402
+ },
4403
+ processContent(content)
4404
+ ));
4405
+ }
4406
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4407
+ if (numberMatch) {
4408
+ const [_, space, numberStr, content] = numberMatch;
4409
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-mono font-bold text-xs mt-[3px] shrink-0" }, numberStr), /* @__PURE__ */ React6.createElement("span", { className: "text-slate-200" }, processContent(content)));
4410
+ }
4214
4411
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4215
4412
  const content = trimmedLine.trim().substring(2);
4216
- return /* @__PURE__ */ React6.createElement("span", { className: "pl-2 text-slate-200 break-words" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold mr-1.5" }, "\u2022"), processContent(content));
4413
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1 text-slate-200" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold shrink-0 mt-[2px] text-xs" }, "\u2022"), /* @__PURE__ */ React6.createElement("span", null, processContent(content)));
4217
4414
  }
4218
4415
  return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
4219
4416
  };
@@ -4225,14 +4422,31 @@ function DescriptionDisplay({
4225
4422
  onOpenReference,
4226
4423
  onMentionClick,
4227
4424
  onImageClick,
4228
- // <--- NOVA PROP RECEBIDA
4229
4425
  onSectionChange,
4230
4426
  onBranchNav,
4231
4427
  onHighlightNode,
4232
4428
  initialSectionId,
4233
- currentBranchDirection = null
4429
+ currentBranchDirection = null,
4430
+ onSaveDescription
4234
4431
  }) {
4235
- const sections = useMemo5(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4432
+ const [localDescription, setLocalDescription] = useState7(description || "");
4433
+ useEffect6(() => {
4434
+ setLocalDescription(description || "");
4435
+ }, [description]);
4436
+ const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4437
+ const globalCheckboxCounterRef = useRef6(0);
4438
+ const handleToggleCheckbox = (targetIndex) => {
4439
+ let currentIndex = 0;
4440
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4441
+ if (currentIndex === targetIndex) {
4442
+ currentIndex++;
4443
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4444
+ }
4445
+ currentIndex++;
4446
+ return match;
4447
+ });
4448
+ setLocalDescription(newDesc);
4449
+ };
4236
4450
  const flatNavigation = useMemo5(() => {
4237
4451
  const navItems = [];
4238
4452
  sections.forEach((section, sIdx) => {
@@ -4259,7 +4473,7 @@ function DescriptionDisplay({
4259
4473
  });
4260
4474
  return navItems;
4261
4475
  }, [sections]);
4262
- const [currentStepIndex, setCurrentStepIndex] = useState6(0);
4476
+ const [currentStepIndex, setCurrentStepIndex] = useState7(0);
4263
4477
  const activeRef = useRef6(null);
4264
4478
  const lastNotifiedSectionId = useRef6(null);
4265
4479
  const isInitialMount = useRef6(true);
@@ -4373,26 +4587,27 @@ function DescriptionDisplay({
4373
4587
  }
4374
4588
  const lines = part.replace(/\n$/, "").split("\n");
4375
4589
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
4376
- const isLastLine = lineIndex === lines.length - 1;
4377
4590
  const isEmptyLine = line.trim() === "";
4378
4591
  if (isEmptyLine) {
4379
4592
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
4380
4593
  }
4381
4594
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
4382
- "span",
4595
+ "div",
4383
4596
  {
4384
4597
  ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
4385
- onClick: () => {
4386
- const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4387
- if (idx !== -1) setCurrentStepIndex(idx);
4598
+ onClick: (e) => {
4599
+ if (e.target.type !== "checkbox") {
4600
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4601
+ if (idx !== -1) setCurrentStepIndex(idx);
4602
+ }
4388
4603
  },
4389
4604
  className: `
4390
- transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
4391
- ${isActiveSection ? "bg-indigo-500/20 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4605
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4606
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4392
4607
  `
4393
4608
  },
4394
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4395
- ), !isLastLine && /* @__PURE__ */ React6.createElement("br", null));
4609
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4610
+ ));
4396
4611
  }));
4397
4612
  });
4398
4613
  };
@@ -4420,7 +4635,9 @@ function DescriptionDisplay({
4420
4635
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4421
4636
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4422
4637
  };
4423
- return /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-2 pr-9" }, sections.map((section, index) => {
4638
+ globalCheckboxCounterRef.current = 0;
4639
+ const hasUnsavedChanges = localDescription !== (description || "");
4640
+ return /* @__PURE__ */ React6.createElement("div", { className: "relative w-full h-full min-h-[100px]" }, /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-16 pr-9" }, sections.map((section, index) => {
4424
4641
  const currentNavItem = flatNavigation[currentStepIndex];
4425
4642
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4426
4643
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4436,11 +4653,22 @@ function DescriptionDisplay({
4436
4653
  if (index === 0) leadingSpace = "";
4437
4654
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4438
4655
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: index }, /* @__PURE__ */ React6.createElement("span", null, leadingSpace), isRef ? renderReferenceSection(bodyText, index, isSectionContextActive, setRef) : renderMixedContent(bodyText, index, isSectionContextActive, activeMentionIndex, setRef), /* @__PURE__ */ React6.createElement("span", null, trailingSpace));
4439
- }));
4656
+ })), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ React6.createElement("div", { className: "absolute bottom-2 left-2 z-[100] animate-in slide-in-from-bottom-2 fade-in duration-300" }, /* @__PURE__ */ React6.createElement(
4657
+ "button",
4658
+ {
4659
+ onClick: (e) => {
4660
+ e.stopPropagation();
4661
+ onSaveDescription(localDescription);
4662
+ },
4663
+ className: "flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600/90 hover:bg-indigo-500 text-white rounded-md shadow-[0_4px_12px_rgba(99,102,241,0.3)] text-xs font-medium transition-all hover:scale-105 active:scale-95 border border-indigo-400/20 backdrop-blur-sm"
4664
+ },
4665
+ /* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
4666
+ " Salvar Checklist"
4667
+ )));
4440
4668
  }
4441
4669
 
4442
4670
  // src/components/DescriptionReadModePanel.jsx
4443
- import React7, { useState as useState7, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4671
+ import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4444
4672
  import {
4445
4673
  FiArrowLeft,
4446
4674
  FiEdit2,
@@ -4519,7 +4747,6 @@ function DescriptionReadModePanel({
4519
4747
  title,
4520
4748
  description,
4521
4749
  ancestryId,
4522
- // <-- NOVO: Prop recebida do XViewScene
4523
4750
  savedSections,
4524
4751
  onBack,
4525
4752
  onEdit,
@@ -4541,12 +4768,13 @@ function DescriptionReadModePanel({
4541
4768
  userRole,
4542
4769
  abstractionTree = null,
4543
4770
  onRenderAbstractionTree = null,
4544
- initialShowAbstraction = false
4771
+ initialShowAbstraction = false,
4772
+ onSaveDescription
4545
4773
  }) {
4546
- const [showProperties, setShowProperties] = useState7(false);
4547
- const [showAbstraction, setShowAbstraction] = useState7(false);
4548
- const [targetRenderNodeId, setTargetRenderNodeId] = useState7(null);
4549
- const [isLinkCopied, setIsLinkCopied] = useState7(false);
4774
+ const [showProperties, setShowProperties] = useState8(false);
4775
+ const [showAbstraction, setShowAbstraction] = useState8(false);
4776
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
4777
+ const [isLinkCopied, setIsLinkCopied] = useState8(false);
4550
4778
  const handleCopyLink = (e) => {
4551
4779
  e.stopPropagation();
4552
4780
  if (!ancestryId) return;
@@ -4628,7 +4856,7 @@ function DescriptionReadModePanel({
4628
4856
  return /* @__PURE__ */ React7.createElement(
4629
4857
  "div",
4630
4858
  {
4631
- className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
4859
+ className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
4632
4860
  onPointerDown: swallow,
4633
4861
  onClick: swallow
4634
4862
  },
@@ -4700,7 +4928,7 @@ function DescriptionReadModePanel({
4700
4928
  },
4701
4929
  "\xD7"
4702
4930
  ))),
4703
- /* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
4931
+ /* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10 min-h-0", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
4704
4932
  "button",
4705
4933
  {
4706
4934
  onClick: (e) => {
@@ -4759,7 +4987,8 @@ function DescriptionReadModePanel({
4759
4987
  onHighlightNode,
4760
4988
  initialSectionId,
4761
4989
  currentBranchDirection,
4762
- onImageClick
4990
+ onImageClick,
4991
+ onSaveDescription
4763
4992
  }
4764
4993
  )),
4765
4994
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
@@ -4801,11 +5030,11 @@ function AncestryRelationshipPanel({
4801
5030
  onMentionClick,
4802
5031
  onUploadFile
4803
5032
  }) {
4804
- const [description, setDescription] = useState8((data == null ? void 0 : data.description) ?? "");
4805
- const [customProps, setCustomProps] = useState8(() => extractCustomPropsFromNode(data || {}));
4806
- const [existingSections, setExistingSections] = useState8((data == null ? void 0 : data.description_sections) || []);
4807
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState8(false);
4808
- const [isReadMode, setIsReadMode] = useState8(false);
5033
+ const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
5034
+ const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
5035
+ const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
5036
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
5037
+ const [isReadMode, setIsReadMode] = useState9(false);
4809
5038
  const propsEndRef = useRef7(null);
4810
5039
  useEffect8(() => {
4811
5040
  setDescription((data == null ? void 0 : data.description) ?? "");
@@ -4829,6 +5058,17 @@ function AncestryRelationshipPanel({
4829
5058
  return newProps;
4830
5059
  });
4831
5060
  };
5061
+ const handleSaveDescriptionInline = (newDescription) => {
5062
+ setDescription(newDescription);
5063
+ const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
5064
+ const processedSections = processDescriptionForSave(newDescription, existingSections);
5065
+ const dataToSave = {
5066
+ description: newDescription,
5067
+ description_sections: processedSections,
5068
+ ...extrasObj
5069
+ };
5070
+ onSave(dataToSave);
5071
+ };
4832
5072
  const handleSave = () => {
4833
5073
  const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
4834
5074
  const processedSections = processDescriptionForSave(description, existingSections);
@@ -4878,7 +5118,8 @@ function AncestryRelationshipPanel({
4878
5118
  availableAncestries,
4879
5119
  onOpenReference,
4880
5120
  onMentionClick,
4881
- onImageClick: handleImageClickFromText
5121
+ onImageClick: handleImageClickFromText,
5122
+ onSaveDescription: handleSaveDescriptionInline
4882
5123
  }
4883
5124
  ) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React8.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-cyan-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React8.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o de Ancestralidade")), /* @__PURE__ */ React8.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Editar Rela\xE7\xE3o")), /* @__PURE__ */ React8.createElement("button", { onClick: onClose, 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")), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pb-4 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React8.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o da Rela\xE7\xE3o"), /* @__PURE__ */ React8.createElement("div", { className: "relative group min-h-[60px] bg-slate-800/40 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React8.createElement(
4884
5125
  DescriptionDisplay,
@@ -4889,7 +5130,8 @@ function AncestryRelationshipPanel({
4889
5130
  availableAncestries,
4890
5131
  onOpenReference,
4891
5132
  onMentionClick,
4892
- onImageClick: handleImageClickFromText
5133
+ onImageClick: handleImageClickFromText,
5134
+ onSaveDescription: handleSaveDescriptionInline
4893
5135
  }
4894
5136
  ), /* @__PURE__ */ React8.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React8.createElement(
4895
5137
  "button",
@@ -4947,7 +5189,7 @@ function AncestryRelationshipPanel({
4947
5189
  }
4948
5190
 
4949
5191
  // src/components/CreateAncestryPanel.jsx
4950
- import React10, { useState as useState10, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback } from "react";
5192
+ import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
4951
5193
  import {
4952
5194
  FiEdit2 as FiEdit23,
4953
5195
  FiBookOpen as FiBookOpen2,
@@ -4967,7 +5209,7 @@ import {
4967
5209
  } from "react-icons/fi";
4968
5210
 
4969
5211
  // src/components/AncestryPickerModal.jsx
4970
- import React9, { useState as useState9, useMemo as useMemo7, useEffect as useEffect9 } from "react";
5212
+ import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
4971
5213
  import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
4972
5214
  function AncestryPickerModal({
4973
5215
  isOpen,
@@ -4977,7 +5219,7 @@ function AncestryPickerModal({
4977
5219
  availableNodes = [],
4978
5220
  currentAncestryId
4979
5221
  }) {
4980
- const [searchTerm, setSearchTerm] = useState9("");
5222
+ const [searchTerm, setSearchTerm] = useState10("");
4981
5223
  useEffect9(() => {
4982
5224
  if (!isOpen) return;
4983
5225
  const handleKeyDown = (e) => {
@@ -5062,7 +5304,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
5062
5304
  var _a, _b;
5063
5305
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
5064
5306
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
5065
- const [isDragOver, setIsDragOver] = useState10(false);
5307
+ const [isDragOver, setIsDragOver] = useState11(false);
5066
5308
  const isSelectedParent = String(selectedParentId) === String(itemId);
5067
5309
  const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
5068
5310
  const isHighlightedPath = highlightedPathIds.includes(String(itemId));
@@ -5198,8 +5440,8 @@ function CreateAncestryPanel({
5198
5440
  isAddingNodes,
5199
5441
  currentAncestryId
5200
5442
  } = ancestryMode;
5201
- const [isSaving, setIsSaving] = useState10(false);
5202
- const [isLinkCopied, setIsLinkCopied] = useState10(false);
5443
+ const [isSaving, setIsSaving] = useState11(false);
5444
+ const [isLinkCopied, setIsLinkCopied] = useState11(false);
5203
5445
  const handleCopyLink = (e) => {
5204
5446
  e.stopPropagation();
5205
5447
  if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
@@ -5213,11 +5455,11 @@ function CreateAncestryPanel({
5213
5455
  setTimeout(() => setIsLinkCopied(false), 2e3);
5214
5456
  }).catch((err) => console.error("Erro ao copiar link:", err));
5215
5457
  };
5216
- const [isPickerOpen, setIsPickerOpen] = useState10(false);
5217
- const [customProps, setCustomProps] = useState10([]);
5458
+ const [isPickerOpen, setIsPickerOpen] = useState11(false);
5459
+ const [customProps, setCustomProps] = useState11([]);
5218
5460
  const propsEndRef = useRef8(null);
5219
- const [branchStack, setBranchStack] = useState10([]);
5220
- const [targetRenderNodeId, setTargetRenderNodeId] = useState10(null);
5461
+ const [branchStack, setBranchStack] = useState11([]);
5462
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
5221
5463
  const highlightedPathIds = useMemo8(() => {
5222
5464
  var _a, _b;
5223
5465
  if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
@@ -5231,17 +5473,27 @@ function CreateAncestryPanel({
5231
5473
  }
5232
5474
  return ids;
5233
5475
  }, [targetRenderNodeId, ancestryMode.abstraction_tree]);
5234
- const [targetScrollSectionId, setTargetScrollSectionId] = useState10(null);
5235
- const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState10(null);
5236
- const [ancestryName, setAncestryName] = useState10(initialName);
5237
- const [description, setDescription] = useState10(initialDescription || "");
5238
- const [existingSections, setExistingSections] = useState10(initialSections || []);
5239
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState10(false);
5240
- const [isReadMode, setIsReadMode] = useState10(false);
5476
+ const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
5477
+ const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
5478
+ const [ancestryName, setAncestryName] = useState11(initialName);
5479
+ const [description, setDescription] = useState11(initialDescription || "");
5480
+ const [existingSections, setExistingSections] = useState11(initialSections || []);
5481
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
5482
+ const [isReadMode, setIsReadMode] = useState11(false);
5483
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
5484
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
5485
+ initialWidth: isReadMode ? 700 : 440,
5486
+ minWidth: 320,
5487
+ maxWidth: maxPanelW
5488
+ });
5489
+ useEffect10(() => {
5490
+ setWidth(isReadMode ? 700 : 440);
5491
+ }, [isReadMode, setWidth]);
5241
5492
  const currentMaxRenderIndexRef = useRef8(0);
5242
5493
  const branchProgressMapRef = useRef8({});
5243
- const [lastSavedSnapshot, setLastSavedSnapshot] = useState10(null);
5244
- const [isPrivate, setIsPrivate] = useState10(ancestryMode.is_private || false);
5494
+ const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
5495
+ const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
5496
+ const initializedContextIdRef = useRef8(null);
5245
5497
  const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
5246
5498
  const handleImageClickFromText = (url, name) => {
5247
5499
  if (onOpenImageViewer) {
@@ -5259,7 +5511,7 @@ function CreateAncestryPanel({
5259
5511
  }
5260
5512
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5261
5513
  };
5262
- const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
5514
+ const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
5263
5515
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
5264
5516
  const treeKey = isAbstraction ? "abstraction_tree" : "tree";
5265
5517
  setAncestryMode((prev) => {
@@ -5440,6 +5692,11 @@ function CreateAncestryPanel({
5440
5692
  }, [isContextLinked, branchStack]);
5441
5693
  useEffect10(() => {
5442
5694
  const ctx = getCurrentContext();
5695
+ const currentContextId = branchStack.length > 0 ? branchStack[branchStack.length - 1].branchId : ancestryMode.currentAncestryId || `new_${ancestryMode.ancestral_node}`;
5696
+ if (initializedContextIdRef.current === currentContextId) {
5697
+ return;
5698
+ }
5699
+ initializedContextIdRef.current = currentContextId;
5443
5700
  let sourceObject = {};
5444
5701
  if (ctx) {
5445
5702
  sourceObject = ctx;
@@ -5790,7 +6047,7 @@ function CreateAncestryPanel({
5790
6047
  const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
5791
6048
  abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
5792
6049
  }
5793
- return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
6050
+ return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged || abstractionTreeChanged;
5794
6051
  }, [
5795
6052
  ancestryName,
5796
6053
  description,
@@ -6138,6 +6395,10 @@ function CreateAncestryPanel({
6138
6395
  setInternalHighlightedNodeId(id);
6139
6396
  if (onHighlightNode) onHighlightNode(id);
6140
6397
  };
6398
+ const handleSaveDescriptionInline = (newDesc) => {
6399
+ setDescription(newDesc);
6400
+ handleLocalSave(true, { description: newDesc });
6401
+ };
6141
6402
  const swallow = (e) => e.stopPropagation();
6142
6403
  const getSelectedParentName = () => {
6143
6404
  if (!activeTree || !selectedParentId) return "";
@@ -6210,10 +6471,8 @@ function CreateAncestryPanel({
6210
6471
  return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
6211
6472
  "div",
6212
6473
  {
6213
- 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
6214
- ${isReadMode ? "w-[min(92vw,700px)]" : "w-[min(92vw,440px)]"}
6215
- `,
6216
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" },
6474
+ 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"}`,
6475
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
6217
6476
  onPointerDown: swallow,
6218
6477
  onPointerMove: swallow,
6219
6478
  onPointerUp: swallow,
@@ -6222,6 +6481,17 @@ function CreateAncestryPanel({
6222
6481
  onContextMenu: swallow,
6223
6482
  onDoubleClick: swallow
6224
6483
  },
6484
+ /* @__PURE__ */ React10.createElement(
6485
+ "div",
6486
+ {
6487
+ onPointerDown: (e) => {
6488
+ e.stopPropagation();
6489
+ handleResize(e);
6490
+ },
6491
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
6492
+ title: "Arraste para redimensionar"
6493
+ }
6494
+ ),
6225
6495
  isReadMode ? /* @__PURE__ */ React10.createElement(
6226
6496
  DescriptionReadModePanel,
6227
6497
  {
@@ -6240,7 +6510,8 @@ function CreateAncestryPanel({
6240
6510
  onMentionClick,
6241
6511
  onSectionChange: handleSectionChangeWrapper,
6242
6512
  onHighlightNode,
6243
- onImageClick: handleImageClickFromText
6513
+ onImageClick: handleImageClickFromText,
6514
+ onSaveDescription: handleSaveDescriptionInline
6244
6515
  }
6245
6516
  ) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 flex-shrink-0" }, /* @__PURE__ */ React10.createElement("div", { className: "w-full" }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React10.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React10.createElement("p", { className: "text-xs/relaxed text-slate-300" }, branchStack.length > 0 ? `Ramifica\xE7\xE3o (N\xEDvel ${branchStack.length})` : isEditMode ? "Editar Ancestralidade" : "Criar Ancestralidade"), currentAncestryId && currentAncestryId !== "temp_creating" && currentAncestryId !== "temp_root" && /* @__PURE__ */ React10.createElement(
6246
6517
  "button",
@@ -6297,7 +6568,8 @@ function CreateAncestryPanel({
6297
6568
  onHighlightNode: handleHighlightWrapper,
6298
6569
  initialSectionId: targetScrollSectionId,
6299
6570
  currentBranchDirection: currentContext ? currentContext.direction : null,
6300
- onImageClick: handleImageClickFromText
6571
+ onImageClick: handleImageClickFromText,
6572
+ onSaveDescription: handleSaveDescriptionInline
6301
6573
  }
6302
6574
  ), /* @__PURE__ */ React10.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5 z-30" }, /* @__PURE__ */ React10.createElement(
6303
6575
  "button",
@@ -6518,25 +6790,25 @@ function CreateAncestryPanel({
6518
6790
  }
6519
6791
 
6520
6792
  // src/components/ImageViewer.jsx
6521
- import React11, { useState as useState11, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback2 } from "react";
6793
+ import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
6522
6794
  import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
6523
6795
  function ImageViewer({ data, onClose }) {
6524
6796
  var _a;
6525
6797
  const { images = [], startIndex = 0, visible } = data;
6526
- const [currentIndex, setCurrentIndex] = useState11(startIndex);
6527
- const [isLoading, setIsLoading] = useState11(false);
6528
- const [loadedSrc, setLoadedSrc] = useState11(null);
6798
+ const [currentIndex, setCurrentIndex] = useState12(startIndex);
6799
+ const [isLoading, setIsLoading] = useState12(false);
6800
+ const [loadedSrc, setLoadedSrc] = useState12(null);
6529
6801
  useLayoutEffect2(() => {
6530
6802
  if (visible) {
6531
6803
  setCurrentIndex(startIndex);
6532
6804
  }
6533
6805
  }, [visible, startIndex]);
6534
- const handleNext = useCallback2(() => {
6806
+ const handleNext = useCallback3(() => {
6535
6807
  if (images.length > 1) {
6536
6808
  setCurrentIndex((prev) => (prev + 1) % images.length);
6537
6809
  }
6538
6810
  }, [images.length]);
6539
- const handlePrev = useCallback2(() => {
6811
+ const handlePrev = useCallback3(() => {
6540
6812
  if (images.length > 1) {
6541
6813
  setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
6542
6814
  }
@@ -6641,10 +6913,10 @@ function ImageViewer({ data, onClose }) {
6641
6913
  }
6642
6914
 
6643
6915
  // src/components/InSceneCreationForm.jsx
6644
- import React13, { useState as useState13, useEffect as useEffect13, useRef as useRef10 } from "react";
6916
+ import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
6645
6917
 
6646
6918
  // src/components/ColorPicker.jsx
6647
- import React12, { useState as useState12, useEffect as useEffect12, useRef as useRef9 } from "react";
6919
+ import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
6648
6920
  import { HexColorPicker } from "react-colorful";
6649
6921
  import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
6650
6922
  var PRESET_COLORS = [
@@ -6665,7 +6937,7 @@ var PRESET_COLORS = [
6665
6937
  "#000000"
6666
6938
  ];
6667
6939
  function ColorPicker({ color, onChange, disabled }) {
6668
- const [isOpen, setIsOpen] = useState12(false);
6940
+ const [isOpen, setIsOpen] = useState13(false);
6669
6941
  const popoverRef = useRef9(null);
6670
6942
  useEffect12(() => {
6671
6943
  const handleClickOutside = (event) => {
@@ -6740,7 +7012,7 @@ function ColorPicker({ color, onChange, disabled }) {
6740
7012
  }
6741
7013
 
6742
7014
  // src/components/InSceneCreationForm.jsx
6743
- import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun } from "react-icons/fi";
7015
+ import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
6744
7016
  function InSceneCreationForm({
6745
7017
  onSave,
6746
7018
  onCancel,
@@ -6758,21 +7030,44 @@ function InSceneCreationForm({
6758
7030
  availableAncestries = [],
6759
7031
  onMentionClick,
6760
7032
  sourceTypes,
6761
- onUploadFile
7033
+ onUploadFile,
7034
+ availableDatasets = [],
7035
+ sourceNodeDatasetId,
7036
+ viewType
6762
7037
  }) {
6763
- const [name, setName] = useState13("");
6764
- const [types, setTypes] = useState13([]);
6765
- const [typeInput, setTypeInput] = useState13("");
6766
- const [color, setColor] = useState13(initialColor || "#cccccc");
6767
- const [size, setSize] = useState13("medium");
6768
- const [intensity, setIntensity] = useState13(0);
6769
- const [description, setDescription] = useState13("");
6770
- const [customProps, setCustomProps] = useState13([]);
6771
- const [showTypeSuggestions, setShowTypeSuggestions] = useState13(false);
6772
- const [filteredTypes, setFilteredTypes] = useState13([]);
6773
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState13(false);
6774
- const [useImageAsTexture, setUseImageAsTexture] = useState13(false);
6775
- const [selectedImageUrl, setSelectedImageUrl] = useState13(null);
7038
+ var _a;
7039
+ const [name, setName] = useState14("");
7040
+ const [types, setTypes] = useState14([]);
7041
+ const [typeInput, setTypeInput] = useState14("");
7042
+ const [color, setColor] = useState14(initialColor || "#cccccc");
7043
+ const [size, setSize] = useState14("medium");
7044
+ const [intensity, setIntensity] = useState14(0);
7045
+ const [description, setDescription] = useState14("");
7046
+ const [customProps, setCustomProps] = useState14([]);
7047
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
7048
+ const [filteredTypes, setFilteredTypes] = useState14([]);
7049
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
7050
+ const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
7051
+ const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
7052
+ const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
7053
+ const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
7054
+ const datasetDropdownRef = useRef10(null);
7055
+ useEffect13(() => {
7056
+ if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
7057
+ }, [sourceNodeDatasetId]);
7058
+ useEffect13(() => {
7059
+ function handleClickOutside(event) {
7060
+ if (datasetDropdownRef.current && !datasetDropdownRef.current.contains(event.target)) {
7061
+ setIsDatasetDropdownOpen(false);
7062
+ }
7063
+ }
7064
+ if (isDatasetDropdownOpen) {
7065
+ document.addEventListener("mousedown", handleClickOutside);
7066
+ }
7067
+ return () => {
7068
+ document.removeEventListener("mousedown", handleClickOutside);
7069
+ };
7070
+ }, [isDatasetDropdownOpen]);
6776
7071
  const propsEndRef = useRef10(null);
6777
7072
  const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
6778
7073
  useEffect13(() => {
@@ -6818,8 +7113,8 @@ function InSceneCreationForm({
6818
7113
  const newProp = createNewCustomProperty(customProps);
6819
7114
  setCustomProps([...customProps, newProp]);
6820
7115
  setTimeout(() => {
6821
- var _a;
6822
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
7116
+ var _a2;
7117
+ (_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
6823
7118
  }, 100);
6824
7119
  };
6825
7120
  const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
@@ -6852,12 +7147,12 @@ function InSceneCreationForm({
6852
7147
  onSizeChange == null ? void 0 : onSizeChange(newSize);
6853
7148
  };
6854
7149
  const handleToggleImageMode = () => {
6855
- var _a, _b;
7150
+ var _a2, _b;
6856
7151
  const newValue = !useImageAsTexture;
6857
7152
  setUseImageAsTexture(newValue);
6858
7153
  if (newValue) {
6859
7154
  const firstImageProp = customProps.find((p) => p.type === "images");
6860
- if (firstImageProp && ((_b = (_a = firstImageProp.value) == null ? void 0 : _a[0]) == null ? void 0 : _b.value)) {
7155
+ if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
6861
7156
  const url = firstImageProp.value[0].value;
6862
7157
  setSelectedImageUrl(url);
6863
7158
  onImageChange == null ? void 0 : onImageChange(true, url);
@@ -6890,6 +7185,7 @@ function InSceneCreationForm({
6890
7185
  description_sections: processedSections,
6891
7186
  useImageAsTexture,
6892
7187
  textureImageUrl: useImageAsTexture ? selectedImageUrl : null,
7188
+ targetDatasetId,
6893
7189
  ...additionalData
6894
7190
  });
6895
7191
  };
@@ -6910,6 +7206,7 @@ function InSceneCreationForm({
6910
7206
  onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
6911
7207
  }
6912
7208
  };
7209
+ const selectedDatasetName = ((_a = availableDatasets.find((ds) => ds.id === targetDatasetId)) == null ? void 0 : _a.name) || "Selecione um Dataset...";
6913
7210
  return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
6914
7211
  "div",
6915
7212
  {
@@ -6967,7 +7264,27 @@ function InSceneCreationForm({
6967
7264
  }
6968
7265
  },
6969
7266
  suggestedType
6970
- ))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React13.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React13.createElement(
7267
+ ))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), viewType === "view" && availableDatasets.length > 0 && /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative", ref: datasetDropdownRef }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Criar Node no Dataset:"), /* @__PURE__ */ React13.createElement(
7268
+ "button",
7269
+ {
7270
+ type: "button",
7271
+ onClick: () => setIsDatasetDropdownOpen(!isDatasetDropdownOpen),
7272
+ className: "w-full flex items-center justify-between bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 hover:bg-slate-700/70 transition-colors text-slate-200 text-left"
7273
+ },
7274
+ /* @__PURE__ */ React13.createElement("span", { className: "truncate pr-2" }, selectedDatasetName),
7275
+ /* @__PURE__ */ React13.createElement(FiChevronDown4, { className: `flex-shrink-0 text-slate-400 transition-transform ${isDatasetDropdownOpen ? "rotate-180" : ""}` })
7276
+ ), isDatasetDropdownOpen && /* @__PURE__ */ React13.createElement("ul", { className: "custom-scrollbar absolute top-[66px] left-0 z-20 w-full max-h-48 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-xl py-1" }, availableDatasets.map((ds) => /* @__PURE__ */ React13.createElement(
7277
+ "li",
7278
+ {
7279
+ key: ds.id,
7280
+ onClick: () => {
7281
+ setTargetDatasetId(ds.id);
7282
+ setIsDatasetDropdownOpen(false);
7283
+ },
7284
+ className: `px-3 py-2 text-sm cursor-pointer transition-colors ${targetDatasetId === ds.id ? "bg-indigo-600/40 text-indigo-200 font-medium" : "text-slate-300 hover:bg-white/5"}`
7285
+ },
7286
+ ds.name
7287
+ )))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React13.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React13.createElement(
6971
7288
  DescriptionDisplay,
6972
7289
  {
6973
7290
  description,
@@ -6975,7 +7292,8 @@ function InSceneCreationForm({
6975
7292
  availableNodes,
6976
7293
  availableAncestries,
6977
7294
  onMentionClick,
6978
- onImageClick: handleImageClickFromText
7295
+ onImageClick: handleImageClickFromText,
7296
+ onSaveDescription: (newDesc) => setDescription(newDesc)
6979
7297
  }
6980
7298
  ), /* @__PURE__ */ React13.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React13.createElement(
6981
7299
  "button",
@@ -7066,7 +7384,7 @@ function InSceneCreationForm({
7066
7384
  }
7067
7385
 
7068
7386
  // src/components/InSceneVersionForm.jsx
7069
- import React14, { useState as useState14, useEffect as useEffect14, useRef as useRef11 } from "react";
7387
+ import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
7070
7388
  import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
7071
7389
  function InSceneVersionForm({
7072
7390
  onSave,
@@ -7084,14 +7402,14 @@ function InSceneVersionForm({
7084
7402
  onMentionClick,
7085
7403
  onUploadFile
7086
7404
  }) {
7087
- const [name, setName] = useState14("");
7088
- const [size, setSize] = useState14("medium");
7089
- const [description, setDescription] = useState14("");
7090
- const [customProps, setCustomProps] = useState14([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
7091
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
7405
+ const [name, setName] = useState15("");
7406
+ const [size, setSize] = useState15("medium");
7407
+ const [description, setDescription] = useState15("");
7408
+ const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
7409
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
7092
7410
  const propsEndRef = useRef11(null);
7093
- const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
7094
- const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
7411
+ const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
7412
+ const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
7095
7413
  const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
7096
7414
  useEffect14(() => {
7097
7415
  if (!hasImages && useImageAsTexture) {
@@ -7212,7 +7530,8 @@ function InSceneVersionForm({
7212
7530
  availableNodes,
7213
7531
  availableAncestries,
7214
7532
  onMentionClick,
7215
- onImageClick: handleImageClickFromText
7533
+ onImageClick: handleImageClickFromText,
7534
+ onSaveDescription: (newDesc) => setDescription(newDesc)
7216
7535
  }
7217
7536
  ), /* @__PURE__ */ React14.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React14.createElement(
7218
7537
  "button",
@@ -7284,8 +7603,8 @@ function InSceneVersionForm({
7284
7603
  }
7285
7604
 
7286
7605
  // src/components/NodeDetailsPanel.jsx
7287
- import React15, { useState as useState15, useEffect as useEffect15, useRef as useRef12 } from "react";
7288
- 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 } from "react-icons/fi";
7606
+ import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
7607
+ 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";
7289
7608
  function NodeDetailsPanel({
7290
7609
  node,
7291
7610
  onClose,
@@ -7303,29 +7622,39 @@ function NodeDetailsPanel({
7303
7622
  onMentionClick,
7304
7623
  onIntensityChange,
7305
7624
  onUploadFile,
7306
- userRole
7625
+ userRole,
7626
+ currentDatasetName
7307
7627
  }) {
7308
- const [name, setName] = useState15((node == null ? void 0 : node.name) ?? "");
7309
- const [types, setTypes] = useState15([]);
7310
- const [typeInput, setTypeInput] = useState15("");
7311
- const [color, setColor] = useState15((node == null ? void 0 : node.color) ?? "#8b5cf6");
7312
- const [size, setSize] = useState15((node == null ? void 0 : node.size) ?? "medium");
7313
- const [description, setDescription] = useState15((node == null ? void 0 : node.description) ?? "");
7314
- const [intensity, setIntensity] = useState15((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
7315
- const [customProps, setCustomProps] = useState15(() => extractCustomPropsFromNode(node || {}));
7316
- const [showTypeSuggestions, setShowTypeSuggestions] = useState15(false);
7317
- const [filteredTypes, setFilteredTypes] = useState15([]);
7318
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
7319
- const [isReadMode, setIsReadMode] = useState15(false);
7320
- const [existingSections, setExistingSections] = useState15((node == null ? void 0 : node.description_sections) || []);
7321
- const [isSaving, setIsSaving] = useState15(false);
7322
- const [isLinkCopied, setIsLinkCopied] = useState15(false);
7323
- const [useImageAsTexture, setUseImageAsTexture] = useState15(() => {
7628
+ const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
7629
+ const [types, setTypes] = useState16([]);
7630
+ const [typeInput, setTypeInput] = useState16("");
7631
+ const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
7632
+ const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
7633
+ const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
7634
+ const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
7635
+ const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
7636
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
7637
+ const [filteredTypes, setFilteredTypes] = useState16([]);
7638
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
7639
+ const [isReadMode, setIsReadMode] = useState16(false);
7640
+ const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
7641
+ const [isSaving, setIsSaving] = useState16(false);
7642
+ const [isLinkCopied, setIsLinkCopied] = useState16(false);
7643
+ const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
7324
7644
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
7325
7645
  if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
7326
7646
  return !!(node == null ? void 0 : node.useImageAsTexture);
7327
7647
  });
7328
- const [selectedImageUrl, setSelectedImageUrl] = useState15((node == null ? void 0 : node.textureImageUrl) ?? null);
7648
+ const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
7649
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
7650
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
7651
+ initialWidth: isReadMode ? 700 : 440,
7652
+ minWidth: 320,
7653
+ maxWidth: maxPanelW
7654
+ });
7655
+ useEffect15(() => {
7656
+ setWidth(isReadMode ? 700 : 440);
7657
+ }, [isReadMode, setWidth]);
7329
7658
  const prevNodeIdRef = useRef12(null);
7330
7659
  const propsEndRef = useRef12(null);
7331
7660
  const canEdit = userRole !== "viewer";
@@ -7478,6 +7807,11 @@ function NodeDetailsPanel({
7478
7807
  textureImageUrl: url
7479
7808
  });
7480
7809
  };
7810
+ const handleSaveDescriptionInline = (newDescription) => {
7811
+ setDescription(newDescription);
7812
+ onDataUpdate({ ...node, description: newDescription });
7813
+ triggerAutoSave({ description: newDescription });
7814
+ };
7481
7815
  const handleSave = async (keepOpen = false, overrides = {}) => {
7482
7816
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7483
7817
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7533,10 +7867,8 @@ function NodeDetailsPanel({
7533
7867
  return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
7534
7868
  "div",
7535
7869
  {
7536
- 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 transition-all duration-300 ease-out
7537
- ${isReadMode ? "w-[min(92vw,700px)]" : "w-[min(92vw,440px)]"}
7538
- `,
7539
- style: { top: 16, right: 16, zIndex: 1100 },
7870
+ 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"}`,
7871
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
7540
7872
  onPointerDown: swallow,
7541
7873
  onPointerMove: swallow,
7542
7874
  onPointerUp: swallow,
@@ -7545,6 +7877,17 @@ function NodeDetailsPanel({
7545
7877
  onContextMenu: swallow,
7546
7878
  onDoubleClick: swallow
7547
7879
  },
7880
+ /* @__PURE__ */ React15.createElement(
7881
+ "div",
7882
+ {
7883
+ onPointerDown: (e) => {
7884
+ e.stopPropagation();
7885
+ handleResize(e);
7886
+ },
7887
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
7888
+ title: "Arraste para redimensionar"
7889
+ }
7890
+ ),
7548
7891
  isReadMode ? /* @__PURE__ */ React15.createElement(
7549
7892
  DescriptionReadModePanel,
7550
7893
  {
@@ -7563,7 +7906,8 @@ function NodeDetailsPanel({
7563
7906
  availableAncestries,
7564
7907
  onOpenReference,
7565
7908
  onMentionClick,
7566
- onImageClick: handleImageClickFromText
7909
+ onImageClick: handleImageClickFromText,
7910
+ onSaveDescription: handleSaveDescriptionInline
7567
7911
  }
7568
7912
  ) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React15.createElement(
7569
7913
  "button",
@@ -7631,7 +7975,8 @@ function NodeDetailsPanel({
7631
7975
  availableAncestries,
7632
7976
  onOpenReference,
7633
7977
  onMentionClick,
7634
- onImageClick: handleImageClickFromText
7978
+ onImageClick: handleImageClickFromText,
7979
+ onSaveDescription: handleSaveDescriptionInline
7635
7980
  }
7636
7981
  ), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement(
7637
7982
  "button",
@@ -7714,7 +8059,7 @@ function NodeDetailsPanel({
7714
8059
  onUploadFile: canEdit ? onUploadFile : void 0,
7715
8060
  readOnly: !canEdit
7716
8061
  }
7717
- )), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm disabled:opacity-50" }, canEdit ? "Cancelar" : "Fechar"), canEdit && /* @__PURE__ */ React15.createElement(
8062
+ )), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React15.createElement("div", { className: "pt-3 mt-4 border-t border-white/10 flex items-center justify-end gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React15.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm disabled:opacity-50" }, canEdit ? "Cancelar" : "Fechar"), canEdit && /* @__PURE__ */ React15.createElement(
7718
8063
  "button",
7719
8064
  {
7720
8065
  onClick: () => handleSave(false),
@@ -7746,7 +8091,7 @@ function NodeDetailsPanel({
7746
8091
  }
7747
8092
 
7748
8093
  // src/components/MultiNodeContextMenu.jsx
7749
- import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState16, useEffect as useEffect16 } from "react";
8094
+ import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
7750
8095
  function MultiNodeContextMenu({
7751
8096
  data,
7752
8097
  userRole,
@@ -7757,7 +8102,7 @@ function MultiNodeContextMenu({
7757
8102
  onDeleteNodes
7758
8103
  }) {
7759
8104
  const menuRef = useRef13(null);
7760
- const [menuPos, setMenuPos] = useState16({ left: 0, top: 0 });
8105
+ const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
7761
8106
  const ability = defineAbilityFor(userRole);
7762
8107
  const canDelete = ability.can("delete", "Node");
7763
8108
  useLayoutEffect3(() => {
@@ -7806,7 +8151,7 @@ function MultiNodeContextMenu({
7806
8151
  }
7807
8152
 
7808
8153
  // src/components/RelationshipDetailsPanel.jsx
7809
- import React17, { useState as useState17, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
8154
+ import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
7810
8155
  import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
7811
8156
  function RelationshipDetailsPanel({
7812
8157
  link,
@@ -7820,15 +8165,14 @@ function RelationshipDetailsPanel({
7820
8165
  onMentionClick,
7821
8166
  onUploadFile,
7822
8167
  userRole
7823
- // Recebendo userRole via props
7824
8168
  }) {
7825
- const [name, setName] = useState17((link == null ? void 0 : link.name) ?? "");
7826
- const [description, setDescription] = useState17((link == null ? void 0 : link.description) ?? "");
7827
- const [customProps, setCustomProps] = useState17(() => extractCustomPropsFromNode(link || {}));
7828
- const [existingSections, setExistingSections] = useState17((link == null ? void 0 : link.description_sections) || []);
7829
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
7830
- const [isSaving, setIsSaving] = useState17(false);
7831
- const [isReadMode, setIsReadMode] = useState17(false);
8169
+ const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
8170
+ const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
8171
+ const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
8172
+ const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
8173
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
8174
+ const [isSaving, setIsSaving] = useState18(false);
8175
+ const [isReadMode, setIsReadMode] = useState18(false);
7832
8176
  const propsEndRef = useRef14(null);
7833
8177
  const canEdit = useMemo9(() => {
7834
8178
  const ability = defineAbilityFor(userRole);
@@ -7883,6 +8227,12 @@ function RelationshipDetailsPanel({
7883
8227
  const triggerAutoSave = (overrides = {}) => {
7884
8228
  if (canEdit) handleSave(true, overrides);
7885
8229
  };
8230
+ const handleSaveDescriptionInline = (newDescription) => {
8231
+ if (!canEdit) return;
8232
+ setDescription(newDescription);
8233
+ onDataUpdate((prev) => ({ ...prev, description: newDescription }));
8234
+ triggerAutoSave({ description: newDescription });
8235
+ };
7886
8236
  const handleRemoveProp = (i) => {
7887
8237
  const newProps = customProps.filter((_, idx) => idx !== i);
7888
8238
  setCustomProps(newProps);
@@ -7936,7 +8286,8 @@ function RelationshipDetailsPanel({
7936
8286
  availableAncestries,
7937
8287
  onOpenReference,
7938
8288
  onMentionClick,
7939
- onImageClick: handleImageClickFromText
8289
+ onImageClick: handleImageClickFromText,
8290
+ onSaveDescription: handleSaveDescriptionInline
7940
8291
  }
7941
8292
  ) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-teal-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("button", { onClick: onClose, disabled: isSaving, 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 disabled:opacity-50", title: "Fechar" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React17.createElement(
7942
8293
  "input",
@@ -7959,7 +8310,8 @@ function RelationshipDetailsPanel({
7959
8310
  availableAncestries,
7960
8311
  onOpenReference,
7961
8312
  onMentionClick,
7962
- onImageClick: handleImageClickFromText
8313
+ onImageClick: handleImageClickFromText,
8314
+ onSaveDescription: handleSaveDescriptionInline
7963
8315
  }
7964
8316
  ), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React17.createElement(
7965
8317
  "button",
@@ -8031,7 +8383,7 @@ function RelationshipDetailsPanel({
8031
8383
  }
8032
8384
 
8033
8385
  // src/components/RelationshipContextMenu.jsx
8034
- import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState18, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8386
+ import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8035
8387
  function RelationshipContextMenu({
8036
8388
  data,
8037
8389
  userRole,
@@ -8043,7 +8395,7 @@ function RelationshipContextMenu({
8043
8395
  onClose
8044
8396
  }) {
8045
8397
  const menuRef = useRef15(null);
8046
- const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
8398
+ const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
8047
8399
  const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
8048
8400
  const sourceName = useMemo10(
8049
8401
  () => {
@@ -8245,7 +8597,7 @@ function LoadingScreen() {
8245
8597
  }
8246
8598
 
8247
8599
  // src/components/ImportParentFileModal.jsx
8248
- import React20, { useEffect as useEffect19, useState as useState19 } from "react";
8600
+ import React20, { useEffect as useEffect19, useState as useState20 } from "react";
8249
8601
  function ImportParentFileModal({
8250
8602
  isOpen,
8251
8603
  onClose,
@@ -8256,11 +8608,11 @@ function ImportParentFileModal({
8256
8608
  onFetchAvailableFiles,
8257
8609
  currentViewName
8258
8610
  }) {
8259
- const [activeTab, setActiveTab] = useState19("databases");
8260
- const [availableDbs, setAvailableDbs] = useState19([]);
8261
- const [availableViews, setAvailableViews] = useState19([]);
8262
- const [selectedItem, setSelectedItem] = useState19(null);
8263
- const [isLoading, setIsLoading] = useState19(false);
8611
+ const [activeTab, setActiveTab] = useState20("databases");
8612
+ const [availableDbs, setAvailableDbs] = useState20([]);
8613
+ const [availableViews, setAvailableViews] = useState20([]);
8614
+ const [selectedItem, setSelectedItem] = useState20(null);
8615
+ const [isLoading, setIsLoading] = useState20(false);
8264
8616
  useEffect19(() => {
8265
8617
  if (isOpen && session && onFetchAvailableFiles) {
8266
8618
  const fetchData = async () => {
@@ -8406,7 +8758,7 @@ function ImportParentFileModal({
8406
8758
  }
8407
8759
 
8408
8760
  // src/components/AncestryLinkDetailsPanel.jsx
8409
- import React21, { useState as useState20 } from "react";
8761
+ import React21, { useState as useState21 } from "react";
8410
8762
  import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
8411
8763
  function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
8412
8764
  var _a, _b, _c, _d;
@@ -8416,7 +8768,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8416
8768
  const customProps = extractCustomPropsFromNode(relationshipData);
8417
8769
  const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
8418
8770
  const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
8419
- const [isReadMode, setIsReadMode] = useState20(false);
8771
+ const [isReadMode, setIsReadMode] = useState21(false);
8420
8772
  const swallow = (e) => e.stopPropagation();
8421
8773
  const handleImageClickFromText = (url, name) => {
8422
8774
  if (onOpenImageViewer) {
@@ -8482,7 +8834,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8482
8834
  }
8483
8835
 
8484
8836
  // src/components/AncestryBoard.jsx
8485
- import React22, { useState as useState21, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8837
+ import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8486
8838
  import {
8487
8839
  FiSearch as FiSearch4,
8488
8840
  FiLayers as FiLayers6,
@@ -8659,11 +9011,11 @@ function AncestryBoard({
8659
9011
  userRole
8660
9012
  // [NOVO] Recebe a role do usuário
8661
9013
  }) {
8662
- const [searchTerm, setSearchTerm] = useState21("");
8663
- const [groups, setGroups] = useState21([]);
8664
- const [isLoaded, setIsLoaded] = useState21(false);
8665
- const [pickingGroupId, setPickingGroupId] = useState21(null);
8666
- const [saveStatus, setSaveStatus] = useState21("idle");
9014
+ const [searchTerm, setSearchTerm] = useState22("");
9015
+ const [groups, setGroups] = useState22([]);
9016
+ const [isLoaded, setIsLoaded] = useState22(false);
9017
+ const [pickingGroupId, setPickingGroupId] = useState22(null);
9018
+ const [saveStatus, setSaveStatus] = useState22("idle");
8667
9019
  const canEdit = useMemo11(() => {
8668
9020
  return userRole !== "viewer";
8669
9021
  }, [userRole]);
@@ -9048,7 +9400,7 @@ function XViewScene({
9048
9400
  delete_file_action,
9049
9401
  check_user_permission
9050
9402
  }) {
9051
- var _a, _b, _c, _d, _e, _f;
9403
+ var _a, _b, _c, _d, _e, _f, _g;
9052
9404
  const { data: session, status } = useSession();
9053
9405
  const router = useRouter();
9054
9406
  const searchParams = useSearchParams();
@@ -9113,37 +9465,37 @@ function XViewScene({
9113
9465
  const sceneDataRef = useRef17(null);
9114
9466
  const parentDataRef = useRef17(null);
9115
9467
  const ancestryDataRef = useRef17(null);
9116
- const [isLoading, setIsLoading] = useState22(true);
9117
- const [permissionStatus, setPermissionStatus] = useState22("loading");
9118
- const [userPermissionRole, setUserPermissionRole] = useState22(null);
9119
- const [isInitialized, setIsInitialized] = useState22(false);
9120
- const [sceneVersion, setSceneVersion] = useState22(0);
9121
- const [contextMenu, setContextMenu] = useState22({ visible: false, x: 0, y: 0, nodeData: null });
9122
- const [multiContextMenu, setMultiContextMenu] = useState22({ visible: false, x: 0, y: 0, nodeIds: null });
9123
- const [relationshipMenu, setRelationshipMenu] = useState22({ visible: false, x: 0, y: 0, linkObject: null });
9124
- const [creationMode, setCreationMode] = useState22({ isActive: false, sourceNodeData: null });
9125
- const [versionMode, setVersionMode] = useState22({ isActive: false, sourceNodeData: null });
9126
- const [hasFocusedInitial, setHasFocusedInitial] = useState22(false);
9127
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState22(false);
9128
- const [ancestryMode, setAncestryMode] = useState22({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9129
- const [readingMode, setReadingMode] = useState22({
9468
+ const [isLoading, setIsLoading] = useState23(true);
9469
+ const [permissionStatus, setPermissionStatus] = useState23("loading");
9470
+ const [userPermissionRole, setUserPermissionRole] = useState23(null);
9471
+ const [isInitialized, setIsInitialized] = useState23(false);
9472
+ const [sceneVersion, setSceneVersion] = useState23(0);
9473
+ const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
9474
+ const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
9475
+ const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
9476
+ const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
9477
+ const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
9478
+ const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
9479
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
9480
+ const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9481
+ const [readingMode, setReadingMode] = useState23({
9130
9482
  isActive: false,
9131
9483
  ancestry: null,
9132
9484
  branchStack: [],
9133
9485
  autoAbstraction: false
9134
9486
  });
9135
- const [formPosition, setFormPosition] = useState22({ left: 16, top: 16, opacity: 0 });
9136
- const [detailsNode, setDetailsNode] = useState22(null);
9137
- const [detailsLink, setDetailsLink] = useState22(null);
9138
- const [ancestryLinkDetails, setAncestryLinkDetails] = useState22(null);
9139
- const [imageViewer, setImageViewer] = useState22({ visible: false, images: [], startIndex: 0 });
9140
- const [editingAncestryRel, setEditingAncestryRel] = useState22({ visible: false, data: null, path: null });
9141
- const [isImportModalOpen, setIsImportModalOpen] = useState22(false);
9142
- const [importSuccessMessage, setImportSuccessMessage] = useState22("");
9143
- const [highlightedNodeId, setHighlightedNodeId] = useState22(null);
9144
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState22(false);
9145
- const [ancestryBoardData, setAncestryBoardData] = useState22([]);
9146
- const [isSidebarOpen, setIsSidebarOpen] = useState22(false);
9487
+ const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
9488
+ const [detailsNode, setDetailsNode] = useState23(null);
9489
+ const [detailsLink, setDetailsLink] = useState23(null);
9490
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
9491
+ const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
9492
+ const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
9493
+ const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
9494
+ const [importSuccessMessage, setImportSuccessMessage] = useState23("");
9495
+ const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
9496
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
9497
+ const [ancestryBoardData, setAncestryBoardData] = useState23([]);
9498
+ const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
9147
9499
  const mountRef = useRef17(null);
9148
9500
  const tooltipRef = useRef17(null);
9149
9501
  const formRef = useRef17(null);
@@ -9186,6 +9538,12 @@ function XViewScene({
9186
9538
  lastDescriptionLength: 0,
9187
9539
  highlightedNodeId: null
9188
9540
  });
9541
+ const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
9542
+ const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
9543
+ initialWidth: 700,
9544
+ minWidth: 320,
9545
+ maxWidth: maxReadPanelW
9546
+ });
9189
9547
  useEffect21(() => {
9190
9548
  stateRef.current.ancestry = ancestryMode;
9191
9549
  }, [ancestryMode]);
@@ -9200,19 +9558,20 @@ function XViewScene({
9200
9558
  const parentFile = allParentData[parentFileId];
9201
9559
  const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
9202
9560
  const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
9561
+ const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
9203
9562
  if (parentFile.nodes && ownerId2) {
9204
9563
  for (const node of parentFile.nodes) {
9205
- map.set(String(node.id), { parentFileId, ownerId: ownerId2 });
9564
+ map.set(String(node.id), { parentFileId, ownerId: ownerId2, datasetName });
9206
9565
  }
9207
9566
  }
9208
9567
  }
9209
9568
  }
9210
9569
  stateRef.current.nodeIdToParentFileMap = map;
9211
9570
  }, [isInitialized, sceneVersion]);
9212
- const handleNavigateBack = useCallback3(() => {
9571
+ const handleNavigateBack = useCallback4(() => {
9213
9572
  router.push("/dashboard/scenes");
9214
9573
  }, [router]);
9215
- const handleConfirmImport = useCallback3(
9574
+ const handleConfirmImport = useCallback4(
9216
9575
  async (importPayload) => {
9217
9576
  var _a2, _b2;
9218
9577
  let files = [];
@@ -9260,7 +9619,6 @@ function XViewScene({
9260
9619
  if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
9261
9620
  const viewSpecificAncestries = ancestryResponse.data.filter(
9262
9621
  (anc) => anc._source_file_id === viewToImport.id && !anc.is_private
9263
- // <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
9264
9622
  );
9265
9623
  const processedAncestries = viewSpecificAncestries.map((anc) => ({
9266
9624
  ...anc,
@@ -9311,7 +9669,7 @@ function XViewScene({
9311
9669
  const handleOpenImageViewer = (images, startIndex) => {
9312
9670
  setImageViewer({ visible: true, images, startIndex });
9313
9671
  };
9314
- const tweenToTarget = useCallback3((target, zoomFactor = 1, forcedDirection = null) => {
9672
+ const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
9315
9673
  const { camera, controls, tweenGroup } = stateRef.current;
9316
9674
  if (!camera || !controls || !tweenGroup) return;
9317
9675
  const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
@@ -9334,7 +9692,7 @@ function XViewScene({
9334
9692
  if (!t || typeof t.closest !== "function") return false;
9335
9693
  return !!t.closest(".ui-overlay");
9336
9694
  };
9337
- const buildFullAncestryTree = useCallback3((idTree, nodes, ancestries = []) => {
9695
+ const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
9338
9696
  if (!idTree) return null;
9339
9697
  const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
9340
9698
  const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
@@ -9360,14 +9718,10 @@ function XViewScene({
9360
9718
  return {
9361
9719
  ...branch,
9362
9720
  name: linkedAncestry.name,
9363
- // Sobrescreve nome para exibição
9364
9721
  description: linkedAncestry.description,
9365
- // Sobrescreve descrição
9366
9722
  description_sections: linkedAncestry.description_sections,
9367
9723
  tree: graftedTree,
9368
- // ENXERTA A ÁRVORE AQUI
9369
9724
  isLinked: true
9370
- // Flag útil
9371
9725
  };
9372
9726
  }
9373
9727
  }
@@ -9414,7 +9768,7 @@ function XViewScene({
9414
9768
  }
9415
9769
  return recursiveBuild(idTree);
9416
9770
  }, []);
9417
- const handleActivateTimeline = useCallback3(() => {
9771
+ const handleActivateTimeline = useCallback4(() => {
9418
9772
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
9419
9773
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
9420
9774
  while (timelineIntervalsGroup.children.length > 0) {
@@ -9567,7 +9921,7 @@ function XViewScene({
9567
9921
  }
9568
9922
  });
9569
9923
  }, []);
9570
- const handleVersionTimeline = useCallback3((sourceMesh, versionMeshes) => {
9924
+ const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
9571
9925
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
9572
9926
  if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
9573
9927
  versionMeshes.forEach((mesh) => {
@@ -9722,6 +10076,9 @@ function XViewScene({
9722
10076
  sceneDataRef.current = sceneResponse.data.scene;
9723
10077
  parentDataRef.current = sceneResponse.data.parent;
9724
10078
  ancestryDataRef.current = sceneResponse.data.ancestry;
10079
+ console.log("Console de sceneResponse.data.scene:", sceneResponse.data.scene);
10080
+ console.log("Console de sceneResponse.data.parent:", sceneResponse.data.parent);
10081
+ console.log("Console de sceneResponse.data.ancestry:", sceneResponse.data.ancestry);
9725
10082
  setIsInitialized(true);
9726
10083
  } else {
9727
10084
  console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
@@ -9757,16 +10114,14 @@ function XViewScene({
9757
10114
  isInitialized,
9758
10115
  permissionStatus,
9759
10116
  focusNodeId,
9760
- // <-- MANTIDO
9761
10117
  focusAncestryId
9762
- // <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
9763
10118
  ]);
9764
- const isNodeInView = useCallback3((id) => {
10119
+ const isNodeInView = useCallback4((id) => {
9765
10120
  const key = String(id);
9766
10121
  const objs = stateRef.current.nodeObjects || {};
9767
10122
  return !!objs[key];
9768
10123
  }, []);
9769
- const addOrUpdateNodeMesh = useCallback3((nodeData, position, suppressVersionUpdate = false) => {
10124
+ const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
9770
10125
  const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
9771
10126
  const nodeId = String(nodeData.id);
9772
10127
  if (nodeObjects[nodeId]) {
@@ -10415,7 +10770,7 @@ function XViewScene({
10415
10770
  }
10416
10771
  };
10417
10772
  }, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
10418
- const handleGhostNodeImageChange = useCallback3((useImage, imageUrl) => {
10773
+ const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
10419
10774
  const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
10420
10775
  const { graphGroup, glowTexture } = stateRef.current;
10421
10776
  if (!ghostNode || !graphGroup) return;
@@ -10457,7 +10812,7 @@ function XViewScene({
10457
10812
  aura: newGhostNode.getObjectByName("aura")
10458
10813
  };
10459
10814
  }, []);
10460
- const handleGhostNodeIntensityChange = useCallback3((newIntensity) => {
10815
+ const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
10461
10816
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
10462
10817
  if (!ghostNode) return;
10463
10818
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10478,7 +10833,7 @@ function XViewScene({
10478
10833
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
10479
10834
  }
10480
10835
  }, []);
10481
- const handleDetailNodeIntensityChange = useCallback3((nodeId, newIntensity) => {
10836
+ const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
10482
10837
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
10483
10838
  if (!mesh) return;
10484
10839
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10503,32 +10858,33 @@ function XViewScene({
10503
10858
  const handleGhostNodeColorChange = (newColor) => {
10504
10859
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
10505
10860
  if (!ghostNode) return;
10506
- const { emissiveIntensity } = computeNodeMaterialProps(newColor);
10507
- const pureColor = new THREE3.Color(newColor);
10861
+ const { color, emissive } = computeNodeMaterialProps(newColor);
10862
+ const currentIntensity = ghostNode.userData.intensity !== void 0 ? Number(ghostNode.userData.intensity) : 0;
10863
+ const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
10508
10864
  const isImageNode = ghostNode.userData.useImageAsTexture === true || String(ghostNode.userData.useImageAsTexture) === "true";
10509
10865
  if (isImageNode) {
10510
10866
  const borderMesh = ghostNode.getObjectByName("borderRing");
10511
10867
  if (borderMesh && borderMesh.material) {
10512
- borderMesh.material.color.copy(pureColor);
10868
+ borderMesh.material.color.copy(color);
10513
10869
  if (borderMesh.material.emissive) {
10514
- borderMesh.material.emissive.copy(pureColor);
10515
- borderMesh.material.emissiveIntensity = emissiveIntensity;
10870
+ borderMesh.material.emissive.copy(emissive);
10871
+ borderMesh.material.emissiveIntensity = finalIntensity;
10516
10872
  }
10517
10873
  }
10518
10874
  } else {
10519
10875
  if (ghostNode.material) {
10520
- ghostNode.material.color.copy(pureColor);
10876
+ ghostNode.material.color.copy(color);
10521
10877
  if (ghostNode.material.emissive) {
10522
- ghostNode.material.emissive.copy(pureColor);
10523
- ghostNode.material.emissiveIntensity = emissiveIntensity;
10878
+ ghostNode.material.emissive.copy(emissive);
10879
+ ghostNode.material.emissiveIntensity = finalIntensity;
10524
10880
  }
10525
10881
  }
10526
10882
  }
10527
10883
  if (ghostAura && ghostAura.material) {
10528
- ghostAura.material.color.set(newColor);
10884
+ ghostAura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
10529
10885
  }
10530
10886
  ghostNode.userData.color = newColor;
10531
- ghostNode.userData._baseEmissiveIntensity = emissiveIntensity;
10887
+ ghostNode.userData._baseEmissiveIntensity = finalIntensity;
10532
10888
  };
10533
10889
  const handleGhostNodeSizeChange = (sizeKey) => {
10534
10890
  const { node: ghostNode } = stateRef.current.ghostElements;
@@ -10569,7 +10925,9 @@ function XViewScene({
10569
10925
  var _a2;
10570
10926
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
10571
10927
  if (!mesh) return;
10572
- const { color, emissive, emissiveIntensity } = computeNodeMaterialProps(newColor);
10928
+ const { color, emissive } = computeNodeMaterialProps(newColor);
10929
+ const currentIntensity = mesh.userData.intensity !== void 0 ? Number(mesh.userData.intensity) : 0;
10930
+ const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
10573
10931
  const isImageNode = mesh.userData.useImageAsTexture === true || String(mesh.userData.useImageAsTexture) === "true";
10574
10932
  if (isImageNode) {
10575
10933
  const borderMesh = mesh.getObjectByName("borderRing");
@@ -10577,20 +10935,22 @@ function XViewScene({
10577
10935
  borderMesh.material.color.copy(color);
10578
10936
  if (borderMesh.material.emissive) {
10579
10937
  borderMesh.material.emissive.copy(emissive);
10580
- borderMesh.material.emissiveIntensity = emissiveIntensity;
10938
+ borderMesh.material.emissiveIntensity = finalIntensity;
10581
10939
  }
10582
10940
  }
10583
10941
  } else {
10584
10942
  if (mesh.material) {
10585
10943
  mesh.material.color.copy(color);
10586
10944
  mesh.material.emissive.copy(emissive);
10587
- mesh.material.emissiveIntensity = emissiveIntensity;
10945
+ mesh.material.emissiveIntensity = finalIntensity;
10588
10946
  }
10589
10947
  }
10590
10948
  const aura = mesh.getObjectByName("aura");
10591
- if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) aura.material.color.set(newColor);
10949
+ if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) {
10950
+ aura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
10951
+ }
10592
10952
  mesh.userData.color = newColor;
10593
- mesh.userData._baseEmissiveIntensity = emissiveIntensity;
10953
+ mesh.userData._baseEmissiveIntensity = finalIntensity;
10594
10954
  };
10595
10955
  const handleDetailNodeSizeChange = (nodeId, newSize) => {
10596
10956
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
@@ -10619,7 +10979,7 @@ function XViewScene({
10619
10979
  mountRef.current.style.cursor = "default";
10620
10980
  }
10621
10981
  };
10622
- const handleAncestryTreeUpdate = useCallback3((newTree, extraData = null) => {
10982
+ const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
10623
10983
  setAncestryMode((prev) => {
10624
10984
  const prevTreeStr = JSON.stringify(prev.tree);
10625
10985
  const newTreeStr = JSON.stringify(newTree);
@@ -10689,7 +11049,7 @@ function XViewScene({
10689
11049
  const handleStartVersioning = (nodeData) => {
10690
11050
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
10691
11051
  };
10692
- const handleClearAncestryVisuals = useCallback3((ancestryId) => {
11052
+ const handleClearAncestryVisuals = useCallback4((ancestryId) => {
10693
11053
  const { renderedAncestries, ancestryGroup } = stateRef.current;
10694
11054
  const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
10695
11055
  if (renderIndex !== -1) {
@@ -10703,7 +11063,7 @@ function XViewScene({
10703
11063
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
10704
11064
  }
10705
11065
  }, []);
10706
- const handleRenderAncestry = useCallback3(
11066
+ const handleRenderAncestry = useCallback4(
10707
11067
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
10708
11068
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10709
11069
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11119,7 +11479,7 @@ function XViewScene({
11119
11479
  },
11120
11480
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
11121
11481
  );
11122
- const handleRenderAbstractionTree = useCallback3((ancestryObject, targetNodeId = null) => {
11482
+ const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
11123
11483
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11124
11484
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
11125
11485
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
@@ -11180,7 +11540,7 @@ function XViewScene({
11180
11540
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
11181
11541
  tweenToTarget(rootTargetPos, 0.7);
11182
11542
  }, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
11183
- const handleReadModeBranchNav = useCallback3((nodeId, action, direction = "right") => {
11543
+ const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
11184
11544
  const { ancestry, branchStack } = readingMode;
11185
11545
  if (!ancestry || !ancestry.tree) return;
11186
11546
  const allAncestries = ancestryDataRef.current || [];
@@ -11218,9 +11578,7 @@ function XViewScene({
11218
11578
  description_sections: branchToOpen.description_sections,
11219
11579
  tree: branchToOpen.tree,
11220
11580
  _originNodeId: nodeId,
11221
- // <--- ID do node pai (link visual)
11222
11581
  _branchDirection: direction
11223
- // <--- Direção para cálculo de posição
11224
11582
  };
11225
11583
  const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
11226
11584
  const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
@@ -11276,7 +11634,6 @@ function XViewScene({
11276
11634
  const parentAncestryObj = {
11277
11635
  ...targetAncestryInfo,
11278
11636
  tree: targetTreeToRender,
11279
- // Re-injeta a origem se o pai também for uma branch aninhada
11280
11637
  _originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
11281
11638
  _branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
11282
11639
  };
@@ -11324,7 +11681,7 @@ function XViewScene({
11324
11681
  }));
11325
11682
  }
11326
11683
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
11327
- const handleReadModeHighlight = useCallback3((nodeId) => {
11684
+ const handleReadModeHighlight = useCallback4((nodeId) => {
11328
11685
  if (stateRef.current.highlightedNodeId !== nodeId) {
11329
11686
  stateRef.current.highlightedNodeId = nodeId;
11330
11687
  }
@@ -11336,7 +11693,6 @@ function XViewScene({
11336
11693
  readingMode.ancestry.tree,
11337
11694
  Object.values(parentDataRef.current).flatMap((f) => f.nodes),
11338
11695
  ancestryDataRef.current
11339
- // <--- Adicionar
11340
11696
  );
11341
11697
  const findNodeInTree = (tree, targetId) => {
11342
11698
  if (!tree) return null;
@@ -11390,7 +11746,6 @@ function XViewScene({
11390
11746
  description_sections: ancestry.description_sections,
11391
11747
  direction: null,
11392
11748
  customProperties: rootProps
11393
- // <--- ADICIONADO
11394
11749
  };
11395
11750
  }
11396
11751
  const fullTree = buildFullAncestryTree(
@@ -11419,7 +11774,6 @@ function XViewScene({
11419
11774
  description_sections: currentMeta.description_sections,
11420
11775
  direction: currentDirection,
11421
11776
  customProperties: branchProps
11422
- // <--- ADICIONADO
11423
11777
  };
11424
11778
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
11425
11779
  const readModeAbstractionTree = useMemo12(() => {
@@ -11434,7 +11788,7 @@ function XViewScene({
11434
11788
  allAncestries
11435
11789
  );
11436
11790
  }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
11437
- const handleStartReadingAncestry = useCallback3(
11791
+ const handleStartReadingAncestry = useCallback4(
11438
11792
  async (ancestryObject) => {
11439
11793
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11440
11794
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11455,7 +11809,6 @@ function XViewScene({
11455
11809
  ancestry: ancestryObject,
11456
11810
  branchStack: [],
11457
11811
  autoAbstraction: shouldAutoRenderAbstraction
11458
- // <--- FLAG ENVIADA PARA A UI
11459
11812
  });
11460
11813
  if (shouldAutoRenderAbstraction) {
11461
11814
  handleRenderAbstractionTree(ancestryObject, null);
@@ -11469,9 +11822,8 @@ function XViewScene({
11469
11822
  }
11470
11823
  },
11471
11824
  [handleRenderAncestry, handleRenderAbstractionTree]
11472
- // <--- DEPENDÊNCIA ADICIONADA
11473
11825
  );
11474
- const handleReadModeSectionChange = useCallback3((activeSectionId) => {
11826
+ const handleReadModeSectionChange = useCallback4((activeSectionId) => {
11475
11827
  const { ancestry, branchStack } = readingMode;
11476
11828
  if (!ancestry || !readingMode.isActive) return;
11477
11829
  let targetObj = ancestry;
@@ -11540,10 +11892,10 @@ function XViewScene({
11540
11892
  }, 0);
11541
11893
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11542
11894
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
11543
- const handleCloseReadMode = useCallback3(() => {
11895
+ const handleCloseReadMode = useCallback4(() => {
11544
11896
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
11545
11897
  }, []);
11546
- const handleAncestrySectionChange = useCallback3((activeSectionId, ancestryOverride = null, rotation = 0) => {
11898
+ const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
11547
11899
  var _a2, _b2;
11548
11900
  const currentMode = stateRef.current.ancestry;
11549
11901
  let targetObj = ancestryOverride;
@@ -11595,7 +11947,7 @@ function XViewScene({
11595
11947
  const renderPayload = { ...targetObj, tree: treeToRender };
11596
11948
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11597
11949
  }, [handleRenderAncestry]);
11598
- const handleEditAncestry = useCallback3(
11950
+ const handleEditAncestry = useCallback4(
11599
11951
  async (ancestryObject) => {
11600
11952
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11601
11953
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11618,10 +11970,8 @@ function XViewScene({
11618
11970
  ...ancestryObject,
11619
11971
  tree: fullTree,
11620
11972
  abstraction_tree: fullAbstractionTree,
11621
- // NOVO
11622
11973
  selectedParentId: ancestryObject.ancestral_node,
11623
11974
  selectedAbstractionParentId: ancestryObject.ancestral_node,
11624
- // NOVO
11625
11975
  isEditMode: true,
11626
11976
  currentAncestryId: ancestryObject.ancestry_id,
11627
11977
  ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
@@ -11629,7 +11979,6 @@ function XViewScene({
11629
11979
  ancestryDescriptionSections: ancestryObject.description_sections || [],
11630
11980
  isAddingNodes: false,
11631
11981
  isAddingAbstractionNodes: false
11632
- // NOVO
11633
11982
  });
11634
11983
  },
11635
11984
  [handleRenderAncestry, buildFullAncestryTree]
@@ -11637,7 +11986,7 @@ function XViewScene({
11637
11986
  const handleSelectAncestryParent = (nodeId) => {
11638
11987
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
11639
11988
  };
11640
- const handleRemoveFromAncestry = useCallback3((pathToRemove) => {
11989
+ const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
11641
11990
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
11642
11991
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
11643
11992
  return;
@@ -11662,7 +12011,7 @@ function XViewScene({
11662
12011
  return { ...prev, tree: newTree };
11663
12012
  });
11664
12013
  }, []);
11665
- const handleSaveAncestry = useCallback3(
12014
+ const handleSaveAncestry = useCallback4(
11666
12015
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
11667
12016
  const treeToUse = treeOverride || ancestryMode.tree;
11668
12017
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -11866,7 +12215,7 @@ function XViewScene({
11866
12215
  });
11867
12216
  setEditingAncestryRel({ visible: false, data: null, path: null });
11868
12217
  };
11869
- const handleDeleteAncestry = useCallback3(
12218
+ const handleDeleteAncestry = useCallback4(
11870
12219
  async (ancestryIdToDelete) => {
11871
12220
  if (!ancestryIdToDelete) {
11872
12221
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -11928,15 +12277,15 @@ function XViewScene({
11928
12277
  },
11929
12278
  [save_view_data, delete_file_action]
11930
12279
  );
11931
- const handleOpenAncestryBoard = useCallback3(() => {
12280
+ const handleOpenAncestryBoard = useCallback4(() => {
11932
12281
  setIsAncestryBoardOpen(true);
11933
12282
  }, []);
11934
- const handleSelectAncestryFromBoard = useCallback3((ancestry) => {
12283
+ const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
11935
12284
  setIsAncestryBoardOpen(false);
11936
12285
  setIsSidebarOpen(false);
11937
12286
  handleStartReadingAncestry(ancestry);
11938
12287
  }, [handleStartReadingAncestry]);
11939
- const handleSaveAncestryBoard = useCallback3(async (groups) => {
12288
+ const handleSaveAncestryBoard = useCallback4(async (groups) => {
11940
12289
  if (!sceneConfigId || !viewParams || !session) return;
11941
12290
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
11942
12291
  await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
@@ -11960,13 +12309,13 @@ function XViewScene({
11960
12309
  return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
11961
12310
  });
11962
12311
  }, [parentDataRef.current, sceneVersion]);
11963
- const handleAddExistingNode = useCallback3(
12312
+ const handleAddExistingNode = useCallback4(
11964
12313
  (nodeId) => {
11965
12314
  return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
11966
12315
  },
11967
12316
  [actionHandlerContext]
11968
12317
  );
11969
- const handleSaveCurrentView = useCallback3(async () => {
12318
+ const handleSaveCurrentView = useCallback4(async () => {
11970
12319
  const { nodeObjects, allLinks } = stateRef.current;
11971
12320
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
11972
12321
  console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
@@ -12006,7 +12355,7 @@ function XViewScene({
12006
12355
  const allAvailableAncestries = useMemo12(() => {
12007
12356
  return ancestryDataRef.current || [];
12008
12357
  }, [sceneVersion, isInitialized]);
12009
- const handleOpenReference = useCallback3((referenceData) => {
12358
+ const handleOpenReference = useCallback4((referenceData) => {
12010
12359
  const { type, id } = referenceData;
12011
12360
  if (type === "node") {
12012
12361
  const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
@@ -12033,16 +12382,28 @@ function XViewScene({
12033
12382
  }
12034
12383
  }
12035
12384
  }, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
12036
- const handleToggleAncestryAddMode = useCallback3(() => {
12385
+ const handleToggleAncestryAddMode = useCallback4(() => {
12037
12386
  setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
12038
12387
  }, []);
12039
- const handleFocusNode = useCallback3((nodeData) => {
12388
+ const handleFocusNode = useCallback4((nodeData) => {
12040
12389
  if (!nodeData) return;
12041
12390
  const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
12042
12391
  if (nodeMesh) {
12043
12392
  tweenToTarget(nodeMesh, 1.2);
12044
12393
  }
12045
12394
  }, [tweenToTarget]);
12395
+ const availableDatasets = useMemo12(() => {
12396
+ if (!sceneDataRef.current || !parentDataRef.current) return [];
12397
+ return sceneDataRef.current.parent_dbs.map((db) => {
12398
+ var _a2;
12399
+ return {
12400
+ id: db.db_id,
12401
+ name: ((_a2 = parentDataRef.current[db.db_id]) == null ? void 0 : _a2.dataset_name) || `Dataset #${db.db_id.substring(0, 6)}`
12402
+ };
12403
+ });
12404
+ }, [sceneVersion, isInitialized]);
12405
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
12406
+ const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
12046
12407
  useEffect21(() => {
12047
12408
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
12048
12409
  const nodeObjects = stateRef.current.nodeObjects || {};
@@ -12094,7 +12455,6 @@ function XViewScene({
12094
12455
  height: "100vh",
12095
12456
  position: "relative",
12096
12457
  overflow: "hidden",
12097
- // <--- ADICIONE ESTA LINHA
12098
12458
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
12099
12459
  }
12100
12460
  },
@@ -12132,10 +12492,13 @@ function XViewScene({
12132
12492
  style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
12133
12493
  refEl: formRef,
12134
12494
  existingTypes: existingNodeTypes,
12135
- initialColor: (_b = creationMode.sourceNodeData) == null ? void 0 : _b.color,
12136
- sourceTypes: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.type,
12495
+ initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
12496
+ sourceTypes: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.type,
12137
12497
  onIntensityChange: handleGhostNodeIntensityChange,
12138
- onUploadFile: upload_file_action
12498
+ onUploadFile: upload_file_action,
12499
+ availableDatasets,
12500
+ sourceNodeDatasetId,
12501
+ viewType: viewParams == null ? void 0 : viewParams.type
12139
12502
  }
12140
12503
  ),
12141
12504
  versionMode.isActive && /* @__PURE__ */ React23.createElement(
@@ -12150,17 +12513,28 @@ function XViewScene({
12150
12513
  onMentionClick: handleAddExistingNode,
12151
12514
  style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
12152
12515
  refEl: formRef,
12153
- fixedType: (_d = versionMode.sourceNodeData) == null ? void 0 : _d.type,
12154
- fixedColor: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.color,
12516
+ fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
12517
+ fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
12155
12518
  onUploadFile: upload_file_action
12156
12519
  }
12157
12520
  ),
12158
12521
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
12159
12522
  "div",
12160
12523
  {
12161
- 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)]",
12162
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
12524
+ 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"}`,
12525
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
12163
12526
  },
12527
+ /* @__PURE__ */ React23.createElement(
12528
+ "div",
12529
+ {
12530
+ onPointerDown: (e) => {
12531
+ e.stopPropagation();
12532
+ handleReadModeResize(e);
12533
+ },
12534
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
12535
+ title: "Arraste para redimensionar"
12536
+ }
12537
+ ),
12164
12538
  /* @__PURE__ */ React23.createElement(
12165
12539
  DescriptionReadModePanel,
12166
12540
  {
@@ -12260,7 +12634,8 @@ function XViewScene({
12260
12634
  onMentionClick: handleAddExistingNode,
12261
12635
  onIntensityChange: handleDetailNodeIntensityChange,
12262
12636
  onUploadFile: upload_file_action,
12263
- userRole: userPermissionRole
12637
+ userRole: userPermissionRole,
12638
+ currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
12264
12639
  }
12265
12640
  ),
12266
12641
  detailsLink && /* @__PURE__ */ React23.createElement(
@@ -12388,7 +12763,7 @@ function XViewScene({
12388
12763
  onClose: () => setIsImportModalOpen(false),
12389
12764
  onConfirm: handleConfirmImport,
12390
12765
  session,
12391
- parentDbs: ((_f = sceneDataRef.current) == null ? void 0 : _f.parent_dbs) || [],
12766
+ parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
12392
12767
  onFetchAvailableFiles: import_parent_file_modal_get,
12393
12768
  currentViewName: viewParams == null ? void 0 : viewParams.name,
12394
12769
  currentAncestries: ancestryDataRef.current || []