@lv-x-software-house/x_view 1.1.9-dev.1 → 1.1.9-dev.10

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 +362 -152
  2. package/dist/index.mjs +367 -155
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -2654,7 +2654,10 @@ var IGNORED_KEYS = [
2654
2654
  "isAddingNodes",
2655
2655
  "ancestryDescriptionSections",
2656
2656
  "direction",
2657
- "is_private"
2657
+ "is_private",
2658
+ "abstraction_tree",
2659
+ "selectedAbstractionParentId",
2660
+ "isAddingAbstractionNodes"
2658
2661
  ];
2659
2662
  function extractCustomPropsFromNode(node) {
2660
2663
  const customPropTypes = node._customPropTypes || {};
@@ -4428,8 +4431,69 @@ import {
4428
4431
  FiCornerUpLeft,
4429
4432
  FiCornerUpRight,
4430
4433
  FiList as FiList2,
4431
- FiAlignLeft
4434
+ FiAlignLeft,
4435
+ FiGitBranch,
4436
+ FiFolder
4432
4437
  } from "react-icons/fi";
4438
+ var findNodePath = (tree, targetNodeId, currentPath = []) => {
4439
+ var _a;
4440
+ if (!tree) return null;
4441
+ const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
4442
+ if (String(currentNodeId) === String(targetNodeId)) {
4443
+ return { node: tree, path: currentPath };
4444
+ }
4445
+ if (tree.children) {
4446
+ for (let i = 0; i < tree.children.length; i++) {
4447
+ const res = findNodePath(tree.children[i], targetNodeId, [...currentPath, i]);
4448
+ if (res) return res;
4449
+ }
4450
+ }
4451
+ return null;
4452
+ };
4453
+ var ReadOnlyNodeItem = ({ nodeData, onViewSelect, highlightedPathIds = [], targetRenderNodeId, level = 0, isLast = false }) => {
4454
+ var _a, _b;
4455
+ const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4456
+ const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4457
+ const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
4458
+ const isHighlightedPath = highlightedPathIds.includes(String(itemId));
4459
+ const hasChildren = nodeData.children && nodeData.children.length > 0;
4460
+ let itemBgClass = "bg-slate-900/50 hover:bg-slate-800/80";
4461
+ let textColorClass = "text-slate-200";
4462
+ if (nodeData.is_section) {
4463
+ itemBgClass = "bg-purple-900/20 border border-purple-500/30 hover:bg-purple-900/40";
4464
+ textColorClass = "text-purple-300";
4465
+ } else {
4466
+ if (isTargetViewNode) {
4467
+ itemBgClass = "bg-fuchsia-600/40 ring-2 ring-fuchsia-400 shadow-[0_0_15px_rgba(217,70,239,0.3)]";
4468
+ textColorClass = "text-white font-bold";
4469
+ } else if (isHighlightedPath) {
4470
+ itemBgClass = "bg-fuchsia-900/30 border border-fuchsia-500/40";
4471
+ textColorClass = "text-fuchsia-200 font-semibold";
4472
+ }
4473
+ }
4474
+ return /* @__PURE__ */ React7.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("span", { className: `absolute -left-4 top-0 w-px ${isHighlightedPath ? "bg-fuchsia-500 shadow-[0_0_8px_rgba(217,70,239,0.8)]" : "bg-cyan-600/60"} ${isLast ? "h-[1.125rem]" : "h-full"}`, "aria-hidden": "true" }), /* @__PURE__ */ React7.createElement("span", { className: `absolute -left-4 top-[1.125rem] h-px w-4 ${isHighlightedPath ? "bg-fuchsia-500 shadow-[0_0_8px_rgba(217,70,239,0.8)]" : "bg-cyan-600/60"}`, "aria-hidden": "true" })), /* @__PURE__ */ React7.createElement(
4475
+ "div",
4476
+ {
4477
+ onClick: (e) => {
4478
+ e.stopPropagation();
4479
+ if (onViewSelect) onViewSelect(itemId);
4480
+ },
4481
+ className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border border-transparent cursor-pointer ${itemBgClass}`
4482
+ },
4483
+ /* @__PURE__ */ React7.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ React7.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "mr-1.5 inline-block" }, /* @__PURE__ */ React7.createElement("circle", { cx: "9", cy: "9", r: "7" }), /* @__PURE__ */ React7.createElement("circle", { cx: "15", cy: "15", r: "7" })), nodeData.is_section && /* @__PURE__ */ React7.createElement(FiFolder, { className: "mr-2" }), itemName)
4484
+ ), hasChildren && /* @__PURE__ */ React7.createElement("div", { className: "mt-2 space-y-2 pl-8" }, nodeData.children.map((child, index) => /* @__PURE__ */ React7.createElement(
4485
+ ReadOnlyNodeItem,
4486
+ {
4487
+ key: `${child.is_section ? child.id : child.node.id}-${index}`,
4488
+ nodeData: child,
4489
+ onViewSelect,
4490
+ highlightedPathIds,
4491
+ targetRenderNodeId,
4492
+ level: level + 1,
4493
+ isLast: index === nodeData.children.length - 1
4494
+ }
4495
+ ))));
4496
+ };
4433
4497
  function DescriptionReadModePanel({
4434
4498
  title,
4435
4499
  description,
@@ -4451,14 +4515,40 @@ function DescriptionReadModePanel({
4451
4515
  backNavigationInfo,
4452
4516
  customProperties = [],
4453
4517
  onImageClick,
4454
- userRole
4455
- // <--- NOVA PROP: Recebendo a role do usuário
4518
+ userRole,
4519
+ // --- NOVAS PROPS PARA ABSTRAÇÃO ---
4520
+ abstractionTree = null,
4521
+ onRenderAbstractionTree = null
4456
4522
  }) {
4457
4523
  const [showProperties, setShowProperties] = useState7(false);
4524
+ const [showAbstraction, setShowAbstraction] = useState7(false);
4525
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState7(null);
4458
4526
  const swallow = (e) => e.stopPropagation();
4459
4527
  const hasCustomProps = customProperties && customProperties.length > 0;
4528
+ const hasAbstraction = Boolean(abstractionTree && (abstractionTree.node || abstractionTree.children && abstractionTree.children.length > 0));
4460
4529
  const ability = useMemo6(() => defineAbilityFor(userRole), [userRole]);
4461
4530
  const canEditAncestry = ability.can("update", "Ancestry");
4531
+ const highlightedPathIds = useMemo6(() => {
4532
+ var _a, _b;
4533
+ if (!targetRenderNodeId || !abstractionTree) return [];
4534
+ const found = findNodePath(abstractionTree, targetRenderNodeId);
4535
+ if (!found) return [];
4536
+ let current = abstractionTree;
4537
+ const ids = [current.is_section ? current.section_id : String((_a = current.node) == null ? void 0 : _a.id)];
4538
+ for (let i of found.path) {
4539
+ current = current.children[i];
4540
+ ids.push(current.is_section ? current.section_id : String((_b = current.node) == null ? void 0 : _b.id));
4541
+ }
4542
+ return ids;
4543
+ }, [targetRenderNodeId, abstractionTree]);
4544
+ const handleToggleProperties = () => {
4545
+ setShowProperties(!showProperties);
4546
+ if (!showProperties) setShowAbstraction(false);
4547
+ };
4548
+ const handleToggleAbstraction = () => {
4549
+ setShowAbstraction(!showAbstraction);
4550
+ if (!showAbstraction) setShowProperties(false);
4551
+ };
4462
4552
  const leftAction = useMemo6(() => {
4463
4553
  if (activeNodeBranches == null ? void 0 : activeNodeBranches.left) {
4464
4554
  return {
@@ -4503,21 +4593,38 @@ function DescriptionReadModePanel({
4503
4593
  /* @__PURE__ */ React7.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 border-b border-white/10 shrink-0 bg-slate-950/50 backdrop-blur-md z-20" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ React7.createElement(
4504
4594
  "button",
4505
4595
  {
4506
- onClick: onBack,
4596
+ onClick: () => {
4597
+ if (showAbstraction) {
4598
+ setShowAbstraction(false);
4599
+ } else if (showProperties) {
4600
+ setShowProperties(false);
4601
+ } else if (onBack) {
4602
+ onBack();
4603
+ }
4604
+ },
4507
4605
  className: "w-8 h-8 flex-shrink-0 grid place-content-center rounded-lg border border-white/10 bg-white/5 hover:bg-white/10 transition-colors text-slate-300",
4508
4606
  title: "Voltar"
4509
4607
  },
4510
4608
  /* @__PURE__ */ React7.createElement(FiArrowLeft, { size: 16 })
4511
- ), /* @__PURE__ */ React7.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React7.createElement("p", { className: "text-xs/relaxed text-slate-400 uppercase tracking-wider font-semibold" }, showProperties ? "Propriedades Adicionais" : "Modo de Leitura"), /* @__PURE__ */ React7.createElement("h2", { className: "text-lg sm:text-xl font-semibold tracking-tight text-white truncate", title }, title || "Sem T\xEDtulo"))), /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" }, hasCustomProps && /* @__PURE__ */ React7.createElement(
4609
+ ), /* @__PURE__ */ React7.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React7.createElement("p", { className: "text-xs/relaxed text-slate-400 uppercase tracking-wider font-semibold" }, showAbstraction ? "Tree de Abstra\xE7\xE3o" : showProperties ? "Propriedades Adicionais" : "Modo de Leitura"), /* @__PURE__ */ React7.createElement("h2", { className: "text-lg sm:text-xl font-semibold tracking-tight text-white truncate", title }, title || "Sem T\xEDtulo"))), /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" }, hasCustomProps && /* @__PURE__ */ React7.createElement(
4512
4610
  "button",
4513
4611
  {
4514
- onClick: () => setShowProperties(!showProperties),
4612
+ onClick: handleToggleProperties,
4515
4613
  className: `relative w-9 h-9 grid place-content-center rounded-lg border transition-colors
4516
4614
  ${showProperties ? "border-cyan-500/50 bg-cyan-500/10 text-cyan-300" : "border-white/15 bg-transparent hover:bg-white/5 text-slate-300 hover:text-white"}`,
4517
4615
  title: showProperties ? "Ver Descri\xE7\xE3o" : "Ver Propriedades Adicionais"
4518
4616
  },
4519
4617
  showProperties ? /* @__PURE__ */ React7.createElement(FiAlignLeft, { size: 16 }) : /* @__PURE__ */ React7.createElement(FiList2, { size: 16 }),
4520
- !showProperties && /* @__PURE__ */ React7.createElement("span", { className: "absolute top-1.5 right-1.5 block h-2 w-2 rounded-full bg-cyan-400 ring-2 ring-slate-900 animate-pulse" })
4618
+ !showProperties && !showAbstraction && /* @__PURE__ */ React7.createElement("span", { className: "absolute top-1.5 right-1.5 block h-2 w-2 rounded-full bg-cyan-400 ring-2 ring-slate-900 animate-pulse" })
4619
+ ), hasAbstraction && /* @__PURE__ */ React7.createElement(
4620
+ "button",
4621
+ {
4622
+ onClick: handleToggleAbstraction,
4623
+ className: `relative w-9 h-9 grid place-content-center rounded-lg border transition-colors
4624
+ ${showAbstraction ? "border-purple-500/50 bg-purple-500/10 text-purple-300" : "border-white/15 bg-transparent hover:bg-white/5 text-slate-300 hover:text-white"}`,
4625
+ title: showAbstraction ? "Voltar \xE0 Descri\xE7\xE3o" : "Ver Tree de Abstra\xE7\xE3o"
4626
+ },
4627
+ /* @__PURE__ */ React7.createElement(FiGitBranch, { size: 16 })
4521
4628
  ), onRenderFullAncestry && /* @__PURE__ */ React7.createElement(
4522
4629
  "button",
4523
4630
  {
@@ -4531,7 +4638,7 @@ function DescriptionReadModePanel({
4531
4638
  {
4532
4639
  onClick: onEdit,
4533
4640
  className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-slate-300 hover:text-white",
4534
- title: "Editar Descri\xE7\xE3o"
4641
+ title: "Editar Descri\xE7\xE3o / Estrutura"
4535
4642
  },
4536
4643
  /* @__PURE__ */ React7.createElement(FiEdit2, { size: 16 })
4537
4644
  ), /* @__PURE__ */ React7.createElement(
@@ -4543,7 +4650,40 @@ function DescriptionReadModePanel({
4543
4650
  },
4544
4651
  "\xD7"
4545
4652
  ))),
4546
- /* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10" }, showProperties ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300" }, customProperties.map((prop) => /* @__PURE__ */ React7.createElement(
4653
+ /* @__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(
4654
+ "button",
4655
+ {
4656
+ onClick: (e) => {
4657
+ e.stopPropagation();
4658
+ onRenderAbstractionTree(targetRenderNodeId);
4659
+ },
4660
+ className: "px-3 py-1.5 rounded-md bg-fuchsia-600 text-white hover:bg-fuchsia-500 transition-colors flex items-center gap-1.5 text-xs font-bold shadow-lg animate-in zoom-in-95 duration-200",
4661
+ title: "Renderiza no 3D apenas o caminho at\xE9 o Node selecionado"
4662
+ },
4663
+ /* @__PURE__ */ React7.createElement(FiLayers3, { size: 14 }),
4664
+ " Renderizar Caminho"
4665
+ ), onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
4666
+ "button",
4667
+ {
4668
+ onClick: (e) => {
4669
+ e.stopPropagation();
4670
+ setTargetRenderNodeId(null);
4671
+ onRenderAbstractionTree(null);
4672
+ },
4673
+ className: "px-3 py-1.5 rounded-md bg-slate-700 border border-white/10 text-slate-200 hover:bg-slate-600 hover:text-white transition-colors flex items-center gap-1.5 text-xs font-semibold",
4674
+ title: "Renderiza a Abstraction Tree inteira verticalmente"
4675
+ },
4676
+ /* @__PURE__ */ React7.createElement(FiLayers3, { size: 14 }),
4677
+ " Renderizar Completa"
4678
+ ))), /* @__PURE__ */ React7.createElement("div", { className: "bg-slate-900/60 border border-white/10 rounded-lg p-4" }, /* @__PURE__ */ React7.createElement(
4679
+ ReadOnlyNodeItem,
4680
+ {
4681
+ nodeData: abstractionTree,
4682
+ onViewSelect: setTargetRenderNodeId,
4683
+ highlightedPathIds,
4684
+ targetRenderNodeId
4685
+ }
4686
+ ))) : showProperties ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300" }, customProperties.map((prop) => /* @__PURE__ */ React7.createElement(
4547
4687
  CustomPropertyDisplay,
4548
4688
  {
4549
4689
  key: prop.id,
@@ -4572,7 +4712,7 @@ function DescriptionReadModePanel({
4572
4712
  onImageClick
4573
4713
  }
4574
4714
  )),
4575
- leftAction && /* @__PURE__ */ React7.createElement(
4715
+ leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
4576
4716
  "button",
4577
4717
  {
4578
4718
  onClick: leftAction.onClick,
@@ -4584,7 +4724,7 @@ function DescriptionReadModePanel({
4584
4724
  ${leftAction.type === "branch" ? "bg-indigo-500/20 text-indigo-300 group-hover/btn:text-white group-hover/btn:bg-indigo-500" : "bg-rose-500/20 text-rose-300 group-hover/btn:text-white group-hover/btn:bg-rose-500"}
4585
4725
  ` }, leftAction.type === "branch" ? /* @__PURE__ */ React7.createElement(FiChevronLeft, { size: 20 }) : /* @__PURE__ */ React7.createElement(FiCornerUpLeft, { size: 20 }))
4586
4726
  ),
