@lv-x-software-house/x_view 1.1.9-dev.2 → 1.1.9-dev.5

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 +191 -131
  2. package/dist/index.mjs +191 -131
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -186,8 +186,8 @@ function ContextMenu({
186
186
  return !isVisible;
187
187
  }).map((link) => {
188
188
  const isSource = String(link.source) === String(data.nodeData.id);
189
- const targetNodeId = isSource ? link.target : link.source;
190
- const targetNode = nodeMap.get(String(targetNodeId));
189
+ const targetNodeId2 = isSource ? link.target : link.source;
190
+ const targetNode = nodeMap.get(String(targetNodeId2));
191
191
  return { link, targetNode, direction: isSource ? "outgoing" : "incoming" };
192
192
  }).filter((c) => {
193
193
  var _a2;
@@ -1812,16 +1812,16 @@ var userActionHandlers = {
1812
1812
  linksToExpand.forEach((link) => {
1813
1813
  var _a;
1814
1814
  const isSource = String(link.source) === String(sourceNode.id);
1815
- const targetNodeId = isSource ? link.target : link.source;
1815
+ const targetNodeId2 = isSource ? link.target : link.source;
1816
1816
  const linkAlreadyInSceneData = sceneDataRef.current.links.some((l) => String(l.id) === String(link.id));
1817
1817
  if (!linkAlreadyInSceneData) {
1818
1818
  sceneDataRef.current.links.push(link);
1819
1819
  }
1820
- if (!nodeObjects[String(targetNodeId)]) {
1820
+ if (!nodeObjects[String(targetNodeId2)]) {
1821
1821
  const allParentNodes = Object.values(graphDataRef.current).flatMap((fileData) => fileData.nodes);
1822
- const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId));
1822
+ const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId2));
1823
1823
  if (!nodeData) {
1824
- console.warn(`Dados do Node com ID ${targetNodeId} n\xE3o encontrados no cache.`);
1824
+ console.warn(`Dados do Node com ID ${targetNodeId2} n\xE3o encontrados no cache.`);
1825
1825
  return;
1826
1826
  }
1827
1827
  if (!sceneDataRef.current.nodes.some((n) => String(n.id) === String(nodeData.id))) {
@@ -1838,7 +1838,7 @@ var userActionHandlers = {
1838
1838
  if (targetMesh.userData.labelObject) {
1839
1839
  graphGroup.add(targetMesh.userData.labelObject);
1840
1840
  }
1841
- nodeObjects[String(targetNodeId)] = targetMesh;
1841
+ nodeObjects[String(targetNodeId2)] = targetMesh;
1842
1842
  clickableNodes.push(targetMesh);
1843
1843
  const posTween = new import_tween.Tween(targetMesh.position).to(endPosition, 1200).easing(import_tween.Easing.Quadratic.Out);
1844
1844
  tweenGroup.add(posTween);
@@ -2698,7 +2698,10 @@ var IGNORED_KEYS = [
2698
2698
  "isAddingNodes",
2699
2699
  "ancestryDescriptionSections",
2700
2700
  "direction",
2701
- "is_private"
2701
+ "is_private",
2702
+ "abstraction_tree",
2703
+ "selectedAbstractionParentId",
2704
+ "isAddingAbstractionNodes"
2702
2705
  ];
2703
2706
  function extractCustomPropsFromNode(node) {
2704
2707
  const customPropTypes = node._customPropTypes || {};
@@ -4871,31 +4874,50 @@ function AncestryPickerModal({
4871
4874
  }
4872
4875
 
4873
4876
  // src/components/CreateAncestryPanel.jsx
4874
- var findNodePath = (tree, targetNodeId, currentPath = []) => {
4877
+ var findNodePath = (tree, targetNodeId2, currentPath = []) => {
4875
4878
  var _a;
4876
4879
  if (!tree) return null;
4877
4880
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
4878
- if (String(currentNodeId) === String(targetNodeId)) {
4881
+ if (String(currentNodeId) === String(targetNodeId2)) {
4879
4882
  return { node: tree, path: currentPath };
4880
4883
  }
4881
4884
  if (tree.children) {
4882
4885
  for (let i = 0; i < tree.children.length; i++) {
4883
- const res = findNodePath(tree.children[i], targetNodeId, [...currentPath, i]);
4886
+ const res = findNodePath(tree.children[i], targetNodeId2, [...currentPath, i]);
4884
4887
  if (res) return res;
4885
4888
  }
4886
4889
  }
4887
4890
  return null;
4888
4891
  };
4889
- var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
4892
+ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [], targetRenderNodeId, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
4890
4893
  var _a, _b;
4891
4894
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4892
4895
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4893
4896
  const [isDragOver, setIsDragOver] = (0, import_react10.useState)(false);
4894
- const isSelected = String(selectedParentId) === String(itemId);
4897
+ const isSelectedParent = String(selectedParentId) === String(itemId);
4898
+ const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
4899
+ const isHighlightedPath = highlightedPathIds.includes(String(itemId));
4895
4900
  const hasChildren = nodeData.children && nodeData.children.length > 0;
4896
- 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";
4897
- const textColorClass = nodeData.is_section ? isSelected ? "text-indigo-200 font-bold" : "text-indigo-300" : isSelected ? "text-cyan-200 font-semibold" : "text-slate-200";
4898
- const cursorClass = isEditable ? "cursor-grab active:cursor-grabbing" : "cursor-default";
4901
+ let itemBgClass = "bg-slate-900/50 hover:bg-slate-800/80";
4902
+ let textColorClass = "text-slate-200";
4903
+ if (nodeData.is_section) {
4904
+ 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";
4905
+ textColorClass = isSelectedParent ? "text-indigo-200 font-bold" : "text-indigo-300";
4906
+ } else {
4907
+ if (isSelectedParent) {
4908
+ itemBgClass = "bg-purple-500/30 ring-2 ring-purple-400";
4909
+ textColorClass = "text-purple-200 font-semibold";
4910
+ } else if (isTargetViewNode) {
4911
+ itemBgClass = "bg-fuchsia-600/40 ring-2 ring-fuchsia-400 shadow-[0_0_15px_rgba(217,70,239,0.3)]";
4912
+ textColorClass = "text-white font-bold";
4913
+ } else if (isHighlightedPath) {
4914
+ itemBgClass = "bg-fuchsia-900/30 border border-fuchsia-500/40";
4915
+ textColorClass = "text-fuchsia-200 font-semibold";
4916
+ } else {
4917
+ textColorClass = "text-slate-200";
4918
+ }
4919
+ }
4920
+ const cursorClass = isEditable ? "cursor-grab active:cursor-grabbing" : "cursor-pointer";
4899
4921
  const handleDragStart = (e) => {
4900
4922
  if (!isEditable) {
4901
4923
  e.preventDefault();
@@ -4925,23 +4947,9 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4925
4947
  if (!isEditable) return;
4926
4948
  const sourceId = e.dataTransfer.getData("nodeId");
4927
4949
  if (sourceId === String(itemId)) return;
4928
- if (onMoveNode) {
4929
- onMoveNode(sourceId, itemId);
4930
- }
4950
+ if (onMoveNode) onMoveNode(sourceId, itemId);
4931
4951
  };
4932
- return /* @__PURE__ */ import_react10.default.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(
4933
- "span",
4934
- {
4935
- className: `absolute -left-4 top-0 w-px bg-cyan-600/60 ${isLast ? "h-[1.125rem]" : "h-full"}`,
4936
- "aria-hidden": "true"
4937
- }
4938
- ), /* @__PURE__ */ import_react10.default.createElement(
4939
- "span",
4940
- {
4941
- className: `absolute -left-4 top-[1.125rem] h-px w-4 bg-cyan-600/60`,
4942
- "aria-hidden": "true"
4943
- }
4944
- )), /* @__PURE__ */ import_react10.default.createElement(
4952
+ return /* @__PURE__ */ import_react10.default.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.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__ */ import_react10.default.createElement(
4945
4953
  "div",
4946
4954
  {
4947
4955
  draggable: isEditable,
@@ -4949,63 +4957,35 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4949
4957
  onDragOver: handleDragOver,
4950
4958
  onDragLeave: handleDragLeave,
4951
4959
  onDrop: handleDrop,
4952
- onClick: () => {
4960
+ onClick: (e) => {
4961
+ e.stopPropagation();
4953
4962
  if (isEditable) {
4954
4963
  onSelectParent(itemId);
4964
+ } else if (onViewSelect) {
4965
+ onViewSelect(itemId);
4955
4966
  }
4956
4967
  },
4957
4968
  className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border
4958
4969
  ${isDragOver ? "border-dashed border-yellow-400 bg-yellow-400/10" : "border-transparent"}
4959
4970
  ${itemBgClass} ${cursorClass}`
4960
4971
  },
4961
- /* @__PURE__ */ import_react10.default.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(
4962
- "svg",
4963
- {
4964
- xmlns: "http://www.w3.org/2000/svg",
4965
- width: "16",
4966
- height: "16",
4967
- viewBox: "0 0 24 24",
4968
- fill: "none",
4969
- stroke: "currentColor",
4970
- strokeWidth: "2",
4971
- strokeLinecap: "round",
4972
- strokeLinejoin: "round",
4973
- className: "lucide lucide-blend-icon lucide-blend mr-1.5 inline-block"
4974
- },
4975
- /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "9", cy: "9", r: "7" }),
4976
- /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "15", cy: "15", r: "7" })
4977
- ), nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiFolder, { className: "mr-2" }), itemName),
4978
- level > 0 && isEditable && /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-1 animate-in fade-in duration-200" }, !nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(
4979
- "button",
4980
- {
4981
- onClick: (e) => {
4982
- e.stopPropagation();
4983
- onEditRelationship(path, nodeData.relationship || {});
4984
- },
4985
- className: "w-6 h-6 grid place-content-center rounded-full hover:bg-cyan-500/20 text-cyan-400 transition-colors flex-shrink-0",
4986
- title: "Editar detalhes da rela\xE7\xE3o",
4987
- style: { cursor: "pointer" }
4988
- },
4989
- /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 12 })
4990
- ), /* @__PURE__ */ import_react10.default.createElement(
4991
- "button",
4992
- {
4993
- onClick: (e) => {
4994
- e.stopPropagation();
4995
- onRemoveNode(path);
4996
- },
4997
- 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",
4998
- title: "Remover Node da ancestralidade",
4999
- style: { cursor: "pointer" }
5000
- },
5001
- "\xD7"
5002
- ))
4972
+ /* @__PURE__ */ import_react10.default.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement("circle", { cx: "9", cy: "9", r: "7" }), /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "15", cy: "15", r: "7" })), nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiFolder, { className: "mr-2" }), itemName),
4973
+ level > 0 && isEditable && /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-1 animate-in fade-in duration-200" }, !nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement("button", { onClick: (e) => {
4974
+ e.stopPropagation();
4975
+ onEditRelationship(path, nodeData.relationship || {});
4976
+ }, 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__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 12 })), /* @__PURE__ */ import_react10.default.createElement("button", { onClick: (e) => {
4977
+ e.stopPropagation();
4978
+ onRemoveNode(path);
4979
+ }, 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"))
5003
4980
  ), hasChildren && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-2 space-y-2 pl-8" }, nodeData.children.map((child, index) => /* @__PURE__ */ import_react10.default.createElement(
5004
4981
  NodeItem,
5005
4982
  {
5006
4983
  key: `${child.is_section ? child.id : child.node.id}-${index}`,
5007
4984
  nodeData: child,
5008
4985
  onSelectParent,
4986
+ onViewSelect,
4987
+ highlightedPathIds,
4988
+ targetRenderNodeId,
5009
4989
  onRemoveNode,
5010
4990
  onEditRelationship,
5011
4991
  onMoveNode,
@@ -5020,11 +5000,8 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
5020
5000
  function CreateAncestryPanel({
5021
5001
  ancestryMode,
5022
5002
  setAncestryMode,
5023
- // <--- Nova prop necessária para as novas funções manipuladoras
5024
5003
  onSelectParent,
5025
- // Mantido para compatibilidade, mas as novas funções usam setAncestryMode
5026
5004
  onRemoveNode,
5027
- // Mantido para compatibilidade
5028
5005
  onSave,
5029
5006
  onClose,
5030
5007
  onEditRelationship,
@@ -5035,14 +5012,12 @@ function CreateAncestryPanel({
5035
5012
  onUpdateTree,
5036
5013
  onAncestrySectionChange,
5037
5014
  onToggleAddNodes,
5038
- // Mantido para compatibilidade
5039
5015
  onRenderFullAncestry,
5040
5016
  onHighlightNode,
5041
5017
  onClearAncestryVisuals,
5042
5018
  onUploadFile,
5043
5019
  onOpenImageViewer,
5044
5020
  onRenderAbstractionTree
5045
- // <--- Nova prop recebida
5046
5021
  }) {
5047
5022
  const {
5048
5023
  tree: rootTree,
@@ -5059,6 +5034,20 @@ function CreateAncestryPanel({
5059
5034
  const [customProps, setCustomProps] = (0, import_react10.useState)([]);
5060
5035
  const propsEndRef = (0, import_react10.useRef)(null);
5061
5036
  const [branchStack, setBranchStack] = (0, import_react10.useState)([]);
5037
+ const [targetRenderNodeId, setTargetRenderNodeId] = (0, import_react10.useState)(null);
5038
+ const highlightedPathIds = (0, import_react10.useMemo)(() => {
5039
+ var _a, _b;
5040
+ if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
5041
+ const found = findNodePath(ancestryMode.abstraction_tree, targetRenderNodeId);
5042
+ if (!found) return [];
5043
+ let current = ancestryMode.abstraction_tree;
5044
+ const ids = [current.is_section ? current.section_id : String((_a = current.node) == null ? void 0 : _a.id)];
5045
+ for (let i of found.path) {
5046
+ current = current.children[i];
5047
+ ids.push(current.is_section ? current.section_id : String((_b = current.node) == null ? void 0 : _b.id));
5048
+ }
5049
+ return ids;
5050
+ }, [targetRenderNodeId, ancestryMode.abstraction_tree]);
5062
5051
  const [targetScrollSectionId, setTargetScrollSectionId] = (0, import_react10.useState)(null);
5063
5052
  const [internalHighlightedNodeId, setInternalHighlightedNodeId] = (0, import_react10.useState)(null);
5064
5053
  const [ancestryName, setAncestryName] = (0, import_react10.useState)(initialName);
@@ -5082,6 +5071,9 @@ function CreateAncestryPanel({
5082
5071
  setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
5083
5072
  };
5084
5073
  const handleToggleAddMode = (isAbstraction = false) => {
5074
+ if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
5075
+ setTargetRenderNodeId(null);
5076
+ }
5085
5077
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5086
5078
  };
5087
5079
  const handleRemoveNode = (0, import_react10.useCallback)((pathToRemove, isAbstraction = false) => {
@@ -5163,14 +5155,15 @@ function CreateAncestryPanel({
5163
5155
  }
5164
5156
  }
5165
5157
  };
5166
- const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal) => {
5158
+ const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal, abstractionTree = null) => {
5167
5159
  return {
5168
5160
  tree: JSON.stringify(tree),
5169
5161
  name,
5170
5162
  description: desc || "",
5171
5163
  sections: JSON.stringify(sections || []),
5172
5164
  customProps: JSON.stringify(customProps2 || []),
5173
- isPrivate: isPrivateVal
5165
+ isPrivate: isPrivateVal,
5166
+ abstractionTree: JSON.stringify(abstractionTree)
5174
5167
  };
5175
5168
  };
5176
5169
  const getCurrentContext = () => {
@@ -5304,7 +5297,8 @@ function CreateAncestryPanel({
5304
5297
  ancestryMode.ancestryDescription,
5305
5298
  ancestryMode.ancestryDescriptionSections,
5306
5299
  extractedProps,
5307
- ancestryMode.is_private
5300
+ ancestryMode.is_private,
5301
+ ancestryMode.abstraction_tree
5308
5302
  ));
5309
5303
  } else if (ctx) {
5310
5304
  setLastSavedSnapshot(takeSnapshot(
@@ -5313,7 +5307,8 @@ function CreateAncestryPanel({
5313
5307
  ctx.description,
5314
5308
  ctx.sections,
5315
5309
  extractedProps,
5316
- isPrivate
5310
+ isPrivate,
5311
+ ancestryMode.abstraction_tree
5317
5312
  ));
5318
5313
  }
5319
5314
  }, [branchStack, ancestryMode]);
@@ -5356,7 +5351,7 @@ function CreateAncestryPanel({
5356
5351
  rootTreeClone,
5357
5352
  rootExtras
5358
5353
  );
5359
- setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate));
5354
+ setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate, ancestryMode.abstraction_tree));
5360
5355
  if (onRenderFullAncestry) {
5361
5356
  const fullTreePayload = {
5362
5357
  ancestry_id: ancestryMode.currentAncestryId || "temp_root",
@@ -5417,7 +5412,8 @@ function CreateAncestryPanel({
5417
5412
  ancestryMode.ancestryDescription,
5418
5413
  ancestryMode.ancestryDescriptionSections,
5419
5414
  currentRootProps,
5420
- isPrivate
5415
+ isPrivate,
5416
+ ancestryMode.abstraction_tree
5421
5417
  ));
5422
5418
  if (onClearAncestryVisuals) {
5423
5419
  onClearAncestryVisuals(currentStep.branchId);
@@ -5606,6 +5602,11 @@ function CreateAncestryPanel({
5606
5602
  const sectionsChanged = JSON.stringify(existingSections) !== lastSavedSnapshot.sections;
5607
5603
  const propsChanged = JSON.stringify(customProps) !== lastSavedSnapshot.customProps;
5608
5604
  const privateChanged = isPrivate !== lastSavedSnapshot.isPrivate;
5605
+ let abstractionTreeChanged = false;
5606
+ if (branchStack.length === 0) {
5607
+ const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
5608
+ abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
5609
+ }
5609
5610
  return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
5610
5611
  }, [
5611
5612
  ancestryName,
@@ -5615,6 +5616,7 @@ function CreateAncestryPanel({
5615
5616
  branchStack,
5616
5617
  lastSavedSnapshot,
5617
5618
  ancestryMode.tree,
5619
+ ancestryMode.abstraction_tree,
5618
5620
  customProps,
5619
5621
  isPrivate
5620
5622
  ]);
@@ -5857,7 +5859,8 @@ function CreateAncestryPanel({
5857
5859
  currentInputDesc,
5858
5860
  processedSections,
5859
5861
  customProps,
5860
- isPrivate
5862
+ isPrivate,
5863
+ ancestryMode.abstraction_tree
5861
5864
  ));
5862
5865
  if (onRenderFullAncestry) {
5863
5866
  const rotation = branchStack.reduce((acc, step) => {
@@ -5916,7 +5919,8 @@ function CreateAncestryPanel({
5916
5919
  currentInputDesc,
5917
5920
  processedSections,
5918
5921
  customProps,
5919
- isPrivate
5922
+ isPrivate,
5923
+ ancestryMode.abstraction_tree
5920
5924
  ));
5921
5925
  if (!keepOpen) onClose();
5922
5926
  } finally {
@@ -5969,7 +5973,9 @@ function CreateAncestryPanel({
5969
5973
  const node = findNode(activeTree, selectedParentId);
5970
5974
  return node ? node.name : "Nenhum";
5971
5975
  };
5972
- const hasChildren = activeTree && activeTree.children && activeTree.children.length > 0;
5976
+ const hasMainChildren = activeTree && activeTree.children && activeTree.children.length > 0;
5977
+ const hasAbstractionChildren = branchStack.length === 0 && ancestryMode.abstraction_tree && ancestryMode.abstraction_tree.children && ancestryMode.abstraction_tree.children.length > 0;
5978
+ const canSave = hasMainChildren || hasAbstractionChildren;
5973
5979
  const handleSectionChangeWrapper = (sectionId) => {
5974
5980
  const ctx = getCurrentContext();
5975
5981
  const currentDesc = ctx ? ctx.description : description;
@@ -6203,44 +6209,77 @@ function CreateAncestryPanel({
6203
6209
  path: [],
6204
6210
  isEditable: isAddingNodes
6205
6211
  }
6206
- ), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.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__ */ import_react10.default.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__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react10.default.createElement(
6207
- "button",
6208
- {
6209
- type: "button",
6210
- onClick: () => {
6211
- const tempPayload = {
6212
- ancestry_id: currentAncestryId || "temp_rendering",
6213
- abstraction_tree: ancestryMode.abstraction_tree
6214
- };
6215
- if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6216
- },
6217
- className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6218
- title: "Renderizar Verticalmente no Cen\xE1rio"
6219
- },
6220
- /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLayers, { size: 14 })
6221
- ), /* @__PURE__ */ import_react10.default.createElement(
6222
- "button",
6212
+ ), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(
6213
+ "div",
6223
6214
  {
6224
- onClick: () => handleToggleAddMode(true),
6225
- 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"}`,
6226
- title: "Editar estrutura da abstra\xE7\xE3o"
6215
+ 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"}`,
6216
+ onClick: () => setTargetRenderNodeId(null)
6227
6217
  },
6228
- ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 14 }) : /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 14 })
6229
- ))), /* @__PURE__ */ import_react10.default.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ import_react10.default.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ import_react10.default.createElement(
6230
- NodeItem,
6231
- {
6232
- nodeData: ancestryMode.abstraction_tree,
6233
- onSelectParent: (id) => handleSelectAncestryParent(id, true),
6234
- onRemoveNode: (path) => handleRemoveNode(path, true),
6235
- onEditRelationship,
6236
- onMoveNode: (s, t) => handleMoveNode(s, t, true),
6237
- selectedParentId: ancestryMode.selectedAbstractionParentId,
6238
- level: 0,
6239
- isLast: true,
6240
- path: [],
6241
- isEditable: ancestryMode.isAddingAbstractionNodes
6242
- }
6243
- ))), branchStack.length === 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ import_react10.default.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 12, className: "text-white" })), /* @__PURE__ */ import_react10.default.createElement(
6218
+ /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, targetRenderNodeId && !ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ import_react10.default.createElement(
6219
+ "button",
6220
+ {
6221
+ type: "button",
6222
+ onClick: (e) => {
6223
+ e.stopPropagation();
6224
+ const tempPayload = {
6225
+ ancestry_id: currentAncestryId || "temp_rendering",
6226
+ abstraction_tree: ancestryMode.abstraction_tree
6227
+ };
6228
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload, targetRenderNodeId);
6229
+ },
6230
+ 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",
6231
+ title: "Renderizar cen\xE1rio at\xE9 o caminho selecionado"
6232
+ },
6233
+ /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLayers, { size: 13 }),
6234
+ /* @__PURE__ */ import_react10.default.createElement("span", { className: "text-[10px] font-bold uppercase tracking-wider" }, "Caminho")
6235
+ ), /* @__PURE__ */ import_react10.default.createElement(
6236
+ "button",
6237
+ {
6238
+ type: "button",
6239
+ onClick: (e) => {
6240
+ e.stopPropagation();
6241
+ const tempPayload = {
6242
+ ancestry_id: currentAncestryId || "temp_rendering",
6243
+ abstraction_tree: ancestryMode.abstraction_tree
6244
+ };
6245
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6246
+ },
6247
+ className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6248
+ title: "Renderizar Verticalmente Completo"
6249
+ },
6250
+ /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLayers, { size: 14 })
6251
+ ), /* @__PURE__ */ import_react10.default.createElement(
6252
+ "button",
6253
+ {
6254
+ type: "button",
6255
+ onClick: (e) => {
6256
+ e.stopPropagation();
6257
+ handleToggleAddMode(true);
6258
+ },
6259
+ 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"}`,
6260
+ title: "Editar estrutura da abstra\xE7\xE3o"
6261
+ },
6262
+ ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 14 }) : /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 14 })
6263
+ ))),
6264
+ /* @__PURE__ */ import_react10.default.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ import_react10.default.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ import_react10.default.createElement(
6265
+ NodeItem,
6266
+ {
6267
+ nodeData: ancestryMode.abstraction_tree,
6268
+ onSelectParent: (id) => handleSelectAncestryParent(id, true),
6269
+ onViewSelect: setTargetRenderNodeId,
6270
+ highlightedPathIds,
6271
+ targetRenderNodeId,
6272
+ onRemoveNode: (path) => handleRemoveNode(path, true),
6273
+ onEditRelationship,
6274
+ onMoveNode: (s, t) => handleMoveNode(s, t, true),
6275
+ selectedParentId: ancestryMode.selectedAbstractionParentId,
6276
+ level: 0,
6277
+ isLast: true,
6278
+ path: [],
6279
+ isEditable: ancestryMode.isAddingAbstractionNodes
6280
+ }
6281
+ ))
6282
+ ), branchStack.length === 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ import_react10.default.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 12, className: "text-white" })), /* @__PURE__ */ import_react10.default.createElement(
6244
6283
  "input",
6245
6284
  {
6246
6285
  type: "checkbox",
@@ -6248,7 +6287,7 @@ function CreateAncestryPanel({
6248
6287
  onChange: (e) => setIsPrivate(e.target.checked),
6249
6288
  className: "hidden"
6250
6289
  }
6251
- ), /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiLock, { size: 10 }), " N\xE3o Export\xE1vel"))))), /* @__PURE__ */ import_react10.default.createElement("div", { className: "px-6 pt-2 pb-5 flex-shrink-0" }, hasChildren && /* @__PURE__ */ import_react10.default.createElement(
6290
+ ), /* @__PURE__ */ import_react10.default.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__ */ import_react10.default.createElement(import_fi9.FiLock, { size: 10 }), " N\xE3o Export\xE1vel"))))), /* @__PURE__ */ import_react10.default.createElement("div", { className: "px-6 pt-2 pb-5 flex-shrink-0" }, canSave && /* @__PURE__ */ import_react10.default.createElement(
6252
6291
  "button",
6253
6292
  {
6254
6293
  onClick: () => handleLocalSave(false),
@@ -8758,16 +8797,16 @@ var getAllNodeIdsFromTree = (treeNode) => {
8758
8797
  traverse(treeNode);
8759
8798
  return Array.from(ids);
8760
8799
  };
8761
- var findNodePath2 = (tree, targetNodeId, currentPath = []) => {
8800
+ var findNodePath2 = (tree, targetNodeId2, currentPath = []) => {
8762
8801
  var _a;
8763
8802
  if (!tree) return null;
8764
8803
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
8765
- if (String(currentNodeId) === String(targetNodeId)) {
8804
+ if (String(currentNodeId) === String(targetNodeId2)) {
8766
8805
  return { node: tree, path: currentPath };
8767
8806
  }
8768
8807
  if (tree.children) {
8769
8808
  for (let i = 0; i < tree.children.length; i++) {
8770
- const res = findNodePath2(tree.children[i], targetNodeId, [...currentPath, i]);
8809
+ const res = findNodePath2(tree.children[i], targetNodeId2, [...currentPath, i]);
8771
8810
  if (res) return res;
8772
8811
  }
8773
8812
  }
@@ -10841,8 +10880,29 @@ function XViewScene({
10841
10880
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
10842
10881
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
10843
10882
  const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
10844
- const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10883
+ let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10845
10884
  if (!fullTree || !fullTree.node) return;
10885
+ if (targetNodeId) {
10886
+ const pruneTreeToPath = (treeNode, targetId) => {
10887
+ var _a2;
10888
+ if (!treeNode) return null;
10889
+ const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
10890
+ if (String(currentId) === String(targetId)) {
10891
+ return { ...treeNode, children: [] };
10892
+ }
10893
+ if (treeNode.children && treeNode.children.length > 0) {
10894
+ for (let child of treeNode.children) {
10895
+ const prunedChild = pruneTreeToPath(child, targetId);
10896
+ if (prunedChild) {
10897
+ return { ...treeNode, children: [prunedChild] };
10898
+ }
10899
+ }
10900
+ }
10901
+ return null;
10902
+ };
10903
+ const pruned = pruneTreeToPath(fullTree, targetNodeId);
10904
+ if (pruned) fullTree = pruned;
10905
+ }
10846
10906
  const absId = ancestryObject.ancestry_id + "_abs";
10847
10907
  handleClearAncestryVisuals(absId);
10848
10908
  const colorHex = 9133302;
@@ -11854,7 +11914,7 @@ function XViewScene({
11854
11914
  onClearAncestryVisuals: handleClearAncestryVisuals,
11855
11915
  onUploadFile: upload_file_action,
11856
11916
  onOpenImageViewer: handleOpenImageViewer,
11857
- onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
11917
+ onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
11858
11918
  }
11859
11919
  ),
11860
11920
  editingAncestryRel.visible && /* @__PURE__ */ import_react23.default.createElement(
package/dist/index.mjs CHANGED
@@ -142,8 +142,8 @@ function ContextMenu({
142
142
  return !isVisible;
143
143
  }).map((link) => {
144
144
  const isSource = String(link.source) === String(data.nodeData.id);
145
- const targetNodeId = isSource ? link.target : link.source;
146
- const targetNode = nodeMap.get(String(targetNodeId));
145
+ const targetNodeId2 = isSource ? link.target : link.source;
146
+ const targetNode = nodeMap.get(String(targetNodeId2));
147
147
  return { link, targetNode, direction: isSource ? "outgoing" : "incoming" };
148
148
  }).filter((c) => {
149
149
  var _a2;
@@ -1768,16 +1768,16 @@ var userActionHandlers = {
1768
1768
  linksToExpand.forEach((link) => {
1769
1769
  var _a;
1770
1770
  const isSource = String(link.source) === String(sourceNode.id);
1771
- const targetNodeId = isSource ? link.target : link.source;
1771
+ const targetNodeId2 = isSource ? link.target : link.source;
1772
1772
  const linkAlreadyInSceneData = sceneDataRef.current.links.some((l) => String(l.id) === String(link.id));
1773
1773
  if (!linkAlreadyInSceneData) {
1774
1774
  sceneDataRef.current.links.push(link);
1775
1775
  }
1776
- if (!nodeObjects[String(targetNodeId)]) {
1776
+ if (!nodeObjects[String(targetNodeId2)]) {
1777
1777
  const allParentNodes = Object.values(graphDataRef.current).flatMap((fileData) => fileData.nodes);
1778
- const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId));
1778
+ const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId2));
1779
1779
  if (!nodeData) {
1780
- console.warn(`Dados do Node com ID ${targetNodeId} n\xE3o encontrados no cache.`);
1780
+ console.warn(`Dados do Node com ID ${targetNodeId2} n\xE3o encontrados no cache.`);
1781
1781
  return;
1782
1782
  }
1783
1783
  if (!sceneDataRef.current.nodes.some((n) => String(n.id) === String(nodeData.id))) {
@@ -1794,7 +1794,7 @@ var userActionHandlers = {
1794
1794
  if (targetMesh.userData.labelObject) {
1795
1795
  graphGroup.add(targetMesh.userData.labelObject);
1796
1796
  }
1797
- nodeObjects[String(targetNodeId)] = targetMesh;
1797
+ nodeObjects[String(targetNodeId2)] = targetMesh;
1798
1798
  clickableNodes.push(targetMesh);
1799
1799
  const posTween = new Tween(targetMesh.position).to(endPosition, 1200).easing(Easing.Quadratic.Out);
1800
1800
  tweenGroup.add(posTween);
@@ -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 || {};
@@ -4852,31 +4855,50 @@ function AncestryPickerModal({
4852
4855
  }
4853
4856
 
4854
4857
  // src/components/CreateAncestryPanel.jsx
4855
- var findNodePath = (tree, targetNodeId, currentPath = []) => {
4858
+ var findNodePath = (tree, targetNodeId2, currentPath = []) => {
4856
4859
  var _a;
4857
4860
  if (!tree) return null;
4858
4861
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
4859
- if (String(currentNodeId) === String(targetNodeId)) {
4862
+ if (String(currentNodeId) === String(targetNodeId2)) {
4860
4863
  return { node: tree, path: currentPath };
4861
4864
  }
4862
4865
  if (tree.children) {
4863
4866
  for (let i = 0; i < tree.children.length; i++) {
4864
- const res = findNodePath(tree.children[i], targetNodeId, [...currentPath, i]);
4867
+ const res = findNodePath(tree.children[i], targetNodeId2, [...currentPath, i]);
4865
4868
  if (res) return res;
4866
4869
  }
4867
4870
  }
4868
4871
  return null;
4869
4872
  };
4870
- var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
4873
+ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [], targetRenderNodeId, onRemoveNode, onEditRelationship, onMoveNode, selectedParentId, level = 0, isLast = false, path = [], isEditable }) => {
4871
4874
  var _a, _b;
4872
4875
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4873
4876
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4874
4877
  const [isDragOver, setIsDragOver] = useState10(false);
4875
- const isSelected = String(selectedParentId) === String(itemId);
4878
+ const isSelectedParent = String(selectedParentId) === String(itemId);
4879
+ const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
4880
+ const isHighlightedPath = highlightedPathIds.includes(String(itemId));
4876
4881
  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";
4882
+ let itemBgClass = "bg-slate-900/50 hover:bg-slate-800/80";
4883
+ let textColorClass = "text-slate-200";
4884
+ if (nodeData.is_section) {
4885
+ 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";
4886
+ textColorClass = isSelectedParent ? "text-indigo-200 font-bold" : "text-indigo-300";
4887
+ } else {
4888
+ if (isSelectedParent) {
4889
+ itemBgClass = "bg-purple-500/30 ring-2 ring-purple-400";
4890
+ textColorClass = "text-purple-200 font-semibold";
4891
+ } else if (isTargetViewNode) {
4892
+ itemBgClass = "bg-fuchsia-600/40 ring-2 ring-fuchsia-400 shadow-[0_0_15px_rgba(217,70,239,0.3)]";
4893
+ textColorClass = "text-white font-bold";
4894
+ } else if (isHighlightedPath) {
4895
+ itemBgClass = "bg-fuchsia-900/30 border border-fuchsia-500/40";
4896
+ textColorClass = "text-fuchsia-200 font-semibold";
4897
+ } else {
4898
+ textColorClass = "text-slate-200";
4899
+ }
4900
+ }
4901
+ const cursorClass = isEditable ? "cursor-grab active:cursor-grabbing" : "cursor-pointer";
4880
4902
  const handleDragStart = (e) => {
4881
4903
  if (!isEditable) {
4882
4904
  e.preventDefault();
@@ -4906,23 +4928,9 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4906
4928
  if (!isEditable) return;
4907
4929
  const sourceId = e.dataTransfer.getData("nodeId");
4908
4930
  if (sourceId === String(itemId)) return;
4909
- if (onMoveNode) {
4910
- onMoveNode(sourceId, itemId);
4911
- }
4931
+ if (onMoveNode) onMoveNode(sourceId, itemId);
4912
4932
  };
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(
4933
+ 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
4934
  "div",
4927
4935
  {
4928
4936
  draggable: isEditable,
@@ -4930,63 +4938,35 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4930
4938
  onDragOver: handleDragOver,
4931
4939
  onDragLeave: handleDragLeave,
4932
4940
  onDrop: handleDrop,
4933
- onClick: () => {
4941
+ onClick: (e) => {
4942
+ e.stopPropagation();
4934
4943
  if (isEditable) {
4935
4944
  onSelectParent(itemId);
4945
+ } else if (onViewSelect) {
4946
+ onViewSelect(itemId);
4936
4947
  }
4937
4948
  },
4938
4949
  className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border
4939
4950
  ${isDragOver ? "border-dashed border-yellow-400 bg-yellow-400/10" : "border-transparent"}
4940
4951
  ${itemBgClass} ${cursorClass}`
4941
4952
  },
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
- ))
4953
+ /* @__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(FiFolder, { className: "mr-2" }), itemName),
4954
+ 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) => {
4955
+ e.stopPropagation();
4956
+ onEditRelationship(path, nodeData.relationship || {});
4957
+ }, 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) => {
4958
+ e.stopPropagation();
4959
+ onRemoveNode(path);
4960
+ }, 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
4961
  ), hasChildren && /* @__PURE__ */ React10.createElement("div", { className: "mt-2 space-y-2 pl-8" }, nodeData.children.map((child, index) => /* @__PURE__ */ React10.createElement(
4985
4962
  NodeItem,
4986
4963
  {
4987
4964
  key: `${child.is_section ? child.id : child.node.id}-${index}`,
4988
4965
  nodeData: child,
4989
4966
  onSelectParent,
4967
+ onViewSelect,
4968
+ highlightedPathIds,
4969
+ targetRenderNodeId,
4990
4970
  onRemoveNode,
4991
4971
  onEditRelationship,
4992
4972
  onMoveNode,
@@ -5001,11 +4981,8 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
5001
4981
  function CreateAncestryPanel({
5002
4982
  ancestryMode,
5003
4983
  setAncestryMode,
5004
- // <--- Nova prop necessária para as novas funções manipuladoras
5005
4984
  onSelectParent,
5006
- // Mantido para compatibilidade, mas as novas funções usam setAncestryMode
5007
4985
  onRemoveNode,
5008
- // Mantido para compatibilidade
5009
4986
  onSave,
5010
4987
  onClose,
5011
4988
  onEditRelationship,
@@ -5016,14 +4993,12 @@ function CreateAncestryPanel({
5016
4993
  onUpdateTree,
5017
4994
  onAncestrySectionChange,
5018
4995
  onToggleAddNodes,
5019
- // Mantido para compatibilidade
5020
4996
  onRenderFullAncestry,
5021
4997
  onHighlightNode,
5022
4998
  onClearAncestryVisuals,
5023
4999
  onUploadFile,
5024
5000
  onOpenImageViewer,
5025
5001
  onRenderAbstractionTree
5026
- // <--- Nova prop recebida
5027
5002
  }) {
5028
5003
  const {
5029
5004
  tree: rootTree,
@@ -5040,6 +5015,20 @@ function CreateAncestryPanel({
5040
5015
  const [customProps, setCustomProps] = useState10([]);
5041
5016
  const propsEndRef = useRef8(null);
5042
5017
  const [branchStack, setBranchStack] = useState10([]);
5018
+ const [targetRenderNodeId, setTargetRenderNodeId] = useState10(null);
5019
+ const highlightedPathIds = useMemo8(() => {
5020
+ var _a, _b;
5021
+ if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
5022
+ const found = findNodePath(ancestryMode.abstraction_tree, targetRenderNodeId);
5023
+ if (!found) return [];
5024
+ let current = ancestryMode.abstraction_tree;
5025
+ const ids = [current.is_section ? current.section_id : String((_a = current.node) == null ? void 0 : _a.id)];
5026
+ for (let i of found.path) {
5027
+ current = current.children[i];
5028
+ ids.push(current.is_section ? current.section_id : String((_b = current.node) == null ? void 0 : _b.id));
5029
+ }
5030
+ return ids;
5031
+ }, [targetRenderNodeId, ancestryMode.abstraction_tree]);
5043
5032
  const [targetScrollSectionId, setTargetScrollSectionId] = useState10(null);
5044
5033
  const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState10(null);
5045
5034
  const [ancestryName, setAncestryName] = useState10(initialName);
@@ -5063,6 +5052,9 @@ function CreateAncestryPanel({
5063
5052
  setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
5064
5053
  };
5065
5054
  const handleToggleAddMode = (isAbstraction = false) => {
5055
+ if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
5056
+ setTargetRenderNodeId(null);
5057
+ }
5066
5058
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5067
5059
  };
5068
5060
  const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
@@ -5144,14 +5136,15 @@ function CreateAncestryPanel({
5144
5136
  }
5145
5137
  }
5146
5138
  };
5147
- const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal) => {
5139
+ const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal, abstractionTree = null) => {
5148
5140
  return {
5149
5141
  tree: JSON.stringify(tree),
5150
5142
  name,
5151
5143
  description: desc || "",
5152
5144
  sections: JSON.stringify(sections || []),
5153
5145
  customProps: JSON.stringify(customProps2 || []),
5154
- isPrivate: isPrivateVal
5146
+ isPrivate: isPrivateVal,
5147
+ abstractionTree: JSON.stringify(abstractionTree)
5155
5148
  };
5156
5149
  };
5157
5150
  const getCurrentContext = () => {
@@ -5285,7 +5278,8 @@ function CreateAncestryPanel({
5285
5278
  ancestryMode.ancestryDescription,
5286
5279
  ancestryMode.ancestryDescriptionSections,
5287
5280
  extractedProps,
5288
- ancestryMode.is_private
5281
+ ancestryMode.is_private,
5282
+ ancestryMode.abstraction_tree
5289
5283
  ));
5290
5284
  } else if (ctx) {
5291
5285
  setLastSavedSnapshot(takeSnapshot(
@@ -5294,7 +5288,8 @@ function CreateAncestryPanel({
5294
5288
  ctx.description,
5295
5289
  ctx.sections,
5296
5290
  extractedProps,
5297
- isPrivate
5291
+ isPrivate,
5292
+ ancestryMode.abstraction_tree
5298
5293
  ));
5299
5294
  }
5300
5295
  }, [branchStack, ancestryMode]);
@@ -5337,7 +5332,7 @@ function CreateAncestryPanel({
5337
5332
  rootTreeClone,
5338
5333
  rootExtras
5339
5334
  );
5340
- setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate));
5335
+ setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate, ancestryMode.abstraction_tree));
5341
5336
  if (onRenderFullAncestry) {
5342
5337
  const fullTreePayload = {
5343
5338
  ancestry_id: ancestryMode.currentAncestryId || "temp_root",
@@ -5398,7 +5393,8 @@ function CreateAncestryPanel({
5398
5393
  ancestryMode.ancestryDescription,
5399
5394
  ancestryMode.ancestryDescriptionSections,
5400
5395
  currentRootProps,
5401
- isPrivate
5396
+ isPrivate,
5397
+ ancestryMode.abstraction_tree
5402
5398
  ));
5403
5399
  if (onClearAncestryVisuals) {
5404
5400
  onClearAncestryVisuals(currentStep.branchId);
@@ -5587,6 +5583,11 @@ function CreateAncestryPanel({
5587
5583
  const sectionsChanged = JSON.stringify(existingSections) !== lastSavedSnapshot.sections;
5588
5584
  const propsChanged = JSON.stringify(customProps) !== lastSavedSnapshot.customProps;
5589
5585
  const privateChanged = isPrivate !== lastSavedSnapshot.isPrivate;
5586
+ let abstractionTreeChanged = false;
5587
+ if (branchStack.length === 0) {
5588
+ const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
5589
+ abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
5590
+ }
5590
5591
  return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
5591
5592
  }, [
5592
5593
  ancestryName,
@@ -5596,6 +5597,7 @@ function CreateAncestryPanel({
5596
5597
  branchStack,
5597
5598
  lastSavedSnapshot,
5598
5599
  ancestryMode.tree,
5600
+ ancestryMode.abstraction_tree,
5599
5601
  customProps,
5600
5602
  isPrivate
5601
5603
  ]);
@@ -5838,7 +5840,8 @@ function CreateAncestryPanel({
5838
5840
  currentInputDesc,
5839
5841
  processedSections,
5840
5842
  customProps,
5841
- isPrivate
5843
+ isPrivate,
5844
+ ancestryMode.abstraction_tree
5842
5845
  ));
5843
5846
  if (onRenderFullAncestry) {
5844
5847
  const rotation = branchStack.reduce((acc, step) => {
@@ -5897,7 +5900,8 @@ function CreateAncestryPanel({
5897
5900
  currentInputDesc,
5898
5901
  processedSections,
5899
5902
  customProps,
5900
- isPrivate
5903
+ isPrivate,
5904
+ ancestryMode.abstraction_tree
5901
5905
  ));
5902
5906
  if (!keepOpen) onClose();
5903
5907
  } finally {
@@ -5950,7 +5954,9 @@ function CreateAncestryPanel({
5950
5954
  const node = findNode(activeTree, selectedParentId);
5951
5955
  return node ? node.name : "Nenhum";
5952
5956
  };
5953
- const hasChildren = activeTree && activeTree.children && activeTree.children.length > 0;
5957
+ const hasMainChildren = activeTree && activeTree.children && activeTree.children.length > 0;
5958
+ const hasAbstractionChildren = branchStack.length === 0 && ancestryMode.abstraction_tree && ancestryMode.abstraction_tree.children && ancestryMode.abstraction_tree.children.length > 0;
5959
+ const canSave = hasMainChildren || hasAbstractionChildren;
5954
5960
  const handleSectionChangeWrapper = (sectionId) => {
5955
5961
  const ctx = getCurrentContext();
5956
5962
  const currentDesc = ctx ? ctx.description : description;
@@ -6184,44 +6190,77 @@ function CreateAncestryPanel({
6184
6190
  path: [],
6185
6191
  isEditable: isAddingNodes
6186
6192
  }
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",
6193
+ ), (!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(
6194
+ "div",
6204
6195
  {
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"
6196
+ 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"}`,
6197
+ onClick: () => setTargetRenderNodeId(null)
6208
6198
  },
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(
6199
+ /* @__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-2" }, targetRenderNodeId && !ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement(
6200
+ "button",
6201
+ {
6202
+ type: "button",
6203
+ onClick: (e) => {
6204
+ e.stopPropagation();
6205
+ const tempPayload = {
6206
+ ancestry_id: currentAncestryId || "temp_rendering",
6207
+ abstraction_tree: ancestryMode.abstraction_tree
6208
+ };
6209
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload, targetRenderNodeId);
6210
+ },
6211
+ 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",
6212
+ title: "Renderizar cen\xE1rio at\xE9 o caminho selecionado"
6213
+ },
6214
+ /* @__PURE__ */ React10.createElement(FiLayers5, { size: 13 }),
6215
+ /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] font-bold uppercase tracking-wider" }, "Caminho")
6216
+ ), /* @__PURE__ */ React10.createElement(
6217
+ "button",
6218
+ {
6219
+ type: "button",
6220
+ onClick: (e) => {
6221
+ e.stopPropagation();
6222
+ const tempPayload = {
6223
+ ancestry_id: currentAncestryId || "temp_rendering",
6224
+ abstraction_tree: ancestryMode.abstraction_tree
6225
+ };
6226
+ if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6227
+ },
6228
+ className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6229
+ title: "Renderizar Verticalmente Completo"
6230
+ },
6231
+ /* @__PURE__ */ React10.createElement(FiLayers5, { size: 14 })
6232
+ ), /* @__PURE__ */ React10.createElement(
6233
+ "button",
6234
+ {
6235
+ type: "button",
6236
+ onClick: (e) => {
6237
+ e.stopPropagation();
6238
+ handleToggleAddMode(true);
6239
+ },
6240
+ 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"}`,
6241
+ title: "Editar estrutura da abstra\xE7\xE3o"
6242
+ },
6243
+ ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ React10.createElement(FiCheck4, { size: 14 }) : /* @__PURE__ */ React10.createElement(FiEdit23, { size: 14 })
6244
+ ))),
6245
+ /* @__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(
6246
+ NodeItem,
6247
+ {
6248
+ nodeData: ancestryMode.abstraction_tree,
6249
+ onSelectParent: (id) => handleSelectAncestryParent(id, true),
6250
+ onViewSelect: setTargetRenderNodeId,
6251
+ highlightedPathIds,
6252
+ targetRenderNodeId,
6253
+ onRemoveNode: (path) => handleRemoveNode(path, true),
6254
+ onEditRelationship,
6255
+ onMoveNode: (s, t) => handleMoveNode(s, t, true),
6256
+ selectedParentId: ancestryMode.selectedAbstractionParentId,
6257
+ level: 0,
6258
+ isLast: true,
6259
+ path: [],
6260
+ isEditable: ancestryMode.isAddingAbstractionNodes
6261
+ }
6262
+ ))
6263
+ ), 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
6264
  "input",
6226
6265
  {
6227
6266
  type: "checkbox",
@@ -6229,7 +6268,7 @@ function CreateAncestryPanel({
6229
6268
  onChange: (e) => setIsPrivate(e.target.checked),
6230
6269
  className: "hidden"
6231
6270
  }
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(
6271
+ ), /* @__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
6272
  "button",
6234
6273
  {
6235
6274
  onClick: () => handleLocalSave(false),
@@ -8752,16 +8791,16 @@ var getAllNodeIdsFromTree = (treeNode) => {
8752
8791
  traverse(treeNode);
8753
8792
  return Array.from(ids);
8754
8793
  };
8755
- var findNodePath2 = (tree, targetNodeId, currentPath = []) => {
8794
+ var findNodePath2 = (tree, targetNodeId2, currentPath = []) => {
8756
8795
  var _a;
8757
8796
  if (!tree) return null;
8758
8797
  const currentNodeId = tree.is_section ? tree.section_id : String((_a = tree.node) == null ? void 0 : _a.id);
8759
- if (String(currentNodeId) === String(targetNodeId)) {
8798
+ if (String(currentNodeId) === String(targetNodeId2)) {
8760
8799
  return { node: tree, path: currentPath };
8761
8800
  }
8762
8801
  if (tree.children) {
8763
8802
  for (let i = 0; i < tree.children.length; i++) {
8764
- const res = findNodePath2(tree.children[i], targetNodeId, [...currentPath, i]);
8803
+ const res = findNodePath2(tree.children[i], targetNodeId2, [...currentPath, i]);
8765
8804
  if (res) return res;
8766
8805
  }
8767
8806
  }
@@ -10835,8 +10874,29 @@ function XViewScene({
10835
10874
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
10836
10875
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
10837
10876
  const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
10838
- const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10877
+ let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10839
10878
  if (!fullTree || !fullTree.node) return;
10879
+ if (targetNodeId) {
10880
+ const pruneTreeToPath = (treeNode, targetId) => {
10881
+ var _a2;
10882
+ if (!treeNode) return null;
10883
+ const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
10884
+ if (String(currentId) === String(targetId)) {
10885
+ return { ...treeNode, children: [] };
10886
+ }
10887
+ if (treeNode.children && treeNode.children.length > 0) {
10888
+ for (let child of treeNode.children) {
10889
+ const prunedChild = pruneTreeToPath(child, targetId);
10890
+ if (prunedChild) {
10891
+ return { ...treeNode, children: [prunedChild] };
10892
+ }
10893
+ }
10894
+ }
10895
+ return null;
10896
+ };
10897
+ const pruned = pruneTreeToPath(fullTree, targetNodeId);
10898
+ if (pruned) fullTree = pruned;
10899
+ }
10840
10900
  const absId = ancestryObject.ancestry_id + "_abs";
10841
10901
  handleClearAncestryVisuals(absId);
10842
10902
  const colorHex = 9133302;
@@ -11848,7 +11908,7 @@ function XViewScene({
11848
11908
  onClearAncestryVisuals: handleClearAncestryVisuals,
11849
11909
  onUploadFile: upload_file_action,
11850
11910
  onOpenImageViewer: handleOpenImageViewer,
11851
- onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
11911
+ onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
11852
11912
  }
11853
11913
  ),
11854
11914
  editingAncestryRel.visible && /* @__PURE__ */ React23.createElement(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.1.9-dev.2",
3
+ "version": "1.1.9-dev.5",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",