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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +1328 -888
  2. package/dist/index.mjs +787 -347
  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) {
@@ -3847,6 +3977,70 @@ function DescriptionEditModal({
3847
3977
  setIsMentionModalOpen(true);
3848
3978
  }
3849
3979
  };
3980
+ const handleKeyDownTextarea = (e) => {
3981
+ const el = textareaRef.current;
3982
+ if (!el) return;
3983
+ if (e.key === "Enter") {
3984
+ const cursorPosition = el.selectionStart;
3985
+ const textBeforeCursor = text.substring(0, cursorPosition);
3986
+ const linesBeforeCursor = textBeforeCursor.split("\n");
3987
+ const currentLine = linesBeforeCursor[linesBeforeCursor.length - 1];
3988
+ const numberMatch = currentLine.match(/^(\s*)(\d+)\.\s(.*)/);
3989
+ if (numberMatch) {
3990
+ e.preventDefault();
3991
+ const space = numberMatch[1];
3992
+ const number = parseInt(numberMatch[2], 10);
3993
+ const content = numberMatch[3];
3994
+ if (content.trim() === "") {
3995
+ const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
3996
+ const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
3997
+ el.value = newText;
3998
+ el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
3999
+ setText(newText);
4000
+ return;
4001
+ }
4002
+ const nextNumber = number + 1;
4003
+ insertAtCursor(`
4004
+ ${space}${nextNumber}. `);
4005
+ return;
4006
+ }
4007
+ const checklistMatch = currentLine.match(/^(\s*)- \[[ xX]\]\s(.*)/);
4008
+ if (checklistMatch) {
4009
+ e.preventDefault();
4010
+ const space = checklistMatch[1];
4011
+ const content = checklistMatch[2];
4012
+ if (content.trim() === "") {
4013
+ const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
4014
+ const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
4015
+ el.value = newText;
4016
+ el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
4017
+ setText(newText);
4018
+ return;
4019
+ }
4020
+ insertAtCursor(`
4021
+ ${space}- [ ] `);
4022
+ return;
4023
+ }
4024
+ const bulletMatch = currentLine.match(/^(\s*)([-*])\s(.*)/);
4025
+ if (bulletMatch) {
4026
+ e.preventDefault();
4027
+ const space = bulletMatch[1];
4028
+ const bullet = bulletMatch[2];
4029
+ const content = bulletMatch[3];
4030
+ if (content.trim() === "") {
4031
+ const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
4032
+ const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
4033
+ el.value = newText;
4034
+ el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
4035
+ setText(newText);
4036
+ return;
4037
+ }
4038
+ insertAtCursor(`
4039
+ ${space}${bullet} `);
4040
+ return;
4041
+ }
4042
+ }
4043
+ };
3850
4044
  const openMentionModalViaButton = () => {
3851
4045
  setMentionTriggerIndex(null);
3852
4046
  setIsMentionModalOpen(true);
@@ -3856,7 +4050,8 @@ function DescriptionEditModal({
3856
4050
  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
4051
  "div",
3858
4052
  {
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",
4053
+ 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"}`,
4054
+ style: { width: `${panelWidth}px`, maxWidth: "90vw" },
3860
4055
  onClick: swallow,
3861
4056
  onPointerDown: swallow,
3862
4057
  onPointerMove: swallow,
@@ -3865,9 +4060,20 @@ function DescriptionEditModal({
3865
4060
  onContextMenu: swallow,
3866
4061
  onDoubleClick: swallow
3867
4062
  },
4063
+ /* @__PURE__ */ React5.createElement(
4064
+ "div",
4065
+ {
4066
+ onPointerDown: (e) => {
4067
+ e.stopPropagation();
4068
+ handleResize(e);
4069
+ },
4070
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
4071
+ title: "Arraste para redimensionar"
4072
+ }
4073
+ ),
3868
4074
  /* @__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
4075
  /* @__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
- /* @__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(
4076
+ /* @__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 flex-wrap" }, /* @__PURE__ */ React5.createElement(
3871
4077
  "button",
3872
4078
  {
3873
4079
  onClick: () => insertAtCursor("# "),
@@ -3894,6 +4100,24 @@ function DescriptionEditModal({
3894
4100
  },
3895
4101
  /* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
3896
4102
  " Lista"
4103
+ ), /* @__PURE__ */ React5.createElement(
4104
+ "button",
4105
+ {
4106
+ onClick: () => insertAtCursor("1. "),
4107
+ 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",
4108
+ title: "Lista Numerada"
4109
+ },
4110
+ /* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
4111
+ " Numerada"
4112
+ ), /* @__PURE__ */ React5.createElement(
4113
+ "button",
4114
+ {
4115
+ onClick: () => insertAtCursor("- [ ] "),
4116
+ 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",
4117
+ title: "Checklist (Checkbox)"
4118
+ },
4119
+ /* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
4120
+ " Checklist"
3897
4121
  ), /* @__PURE__ */ React5.createElement(
3898
4122
  "button",
3899
4123
  {
@@ -3921,7 +4145,7 @@ function DescriptionEditModal({
3921
4145
  },
3922
4146
  /* @__PURE__ */ React5.createElement(FiImage, { size: 12 }),
3923
4147
  " Imagem"
3924
- )), /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 overflow-x-auto custom-scrollbar" }, /* @__PURE__ */ React5.createElement(
4148
+ )), /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ React5.createElement(
3925
4149
  "button",
3926
4150
  {
3927
4151
  onClick: openMentionModalViaButton,
@@ -3954,6 +4178,7 @@ function DescriptionEditModal({
3954
4178
  ref: textareaRef,
3955
4179
  value: text,
3956
4180
  onChange: handleTextChange,
4181
+ onKeyDown: handleKeyDownTextarea,
3957
4182
  placeholder: "Escreva aqui... Use *// para dividir o texto em 'Sess\xF5es'... Digite @ para mencionar...",
3958
4183
  autoFocus: true,
3959
4184
  className: "w-full flex-1 h-full bg-slate-800/70 p-4 text-sm leading-relaxed rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 custom-scrollbar font-mono resize-none"
@@ -4029,7 +4254,7 @@ function DescriptionEditModal({
4029
4254
  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
4255
  },
4031
4256
  "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.")),
4257
+ ))), /* @__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
4258
  /* @__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
4259
  )), tooltipData && /* @__PURE__ */ React5.createElement(
4035
4260
  "div",
@@ -4056,11 +4281,11 @@ function DescriptionEditModal({
4056
4281
  }
4057
4282
 
4058
4283
  // 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";
4284
+ import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
4285
+ 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
4286
  var CodeBlock2 = ({ content, isActive, onClick }) => {
4062
- const [isExpanded, setIsExpanded] = useState6(false);
4063
- const [copied, setCopied] = useState6(false);
4287
+ const [isExpanded, setIsExpanded] = useState7(false);
4288
+ const [copied, setCopied] = useState7(false);
4064
4289
  const cleanContent = content.replace(/^```|```$/g, "").trim();
4065
4290
  const isLongCode = cleanContent.split("\n").length > 4;
4066
4291
  const handleCopy = (e) => {
@@ -4200,7 +4425,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
4200
4425
  );
4201
4426
  });
4202
4427
  };
4203
- var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
4428
+ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
4204
4429
  const trimmedLine = line.replace(/\r$/, "");
4205
4430
  const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
4206
4431
  if (line.startsWith("# ")) {
@@ -4211,9 +4436,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
4211
4436
  const content = line.replace("## ", "");
4212
4437
  return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
4213
4438
  }
4439
+ const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
4440
+ if (checkboxMatch) {
4441
+ const [_, space, state, content] = checkboxMatch;
4442
+ const isChecked = state.toLowerCase() === "x";
4443
+ const currentIdx = globalCheckboxCounterRef.current;
4444
+ globalCheckboxCounterRef.current += 1;
4445
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
4446
+ "div",
4447
+ {
4448
+ onClick: (e) => {
4449
+ e.stopPropagation();
4450
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4451
+ },
4452
+ className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
4453
+ ${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"}
4454
+ `
4455
+ },
4456
+ isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
4457
+ ), /* @__PURE__ */ React6.createElement(
4458
+ "span",
4459
+ {
4460
+ className: `transition-all duration-200 cursor-pointer pt-[1px]
4461
+ ${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
4462
+ `,
4463
+ onClick: (e) => {
4464
+ e.stopPropagation();
4465
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4466
+ }
4467
+ },
4468
+ processContent(content)
4469
+ ));
4470
+ }
4471
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4472
+ if (numberMatch) {
4473
+ const [_, space, numberStr, content] = numberMatch;
4474
+ 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)));
4475
+ }
4214
4476
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4215
4477
  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));
4478
+ 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
4479
  }
4218
4480
  return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
4219
4481
  };
@@ -4225,14 +4487,31 @@ function DescriptionDisplay({
4225
4487
  onOpenReference,
4226
4488
  onMentionClick,
4227
4489
  onImageClick,
4228
- // <--- NOVA PROP RECEBIDA
4229
4490
  onSectionChange,
4230
4491
  onBranchNav,
4231
4492
  onHighlightNode,
4232
4493
  initialSectionId,
4233
- currentBranchDirection = null
4494
+ currentBranchDirection = null,
4495
+ onSaveDescription
4234
4496
  }) {
4235
- const sections = useMemo5(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4497
+ const [localDescription, setLocalDescription] = useState7(description || "");
4498
+ useEffect6(() => {
4499
+ setLocalDescription(description || "");
4500
+ }, [description]);
4501
+ const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4502
+ const globalCheckboxCounterRef = useRef6(0);
4503
+ const handleToggleCheckbox = (targetIndex) => {
4504
+ let currentIndex = 0;
4505
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4506
+ if (currentIndex === targetIndex) {
4507
+ currentIndex++;
4508
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4509
+ }
4510
+ currentIndex++;
4511
+ return match;
4512
+ });
4513
+ setLocalDescription(newDesc);
4514
+ };
4236
4515
  const flatNavigation = useMemo5(() => {
4237
4516
  const navItems = [];
4238
4517
  sections.forEach((section, sIdx) => {
@@ -4259,7 +4538,7 @@ function DescriptionDisplay({
4259
4538
  });
4260
4539
  return navItems;
4261
4540
  }, [sections]);
4262
- const [currentStepIndex, setCurrentStepIndex] = useState6(0);
4541
+ const [currentStepIndex, setCurrentStepIndex] = useState7(0);
4263
4542
  const activeRef = useRef6(null);
4264
4543
  const lastNotifiedSectionId = useRef6(null);
4265
4544
  const isInitialMount = useRef6(true);
@@ -4373,26 +4652,27 @@ function DescriptionDisplay({
4373
4652
  }
4374
4653
  const lines = part.replace(/\n$/, "").split("\n");
4375
4654
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
4376
- const isLastLine = lineIndex === lines.length - 1;
4377
4655
  const isEmptyLine = line.trim() === "";
4378
4656
  if (isEmptyLine) {
4379
4657
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
4380
4658
  }
4381
4659
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
4382
- "span",
4660
+ "div",
4383
4661
  {
4384
4662
  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);
4663
+ onClick: (e) => {
4664
+ if (e.target.type !== "checkbox") {
4665
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4666
+ if (idx !== -1) setCurrentStepIndex(idx);
4667
+ }
4388
4668
  },
4389
4669
  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"}
4670
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4671
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4392
4672
  `
4393
4673
  },
4394
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4395
- ), !isLastLine && /* @__PURE__ */ React6.createElement("br", null));
4674
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4675
+ ));
4396
4676
  }));
4397
4677
  });
4398
4678
  };
@@ -4420,7 +4700,9 @@ function DescriptionDisplay({
4420
4700
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4421
4701
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4422
4702
  };
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) => {
4703
+ globalCheckboxCounterRef.current = 0;
4704
+ const hasUnsavedChanges = localDescription !== (description || "");
4705
+ 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
4706
  const currentNavItem = flatNavigation[currentStepIndex];
4425
4707
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4426
4708
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4436,11 +4718,22 @@ function DescriptionDisplay({
4436
4718
  if (index === 0) leadingSpace = "";
4437
4719
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4438
4720
  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
- }));
4721
+ })), 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(
4722
+ "button",
4723
+ {
4724
+ onClick: (e) => {
4725
+ e.stopPropagation();
4726
+ onSaveDescription(localDescription);
4727
+ },
4728
+ 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"
4729
+ },
4730
+ /* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
4731
+ " Salvar Checklist"
4732
+ )));
4440
4733
  }
4441
4734
 
4442
4735
  // src/components/DescriptionReadModePanel.jsx
4443
- import React7, { useState as useState7, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4736
+ import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
4444
4737
  import {
4445
4738
  FiArrowLeft,
4446
4739
  FiEdit2,
@@ -4519,7 +4812,6 @@ function DescriptionReadModePanel({
4519
4812
  title,
4520
4813
  description,
4521
4814
  ancestryId,
4522
- // <-- NOVO: Prop recebida do XViewScene
4523
4815
  savedSections,
4524
4816
  onBack,
4525
4817
  onEdit,
@@ -4541,12 +4833,13 @@ function DescriptionReadModePanel({
4541
4833
  userRole,
4542
4834
  abstractionTree = null,
4543
4835
  onRenderAbstractionTree = null,
4544
- initialShowAbstraction = false
4836
+ initialShowAbstraction = false,
4837
+ onSaveDescription
4545
4838
  }) {
4546
- const [showProperties, setShowProperties] = useState7(false);
4547
- const [showAbstraction, setShowAbstraction] = useState7(false);
4548
- const [targetRenderNodeId, setTargetRenderNodeId] = useState7(null);
4549
- const [isLinkCopied, setIsLinkCopied] = useState7(false);
4839
+ const [showProperties, setShowProperties] = useState8(false);
4840
+ const [showAbstraction, setShowAbstraction] = useState8(false);
4841
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
4842
+ const [isLinkCopied, setIsLinkCopied] = useState8(false);
4550
4843
  const handleCopyLink = (e) => {
4551
4844
  e.stopPropagation();
4552
4845
  if (!ancestryId) return;
@@ -4628,7 +4921,7 @@ function DescriptionReadModePanel({
4628
4921
  return /* @__PURE__ */ React7.createElement(
4629
4922
  "div",
4630
4923
  {
4631
- className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
4924
+ className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
4632
4925
  onPointerDown: swallow,
4633
4926
  onClick: swallow
4634
4927
  },
@@ -4700,7 +4993,7 @@ function DescriptionReadModePanel({
4700
4993
  },
4701
4994
  "\xD7"
4702
4995
  ))),
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(
4996
+ /* @__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
4997
  "button",
4705
4998
  {
4706
4999
  onClick: (e) => {
@@ -4759,7 +5052,8 @@ function DescriptionReadModePanel({
4759
5052
  onHighlightNode,
4760
5053
  initialSectionId,
4761
5054
  currentBranchDirection,
4762
- onImageClick
5055
+ onImageClick,
5056
+ onSaveDescription
4763
5057
  }
4764
5058
  )),
4765
5059
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
@@ -4801,11 +5095,11 @@ function AncestryRelationshipPanel({
4801
5095
  onMentionClick,
4802
5096
  onUploadFile
4803
5097
  }) {
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);
5098
+ const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
5099
+ const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
5100
+ const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
5101
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
5102
+ const [isReadMode, setIsReadMode] = useState9(false);
4809
5103
  const propsEndRef = useRef7(null);
4810
5104
  useEffect8(() => {
4811
5105
  setDescription((data == null ? void 0 : data.description) ?? "");
@@ -4829,6 +5123,17 @@ function AncestryRelationshipPanel({
4829
5123
  return newProps;
4830
5124
  });
4831
5125
  };
5126
+ const handleSaveDescriptionInline = (newDescription) => {
5127
+ setDescription(newDescription);
5128
+ const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
5129
+ const processedSections = processDescriptionForSave(newDescription, existingSections);
5130
+ const dataToSave = {
5131
+ description: newDescription,
5132
+ description_sections: processedSections,
5133
+ ...extrasObj
5134
+ };
5135
+ onSave(dataToSave);
5136
+ };
4832
5137
  const handleSave = () => {
4833
5138
  const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
4834
5139
  const processedSections = processDescriptionForSave(description, existingSections);
@@ -4878,7 +5183,8 @@ function AncestryRelationshipPanel({
4878
5183
  availableAncestries,
4879
5184
  onOpenReference,
4880
5185
  onMentionClick,
4881
- onImageClick: handleImageClickFromText
5186
+ onImageClick: handleImageClickFromText,
5187
+ onSaveDescription: handleSaveDescriptionInline
4882
5188
  }
4883
5189
  ) : /* @__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
5190
  DescriptionDisplay,
@@ -4889,7 +5195,8 @@ function AncestryRelationshipPanel({
4889
5195
  availableAncestries,
4890
5196
  onOpenReference,
4891
5197
  onMentionClick,
4892
- onImageClick: handleImageClickFromText
5198
+ onImageClick: handleImageClickFromText,
5199
+ onSaveDescription: handleSaveDescriptionInline
4893
5200
  }
4894
5201
  ), /* @__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
5202
  "button",
@@ -4947,7 +5254,7 @@ function AncestryRelationshipPanel({
4947
5254
  }
4948
5255
 
4949
5256
  // src/components/CreateAncestryPanel.jsx
4950
- import React10, { useState as useState10, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback } from "react";
5257
+ import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
4951
5258
  import {
4952
5259
  FiEdit2 as FiEdit23,
4953
5260
  FiBookOpen as FiBookOpen2,
@@ -4967,7 +5274,7 @@ import {
4967
5274
  } from "react-icons/fi";
4968
5275
 
4969
5276
  // src/components/AncestryPickerModal.jsx
4970
- import React9, { useState as useState9, useMemo as useMemo7, useEffect as useEffect9 } from "react";
5277
+ import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
4971
5278
  import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
4972
5279
  function AncestryPickerModal({
4973
5280
  isOpen,
@@ -4977,7 +5284,7 @@ function AncestryPickerModal({
4977
5284
  availableNodes = [],
4978
5285
  currentAncestryId
4979
5286
  }) {
4980
- const [searchTerm, setSearchTerm] = useState9("");
5287
+ const [searchTerm, setSearchTerm] = useState10("");
4981
5288
  useEffect9(() => {
4982
5289
  if (!isOpen) return;
4983
5290
  const handleKeyDown = (e) => {
@@ -5062,7 +5369,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
5062
5369
  var _a, _b;
5063
5370
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
5064
5371
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
5065
- const [isDragOver, setIsDragOver] = useState10(false);
5372
+ const [isDragOver, setIsDragOver] = useState11(false);
5066
5373
  const isSelectedParent = String(selectedParentId) === String(itemId);
5067
5374
  const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
5068
5375
  const isHighlightedPath = highlightedPathIds.includes(String(itemId));
@@ -5198,8 +5505,8 @@ function CreateAncestryPanel({
5198
5505
  isAddingNodes,
5199
5506
  currentAncestryId
5200
5507
  } = ancestryMode;
5201
- const [isSaving, setIsSaving] = useState10(false);
5202
- const [isLinkCopied, setIsLinkCopied] = useState10(false);
5508
+ const [isSaving, setIsSaving] = useState11(false);
5509
+ const [isLinkCopied, setIsLinkCopied] = useState11(false);
5203
5510
  const handleCopyLink = (e) => {
5204
5511
  e.stopPropagation();
5205
5512
  if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
@@ -5213,11 +5520,11 @@ function CreateAncestryPanel({
5213
5520
  setTimeout(() => setIsLinkCopied(false), 2e3);
5214
5521
  }).catch((err) => console.error("Erro ao copiar link:", err));
5215
5522
  };
5216
- const [isPickerOpen, setIsPickerOpen] = useState10(false);
5217
- const [customProps, setCustomProps] = useState10([]);
5523
+ const [isPickerOpen, setIsPickerOpen] = useState11(false);
5524
+ const [customProps, setCustomProps] = useState11([]);
5218
5525
  const propsEndRef = useRef8(null);
5219
- const [branchStack, setBranchStack] = useState10([]);
5220
- const [targetRenderNodeId, setTargetRenderNodeId] = useState10(null);
5526
+ const [branchStack, setBranchStack] = useState11([]);
5527
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
5221
5528
  const highlightedPathIds = useMemo8(() => {
5222
5529
  var _a, _b;
5223
5530
  if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
@@ -5231,17 +5538,27 @@ function CreateAncestryPanel({
5231
5538
  }
5232
5539
  return ids;
5233
5540
  }, [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);
5541
+ const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
5542
+ const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
5543
+ const [ancestryName, setAncestryName] = useState11(initialName);
5544
+ const [description, setDescription] = useState11(initialDescription || "");
5545
+ const [existingSections, setExistingSections] = useState11(initialSections || []);
5546
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
5547
+ const [isReadMode, setIsReadMode] = useState11(false);
5548
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
5549
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
5550
+ initialWidth: isReadMode ? 700 : 440,
5551
+ minWidth: 320,
5552
+ maxWidth: maxPanelW
5553
+ });
5554
+ useEffect10(() => {
5555
+ setWidth(isReadMode ? 700 : 440);
5556
+ }, [isReadMode, setWidth]);
5241
5557
  const currentMaxRenderIndexRef = useRef8(0);
5242
5558
  const branchProgressMapRef = useRef8({});
5243
- const [lastSavedSnapshot, setLastSavedSnapshot] = useState10(null);
5244
- const [isPrivate, setIsPrivate] = useState10(ancestryMode.is_private || false);
5559
+ const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
5560
+ const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
5561
+ const initializedContextIdRef = useRef8(null);
5245
5562
  const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
5246
5563
  const handleImageClickFromText = (url, name) => {
5247
5564
  if (onOpenImageViewer) {
@@ -5259,7 +5576,7 @@ function CreateAncestryPanel({
5259
5576
  }
5260
5577
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5261
5578
  };
5262
- const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
5579
+ const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
5263
5580
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
5264
5581
  const treeKey = isAbstraction ? "abstraction_tree" : "tree";
5265
5582
  setAncestryMode((prev) => {
@@ -5440,6 +5757,11 @@ function CreateAncestryPanel({
5440
5757
  }, [isContextLinked, branchStack]);
5441
5758
  useEffect10(() => {
5442
5759
  const ctx = getCurrentContext();
5760
+ const currentContextId = branchStack.length > 0 ? branchStack[branchStack.length - 1].branchId : ancestryMode.currentAncestryId || `new_${ancestryMode.ancestral_node}`;
5761
+ if (initializedContextIdRef.current === currentContextId) {
5762
+ return;
5763
+ }
5764
+ initializedContextIdRef.current = currentContextId;
5443
5765
  let sourceObject = {};
5444
5766
  if (ctx) {
5445
5767
  sourceObject = ctx;
@@ -5790,7 +6112,7 @@ function CreateAncestryPanel({
5790
6112
  const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
5791
6113
  abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
5792
6114
  }
5793
- return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
6115
+ return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged || abstractionTreeChanged;
5794
6116
  }, [
5795
6117
  ancestryName,
5796
6118
  description,
@@ -6138,6 +6460,10 @@ function CreateAncestryPanel({
6138
6460
  setInternalHighlightedNodeId(id);
6139
6461
  if (onHighlightNode) onHighlightNode(id);
6140
6462
  };
6463
+ const handleSaveDescriptionInline = (newDesc) => {
6464
+ setDescription(newDesc);
6465
+ handleLocalSave(true, { description: newDesc });
6466
+ };
6141
6467
  const swallow = (e) => e.stopPropagation();
6142
6468
  const getSelectedParentName = () => {
6143
6469
  if (!activeTree || !selectedParentId) return "";
@@ -6210,10 +6536,8 @@ function CreateAncestryPanel({
6210
6536
  return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
6211
6537
  "div",
6212
6538
  {
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)" },
6539
+ 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"}`,
6540
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
6217
6541
  onPointerDown: swallow,
6218
6542
  onPointerMove: swallow,
6219
6543
  onPointerUp: swallow,
@@ -6222,6 +6546,17 @@ function CreateAncestryPanel({
6222
6546
  onContextMenu: swallow,
6223
6547
  onDoubleClick: swallow
6224
6548
  },
6549
+ /* @__PURE__ */ React10.createElement(
6550
+ "div",
6551
+ {
6552
+ onPointerDown: (e) => {
6553
+ e.stopPropagation();
6554
+ handleResize(e);
6555
+ },
6556
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
6557
+ title: "Arraste para redimensionar"
6558
+ }
6559
+ ),
6225
6560
  isReadMode ? /* @__PURE__ */ React10.createElement(
6226
6561
  DescriptionReadModePanel,
6227
6562
  {
@@ -6240,7 +6575,8 @@ function CreateAncestryPanel({
6240
6575
  onMentionClick,
6241
6576
  onSectionChange: handleSectionChangeWrapper,
6242
6577
  onHighlightNode,
6243
- onImageClick: handleImageClickFromText
6578
+ onImageClick: handleImageClickFromText,
6579
+ onSaveDescription: handleSaveDescriptionInline
6244
6580
  }
6245
6581
  ) : /* @__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
6582
  "button",
@@ -6297,7 +6633,8 @@ function CreateAncestryPanel({
6297
6633
  onHighlightNode: handleHighlightWrapper,
6298
6634
  initialSectionId: targetScrollSectionId,
6299
6635
  currentBranchDirection: currentContext ? currentContext.direction : null,
6300
- onImageClick: handleImageClickFromText
6636
+ onImageClick: handleImageClickFromText,
6637
+ onSaveDescription: handleSaveDescriptionInline
6301
6638
  }
6302
6639
  ), /* @__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
6640
  "button",
@@ -6518,25 +6855,25 @@ function CreateAncestryPanel({
6518
6855
  }
6519
6856
 
6520
6857
  // src/components/ImageViewer.jsx
6521
- import React11, { useState as useState11, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback2 } from "react";
6858
+ import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
6522
6859
  import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
6523
6860
  function ImageViewer({ data, onClose }) {
6524
6861
  var _a;
6525
6862
  const { images = [], startIndex = 0, visible } = data;
6526
- const [currentIndex, setCurrentIndex] = useState11(startIndex);
6527
- const [isLoading, setIsLoading] = useState11(false);
6528
- const [loadedSrc, setLoadedSrc] = useState11(null);
6863
+ const [currentIndex, setCurrentIndex] = useState12(startIndex);
6864
+ const [isLoading, setIsLoading] = useState12(false);
6865
+ const [loadedSrc, setLoadedSrc] = useState12(null);
6529
6866
  useLayoutEffect2(() => {
6530
6867
  if (visible) {
6531
6868
  setCurrentIndex(startIndex);
6532
6869
  }
6533
6870
  }, [visible, startIndex]);
6534
- const handleNext = useCallback2(() => {
6871
+ const handleNext = useCallback3(() => {
6535
6872
  if (images.length > 1) {
6536
6873
  setCurrentIndex((prev) => (prev + 1) % images.length);
6537
6874
  }
6538
6875
  }, [images.length]);
6539
- const handlePrev = useCallback2(() => {
6876
+ const handlePrev = useCallback3(() => {
6540
6877
  if (images.length > 1) {
6541
6878
  setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
6542
6879
  }
@@ -6641,10 +6978,10 @@ function ImageViewer({ data, onClose }) {
6641
6978
  }
6642
6979
 
6643
6980
  // src/components/InSceneCreationForm.jsx
6644
- import React13, { useState as useState13, useEffect as useEffect13, useRef as useRef10 } from "react";
6981
+ import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
6645
6982
 
6646
6983
  // src/components/ColorPicker.jsx
6647
- import React12, { useState as useState12, useEffect as useEffect12, useRef as useRef9 } from "react";
6984
+ import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
6648
6985
  import { HexColorPicker } from "react-colorful";
6649
6986
  import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
6650
6987
  var PRESET_COLORS = [
@@ -6665,7 +7002,7 @@ var PRESET_COLORS = [
6665
7002
  "#000000"
6666
7003
  ];
6667
7004
  function ColorPicker({ color, onChange, disabled }) {
6668
- const [isOpen, setIsOpen] = useState12(false);
7005
+ const [isOpen, setIsOpen] = useState13(false);
6669
7006
  const popoverRef = useRef9(null);
6670
7007
  useEffect12(() => {
6671
7008
  const handleClickOutside = (event) => {
@@ -6740,7 +7077,7 @@ function ColorPicker({ color, onChange, disabled }) {
6740
7077
  }
6741
7078
 
6742
7079
  // src/components/InSceneCreationForm.jsx
6743
- import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun } from "react-icons/fi";
7080
+ import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
6744
7081
  function InSceneCreationForm({
6745
7082
  onSave,
6746
7083
  onCancel,
@@ -6758,21 +7095,44 @@ function InSceneCreationForm({
6758
7095
  availableAncestries = [],
6759
7096
  onMentionClick,
6760
7097
  sourceTypes,
6761
- onUploadFile
7098
+ onUploadFile,
7099
+ availableDatasets = [],
7100
+ sourceNodeDatasetId,
7101
+ viewType
6762
7102
  }) {
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);
7103
+ var _a;
7104
+ const [name, setName] = useState14("");
7105
+ const [types, setTypes] = useState14([]);
7106
+ const [typeInput, setTypeInput] = useState14("");
7107
+ const [color, setColor] = useState14(initialColor || "#cccccc");
7108
+ const [size, setSize] = useState14("medium");
7109
+ const [intensity, setIntensity] = useState14(0);
7110
+ const [description, setDescription] = useState14("");
7111
+ const [customProps, setCustomProps] = useState14([]);
7112
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
7113
+ const [filteredTypes, setFilteredTypes] = useState14([]);
7114
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
7115
+ const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
7116
+ const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
7117
+ const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
7118
+ const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
7119
+ const datasetDropdownRef = useRef10(null);
7120
+ useEffect13(() => {
7121
+ if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
7122
+ }, [sourceNodeDatasetId]);
7123
+ useEffect13(() => {
7124
+ function handleClickOutside(event) {
7125
+ if (datasetDropdownRef.current && !datasetDropdownRef.current.contains(event.target)) {
7126
+ setIsDatasetDropdownOpen(false);
7127
+ }
7128
+ }
7129
+ if (isDatasetDropdownOpen) {
7130
+ document.addEventListener("mousedown", handleClickOutside);
7131
+ }
7132
+ return () => {
7133
+ document.removeEventListener("mousedown", handleClickOutside);
7134
+ };
7135
+ }, [isDatasetDropdownOpen]);
6776
7136
  const propsEndRef = useRef10(null);
6777
7137
  const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
6778
7138
  useEffect13(() => {
@@ -6818,8 +7178,8 @@ function InSceneCreationForm({
6818
7178
  const newProp = createNewCustomProperty(customProps);
6819
7179
  setCustomProps([...customProps, newProp]);
6820
7180
  setTimeout(() => {
6821
- var _a;
6822
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
7181
+ var _a2;
7182
+ (_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
6823
7183
  }, 100);
6824
7184
  };
6825
7185
  const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
@@ -6852,12 +7212,12 @@ function InSceneCreationForm({
6852
7212
  onSizeChange == null ? void 0 : onSizeChange(newSize);
6853
7213
  };
6854
7214
  const handleToggleImageMode = () => {
6855
- var _a, _b;
7215
+ var _a2, _b;
6856
7216
  const newValue = !useImageAsTexture;
6857
7217
  setUseImageAsTexture(newValue);
6858
7218
  if (newValue) {
6859
7219
  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)) {
7220
+ if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
6861
7221
  const url = firstImageProp.value[0].value;
6862
7222
  setSelectedImageUrl(url);
6863
7223
  onImageChange == null ? void 0 : onImageChange(true, url);
@@ -6890,6 +7250,7 @@ function InSceneCreationForm({
6890
7250
  description_sections: processedSections,
6891
7251
  useImageAsTexture,
6892
7252
  textureImageUrl: useImageAsTexture ? selectedImageUrl : null,
7253
+ targetDatasetId,
6893
7254
  ...additionalData
6894
7255
  });
6895
7256
  };
@@ -6910,6 +7271,7 @@ function InSceneCreationForm({
6910
7271
  onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
6911
7272
  }
6912
7273
  };
7274
+ const selectedDatasetName = ((_a = availableDatasets.find((ds) => ds.id === targetDatasetId)) == null ? void 0 : _a.name) || "Selecione um Dataset...";
6913
7275
  return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
6914
7276
  "div",
6915
7277
  {
@@ -6967,7 +7329,27 @@ function InSceneCreationForm({
6967
7329
  }
6968
7330
  },
6969
7331
  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(
7332
+ ))))), /* @__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(
7333
+ "button",
7334
+ {
7335
+ type: "button",
7336
+ onClick: () => setIsDatasetDropdownOpen(!isDatasetDropdownOpen),
7337
+ 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"
7338
+ },
7339
+ /* @__PURE__ */ React13.createElement("span", { className: "truncate pr-2" }, selectedDatasetName),
7340
+ /* @__PURE__ */ React13.createElement(FiChevronDown4, { className: `flex-shrink-0 text-slate-400 transition-transform ${isDatasetDropdownOpen ? "rotate-180" : ""}` })
7341
+ ), 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(
7342
+ "li",
7343
+ {
7344
+ key: ds.id,
7345
+ onClick: () => {
7346
+ setTargetDatasetId(ds.id);
7347
+ setIsDatasetDropdownOpen(false);
7348
+ },
7349
+ 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"}`
7350
+ },
7351
+ ds.name
7352
+ )))), /* @__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
7353
  DescriptionDisplay,
6972
7354
  {
6973
7355
  description,
@@ -6975,7 +7357,8 @@ function InSceneCreationForm({
6975
7357
  availableNodes,
6976
7358
  availableAncestries,
6977
7359
  onMentionClick,
6978
- onImageClick: handleImageClickFromText
7360
+ onImageClick: handleImageClickFromText,
7361
+ onSaveDescription: (newDesc) => setDescription(newDesc)
6979
7362
  }
6980
7363
  ), /* @__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
7364
  "button",
@@ -7066,7 +7449,7 @@ function InSceneCreationForm({
7066
7449
  }
7067
7450
 
7068
7451
  // src/components/InSceneVersionForm.jsx
7069
- import React14, { useState as useState14, useEffect as useEffect14, useRef as useRef11 } from "react";
7452
+ import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
7070
7453
  import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
7071
7454
  function InSceneVersionForm({
7072
7455
  onSave,
@@ -7084,14 +7467,14 @@ function InSceneVersionForm({
7084
7467
  onMentionClick,
7085
7468
  onUploadFile
7086
7469
  }) {
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);
7470
+ const [name, setName] = useState15("");
7471
+ const [size, setSize] = useState15("medium");
7472
+ const [description, setDescription] = useState15("");
7473
+ const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
7474
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
7092
7475
  const propsEndRef = useRef11(null);
7093
- const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
7094
- const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
7476
+ const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
7477
+ const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
7095
7478
  const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
7096
7479
  useEffect14(() => {
7097
7480
  if (!hasImages && useImageAsTexture) {
@@ -7212,7 +7595,8 @@ function InSceneVersionForm({
7212
7595
  availableNodes,
7213
7596
  availableAncestries,
7214
7597
  onMentionClick,
7215
- onImageClick: handleImageClickFromText
7598
+ onImageClick: handleImageClickFromText,
7599
+ onSaveDescription: (newDesc) => setDescription(newDesc)
7216
7600
  }
7217
7601
  ), /* @__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
7602
  "button",
@@ -7284,8 +7668,8 @@ function InSceneVersionForm({
7284
7668
  }
7285
7669
 
7286
7670
  // 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";
7671
+ import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
7672
+ 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
7673
  function NodeDetailsPanel({
7290
7674
  node,
7291
7675
  onClose,
@@ -7303,29 +7687,39 @@ function NodeDetailsPanel({
7303
7687
  onMentionClick,
7304
7688
  onIntensityChange,
7305
7689
  onUploadFile,
7306
- userRole
7690
+ userRole,
7691
+ currentDatasetName
7307
7692
  }) {
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(() => {
7693
+ const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
7694
+ const [types, setTypes] = useState16([]);
7695
+ const [typeInput, setTypeInput] = useState16("");
7696
+ const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
7697
+ const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
7698
+ const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
7699
+ const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
7700
+ const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
7701
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
7702
+ const [filteredTypes, setFilteredTypes] = useState16([]);
7703
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
7704
+ const [isReadMode, setIsReadMode] = useState16(false);
7705
+ const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
7706
+ const [isSaving, setIsSaving] = useState16(false);
7707
+ const [isLinkCopied, setIsLinkCopied] = useState16(false);
7708
+ const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
7324
7709
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
7325
7710
  if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
7326
7711
  return !!(node == null ? void 0 : node.useImageAsTexture);
7327
7712
  });
7328
- const [selectedImageUrl, setSelectedImageUrl] = useState15((node == null ? void 0 : node.textureImageUrl) ?? null);
7713
+ const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
7714
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
7715
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
7716
+ initialWidth: isReadMode ? 700 : 440,
7717
+ minWidth: 320,
7718
+ maxWidth: maxPanelW
7719
+ });
7720
+ useEffect15(() => {
7721
+ setWidth(isReadMode ? 700 : 440);
7722
+ }, [isReadMode, setWidth]);
7329
7723
  const prevNodeIdRef = useRef12(null);
7330
7724
  const propsEndRef = useRef12(null);
7331
7725
  const canEdit = userRole !== "viewer";
@@ -7478,6 +7872,11 @@ function NodeDetailsPanel({
7478
7872
  textureImageUrl: url
7479
7873
  });
7480
7874
  };
7875
+ const handleSaveDescriptionInline = (newDescription) => {
7876
+ setDescription(newDescription);
7877
+ onDataUpdate({ ...node, description: newDescription });
7878
+ triggerAutoSave({ description: newDescription });
7879
+ };
7481
7880
  const handleSave = async (keepOpen = false, overrides = {}) => {
7482
7881
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7483
7882
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7533,10 +7932,8 @@ function NodeDetailsPanel({
7533
7932
  return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
7534
7933
  "div",
7535
7934
  {
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 },
7935
+ 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"}`,
7936
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
7540
7937
  onPointerDown: swallow,
7541
7938
  onPointerMove: swallow,
7542
7939
  onPointerUp: swallow,
@@ -7545,6 +7942,17 @@ function NodeDetailsPanel({
7545
7942
  onContextMenu: swallow,
7546
7943
  onDoubleClick: swallow
7547
7944
  },
7945
+ /* @__PURE__ */ React15.createElement(
7946
+ "div",
7947
+ {
7948
+ onPointerDown: (e) => {
7949
+ e.stopPropagation();
7950
+ handleResize(e);
7951
+ },
7952
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
7953
+ title: "Arraste para redimensionar"
7954
+ }
7955
+ ),
7548
7956
  isReadMode ? /* @__PURE__ */ React15.createElement(
7549
7957
  DescriptionReadModePanel,
7550
7958
  {
@@ -7563,7 +7971,8 @@ function NodeDetailsPanel({
7563
7971
  availableAncestries,
7564
7972
  onOpenReference,
7565
7973
  onMentionClick,
7566
- onImageClick: handleImageClickFromText
7974
+ onImageClick: handleImageClickFromText,
7975
+ onSaveDescription: handleSaveDescriptionInline
7567
7976
  }
7568
7977
  ) : /* @__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
7978
  "button",
@@ -7631,7 +8040,8 @@ function NodeDetailsPanel({
7631
8040
  availableAncestries,
7632
8041
  onOpenReference,
7633
8042
  onMentionClick,
7634
- onImageClick: handleImageClickFromText
8043
+ onImageClick: handleImageClickFromText,
8044
+ onSaveDescription: handleSaveDescriptionInline
7635
8045
  }
7636
8046
  ), /* @__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
8047
  "button",
@@ -7714,7 +8124,7 @@ function NodeDetailsPanel({
7714
8124
  onUploadFile: canEdit ? onUploadFile : void 0,
7715
8125
  readOnly: !canEdit
7716
8126
  }
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(
8127
+ )), /* @__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
8128
  "button",
7719
8129
  {
7720
8130
  onClick: () => handleSave(false),
@@ -7746,7 +8156,7 @@ function NodeDetailsPanel({
7746
8156
  }
7747
8157
 
7748
8158
  // src/components/MultiNodeContextMenu.jsx
7749
- import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState16, useEffect as useEffect16 } from "react";
8159
+ import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
7750
8160
  function MultiNodeContextMenu({
7751
8161
  data,
7752
8162
  userRole,
@@ -7757,7 +8167,7 @@ function MultiNodeContextMenu({
7757
8167
  onDeleteNodes
7758
8168
  }) {
7759
8169
  const menuRef = useRef13(null);
7760
- const [menuPos, setMenuPos] = useState16({ left: 0, top: 0 });
8170
+ const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
7761
8171
  const ability = defineAbilityFor(userRole);
7762
8172
  const canDelete = ability.can("delete", "Node");
7763
8173
  useLayoutEffect3(() => {
@@ -7806,7 +8216,7 @@ function MultiNodeContextMenu({
7806
8216
  }
7807
8217
 
7808
8218
  // src/components/RelationshipDetailsPanel.jsx
7809
- import React17, { useState as useState17, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
8219
+ import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
7810
8220
  import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
7811
8221
  function RelationshipDetailsPanel({
7812
8222
  link,
@@ -7820,15 +8230,14 @@ function RelationshipDetailsPanel({
7820
8230
  onMentionClick,
7821
8231
  onUploadFile,
7822
8232
  userRole
7823
- // Recebendo userRole via props
7824
8233
  }) {
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);
8234
+ const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
8235
+ const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
8236
+ const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
8237
+ const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
8238
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
8239
+ const [isSaving, setIsSaving] = useState18(false);
8240
+ const [isReadMode, setIsReadMode] = useState18(false);
7832
8241
  const propsEndRef = useRef14(null);
7833
8242
  const canEdit = useMemo9(() => {
7834
8243
  const ability = defineAbilityFor(userRole);
@@ -7883,6 +8292,12 @@ function RelationshipDetailsPanel({
7883
8292
  const triggerAutoSave = (overrides = {}) => {
7884
8293
  if (canEdit) handleSave(true, overrides);
7885
8294
  };
8295
+ const handleSaveDescriptionInline = (newDescription) => {
8296
+ if (!canEdit) return;
8297
+ setDescription(newDescription);
8298
+ onDataUpdate((prev) => ({ ...prev, description: newDescription }));
8299
+ triggerAutoSave({ description: newDescription });
8300
+ };
7886
8301
  const handleRemoveProp = (i) => {
7887
8302
  const newProps = customProps.filter((_, idx) => idx !== i);
7888
8303
  setCustomProps(newProps);
@@ -7936,7 +8351,8 @@ function RelationshipDetailsPanel({
7936
8351
  availableAncestries,
7937
8352
  onOpenReference,
7938
8353
  onMentionClick,
7939
- onImageClick: handleImageClickFromText
8354
+ onImageClick: handleImageClickFromText,
8355
+ onSaveDescription: handleSaveDescriptionInline
7940
8356
  }
7941
8357
  ) : /* @__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
8358
  "input",
@@ -7959,7 +8375,8 @@ function RelationshipDetailsPanel({
7959
8375
  availableAncestries,
7960
8376
  onOpenReference,
7961
8377
  onMentionClick,
7962
- onImageClick: handleImageClickFromText
8378
+ onImageClick: handleImageClickFromText,
8379
+ onSaveDescription: handleSaveDescriptionInline
7963
8380
  }
7964
8381
  ), /* @__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
8382
  "button",
@@ -8031,7 +8448,7 @@ function RelationshipDetailsPanel({
8031
8448
  }
8032
8449
 
8033
8450
  // src/components/RelationshipContextMenu.jsx
8034
- import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState18, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8451
+ import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
8035
8452
  function RelationshipContextMenu({
8036
8453
  data,
8037
8454
  userRole,
@@ -8043,7 +8460,7 @@ function RelationshipContextMenu({
8043
8460
  onClose
8044
8461
  }) {
8045
8462
  const menuRef = useRef15(null);
8046
- const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
8463
+ const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
8047
8464
  const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
8048
8465
  const sourceName = useMemo10(
8049
8466
  () => {
@@ -8245,7 +8662,7 @@ function LoadingScreen() {
8245
8662
  }
8246
8663
 
8247
8664
  // src/components/ImportParentFileModal.jsx
8248
- import React20, { useEffect as useEffect19, useState as useState19 } from "react";
8665
+ import React20, { useEffect as useEffect19, useState as useState20 } from "react";
8249
8666
  function ImportParentFileModal({
8250
8667
  isOpen,
8251
8668
  onClose,
@@ -8256,11 +8673,11 @@ function ImportParentFileModal({
8256
8673
  onFetchAvailableFiles,
8257
8674
  currentViewName
8258
8675
  }) {
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);
8676
+ const [activeTab, setActiveTab] = useState20("databases");
8677
+ const [availableDbs, setAvailableDbs] = useState20([]);
8678
+ const [availableViews, setAvailableViews] = useState20([]);
8679
+ const [selectedItem, setSelectedItem] = useState20(null);
8680
+ const [isLoading, setIsLoading] = useState20(false);
8264
8681
  useEffect19(() => {
8265
8682
  if (isOpen && session && onFetchAvailableFiles) {
8266
8683
  const fetchData = async () => {
@@ -8406,7 +8823,7 @@ function ImportParentFileModal({
8406
8823
  }
8407
8824
 
8408
8825
  // src/components/AncestryLinkDetailsPanel.jsx
8409
- import React21, { useState as useState20 } from "react";
8826
+ import React21, { useState as useState21 } from "react";
8410
8827
  import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
8411
8828
  function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
8412
8829
  var _a, _b, _c, _d;
@@ -8416,7 +8833,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8416
8833
  const customProps = extractCustomPropsFromNode(relationshipData);
8417
8834
  const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
8418
8835
  const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
8419
- const [isReadMode, setIsReadMode] = useState20(false);
8836
+ const [isReadMode, setIsReadMode] = useState21(false);
8420
8837
  const swallow = (e) => e.stopPropagation();
8421
8838
  const handleImageClickFromText = (url, name) => {
8422
8839
  if (onOpenImageViewer) {
@@ -8482,7 +8899,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
8482
8899
  }
8483
8900
 
8484
8901
  // src/components/AncestryBoard.jsx
8485
- import React22, { useState as useState21, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8902
+ import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
8486
8903
  import {
8487
8904
  FiSearch as FiSearch4,
8488
8905
  FiLayers as FiLayers6,
@@ -8659,11 +9076,11 @@ function AncestryBoard({
8659
9076
  userRole
8660
9077
  // [NOVO] Recebe a role do usuário
8661
9078
  }) {
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");
9079
+ const [searchTerm, setSearchTerm] = useState22("");
9080
+ const [groups, setGroups] = useState22([]);
9081
+ const [isLoaded, setIsLoaded] = useState22(false);
9082
+ const [pickingGroupId, setPickingGroupId] = useState22(null);
9083
+ const [saveStatus, setSaveStatus] = useState22("idle");
8667
9084
  const canEdit = useMemo11(() => {
8668
9085
  return userRole !== "viewer";
8669
9086
  }, [userRole]);
@@ -9048,7 +9465,7 @@ function XViewScene({
9048
9465
  delete_file_action,
9049
9466
  check_user_permission
9050
9467
  }) {
9051
- var _a, _b, _c, _d, _e, _f;
9468
+ var _a, _b, _c, _d, _e, _f, _g;
9052
9469
  const { data: session, status } = useSession();
9053
9470
  const router = useRouter();
9054
9471
  const searchParams = useSearchParams();
@@ -9113,37 +9530,37 @@ function XViewScene({
9113
9530
  const sceneDataRef = useRef17(null);
9114
9531
  const parentDataRef = useRef17(null);
9115
9532
  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({
9533
+ const [isLoading, setIsLoading] = useState23(true);
9534
+ const [permissionStatus, setPermissionStatus] = useState23("loading");
9535
+ const [userPermissionRole, setUserPermissionRole] = useState23(null);
9536
+ const [isInitialized, setIsInitialized] = useState23(false);
9537
+ const [sceneVersion, setSceneVersion] = useState23(0);
9538
+ const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
9539
+ const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
9540
+ const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
9541
+ const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
9542
+ const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
9543
+ const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
9544
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
9545
+ const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9546
+ const [readingMode, setReadingMode] = useState23({
9130
9547
  isActive: false,
9131
9548
  ancestry: null,
9132
9549
  branchStack: [],
9133
9550
  autoAbstraction: false
9134
9551
  });
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);
9552
+ const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
9553
+ const [detailsNode, setDetailsNode] = useState23(null);
9554
+ const [detailsLink, setDetailsLink] = useState23(null);
9555
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
9556
+ const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
9557
+ const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
9558
+ const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
9559
+ const [importSuccessMessage, setImportSuccessMessage] = useState23("");
9560
+ const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
9561
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
9562
+ const [ancestryBoardData, setAncestryBoardData] = useState23([]);
9563
+ const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
9147
9564
  const mountRef = useRef17(null);
9148
9565
  const tooltipRef = useRef17(null);
9149
9566
  const formRef = useRef17(null);
@@ -9186,6 +9603,12 @@ function XViewScene({
9186
9603
  lastDescriptionLength: 0,
9187
9604
  highlightedNodeId: null
9188
9605
  });
9606
+ const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
9607
+ const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
9608
+ initialWidth: 700,
9609
+ minWidth: 320,
9610
+ maxWidth: maxReadPanelW
9611
+ });
9189
9612
  useEffect21(() => {
9190
9613
  stateRef.current.ancestry = ancestryMode;
9191
9614
  }, [ancestryMode]);
@@ -9200,19 +9623,20 @@ function XViewScene({
9200
9623
  const parentFile = allParentData[parentFileId];
9201
9624
  const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
9202
9625
  const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
9626
+ const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
9203
9627
  if (parentFile.nodes && ownerId2) {
9204
9628
  for (const node of parentFile.nodes) {
9205
- map.set(String(node.id), { parentFileId, ownerId: ownerId2 });
9629
+ map.set(String(node.id), { parentFileId, ownerId: ownerId2, datasetName });
9206
9630
  }
9207
9631
  }
9208
9632
  }
9209
9633
  }
9210
9634
  stateRef.current.nodeIdToParentFileMap = map;
9211
9635
  }, [isInitialized, sceneVersion]);
9212
- const handleNavigateBack = useCallback3(() => {
9636
+ const handleNavigateBack = useCallback4(() => {
9213
9637
  router.push("/dashboard/scenes");
9214
9638
  }, [router]);
9215
- const handleConfirmImport = useCallback3(
9639
+ const handleConfirmImport = useCallback4(
9216
9640
  async (importPayload) => {
9217
9641
  var _a2, _b2;
9218
9642
  let files = [];
@@ -9260,7 +9684,6 @@ function XViewScene({
9260
9684
  if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
9261
9685
  const viewSpecificAncestries = ancestryResponse.data.filter(
9262
9686
  (anc) => anc._source_file_id === viewToImport.id && !anc.is_private
9263
- // <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
9264
9687
  );
9265
9688
  const processedAncestries = viewSpecificAncestries.map((anc) => ({
9266
9689
  ...anc,
@@ -9311,7 +9734,7 @@ function XViewScene({
9311
9734
  const handleOpenImageViewer = (images, startIndex) => {
9312
9735
  setImageViewer({ visible: true, images, startIndex });
9313
9736
  };
9314
- const tweenToTarget = useCallback3((target, zoomFactor = 1, forcedDirection = null) => {
9737
+ const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
9315
9738
  const { camera, controls, tweenGroup } = stateRef.current;
9316
9739
  if (!camera || !controls || !tweenGroup) return;
9317
9740
  const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
@@ -9334,7 +9757,7 @@ function XViewScene({
9334
9757
  if (!t || typeof t.closest !== "function") return false;
9335
9758
  return !!t.closest(".ui-overlay");
9336
9759
  };
9337
- const buildFullAncestryTree = useCallback3((idTree, nodes, ancestries = []) => {
9760
+ const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
9338
9761
  if (!idTree) return null;
9339
9762
  const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
9340
9763
  const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
@@ -9360,14 +9783,10 @@ function XViewScene({
9360
9783
  return {
9361
9784
  ...branch,
9362
9785
  name: linkedAncestry.name,
9363
- // Sobrescreve nome para exibição
9364
9786
  description: linkedAncestry.description,
9365
- // Sobrescreve descrição
9366
9787
  description_sections: linkedAncestry.description_sections,
9367
9788
  tree: graftedTree,
9368
- // ENXERTA A ÁRVORE AQUI
9369
9789
  isLinked: true
9370
- // Flag útil
9371
9790
  };
9372
9791
  }
9373
9792
  }
@@ -9414,7 +9833,7 @@ function XViewScene({
9414
9833
  }
9415
9834
  return recursiveBuild(idTree);
9416
9835
  }, []);
9417
- const handleActivateTimeline = useCallback3(() => {
9836
+ const handleActivateTimeline = useCallback4(() => {
9418
9837
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
9419
9838
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
9420
9839
  while (timelineIntervalsGroup.children.length > 0) {
@@ -9567,7 +9986,7 @@ function XViewScene({
9567
9986
  }
9568
9987
  });
9569
9988
  }, []);
9570
- const handleVersionTimeline = useCallback3((sourceMesh, versionMeshes) => {
9989
+ const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
9571
9990
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
9572
9991
  if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
9573
9992
  versionMeshes.forEach((mesh) => {
@@ -9722,6 +10141,9 @@ function XViewScene({
9722
10141
  sceneDataRef.current = sceneResponse.data.scene;
9723
10142
  parentDataRef.current = sceneResponse.data.parent;
9724
10143
  ancestryDataRef.current = sceneResponse.data.ancestry;
10144
+ console.log("Console de sceneResponse.data.scene:", sceneResponse.data.scene);
10145
+ console.log("Console de sceneResponse.data.parent:", sceneResponse.data.parent);
10146
+ console.log("Console de sceneResponse.data.ancestry:", sceneResponse.data.ancestry);
9725
10147
  setIsInitialized(true);
9726
10148
  } else {
9727
10149
  console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
@@ -9757,16 +10179,14 @@ function XViewScene({
9757
10179
  isInitialized,
9758
10180
  permissionStatus,
9759
10181
  focusNodeId,
9760
- // <-- MANTIDO
9761
10182
  focusAncestryId
9762
- // <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
9763
10183
  ]);
9764
- const isNodeInView = useCallback3((id) => {
10184
+ const isNodeInView = useCallback4((id) => {
9765
10185
  const key = String(id);
9766
10186
  const objs = stateRef.current.nodeObjects || {};
9767
10187
  return !!objs[key];
9768
10188
  }, []);
9769
- const addOrUpdateNodeMesh = useCallback3((nodeData, position, suppressVersionUpdate = false) => {
10189
+ const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
9770
10190
  const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
9771
10191
  const nodeId = String(nodeData.id);
9772
10192
  if (nodeObjects[nodeId]) {
@@ -10415,7 +10835,7 @@ function XViewScene({
10415
10835
  }
10416
10836
  };
10417
10837
  }, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
10418
- const handleGhostNodeImageChange = useCallback3((useImage, imageUrl) => {
10838
+ const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
10419
10839
  const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
10420
10840
  const { graphGroup, glowTexture } = stateRef.current;
10421
10841
  if (!ghostNode || !graphGroup) return;
@@ -10457,7 +10877,7 @@ function XViewScene({
10457
10877
  aura: newGhostNode.getObjectByName("aura")
10458
10878
  };
10459
10879
  }, []);
10460
- const handleGhostNodeIntensityChange = useCallback3((newIntensity) => {
10880
+ const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
10461
10881
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
10462
10882
  if (!ghostNode) return;
10463
10883
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10478,7 +10898,7 @@ function XViewScene({
10478
10898
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
10479
10899
  }
10480
10900
  }, []);
10481
- const handleDetailNodeIntensityChange = useCallback3((nodeId, newIntensity) => {
10901
+ const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
10482
10902
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
10483
10903
  if (!mesh) return;
10484
10904
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -10503,32 +10923,33 @@ function XViewScene({
10503
10923
  const handleGhostNodeColorChange = (newColor) => {
10504
10924
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
10505
10925
  if (!ghostNode) return;
10506
- const { emissiveIntensity } = computeNodeMaterialProps(newColor);
10507
- const pureColor = new THREE3.Color(newColor);
10926
+ const { color, emissive } = computeNodeMaterialProps(newColor);
10927
+ const currentIntensity = ghostNode.userData.intensity !== void 0 ? Number(ghostNode.userData.intensity) : 0;
10928
+ const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
10508
10929
  const isImageNode = ghostNode.userData.useImageAsTexture === true || String(ghostNode.userData.useImageAsTexture) === "true";
10509
10930
  if (isImageNode) {
10510
10931
  const borderMesh = ghostNode.getObjectByName("borderRing");
10511
10932
  if (borderMesh && borderMesh.material) {
10512
- borderMesh.material.color.copy(pureColor);
10933
+ borderMesh.material.color.copy(color);
10513
10934
  if (borderMesh.material.emissive) {
10514
- borderMesh.material.emissive.copy(pureColor);
10515
- borderMesh.material.emissiveIntensity = emissiveIntensity;
10935
+ borderMesh.material.emissive.copy(emissive);
10936
+ borderMesh.material.emissiveIntensity = finalIntensity;
10516
10937
  }
10517
10938
  }
10518
10939
  } else {
10519
10940
  if (ghostNode.material) {
10520
- ghostNode.material.color.copy(pureColor);
10941
+ ghostNode.material.color.copy(color);
10521
10942
  if (ghostNode.material.emissive) {
10522
- ghostNode.material.emissive.copy(pureColor);
10523
- ghostNode.material.emissiveIntensity = emissiveIntensity;
10943
+ ghostNode.material.emissive.copy(emissive);
10944
+ ghostNode.material.emissiveIntensity = finalIntensity;
10524
10945
  }
10525
10946
  }
10526
10947
  }
10527
10948
  if (ghostAura && ghostAura.material) {
10528
- ghostAura.material.color.set(newColor);
10949
+ ghostAura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
10529
10950
  }
10530
10951
  ghostNode.userData.color = newColor;
10531
- ghostNode.userData._baseEmissiveIntensity = emissiveIntensity;
10952
+ ghostNode.userData._baseEmissiveIntensity = finalIntensity;
10532
10953
  };
10533
10954
  const handleGhostNodeSizeChange = (sizeKey) => {
10534
10955
  const { node: ghostNode } = stateRef.current.ghostElements;
@@ -10569,7 +10990,9 @@ function XViewScene({
10569
10990
  var _a2;
10570
10991
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
10571
10992
  if (!mesh) return;
10572
- const { color, emissive, emissiveIntensity } = computeNodeMaterialProps(newColor);
10993
+ const { color, emissive } = computeNodeMaterialProps(newColor);
10994
+ const currentIntensity = mesh.userData.intensity !== void 0 ? Number(mesh.userData.intensity) : 0;
10995
+ const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
10573
10996
  const isImageNode = mesh.userData.useImageAsTexture === true || String(mesh.userData.useImageAsTexture) === "true";
10574
10997
  if (isImageNode) {
10575
10998
  const borderMesh = mesh.getObjectByName("borderRing");
@@ -10577,20 +11000,22 @@ function XViewScene({
10577
11000
  borderMesh.material.color.copy(color);
10578
11001
  if (borderMesh.material.emissive) {
10579
11002
  borderMesh.material.emissive.copy(emissive);
10580
- borderMesh.material.emissiveIntensity = emissiveIntensity;
11003
+ borderMesh.material.emissiveIntensity = finalIntensity;
10581
11004
  }
10582
11005
  }
10583
11006
  } else {
10584
11007
  if (mesh.material) {
10585
11008
  mesh.material.color.copy(color);
10586
11009
  mesh.material.emissive.copy(emissive);
10587
- mesh.material.emissiveIntensity = emissiveIntensity;
11010
+ mesh.material.emissiveIntensity = finalIntensity;
10588
11011
  }
10589
11012
  }
10590
11013
  const aura = mesh.getObjectByName("aura");
10591
- if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) aura.material.color.set(newColor);
11014
+ if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) {
11015
+ aura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
11016
+ }
10592
11017
  mesh.userData.color = newColor;
10593
- mesh.userData._baseEmissiveIntensity = emissiveIntensity;
11018
+ mesh.userData._baseEmissiveIntensity = finalIntensity;
10594
11019
  };
10595
11020
  const handleDetailNodeSizeChange = (nodeId, newSize) => {
10596
11021
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
@@ -10619,7 +11044,7 @@ function XViewScene({
10619
11044
  mountRef.current.style.cursor = "default";
10620
11045
  }
10621
11046
  };
10622
- const handleAncestryTreeUpdate = useCallback3((newTree, extraData = null) => {
11047
+ const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
10623
11048
  setAncestryMode((prev) => {
10624
11049
  const prevTreeStr = JSON.stringify(prev.tree);
10625
11050
  const newTreeStr = JSON.stringify(newTree);
@@ -10689,7 +11114,7 @@ function XViewScene({
10689
11114
  const handleStartVersioning = (nodeData) => {
10690
11115
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
10691
11116
  };
10692
- const handleClearAncestryVisuals = useCallback3((ancestryId) => {
11117
+ const handleClearAncestryVisuals = useCallback4((ancestryId) => {
10693
11118
  const { renderedAncestries, ancestryGroup } = stateRef.current;
10694
11119
  const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
10695
11120
  if (renderIndex !== -1) {
@@ -10703,7 +11128,7 @@ function XViewScene({
10703
11128
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
10704
11129
  }
10705
11130
  }, []);
10706
- const handleRenderAncestry = useCallback3(
11131
+ const handleRenderAncestry = useCallback4(
10707
11132
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
10708
11133
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10709
11134
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11119,7 +11544,7 @@ function XViewScene({
11119
11544
  },
11120
11545
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
11121
11546
  );
11122
- const handleRenderAbstractionTree = useCallback3((ancestryObject, targetNodeId = null) => {
11547
+ const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
11123
11548
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11124
11549
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
11125
11550
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
@@ -11180,7 +11605,7 @@ function XViewScene({
11180
11605
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
11181
11606
  tweenToTarget(rootTargetPos, 0.7);
11182
11607
  }, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
11183
- const handleReadModeBranchNav = useCallback3((nodeId, action, direction = "right") => {
11608
+ const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
11184
11609
  const { ancestry, branchStack } = readingMode;
11185
11610
  if (!ancestry || !ancestry.tree) return;
11186
11611
  const allAncestries = ancestryDataRef.current || [];
@@ -11218,9 +11643,7 @@ function XViewScene({
11218
11643
  description_sections: branchToOpen.description_sections,
11219
11644
  tree: branchToOpen.tree,
11220
11645
  _originNodeId: nodeId,
11221
- // <--- ID do node pai (link visual)
11222
11646
  _branchDirection: direction
11223
- // <--- Direção para cálculo de posição
11224
11647
  };
11225
11648
  const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
11226
11649
  const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
@@ -11276,7 +11699,6 @@ function XViewScene({
11276
11699
  const parentAncestryObj = {
11277
11700
  ...targetAncestryInfo,
11278
11701
  tree: targetTreeToRender,
11279
- // Re-injeta a origem se o pai também for uma branch aninhada
11280
11702
  _originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
11281
11703
  _branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
11282
11704
  };
@@ -11324,7 +11746,7 @@ function XViewScene({
11324
11746
  }));
11325
11747
  }
11326
11748
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
11327
- const handleReadModeHighlight = useCallback3((nodeId) => {
11749
+ const handleReadModeHighlight = useCallback4((nodeId) => {
11328
11750
  if (stateRef.current.highlightedNodeId !== nodeId) {
11329
11751
  stateRef.current.highlightedNodeId = nodeId;
11330
11752
  }
@@ -11336,7 +11758,6 @@ function XViewScene({
11336
11758
  readingMode.ancestry.tree,
11337
11759
  Object.values(parentDataRef.current).flatMap((f) => f.nodes),
11338
11760
  ancestryDataRef.current
11339
- // <--- Adicionar
11340
11761
  );
11341
11762
  const findNodeInTree = (tree, targetId) => {
11342
11763
  if (!tree) return null;
@@ -11390,7 +11811,6 @@ function XViewScene({
11390
11811
  description_sections: ancestry.description_sections,
11391
11812
  direction: null,
11392
11813
  customProperties: rootProps
11393
- // <--- ADICIONADO
11394
11814
  };
11395
11815
  }
11396
11816
  const fullTree = buildFullAncestryTree(
@@ -11419,7 +11839,6 @@ function XViewScene({
11419
11839
  description_sections: currentMeta.description_sections,
11420
11840
  direction: currentDirection,
11421
11841
  customProperties: branchProps
11422
- // <--- ADICIONADO
11423
11842
  };
11424
11843
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
11425
11844
  const readModeAbstractionTree = useMemo12(() => {
@@ -11434,7 +11853,7 @@ function XViewScene({
11434
11853
  allAncestries
11435
11854
  );
11436
11855
  }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
11437
- const handleStartReadingAncestry = useCallback3(
11856
+ const handleStartReadingAncestry = useCallback4(
11438
11857
  async (ancestryObject) => {
11439
11858
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11440
11859
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11455,7 +11874,6 @@ function XViewScene({
11455
11874
  ancestry: ancestryObject,
11456
11875
  branchStack: [],
11457
11876
  autoAbstraction: shouldAutoRenderAbstraction
11458
- // <--- FLAG ENVIADA PARA A UI
11459
11877
  });
11460
11878
  if (shouldAutoRenderAbstraction) {
11461
11879
  handleRenderAbstractionTree(ancestryObject, null);
@@ -11469,9 +11887,8 @@ function XViewScene({
11469
11887
  }
11470
11888
  },
11471
11889
  [handleRenderAncestry, handleRenderAbstractionTree]
11472
- // <--- DEPENDÊNCIA ADICIONADA
11473
11890
  );
11474
- const handleReadModeSectionChange = useCallback3((activeSectionId) => {
11891
+ const handleReadModeSectionChange = useCallback4((activeSectionId) => {
11475
11892
  const { ancestry, branchStack } = readingMode;
11476
11893
  if (!ancestry || !readingMode.isActive) return;
11477
11894
  let targetObj = ancestry;
@@ -11540,10 +11957,10 @@ function XViewScene({
11540
11957
  }, 0);
11541
11958
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11542
11959
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
11543
- const handleCloseReadMode = useCallback3(() => {
11960
+ const handleCloseReadMode = useCallback4(() => {
11544
11961
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
11545
11962
  }, []);
11546
- const handleAncestrySectionChange = useCallback3((activeSectionId, ancestryOverride = null, rotation = 0) => {
11963
+ const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
11547
11964
  var _a2, _b2;
11548
11965
  const currentMode = stateRef.current.ancestry;
11549
11966
  let targetObj = ancestryOverride;
@@ -11595,7 +12012,7 @@ function XViewScene({
11595
12012
  const renderPayload = { ...targetObj, tree: treeToRender };
11596
12013
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
11597
12014
  }, [handleRenderAncestry]);
11598
- const handleEditAncestry = useCallback3(
12015
+ const handleEditAncestry = useCallback4(
11599
12016
  async (ancestryObject) => {
11600
12017
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11601
12018
  if (!ancestryObject || !ancestryObject.tree) {
@@ -11618,10 +12035,8 @@ function XViewScene({
11618
12035
  ...ancestryObject,
11619
12036
  tree: fullTree,
11620
12037
  abstraction_tree: fullAbstractionTree,
11621
- // NOVO
11622
12038
  selectedParentId: ancestryObject.ancestral_node,
11623
12039
  selectedAbstractionParentId: ancestryObject.ancestral_node,
11624
- // NOVO
11625
12040
  isEditMode: true,
11626
12041
  currentAncestryId: ancestryObject.ancestry_id,
11627
12042
  ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
@@ -11629,7 +12044,6 @@ function XViewScene({
11629
12044
  ancestryDescriptionSections: ancestryObject.description_sections || [],
11630
12045
  isAddingNodes: false,
11631
12046
  isAddingAbstractionNodes: false
11632
- // NOVO
11633
12047
  });
11634
12048
  },
11635
12049
  [handleRenderAncestry, buildFullAncestryTree]
@@ -11637,7 +12051,7 @@ function XViewScene({
11637
12051
  const handleSelectAncestryParent = (nodeId) => {
11638
12052
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
11639
12053
  };
11640
- const handleRemoveFromAncestry = useCallback3((pathToRemove) => {
12054
+ const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
11641
12055
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
11642
12056
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
11643
12057
  return;
@@ -11662,7 +12076,7 @@ function XViewScene({
11662
12076
  return { ...prev, tree: newTree };
11663
12077
  });
11664
12078
  }, []);
11665
- const handleSaveAncestry = useCallback3(
12079
+ const handleSaveAncestry = useCallback4(
11666
12080
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
11667
12081
  const treeToUse = treeOverride || ancestryMode.tree;
11668
12082
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -11866,7 +12280,7 @@ function XViewScene({
11866
12280
  });
11867
12281
  setEditingAncestryRel({ visible: false, data: null, path: null });
11868
12282
  };
11869
- const handleDeleteAncestry = useCallback3(
12283
+ const handleDeleteAncestry = useCallback4(
11870
12284
  async (ancestryIdToDelete) => {
11871
12285
  if (!ancestryIdToDelete) {
11872
12286
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -11928,15 +12342,15 @@ function XViewScene({
11928
12342
  },
11929
12343
  [save_view_data, delete_file_action]
11930
12344
  );
11931
- const handleOpenAncestryBoard = useCallback3(() => {
12345
+ const handleOpenAncestryBoard = useCallback4(() => {
11932
12346
  setIsAncestryBoardOpen(true);
11933
12347
  }, []);
11934
- const handleSelectAncestryFromBoard = useCallback3((ancestry) => {
12348
+ const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
11935
12349
  setIsAncestryBoardOpen(false);
11936
12350
  setIsSidebarOpen(false);
11937
12351
  handleStartReadingAncestry(ancestry);
11938
12352
  }, [handleStartReadingAncestry]);
11939
- const handleSaveAncestryBoard = useCallback3(async (groups) => {
12353
+ const handleSaveAncestryBoard = useCallback4(async (groups) => {
11940
12354
  if (!sceneConfigId || !viewParams || !session) return;
11941
12355
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
11942
12356
  await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
@@ -11960,13 +12374,13 @@ function XViewScene({
11960
12374
  return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
11961
12375
  });
11962
12376
  }, [parentDataRef.current, sceneVersion]);
11963
- const handleAddExistingNode = useCallback3(
12377
+ const handleAddExistingNode = useCallback4(
11964
12378
  (nodeId) => {
11965
12379
  return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
11966
12380
  },
11967
12381
  [actionHandlerContext]
11968
12382
  );
11969
- const handleSaveCurrentView = useCallback3(async () => {
12383
+ const handleSaveCurrentView = useCallback4(async () => {
11970
12384
  const { nodeObjects, allLinks } = stateRef.current;
11971
12385
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
11972
12386
  console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
@@ -12006,7 +12420,7 @@ function XViewScene({
12006
12420
  const allAvailableAncestries = useMemo12(() => {
12007
12421
  return ancestryDataRef.current || [];
12008
12422
  }, [sceneVersion, isInitialized]);
12009
- const handleOpenReference = useCallback3((referenceData) => {
12423
+ const handleOpenReference = useCallback4((referenceData) => {
12010
12424
  const { type, id } = referenceData;
12011
12425
  if (type === "node") {
12012
12426
  const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
@@ -12033,16 +12447,28 @@ function XViewScene({
12033
12447
  }
12034
12448
  }
12035
12449
  }, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
12036
- const handleToggleAncestryAddMode = useCallback3(() => {
12450
+ const handleToggleAncestryAddMode = useCallback4(() => {
12037
12451
  setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
12038
12452
  }, []);
12039
- const handleFocusNode = useCallback3((nodeData) => {
12453
+ const handleFocusNode = useCallback4((nodeData) => {
12040
12454
  if (!nodeData) return;
12041
12455
  const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
12042
12456
  if (nodeMesh) {
12043
12457
  tweenToTarget(nodeMesh, 1.2);
12044
12458
  }
12045
12459
  }, [tweenToTarget]);
12460
+ const availableDatasets = useMemo12(() => {
12461
+ if (!sceneDataRef.current || !parentDataRef.current) return [];
12462
+ return sceneDataRef.current.parent_dbs.map((db) => {
12463
+ var _a2;
12464
+ return {
12465
+ id: db.db_id,
12466
+ name: ((_a2 = parentDataRef.current[db.db_id]) == null ? void 0 : _a2.dataset_name) || `Dataset #${db.db_id.substring(0, 6)}`
12467
+ };
12468
+ });
12469
+ }, [sceneVersion, isInitialized]);
12470
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
12471
+ const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
12046
12472
  useEffect21(() => {
12047
12473
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
12048
12474
  const nodeObjects = stateRef.current.nodeObjects || {};
@@ -12094,7 +12520,6 @@ function XViewScene({
12094
12520
  height: "100vh",
12095
12521
  position: "relative",
12096
12522
  overflow: "hidden",
12097
- // <--- ADICIONE ESTA LINHA
12098
12523
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
12099
12524
  }
12100
12525
  },
@@ -12132,10 +12557,13 @@ function XViewScene({
12132
12557
  style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
12133
12558
  refEl: formRef,
12134
12559
  existingTypes: existingNodeTypes,
12135
- initialColor: (_b = creationMode.sourceNodeData) == null ? void 0 : _b.color,
12136
- sourceTypes: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.type,
12560
+ initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
12561
+ sourceTypes: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.type,
12137
12562
  onIntensityChange: handleGhostNodeIntensityChange,
12138
- onUploadFile: upload_file_action
12563
+ onUploadFile: upload_file_action,
12564
+ availableDatasets,
12565
+ sourceNodeDatasetId,
12566
+ viewType: viewParams == null ? void 0 : viewParams.type
12139
12567
  }
12140
12568
  ),
12141
12569
  versionMode.isActive && /* @__PURE__ */ React23.createElement(
@@ -12150,17 +12578,28 @@ function XViewScene({
12150
12578
  onMentionClick: handleAddExistingNode,
12151
12579
  style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
12152
12580
  refEl: formRef,
12153
- fixedType: (_d = versionMode.sourceNodeData) == null ? void 0 : _d.type,
12154
- fixedColor: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.color,
12581
+ fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
12582
+ fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
12155
12583
  onUploadFile: upload_file_action
12156
12584
  }
12157
12585
  ),
12158
12586
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
12159
12587
  "div",
12160
12588
  {
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)" }
12589
+ 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"}`,
12590
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
12163
12591
  },
12592
+ /* @__PURE__ */ React23.createElement(
12593
+ "div",
12594
+ {
12595
+ onPointerDown: (e) => {
12596
+ e.stopPropagation();
12597
+ handleReadModeResize(e);
12598
+ },
12599
+ className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
12600
+ title: "Arraste para redimensionar"
12601
+ }
12602
+ ),
12164
12603
  /* @__PURE__ */ React23.createElement(
12165
12604
  DescriptionReadModePanel,
12166
12605
  {
@@ -12260,7 +12699,8 @@ function XViewScene({
12260
12699
  onMentionClick: handleAddExistingNode,
12261
12700
  onIntensityChange: handleDetailNodeIntensityChange,
12262
12701
  onUploadFile: upload_file_action,
12263
- userRole: userPermissionRole
12702
+ userRole: userPermissionRole,
12703
+ currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
12264
12704
  }
12265
12705
  ),
12266
12706
  detailsLink && /* @__PURE__ */ React23.createElement(
@@ -12388,7 +12828,7 @@ function XViewScene({
12388
12828
  onClose: () => setIsImportModalOpen(false),
12389
12829
  onConfirm: handleConfirmImport,
12390
12830
  session,
12391
- parentDbs: ((_f = sceneDataRef.current) == null ? void 0 : _f.parent_dbs) || [],
12831
+ parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
12392
12832
  onFetchAvailableFiles: import_parent_file_modal_get,
12393
12833
  currentViewName: viewParams == null ? void 0 : viewParams.name,
12394
12834
  currentAncestries: ancestryDataRef.current || []