4587
- rightAction && /* @__PURE__ */ React7.createElement(
4727
+ rightAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
4588
4728
  "button",
4589
4729
  {
4590
4730
  onClick: rightAction.onClick,
@@ -4761,7 +4901,7 @@ import React10, { useState as useState10, useEffect as useEffect9, useMemo as us
4761
4901
  import {
4762
4902
  FiEdit2 as FiEdit23,
4763
4903
  FiBookOpen as FiBookOpen2,
4764
- FiFolder,
4904
+ FiFolder as FiFolder2,
4765
4905
  FiMousePointer,
4766
4906
  FiCheck as FiCheck4,
4767
4907
  FiLayers as FiLayers5,
@@ -4770,7 +4910,7 @@ import {
4770
4910
  FiChevronRight as FiChevronRight4,
4771
4911
  FiCornerUpLeft as FiCornerUpLeft2,
4772
4912
  FiCornerUpRight as FiCornerUpRight3,
4773
- FiGitBranch,
4913
+ FiGitBranch as FiGitBranch2,
4774
4914
  FiPlus as FiPlus2,
4775
4915
  FiLock
4776
4916
  } from "react-icons/fi";
@@ -4852,7 +4992,7 @@ function AncestryPickerModal({
4852
4992
  }
4853
4993
 
4854
4994
  // src/components/CreateAncestryPanel.jsx
4855
- var findNodePath = (tree, targetNodeId, currentPath = []) => {
4995
+ var findNodePath2 = (tree, targetNodeId, currentPath = []) => {
4856
4996
  var _a;
4857
4997
  if (!tree) return null;
4858
4998
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
@@ -4861,22 +5001,41 @@ var findNodePath = (tree, targetNodeId, currentPath = []) => {
4861
5001
  }
4862
5002
  if (tree.children) {
4863
5003
  for (let i = 0; i < tree.children.length; i++) {
4864
- const res = findNodePath(tree.children[i], targetNodeId, [...currentPath, i]);
5004
+ const res = findNodePath2(tree.children[i], targetNodeId, [...currentPath, i]);
4865
5005
  if (res) return res;
4866
5006
  }
4867
5007
  }
4868
5008
  return null;
4869
5009
  };
4870
- var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
5010
+ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [], targetRenderNodeId, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
4871
5011
  var _a, _b;
4872
5012
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4873
5013
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4874
5014
  const [isDragOver, setIsDragOver] = useState10(false);
4875
- const isSelected = String(selectedParentId) === String(itemId);
5015
+ const isSelectedParent = String(selectedParentId) === String(itemId);
5016
+ const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
5017
+ const isHighlightedPath = highlightedPathIds.includes(String(itemId));
4876
5018
  const hasChildren = nodeData.children && nodeData.children.length > 0;
4877
- const itemBgClass = nodeData.is_section ? isSelected ? "bg-indigo-500/30 ring-2 ring-indigo-400" : "bg-indigo-900/20 border border-indigo-500/30 hover:bg-indigo-900/40" : isSelected ? "bg-cyan-500/20 ring-2 ring-cyan-400" : "bg-slate-900/50 hover:bg-slate-800/80";
4878
- const textColorClass = nodeData.is_section ? isSelected ? "text-indigo-200 font-bold" : "text-indigo-300" : isSelected ? "text-cyan-200 font-semibold" : "text-slate-200";
4879
- const cursorClass = isEditable ? "cursor-grab active:cursor-grabbing" : "cursor-default";
5019
+ let itemBgClass = "bg-slate-900/50 hover:bg-slate-800/80";
5020
+ let textColorClass = "text-slate-200";
5021
+ if (nodeData.is_section) {
5022
+ itemBgClass = isSelectedParent ? "bg-indigo-500/30 ring-2 ring-indigo-400" : "bg-indigo-900/20 border border-indigo-500/30 hover:bg-indigo-900/40";
5023
+ textColorClass = isSelectedParent ? "text-indigo-200 font-bold" : "text-indigo-300";
5024
+ } else {
5025
+ if (isSelectedParent) {
5026
+ itemBgClass = "bg-purple-500/30 ring-2 ring-purple-400";
5027
+ textColorClass = "text-purple-200 font-semibold";
5028
+ } else if (isTargetViewNode) {
5029
+ itemBgClass = "bg-fuchsia-600/40 ring-2 ring-fuchsia-400 shadow-[0_0_15px_rgba(217,70,239,0.3)]";
5030
+ textColorClass = "text-white font-bold";
5031
+ } else if (isHighlightedPath) {
5032
+ itemBgClass = "bg-fuchsia-900/30 border border-fuchsia-500/40";
5033
+ textColorClass = "text-fuchsia-200 font-semibold";
5034
+ } else {
5035
+ textColorClass = "text-slate-200";
5036
+ }
5037
+ }
5038
+ const cursorClass = isEditable ? "cursor-grab active:cursor-grabbing" : "cursor-pointer";
4880
5039
  const handleDragStart = (e) => {
4881
5040
  if (!isEditable) {
4882
5041
  e.preventDefault();
@@ -4906,23 +5065,9 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4906
5065
  if (!isEditable) return;
4907
5066
  const sourceId = e.dataTransfer.getData("nodeId");
4908
5067
  if (sourceId === String(itemId)) return;
4909
- if (onMoveNode) {
4910
- onMoveNode(sourceId, itemId);
4911
- }
5068
+ if (onMoveNode) onMoveNode(sourceId, itemId);
4912
5069
  };
4913
- return /* @__PURE__ */ React10.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
4914
- "span",
4915
- {
4916
- className: `absolute -left-4 top-0 w-px bg-cyan-600/60 ${isLast ? "h-[1.125rem]" : "h-full"}`,
4917
- "aria-hidden": "true"
4918
- }
4919
- ), /* @__PURE__ */ React10.createElement(
4920
- "span",
4921
- {
4922
- className: `absolute -left-4 top-[1.125rem] h-px w-4 bg-cyan-600/60`,
4923
- "aria-hidden": "true"
4924
- }
4925
- )), /* @__PURE__ */ React10.createElement(
5070
+ return /* @__PURE__ */ React10.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement("span", { className: `absolute -left-4 top-0 w-px ${isHighlightedPath ? "bg-fuchsia-500 shadow-[0_0_8px_rgba(217,70,239,0.8)]" : "bg-cyan-600/60"} ${isLast ? "h-[1.125rem]" : "h-full"}`, "aria-hidden": "true" }), /* @__PURE__ */ React10.createElement("span", { className: `absolute -left-4 top-[1.125rem] h-px w-4 ${isHighlightedPath ? "bg-fuchsia-500 shadow-[0_0_8px_rgba(217,70,239,0.8)]" : "bg-cyan-600/60"}`, "aria-hidden": "true" })), /* @__PURE__ */ React10.createElement(
4926
5071
  "div",
4927
5072
  {
4928
5073
  draggable: isEditable,
@@ -4930,63 +5075,35 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4930
5075
  onDragOver: handleDragOver,
4931
5076
  onDragLeave: handleDragLeave,
4932
5077
  onDrop: handleDrop,
4933
- onClick: () => {
5078
+ onClick: (e) => {
5079
+ e.stopPropagation();
4934
5080
  if (isEditable) {
4935
5081
  onSelectParent(itemId);
5082
+ } else if (onViewSelect) {
5083
+ onViewSelect(itemId);
4936
5084
  }
4937
5085
  },
4938
5086
  className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border
4939
5087
  ${isDragOver ? "border-dashed border-yellow-400 bg-yellow-400/10" : "border-transparent"}
4940
5088
  ${itemBgClass} ${cursorClass}`
4941
5089
  },
4942
- /* @__PURE__ */ React10.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ React10.createElement(
4943
- "svg",
4944
- {
4945
- xmlns: "http://www.w3.org/2000/svg",
4946
- width: "16",
4947
- height: "16",
4948
- viewBox: "0 0 24 24",
4949
- fill: "none",
4950
- stroke: "currentColor",
4951
- strokeWidth: "2",
4952
- strokeLinecap: "round",
4953
- strokeLinejoin: "round",
4954
- className: "lucide lucide-blend-icon lucide-blend mr-1.5 inline-block"
4955
- },
4956
- /* @__PURE__ */ React10.createElement("circle", { cx: "9", cy: "9", r: "7" }),
4957
- /* @__PURE__ */ React10.createElement("circle", { cx: "15", cy: "15", r: "7" })
4958
- ), nodeData.is_section && /* @__PURE__ */ React10.createElement(FiFolder, { className: "mr-2" }), itemName),
4959
- level > 0 && isEditable && /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1 animate-in fade-in duration-200" }, !nodeData.is_section && /* @__PURE__ */ React10.createElement(
4960
- "button",
4961
- {
4962
- onClick: (e) => {
4963
- e.stopPropagation();
4964
- onEditRelationship(path, nodeData.relationship || {});
4965
- },
4966
- className: "w-6 h-6 grid place-content-center rounded-full hover:bg-cyan-500/20 text-cyan-400 transition-colors flex-shrink-0",
4967
- title: "Editar detalhes da rela\xE7\xE3o",
4968
- style: { cursor: "pointer" }
4969
- },
4970
- /* @__PURE__ */ React10.createElement(FiEdit23, { size: 12 })
4971
- ), /* @__PURE__ */ React10.createElement(
4972
- "button",
4973
- {
4974
- onClick: (e) => {
4975
- e.stopPropagation();
4976
- onRemoveNode(path);
4977
- },
4978
- className: "w-6 h-6 grid place-content-center rounded-full hover:bg-red-500/20 text-red-400 text-lg transition-colors flex-shrink-0",
4979
- title: "Remover Node da ancestralidade",
4980
- style: { cursor: "pointer" }
4981
- },
4982
- "\xD7"
4983
- ))
5090
+ /* @__PURE__ */ React10.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ React10.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "mr-1.5 inline-block" }, /* @__PURE__ */ React10.createElement("circle", { cx: "9", cy: "9", r: "7" }), /* @__PURE__ */ React10.createElement("circle", { cx: "15", cy: "15", r: "7" })), nodeData.is_section && /* @__PURE__ */ React10.createElement(FiFolder2, { className: "mr-2" }), itemName),
5091
+ level > 0 && isEditable && /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1 animate-in fade-in duration-200" }, !nodeData.is_section && /* @__PURE__ */ React10.createElement("button", { onClick: (e) => {
5092
+ e.stopPropagation();
5093
+ onEditRelationship(path, nodeData.relationship || {});
5094
+ }, className: "w-6 h-6 grid place-content-center rounded-full hover:bg-cyan-500/20 text-cyan-400 transition-colors flex-shrink-0", title: "Editar detalhes da rela\xE7\xE3o" }, /* @__PURE__ */ React10.createElement(FiEdit23, { size: 12 })), /* @__PURE__ */ React10.createElement("button", { onClick: (e) => {
5095
+ e.stopPropagation();
5096
+ onRemoveNode(path);
5097
+ }, className: "w-6 h-6 grid place-content-center rounded-full hover:bg-red-500/20 text-red-400 text-lg transition-colors flex-shrink-0", title: "Remover Node" }, "\xD7"))
4984
5098
  ), hasChildren && /* @__PURE__ */ React10.createElement("div", { className: "mt-2 space-y-2 pl-8" }, nodeData.children.map((child, index) => /* @__PURE__ */ React10.createElement(
4985
5099
  NodeItem,
4986
5100
  {
4987
5101
  key: `${child.is_section ? child.id : child.node.id}-${index}`,
4988
5102
  nodeData: child,
4989
5103
  onSelectParent,
5104
+ onViewSelect,
5105
+ highlightedPathIds,
5106
+ targetRenderNodeId,
4990
5107
  onRemoveNode,
4991
5108
  onEditRelationship,
4992
5109
  onMoveNode,
@@ -5001,11 +5118,8 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
5001
5118
  function CreateAncestryPanel({
5002
5119
  ancestryMode,
5003
5120
  setAncestryMode,
5004
- // <--- Nova prop necessária para as novas funções manipuladoras
5005
5121
  onSelectParent,
5006
- // Mantido para compatibilidade, mas as novas funções usam setAncestryMode
5007
5122
  onRemoveNode,
5008
- // Mantido para compatibilidade
5009
5123
  onSave,
5010
5124
  onClose,
5011
5125
  onEditRelationship,
@@ -5016,14 +5130,12 @@ function CreateAncestryPanel({
5016
5130
  onUpdateTree,
5017
5131
  onAncestrySectionChange,
5018
5132
  onToggleAddNodes,
5019
- // Mantido para compatibilidade
5020
5133
  onRenderFullAncestry,
5021
5134
  onHighlightNode,
5022
5135
  onClearAncestryVisuals,
5023
5136
  onUploadFile,
5024
5137
  onOpenImageViewer,
5025
5138
  onRenderAbstractionTree
5026
- // <--- Nova prop recebida
5027
5139
  }) {
5028
5140
  const {
5029
5141
  tree: rootTree,
@@ -5040,6 +5152,20 @@ function CreateAncestryPanel({
5040
5152
  const [customProps, setCustomProps] = useState10([]);
5041
5153
  const propsEndRef = useRef8(null);
5042
5154
  const [branchStack, setBranchStack] = useState10([]);
5155
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState10(null);
5156
+ const highlightedPathIds = useMemo8(() => {
5157
+ var _a, _b;
5158
+ if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
5159
+ const found = findNodePath2(ancestryMode.abstraction_tree, targetRenderNodeId);
5160
+ if (!found) return [];
5161
+ let current = ancestryMode.abstraction_tree;
5162
+ const ids = [current.is_section ? current.section_id : String((_a = current.node) == null ? void 0 : _a.id)];
5163
+ for (let i of found.path) {
5164
+ current = current.children[i];
5165
+ ids.push(current.is_section ? current.section_id : String((_b = current.node) == null ? void 0 : _b.id));
5166
+ }
5167
+ return ids;
5168
+ }, [targetRenderNodeId, ancestryMode.abstraction_tree]);
5043
5169
  const [targetScrollSectionId, setTargetScrollSectionId] = useState10(null);
5044
5170
  const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState10(null);
5045
5171
  const [ancestryName, setAncestryName] = useState10(initialName);
@@ -5063,6 +5189,9 @@ function CreateAncestryPanel({
5063
5189
  setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
5064
5190
  };
5065
5191
  const handleToggleAddMode = (isAbstraction = false) => {
5192
+ if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
5193
+ setTargetRenderNodeId(null);
5194
+ }
5066
5195
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5067
5196
  };
5068
5197
  const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
@@ -5094,7 +5223,7 @@ function CreateAncestryPanel({
5094
5223
  if (!isAbstraction && branchStack.length > 0) {
5095
5224
  let ptr = rootTreeClone;
5096
5225
  for (const step of branchStack) {
5097
- const found = findNodePath(ptr, step.nodeId);
5226
+ const found = findNodePath2(ptr, step.nodeId);
5098
5227
  if (found && found.node.parallel_branches) {
5099
5228
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5100
5229
  if (branch) ptr = branch.tree;
@@ -5144,14 +5273,15 @@ function CreateAncestryPanel({
5144
5273
  }
5145
5274
  }
5146
5275
  };
5147
- const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal) => {
5276
+ const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal, abstractionTree = null) => {
5148
5277
  return {
5149
5278
  tree: JSON.stringify(tree),
5150
5279
  name,
5151
5280
  description: desc || "",
5152
5281
  sections: JSON.stringify(sections || []),
5153
5282
  customProps: JSON.stringify(customProps2 || []),
5154
- isPrivate: isPrivateVal
5283
+ isPrivate: isPrivateVal,
5284
+ abstractionTree: JSON.stringify(abstractionTree)
5155
5285
  };
5156
5286
  };
5157
5287
  const getCurrentContext = () => {
@@ -5170,7 +5300,7 @@ function CreateAncestryPanel({
5170
5300
  let currentBranch = null;
5171
5301
  let currentDirection = null;
5172
5302
  for (const step of branchStack) {
5173
- const found = findNodePath(currentTreePtr, step.nodeId);
5303
+ const found = findNodePath2(currentTreePtr, step.nodeId);
5174
5304
  if (!found || !found.node.parallel_branches) return null;
5175
5305
  currentBranch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5176
5306
  if (!currentBranch) return null;
@@ -5252,7 +5382,7 @@ function CreateAncestryPanel({
5252
5382
  let ptr = ancestryMode.tree;
5253
5383
  let foundBranch = null;
5254
5384
  for (const step of branchStack) {
5255
- const found = findNodePath(ptr, step.nodeId);
5385
+ const found = findNodePath2(ptr, step.nodeId);
5256
5386
  if (found && found.node.parallel_branches) {
5257
5387
  foundBranch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5258
5388
  if (foundBranch) ptr = foundBranch.tree;
@@ -5285,7 +5415,8 @@ function CreateAncestryPanel({
5285
5415
  ancestryMode.ancestryDescription,
5286
5416
  ancestryMode.ancestryDescriptionSections,
5287
5417
  extractedProps,
5288
- ancestryMode.is_private
5418
+ ancestryMode.is_private,
5419
+ ancestryMode.abstraction_tree
5289
5420
  ));
5290
5421
  } else if (ctx) {
5291
5422
  setLastSavedSnapshot(takeSnapshot(
@@ -5294,7 +5425,8 @@ function CreateAncestryPanel({
5294
5425
  ctx.description,
5295
5426
  ctx.sections,
5296
5427
  extractedProps,
5297
- isPrivate
5428
+ isPrivate,
5429
+ ancestryMode.abstraction_tree
5298
5430
  ));
5299
5431
  }
5300
5432
  }, [branchStack, ancestryMode]);
@@ -5309,7 +5441,7 @@ function CreateAncestryPanel({
5309
5441
  let ptr = rootTreeClone;
5310
5442
  let targetBranch = null;
5311
5443
  for (const step of branchStack) {
5312
- const found = findNodePath(ptr, step.nodeId);
5444
+ const found = findNodePath2(ptr, step.nodeId);
5313
5445
  if (found && found.node.parallel_branches) {
5314
5446
  targetBranch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5315
5447
  if (targetBranch) ptr = targetBranch.tree;
@@ -5337,7 +5469,7 @@ function CreateAncestryPanel({
5337
5469
  rootTreeClone,
5338
5470
  rootExtras
5339
5471
  );
5340
- setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate));
5472
+ setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate, ancestryMode.abstraction_tree));
5341
5473
  if (onRenderFullAncestry) {
5342
5474
  const fullTreePayload = {
5343
5475
  ancestry_id: ancestryMode.currentAncestryId || "temp_root",
@@ -5367,14 +5499,14 @@ function CreateAncestryPanel({
5367
5499
  let ptr = rootTreeClone;
5368
5500
  for (let i = 0; i < branchStack.length - 1; i++) {
5369
5501
  const step = branchStack[i];
5370
- const found = findNodePath(ptr, step.nodeId);
5502
+ const found = findNodePath2(ptr, step.nodeId);
5371
5503
  if (found && found.node.parallel_branches) {
5372
5504
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5373
5505
  if (branch) ptr = branch.tree;
5374
5506
  }
5375
5507
  }
5376
5508
  const currentStep = branchStack[branchStack.length - 1];
5377
- const foundParentPath = findNodePath(ptr, currentStep.nodeId);
5509
+ const foundParentPath = findNodePath2(ptr, currentStep.nodeId);
5378
5510
  if (foundParentPath && foundParentPath.node && foundParentPath.node.parallel_branches) {
5379
5511
  const branchIndex = foundParentPath.node.parallel_branches.findIndex((b) => b.id === currentStep.branchId);
5380
5512
  if (branchIndex !== -1) {
@@ -5398,7 +5530,8 @@ function CreateAncestryPanel({
5398
5530
  ancestryMode.ancestryDescription,
5399
5531
  ancestryMode.ancestryDescriptionSections,
5400
5532
  currentRootProps,
5401
- isPrivate
5533
+ isPrivate,
5534
+ ancestryMode.abstraction_tree
5402
5535
  ));
5403
5536
  if (onClearAncestryVisuals) {
5404
5537
  onClearAncestryVisuals(currentStep.branchId);
@@ -5417,7 +5550,7 @@ function CreateAncestryPanel({
5417
5550
  const actions = { left: null, right: null };
5418
5551
  const isInBranch = branchStack.length > 0;
5419
5552
  if (internalHighlightedNodeId) {
5420
- const found = findNodePath(activeTree, internalHighlightedNodeId);
5553
+ const found = findNodePath2(activeTree, internalHighlightedNodeId);
5421
5554
  if (found && found.node) {
5422
5555
  const branches = found.node.parallel_branches || [];
5423
5556
  const leftBranch = branches.find((b) => (b.direction || "right") === "left");
@@ -5469,7 +5602,7 @@ function CreateAncestryPanel({
5469
5602
  if (branchStack.length > 0) {
5470
5603
  let ptr = rootTreeClone;
5471
5604
  for (const step of branchStack) {
5472
- const found = findNodePath(ptr, step.nodeId);
5605
+ const found = findNodePath2(ptr, step.nodeId);
5473
5606
  if (found && found.node.parallel_branches) {
5474
5607
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5475
5608
  if (branch) ptr = branch.tree;
@@ -5587,6 +5720,11 @@ function CreateAncestryPanel({
5587
5720
  const sectionsChanged = JSON.stringify(existingSections) !== lastSavedSnapshot.sections;
5588
5721
  const propsChanged = JSON.stringify(customProps) !== lastSavedSnapshot.customProps;
5589
5722
  const privateChanged = isPrivate !== lastSavedSnapshot.isPrivate;
5723
+ let abstractionTreeChanged = false;
5724
+ if (branchStack.length === 0) {
5725
+ const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
5726
+ abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
5727
+ }
5590
5728
  return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
5591
5729
  }, [
5592
5730
  ancestryName,
@@ -5596,6 +5734,7 @@ function CreateAncestryPanel({
5596
5734
  branchStack,
5597
5735
  lastSavedSnapshot,
5598
5736
  ancestryMode.tree,
5737
+ ancestryMode.abstraction_tree,
5599
5738
  customProps,
5600
5739
  isPrivate
5601
5740
  ]);
@@ -5609,7 +5748,7 @@ function CreateAncestryPanel({
5609
5748
  let parentTreePtr = rootTree;
5610
5749
  let parentBranch = null;
5611
5750
  for (const step of parentStack) {
5612
- const found = findNodePath(parentTreePtr, step.nodeId);
5751
+ const found = findNodePath2(parentTreePtr, step.nodeId);
5613
5752
  if (found && found.node.parallel_branches) {
5614
5753
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5615
5754
  if (branch) {
@@ -5687,7 +5826,7 @@ function CreateAncestryPanel({
5687
5826
  const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode.tree));
5688
5827
  let ptr = rootTreeClone;
5689
5828
  for (const step of branchStack) {
5690
- const foundParent = findNodePath(ptr, step.nodeId);
5829
+ const foundParent = findNodePath2(ptr, step.nodeId);
5691
5830
  if (foundParent && foundParent.node && foundParent.node.parallel_branches) {
5692
5831
  const existingBranch = foundParent.node.parallel_branches.find((b) => b.id === step.branchId);
5693
5832
  if (existingBranch) {
@@ -5695,7 +5834,7 @@ function CreateAncestryPanel({
5695
5834
  }
5696
5835
  }
5697
5836
  }
5698
- const found = findNodePath(ptr, nodeId);
5837
+ const found = findNodePath2(ptr, nodeId);
5699
5838
  if (!found) {
5700
5839
  console.error("Node alvo n\xE3o encontrado no contexto atual.");
5701
5840
  return;
@@ -5808,7 +5947,7 @@ function CreateAncestryPanel({
5808
5947
  let ptr = updatedRootTree;
5809
5948
  let targetBranch = null;
5810
5949
  for (const step of branchStack) {
5811
- const found = findNodePath(ptr, step.nodeId);
5950
+ const found = findNodePath2(ptr, step.nodeId);
5812
5951
  if (found && found.node.parallel_branches) {
5813
5952
  targetBranch = found.node.parallel_branches.find((b) => b.id === step.branchId);
5814
5953
  if (targetBranch) ptr = targetBranch.tree;
@@ -5838,7 +5977,8 @@ function CreateAncestryPanel({
5838
5977
  currentInputDesc,
5839
5978
  processedSections,
5840
5979
  customProps,
5841
- isPrivate
5980
+ isPrivate,
5981
+ ancestryMode.abstraction_tree
5842
5982
  ));
5843
5983
  if (onRenderFullAncestry) {
5844
5984
  const rotation = branchStack.reduce((acc, step) => {
@@ -5897,7 +6037,8 @@ function CreateAncestryPanel({
5897
6037
  currentInputDesc,
5898
6038
  processedSections,
5899
6039
  customProps,
5900
- isPrivate
6040
+ isPrivate,
6041
+ ancestryMode.abstraction_tree
5901
6042
  ));
5902
6043
  if (!keepOpen) onClose();
5903
6044
  } finally {
@@ -5950,7 +6091,9 @@ function CreateAncestryPanel({
5950
6091
  const node = findNode(activeTree, selectedParentId);
5951
6092
  return node ? node.name : "Nenhum";
5952
6093
  };
5953
- const hasChildren = activeTree && activeTree.children && activeTree.children.length > 0;
6094
+ const hasMainChildren = activeTree && activeTree.children && activeTree.children.length > 0;
6095
+ const hasAbstractionChildren = branchStack.length === 0 && ancestryMode.abstraction_tree && ancestryMode.abstraction_tree.children && ancestryMode.abstraction_tree.children.length > 0;
6096
+ const canSave = hasMainChildren || hasAbstractionChildren;
5954
6097
  const handleSectionChangeWrapper = (sectionId) => {
5955
6098
  const ctx = getCurrentContext();
5956
6099
  const currentDesc = ctx ? ctx.description : description;
@@ -6153,7 +6296,7 @@ function CreateAncestryPanel({
6153
6296
  unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type),
6154
6297
  onUploadFile
6155
6298
  }
6156
- )), /* @__PURE__ */ React10.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React10.createElement("div", { className: `rounded-lg border transition-all duration-300 overflow-hidden ${isAddingNodes ? "border-cyan-500/40 bg-slate-900/60 ring-1 ring-cyan-500/20" : "border-white/10 bg-slate-800/60"}` }, /* @__PURE__ */ React10.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${isAddingNodes ? "bg-cyan-900/20 border-cyan-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${isAddingNodes ? "text-cyan-300" : "text-slate-400"}` }, "Estrutura ", branchStack.length > 0 && "(Aba)"), isAddingNodes && /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] bg-cyan-500/20 text-cyan-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React10.createElement(
6299
+ )), /* @__PURE__ */ React10.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React10.createElement("div", { className: `rounded-lg border transition-all duration-300 overflow-hidden ${isAddingNodes ? "border-cyan-500/40 bg-slate-900/60 ring-1 ring-cyan-500/20" : "border-white/10 bg-slate-800/60"}` }, /* @__PURE__ */ React10.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${isAddingNodes ? "bg-cyan-900/20 border-cyan-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${isAddingNodes ? "text-cyan-300" : "text-slate-400"}` }, "TREE DE ANCESTRALIDADE ", branchStack.length > 0 && "(Aba)"), isAddingNodes && /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] bg-cyan-500/20 text-cyan-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React10.createElement(
6157
6300
  "button",
6158
6301
  {
6159
6302
  type: "button",
@@ -6184,44 +6327,77 @@ function CreateAncestryPanel({
6184
6327
  path: [],
6185
6328
  isEditable: isAddingNodes
6186
6329
  }
6187
- ), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ React10.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && ancestryMode.abstraction_tree && /* @__PURE__ */ React10.createElement("div", { className: `mt-6 rounded-lg border transition-all duration-300 overflow-hidden ${ancestryMode.isAddingAbstractionNodes ? "border-purple-500/40 bg-slate-900/60 ring-1 ring-purple-500/20" : "border-white/10 bg-slate-800/60"}` }, /* @__PURE__ */ React10.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-900/20 border-purple-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${ancestryMode.isAddingAbstractionNodes ? "text-purple-300" : "text-slate-400"}` }, "Estrutura de Abstra\xE7\xE3o"), ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React10.createElement(
6188
- "button",
6189
- {
6190
- type: "button",
6191
- onClick: () => {
6192
- const tempPayload = {
6193
- ancestry_id: currentAncestryId || "temp_rendering",
6194
- abstraction_tree: ancestryMode.abstraction_tree
6195
- };
6196
- if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6197
- },
6198
- className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6199
- title: "Renderizar Verticalmente no Cen\xE1rio"
6200
- },
6201
- /* @__PURE__ */ React10.createElement(FiLayers5, { size: 14 })
6202
- ), /* @__PURE__ */ React10.createElement(
6203
- "button",
6330
+ ), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ React10.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && ancestryMode.abstraction_tree && /* @__PURE__ */ React10.createElement(
6331
+ "div",
6204
6332
  {
6205
- onClick: () => handleToggleAddMode(true),
6206
- className: `p-1.5 rounded-md transition-colors ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-500 text-white shadow-lg shadow-purple-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
6207
- title: "Editar estrutura da abstra\xE7\xE3o"
6333
+ className: `mt-6 rounded-lg border transition-all duration-300 overflow-hidden ${ancestryMode.isAddingAbstractionNodes ? "border-purple-500/40 bg-slate-900/60 ring-1 ring-purple-500/20" : "border-white/10 bg-slate-800/60"}`,
6334
+ onClick: () => setTargetRenderNodeId(null)
6208
6335
  },
6209
- ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ React10.createElement(FiCheck4, { size: 14 }) : /* @__PURE__ */ React10.createElement(FiEdit23, { size: 14 })
6210
- ))), /* @__PURE__ */ React10.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("div", { className: "mb-3 p-2 rounded bg-purple-900/20 border border-purple-500/20 text-xs text-purple-200 flex items-start gap-2" }, /* @__PURE__ */ React10.createElement(FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ React10.createElement(
6211
- NodeItem,
6212
- {
6213
- nodeData: ancestryMode.abstraction_tree,
6214
- onSelectParent: (id) => handleSelectAncestryParent(id, true),
6215
- onRemoveNode: (path) => handleRemoveNode(path, true),
6216
- onEditRelationship,
6217
- onMoveNode: (s, t) => handleMoveNode(s, t, true),
6218
- selectedParentId: ancestryMode.selectedAbstractionParentId,
6219
- level: 0,
6220
- isLast: true,
6221
- path: [],
6222
- isEditable: ancestryMode.isAddingAbstractionNodes
6223
- }
6224
- ))), branchStack.length === 0 && /* @__PURE__ */ React10.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ React10.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ React10.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${isPrivate ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, isPrivate && /* @__PURE__ */ React10.createElement(FiCheck4, { size: 12, className: "text-white" })), /* @__PURE__ */ React10.createElement(
6336
+ /* @__PURE__ */ React10.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-900/20 border-purple-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${ancestryMode.isAddingAbstractionNodes ? "text-purple-300" : "text-slate-400"}` }, "Tree de Abstra\xE7\xE3o"), ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, targetRenderNodeId && !ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement(
6337
+ "button",
6338
+ {
6339
+ type: "button",
6340
+ onClick: (e) => {
6341
+ e.stopPropagation();
6342
+ const tempPayload = {
6343
+ ancestry_id: currentAncestryId || "temp_rendering",
6344
+ abstraction_tree: ancestryMode.abstraction_tree
6345
+ };
6346
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload, targetRenderNodeId);
6347
+ },
6348
+ className: "px-2 py-1.5 rounded-md bg-fuchsia-600 text-white hover:bg-fuchsia-500 transition-colors flex items-center gap-1 shadow-lg animate-in fade-in zoom-in",
6349
+ title: "Renderizar cen\xE1rio at\xE9 o caminho selecionado"
6350
+ },
6351
+ /* @__PURE__ */ React10.createElement(FiLayers5, { size: 13 }),
6352
+ /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] font-bold uppercase tracking-wider" }, "Renderizar")
6353
+ ), /* @__PURE__ */ React10.createElement(
6354
+ "button",
6355
+ {
6356
+ type: "button",
6357
+ onClick: (e) => {
6358
+ e.stopPropagation();
6359
+ const tempPayload = {
6360
+ ancestry_id: currentAncestryId || "temp_rendering",
6361
+ abstraction_tree: ancestryMode.abstraction_tree
6362
+ };
6363
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6364
+ },
6365
+ className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6366
+ title: "Renderizar Verticalmente Completo"
6367
+ },
6368
+ /* @__PURE__ */ React10.createElement(FiLayers5, { size: 14 })
6369
+ ), /* @__PURE__ */ React10.createElement(
6370
+ "button",
6371
+ {
6372
+ type: "button",
6373
+ onClick: (e) => {
6374
+ e.stopPropagation();
6375
+ handleToggleAddMode(true);
6376
+ },
6377
+ className: `p-1.5 rounded-md transition-colors ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-500 text-white shadow-lg shadow-purple-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
6378
+ title: "Editar estrutura da abstra\xE7\xE3o"
6379
+ },
6380
+ ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ React10.createElement(FiCheck4, { size: 14 }) : /* @__PURE__ */ React10.createElement(FiEdit23, { size: 14 })
6381
+ ))),
6382
+ /* @__PURE__ */ React10.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("div", { className: "mb-3 p-2 rounded bg-purple-900/20 border border-purple-500/20 text-xs text-purple-200 flex items-start gap-2" }, /* @__PURE__ */ React10.createElement(FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ React10.createElement(
6383
+ NodeItem,
6384
+ {
6385
+ nodeData: ancestryMode.abstraction_tree,
6386
+ onSelectParent: (id) => handleSelectAncestryParent(id, true),
6387
+ onViewSelect: setTargetRenderNodeId,
6388
+ highlightedPathIds,
6389
+ targetRenderNodeId,
6390
+ onRemoveNode: (path) => handleRemoveNode(path, true),
6391
+ onEditRelationship,
6392
+ onMoveNode: (s, t) => handleMoveNode(s, t, true),
6393
+ selectedParentId: ancestryMode.selectedAbstractionParentId,
6394
+ level: 0,
6395
+ isLast: true,
6396
+ path: [],
6397
+ isEditable: ancestryMode.isAddingAbstractionNodes
6398
+ }
6399
+ ))
6400
+ ), branchStack.length === 0 && /* @__PURE__ */ React10.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ React10.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ React10.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${isPrivate ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, isPrivate && /* @__PURE__ */ React10.createElement(FiCheck4, { size: 12, className: "text-white" })), /* @__PURE__ */ React10.createElement(
6225
6401
  "input",
6226
6402
  {
6227
6403
  type: "checkbox",
@@ -6229,7 +6405,7 @@ function CreateAncestryPanel({
6229
6405
  onChange: (e) => setIsPrivate(e.target.checked),
6230
6406
  className: "hidden"
6231
6407
  }
6232
- ), /* @__PURE__ */ React10.createElement("span", { className: `text-xs flex items-center gap-1 transition-colors ${isPrivate ? "text-indigo-300" : "text-slate-400 group-hover:text-slate-300"}` }, /* @__PURE__ */ React10.createElement(FiLock, { size: 10 }), " N\xE3o Export\xE1vel"))))), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pt-2 pb-5 flex-shrink-0" }, hasChildren && /* @__PURE__ */ React10.createElement(
6408
+ ), /* @__PURE__ */ React10.createElement("span", { className: `text-xs flex items-center gap-1 transition-colors ${isPrivate ? "text-indigo-300" : "text-slate-400 group-hover:text-slate-300"}` }, /* @__PURE__ */ React10.createElement(FiLock, { size: 10 }), " N\xE3o Export\xE1vel"))))), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pt-2 pb-5 flex-shrink-0" }, canSave && /* @__PURE__ */ React10.createElement(
6233
6409
  "button",
6234
6410
  {
6235
6411
  onClick: () => handleLocalSave(false),
@@ -8752,7 +8928,7 @@ var getAllNodeIdsFromTree = (treeNode) => {
8752
8928
  traverse(treeNode);
8753
8929
  return Array.from(ids);
8754
8930
  };
8755
- var findNodePath2 = (tree, targetNodeId, currentPath = []) => {
8931
+ var findNodePath3 = (tree, targetNodeId, currentPath = []) => {
8756
8932
  var _a;
8757
8933
  if (!tree) return null;
8758
8934
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
@@ -8761,7 +8937,7 @@ var findNodePath2 = (tree, targetNodeId, currentPath = []) => {
8761
8937
  }
8762
8938
  if (tree.children) {
8763
8939
  for (let i = 0; i < tree.children.length; i++) {
8764
- const res = findNodePath2(tree.children[i], targetNodeId, [...currentPath, i]);
8940
+ const res = findNodePath3(tree.children[i], targetNodeId, [...currentPath, i]);
8765
8941
  if (res) return res;
8766
8942
  }
8767
8943
  }
@@ -10830,13 +11006,34 @@ function XViewScene({
10830
11006
  },
10831
11007
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
10832
11008
  );
10833
- const handleRenderAbstractionTree = useCallback3((ancestryObject) => {
11009
+ const handleRenderAbstractionTree = useCallback3((ancestryObject, targetNodeId = null) => {
10834
11010
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10835
11011
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
10836
11012
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
10837
11013
  const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
10838
- const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
11014
+ let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10839
11015
  if (!fullTree || !fullTree.node) return;
11016
+ if (targetNodeId) {
11017
+ const pruneTreeToPath = (treeNode, targetId) => {
11018
+ var _a2;
11019
+ if (!treeNode) return null;
11020
+ const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
11021
+ if (String(currentId) === String(targetId)) {
11022
+ return { ...treeNode, children: [] };
11023
+ }
11024
+ if (treeNode.children && treeNode.children.length > 0) {
11025
+ for (let child of treeNode.children) {
11026
+ const prunedChild = pruneTreeToPath(child, targetId);
11027
+ if (prunedChild) {
11028
+ return { ...treeNode, children: [prunedChild] };
11029
+ }
11030
+ }
11031
+ }
11032
+ return null;
11033
+ };
11034
+ const pruned = pruneTreeToPath(fullTree, targetNodeId);
11035
+ if (pruned) fullTree = pruned;
11036
+ }
10840
11037
  const absId = ancestryObject.ancestry_id + "_abs";
10841
11038
  handleClearAncestryVisuals(absId);
10842
11039
  const colorHex = 9133302;
@@ -10878,13 +11075,13 @@ function XViewScene({
10878
11075
  if (action === "open") {
10879
11076
  let currentPtr = fullTree;
10880
11077
  for (const step of branchStack) {
10881
- const found = findNodePath2(currentPtr, step.nodeId);
11078
+ const found = findNodePath3(currentPtr, step.nodeId);
10882
11079
  if (found && found.node.parallel_branches) {
10883
11080
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
10884
11081
  if (branch) currentPtr = branch.tree;
10885
11082
  }
10886
11083
  }
10887
- const foundTarget = findNodePath2(currentPtr, nodeId);
11084
+ const foundTarget = findNodePath3(currentPtr, nodeId);
10888
11085
  if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
10889
11086
  const branchToOpen = foundTarget.node.parallel_branches.find((b) => (b.direction || "right") === direction);
10890
11087
  if (!branchToOpen) return;
@@ -10951,7 +11148,7 @@ function XViewScene({
10951
11148
  if (newStack.length > 0) {
10952
11149
  let ptr = fullTree;
10953
11150
  for (const step of newStack) {
10954
- const found = findNodePath2(ptr, step.nodeId);
11151
+ const found = findNodePath3(ptr, step.nodeId);
10955
11152
  if (found && found.node.parallel_branches) {
10956
11153
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
10957
11154
  if (branch) {
@@ -11092,7 +11289,7 @@ function XViewScene({
11092
11289
  let currentMeta = ancestry;
11093
11290
  let currentDirection = null;
11094
11291
  for (const step of branchStack) {
11095
- const found = findNodePath2(currentPtr, step.nodeId);
11292
+ const found = findNodePath3(currentPtr, step.nodeId);
11096
11293
  if (found && found.node.parallel_branches) {
11097
11294
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
11098
11295
  if (branch) {
@@ -11112,6 +11309,18 @@ function XViewScene({
11112
11309
  // <--- ADICIONADO
11113
11310
  };
11114
11311
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
11312
+ const readModeAbstractionTree = useMemo12(() => {
11313
+ if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
11314
+ return null;
11315
+ }
11316
+ const allNodes = Object.values(parentDataRef.current || {}).flatMap((f) => f.nodes || []);
11317
+ const allAncestries = ancestryDataRef.current || [];
11318
+ return buildFullAncestryTree(
11319
+ readingMode.ancestry.abstraction_tree,
11320
+ allNodes,
11321
+ allAncestries
11322
+ );
11323
+ }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
11115
11324
  const handleStartReadingAncestry = useCallback3(
11116
11325
  async (ancestryObject) => {
11117
11326
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
@@ -11152,7 +11361,7 @@ function XViewScene({
11152
11361
  );
11153
11362
  let currentPtr = fullTree;
11154
11363
  for (const step of branchStack) {
11155
- const found = findNodePath2(currentPtr, step.nodeId);
11364
+ const found = findNodePath3(currentPtr, step.nodeId);
11156
11365
  if (found && found.node && found.node.parallel_branches) {
11157
11366
  const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
11158
11367
  if (branch) {
@@ -11820,7 +12029,9 @@ function XViewScene({
11820
12029
  activeNodeBranches,
11821
12030
  backNavigationInfo,
11822
12031
  onImageClick: (url, name) => handleOpenImageViewer([{ name: name || "Imagem", value: url }], 0),
11823
- userRole: userPermissionRole
12032
+ userRole: userPermissionRole,
12033
+ abstractionTree: readModeAbstractionTree,
12034
+ onRenderAbstractionTree: (targetId) => handleRenderAbstractionTree(readingMode.ancestry, targetId)
11824
12035
  }
11825
12036
  )
11826
12037
  ),
@@ -11828,6 +12039,7 @@ function XViewScene({
11828
12039
  CreateAncestryPanel,
11829
12040
  {
11830
12041
  ancestryMode,
12042
+ setAncestryMode,
11831
12043
  onSelectParent: handleSelectAncestryParent,
11832
12044
  onRemoveNode: handleRemoveFromAncestry,
11833
12045
  onSave: handleSaveAncestry,
@@ -11847,7 +12059,7 @@ function XViewScene({
11847
12059
  onClearAncestryVisuals: handleClearAncestryVisuals,
11848
12060
  onUploadFile: upload_file_action,
11849
12061
  onOpenImageViewer: handleOpenImageViewer,
11850
- onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
12062
+ onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
11851
12063
  }
11852
12064
  ),
11853
12065
  editingAncestryRel.visible && /* @__PURE__ */ React23.createElement(