@lv-x-software-house/x_view 1.1.9-dev.3 → 1.1.9-dev.6

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 +151 -108
  2. package/dist/index.mjs +151 -108
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4889,16 +4889,35 @@ var findNodePath = (tree, targetNodeId, currentPath = []) => {
4889
4889
  }
4890
4890
  return null;
4891
4891
  };
4892
- 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 }) => {
4893
4893
  var _a, _b;
4894
4894
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4895
4895
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4896
4896
  const [isDragOver, setIsDragOver] = (0, import_react10.useState)(false);
4897
- 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));
4898
4900
  const hasChildren = nodeData.children && nodeData.children.length > 0;
4899
- 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";
4900
- const textColorClass = nodeData.is_section ? isSelected ? "text-indigo-200 font-bold" : "text-indigo-300" : isSelected ? "text-cyan-200 font-semibold" : "text-slate-200";
4901
- 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";
4902
4921
  const handleDragStart = (e) => {
4903
4922
  if (!isEditable) {
4904
4923
  e.preventDefault();
@@ -4928,23 +4947,9 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4928
4947
  if (!isEditable) return;
4929
4948
  const sourceId = e.dataTransfer.getData("nodeId");
4930
4949
  if (sourceId === String(itemId)) return;
4931
- if (onMoveNode) {
4932
- onMoveNode(sourceId, itemId);
4933
- }
4950
+ if (onMoveNode) onMoveNode(sourceId, itemId);
4934
4951
  };
4935
- 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(
4936
- "span",
4937
- {
4938
- className: `absolute -left-4 top-0 w-px bg-cyan-600/60 ${isLast ? "h-[1.125rem]" : "h-full"}`,
4939
- "aria-hidden": "true"
4940
- }
4941
- ), /* @__PURE__ */ import_react10.default.createElement(
4942
- "span",
4943
- {
4944
- className: `absolute -left-4 top-[1.125rem] h-px w-4 bg-cyan-600/60`,
4945
- "aria-hidden": "true"
4946
- }
4947
- )), /* @__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(
4948
4953
  "div",
4949
4954
  {
4950
4955
  draggable: isEditable,
@@ -4952,63 +4957,35 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4952
4957
  onDragOver: handleDragOver,
4953
4958
  onDragLeave: handleDragLeave,
4954
4959
  onDrop: handleDrop,
4955
- onClick: () => {
4960
+ onClick: (e) => {
4961
+ e.stopPropagation();
4956
4962
  if (isEditable) {
4957
4963
  onSelectParent(itemId);
4964
+ } else if (onViewSelect) {
4965
+ onViewSelect(itemId);
4958
4966
  }
4959
4967
  },
4960
4968
  className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border
4961
4969
  ${isDragOver ? "border-dashed border-yellow-400 bg-yellow-400/10" : "border-transparent"}
4962
4970
  ${itemBgClass} ${cursorClass}`
4963
4971
  },
4964
- /* @__PURE__ */ import_react10.default.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(
4965
- "svg",
4966
- {
4967
- xmlns: "http://www.w3.org/2000/svg",
4968
- width: "16",
4969
- height: "16",
4970
- viewBox: "0 0 24 24",
4971
- fill: "none",
4972
- stroke: "currentColor",
4973
- strokeWidth: "2",
4974
- strokeLinecap: "round",
4975
- strokeLinejoin: "round",
4976
- className: "lucide lucide-blend-icon lucide-blend mr-1.5 inline-block"
4977
- },
4978
- /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "9", cy: "9", r: "7" }),
4979
- /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "15", cy: "15", r: "7" })
4980
- ), nodeData.is_section && /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiFolder, { className: "mr-2" }), itemName),
4981
- 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(
4982
- "button",
4983
- {
4984
- onClick: (e) => {
4985
- e.stopPropagation();
4986
- onEditRelationship(path, nodeData.relationship || {});
4987
- },
4988
- className: "w-6 h-6 grid place-content-center rounded-full hover:bg-cyan-500/20 text-cyan-400 transition-colors flex-shrink-0",
4989
- title: "Editar detalhes da rela\xE7\xE3o",
4990
- style: { cursor: "pointer" }
4991
- },
4992
- /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 12 })
4993
- ), /* @__PURE__ */ import_react10.default.createElement(
4994
- "button",
4995
- {
4996
- onClick: (e) => {
4997
- e.stopPropagation();
4998
- onRemoveNode(path);
4999
- },
5000
- 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",
5001
- title: "Remover Node da ancestralidade",
5002
- style: { cursor: "pointer" }
5003
- },
5004
- "\xD7"
5005
- ))
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"))
5006
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(
5007
4981
  NodeItem,
5008
4982
  {
5009
4983
  key: `${child.is_section ? child.id : child.node.id}-${index}`,
5010
4984
  nodeData: child,
5011
4985
  onSelectParent,
4986
+ onViewSelect,
4987
+ highlightedPathIds,
4988
+ targetRenderNodeId,
5012
4989
  onRemoveNode,
5013
4990
  onEditRelationship,
5014
4991
  onMoveNode,
@@ -5023,11 +5000,8 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
5023
5000
  function CreateAncestryPanel({
5024
5001
  ancestryMode,
5025
5002
  setAncestryMode,
5026
- // <--- Nova prop necessária para as novas funções manipuladoras
5027
5003
  onSelectParent,
5028
- // Mantido para compatibilidade, mas as novas funções usam setAncestryMode
5029
5004
  onRemoveNode,
5030
- // Mantido para compatibilidade
5031
5005
  onSave,
5032
5006
  onClose,
5033
5007
  onEditRelationship,
@@ -5038,14 +5012,12 @@ function CreateAncestryPanel({
5038
5012
  onUpdateTree,
5039
5013
  onAncestrySectionChange,
5040
5014
  onToggleAddNodes,
5041
- // Mantido para compatibilidade
5042
5015
  onRenderFullAncestry,
5043
5016
  onHighlightNode,
5044
5017
  onClearAncestryVisuals,
5045
5018
  onUploadFile,
5046
5019
  onOpenImageViewer,
5047
5020
  onRenderAbstractionTree
5048
- // <--- Nova prop recebida
5049
5021
  }) {
5050
5022
  const {
5051
5023
  tree: rootTree,
@@ -5062,6 +5034,20 @@ function CreateAncestryPanel({
5062
5034
  const [customProps, setCustomProps] = (0, import_react10.useState)([]);
5063
5035
  const propsEndRef = (0, import_react10.useRef)(null);
5064
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]);
5065
5051
  const [targetScrollSectionId, setTargetScrollSectionId] = (0, import_react10.useState)(null);
5066
5052
  const [internalHighlightedNodeId, setInternalHighlightedNodeId] = (0, import_react10.useState)(null);
5067
5053
  const [ancestryName, setAncestryName] = (0, import_react10.useState)(initialName);
@@ -5085,6 +5071,9 @@ function CreateAncestryPanel({
5085
5071
  setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
5086
5072
  };
5087
5073
  const handleToggleAddMode = (isAbstraction = false) => {
5074
+ if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
5075
+ setTargetRenderNodeId(null);
5076
+ }
5088
5077
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5089
5078
  };
5090
5079
  const handleRemoveNode = (0, import_react10.useCallback)((pathToRemove, isAbstraction = false) => {
@@ -6220,44 +6209,77 @@ function CreateAncestryPanel({
6220
6209
  path: [],
6221
6210
  isEditable: isAddingNodes
6222
6211
  }
6223
- ), (!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(
6224
- "button",
6225
- {
6226
- type: "button",
6227
- onClick: () => {
6228
- const tempPayload = {
6229
- ancestry_id: currentAncestryId || "temp_rendering",
6230
- abstraction_tree: ancestryMode.abstraction_tree
6231
- };
6232
- if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6233
- },
6234
- className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6235
- title: "Renderizar Verticalmente no Cen\xE1rio"
6236
- },
6237
- /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLayers, { size: 14 })
6238
- ), /* @__PURE__ */ import_react10.default.createElement(
6239
- "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",
6240
6214
  {
6241
- onClick: () => handleToggleAddMode(true),
6242
- 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"}`,
6243
- 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)
6244
6217
  },
6245
- ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 14 }) : /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 14 })
6246
- ))), /* @__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(
6247
- NodeItem,
6248
- {
6249
- nodeData: ancestryMode.abstraction_tree,
6250
- onSelectParent: (id) => handleSelectAncestryParent(id, true),
6251
- onRemoveNode: (path) => handleRemoveNode(path, true),
6252
- onEditRelationship,
6253
- onMoveNode: (s, t) => handleMoveNode(s, t, true),
6254
- selectedParentId: ancestryMode.selectedAbstractionParentId,
6255
- level: 0,
6256
- isLast: true,
6257
- path: [],
6258
- isEditable: ancestryMode.isAddingAbstractionNodes
6259
- }
6260
- ))), 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(
6261
6283
  "input",
6262
6284
  {
6263
6285
  type: "checkbox",
@@ -10853,13 +10875,34 @@ function XViewScene({
10853
10875
  },
10854
10876
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
10855
10877
  );
10856
- const handleRenderAbstractionTree = (0, import_react23.useCallback)((ancestryObject) => {
10878
+ const handleRenderAbstractionTree = (0, import_react23.useCallback)((ancestryObject, targetNodeId = null) => {
10857
10879
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10858
10880
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
10859
10881
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
10860
10882
  const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
10861
- const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10883
+ let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10862
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
+ }
10863
10906
  const absId = ancestryObject.ancestry_id + "_abs";
10864
10907
  handleClearAncestryVisuals(absId);
10865
10908
  const colorHex = 9133302;
@@ -11871,7 +11914,7 @@ function XViewScene({
11871
11914
  onClearAncestryVisuals: handleClearAncestryVisuals,
11872
11915
  onUploadFile: upload_file_action,
11873
11916
  onOpenImageViewer: handleOpenImageViewer,
11874
- onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
11917
+ onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
11875
11918
  }
11876
11919
  ),
11877
11920
  editingAncestryRel.visible && /* @__PURE__ */ import_react23.default.createElement(
package/dist/index.mjs CHANGED
@@ -4870,16 +4870,35 @@ var findNodePath = (tree, targetNodeId, currentPath = []) => {
4870
4870
  }
4871
4871
  return null;
4872
4872
  };
4873
- 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 }) => {
4874
4874
  var _a, _b;
4875
4875
  const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
4876
4876
  const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
4877
4877
  const [isDragOver, setIsDragOver] = useState10(false);
4878
- 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));
4879
4881
  const hasChildren = nodeData.children && nodeData.children.length > 0;
4880
- 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";
4881
- const textColorClass = nodeData.is_section ? isSelected ? "text-indigo-200 font-bold" : "text-indigo-300" : isSelected ? "text-cyan-200 font-semibold" : "text-slate-200";
4882
- 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";
4883
4902
  const handleDragStart = (e) => {
4884
4903
  if (!isEditable) {
4885
4904
  e.preventDefault();
@@ -4909,23 +4928,9 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4909
4928
  if (!isEditable) return;
4910
4929
  const sourceId = e.dataTransfer.getData("nodeId");
4911
4930
  if (sourceId === String(itemId)) return;
4912
- if (onMoveNode) {
4913
- onMoveNode(sourceId, itemId);
4914
- }
4931
+ if (onMoveNode) onMoveNode(sourceId, itemId);
4915
4932
  };
4916
- return /* @__PURE__ */ React10.createElement("div", { className: "relative" }, level > 0 && /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
4917
- "span",
4918
- {
4919
- className: `absolute -left-4 top-0 w-px bg-cyan-600/60 ${isLast ? "h-[1.125rem]" : "h-full"}`,
4920
- "aria-hidden": "true"
4921
- }
4922
- ), /* @__PURE__ */ React10.createElement(
4923
- "span",
4924
- {
4925
- className: `absolute -left-4 top-[1.125rem] h-px w-4 bg-cyan-600/60`,
4926
- "aria-hidden": "true"
4927
- }
4928
- )), /* @__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(
4929
4934
  "div",
4930
4935
  {
4931
4936
  draggable: isEditable,
@@ -4933,63 +4938,35 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
4933
4938
  onDragOver: handleDragOver,
4934
4939
  onDragLeave: handleDragLeave,
4935
4940
  onDrop: handleDrop,
4936
- onClick: () => {
4941
+ onClick: (e) => {
4942
+ e.stopPropagation();
4937
4943
  if (isEditable) {
4938
4944
  onSelectParent(itemId);
4945
+ } else if (onViewSelect) {
4946
+ onViewSelect(itemId);
4939
4947
  }
4940
4948
  },
4941
4949
  className: `flex items-center justify-between gap-2 px-3 h-9 rounded-md transition-all duration-150 border
4942
4950
  ${isDragOver ? "border-dashed border-yellow-400 bg-yellow-400/10" : "border-transparent"}
4943
4951
  ${itemBgClass} ${cursorClass}`
4944
4952
  },
4945
- /* @__PURE__ */ React10.createElement("span", { className: `truncate flex items-center ${textColorClass}` }, level === 0 && !nodeData.is_section && /* @__PURE__ */ React10.createElement(
4946
- "svg",
4947
- {
4948
- xmlns: "http://www.w3.org/2000/svg",
4949
- width: "16",
4950
- height: "16",
4951
- viewBox: "0 0 24 24",
4952
- fill: "none",
4953
- stroke: "currentColor",
4954
- strokeWidth: "2",
4955
- strokeLinecap: "round",
4956
- strokeLinejoin: "round",
4957
- className: "lucide lucide-blend-icon lucide-blend mr-1.5 inline-block"
4958
- },
4959
- /* @__PURE__ */ React10.createElement("circle", { cx: "9", cy: "9", r: "7" }),
4960
- /* @__PURE__ */ React10.createElement("circle", { cx: "15", cy: "15", r: "7" })
4961
- ), nodeData.is_section && /* @__PURE__ */ React10.createElement(FiFolder, { className: "mr-2" }), itemName),
4962
- 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(
4963
- "button",
4964
- {
4965
- onClick: (e) => {
4966
- e.stopPropagation();
4967
- onEditRelationship(path, nodeData.relationship || {});
4968
- },
4969
- className: "w-6 h-6 grid place-content-center rounded-full hover:bg-cyan-500/20 text-cyan-400 transition-colors flex-shrink-0",
4970
- title: "Editar detalhes da rela\xE7\xE3o",
4971
- style: { cursor: "pointer" }
4972
- },
4973
- /* @__PURE__ */ React10.createElement(FiEdit23, { size: 12 })
4974
- ), /* @__PURE__ */ React10.createElement(
4975
- "button",
4976
- {
4977
- onClick: (e) => {
4978
- e.stopPropagation();
4979
- onRemoveNode(path);
4980
- },
4981
- 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",
4982
- title: "Remover Node da ancestralidade",
4983
- style: { cursor: "pointer" }
4984
- },
4985
- "\xD7"
4986
- ))
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"))
4987
4961
  ), hasChildren && /* @__PURE__ */ React10.createElement("div", { className: "mt-2 space-y-2 pl-8" }, nodeData.children.map((child, index) => /* @__PURE__ */ React10.createElement(
4988
4962
  NodeItem,
4989
4963
  {
4990
4964
  key: `${child.is_section ? child.id : child.node.id}-${index}`,
4991
4965
  nodeData: child,
4992
4966
  onSelectParent,
4967
+ onViewSelect,
4968
+ highlightedPathIds,
4969
+ targetRenderNodeId,
4993
4970
  onRemoveNode,
4994
4971
  onEditRelationship,
4995
4972
  onMoveNode,
@@ -5004,11 +4981,8 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
5004
4981
  function CreateAncestryPanel({
5005
4982
  ancestryMode,
5006
4983
  setAncestryMode,
5007
- // <--- Nova prop necessária para as novas funções manipuladoras
5008
4984
  onSelectParent,
5009
- // Mantido para compatibilidade, mas as novas funções usam setAncestryMode
5010
4985
  onRemoveNode,
5011
- // Mantido para compatibilidade
5012
4986
  onSave,
5013
4987
  onClose,
5014
4988
  onEditRelationship,
@@ -5019,14 +4993,12 @@ function CreateAncestryPanel({
5019
4993
  onUpdateTree,
5020
4994
  onAncestrySectionChange,
5021
4995
  onToggleAddNodes,
5022
- // Mantido para compatibilidade
5023
4996
  onRenderFullAncestry,
5024
4997
  onHighlightNode,
5025
4998
  onClearAncestryVisuals,
5026
4999
  onUploadFile,
5027
5000
  onOpenImageViewer,
5028
5001
  onRenderAbstractionTree
5029
- // <--- Nova prop recebida
5030
5002
  }) {
5031
5003
  const {
5032
5004
  tree: rootTree,
@@ -5043,6 +5015,20 @@ function CreateAncestryPanel({
5043
5015
  const [customProps, setCustomProps] = useState10([]);
5044
5016
  const propsEndRef = useRef8(null);
5045
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]);
5046
5032
  const [targetScrollSectionId, setTargetScrollSectionId] = useState10(null);
5047
5033
  const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState10(null);
5048
5034
  const [ancestryName, setAncestryName] = useState10(initialName);
@@ -5066,6 +5052,9 @@ function CreateAncestryPanel({
5066
5052
  setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
5067
5053
  };
5068
5054
  const handleToggleAddMode = (isAbstraction = false) => {
5055
+ if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
5056
+ setTargetRenderNodeId(null);
5057
+ }
5069
5058
  setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
5070
5059
  };
5071
5060
  const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
@@ -6201,44 +6190,77 @@ function CreateAncestryPanel({
6201
6190
  path: [],
6202
6191
  isEditable: isAddingNodes
6203
6192
  }
6204
- ), (!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(
6205
- "button",
6206
- {
6207
- type: "button",
6208
- onClick: () => {
6209
- const tempPayload = {
6210
- ancestry_id: currentAncestryId || "temp_rendering",
6211
- abstraction_tree: ancestryMode.abstraction_tree
6212
- };
6213
- if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
6214
- },
6215
- className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
6216
- title: "Renderizar Verticalmente no Cen\xE1rio"
6217
- },
6218
- /* @__PURE__ */ React10.createElement(FiLayers5, { size: 14 })
6219
- ), /* @__PURE__ */ React10.createElement(
6220
- "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",
6221
6195
  {
6222
- onClick: () => handleToggleAddMode(true),
6223
- 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"}`,
6224
- 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)
6225
6198
  },
6226
- ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ React10.createElement(FiCheck4, { size: 14 }) : /* @__PURE__ */ React10.createElement(FiEdit23, { size: 14 })
6227
- ))), /* @__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(
6228
- NodeItem,
6229
- {
6230
- nodeData: ancestryMode.abstraction_tree,
6231
- onSelectParent: (id) => handleSelectAncestryParent(id, true),
6232
- onRemoveNode: (path) => handleRemoveNode(path, true),
6233
- onEditRelationship,
6234
- onMoveNode: (s, t) => handleMoveNode(s, t, true),
6235
- selectedParentId: ancestryMode.selectedAbstractionParentId,
6236
- level: 0,
6237
- isLast: true,
6238
- path: [],
6239
- isEditable: ancestryMode.isAddingAbstractionNodes
6240
- }
6241
- ))), 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(
6242
6264
  "input",
6243
6265
  {
6244
6266
  type: "checkbox",
@@ -10847,13 +10869,34 @@ function XViewScene({
10847
10869
  },
10848
10870
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
10849
10871
  );
10850
- const handleRenderAbstractionTree = useCallback3((ancestryObject) => {
10872
+ const handleRenderAbstractionTree = useCallback3((ancestryObject, targetNodeId = null) => {
10851
10873
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
10852
10874
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
10853
10875
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
10854
10876
  const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
10855
- const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10877
+ let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
10856
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
+ }
10857
10900
  const absId = ancestryObject.ancestry_id + "_abs";
10858
10901
  handleClearAncestryVisuals(absId);
10859
10902
  const colorHex = 9133302;
@@ -11865,7 +11908,7 @@ function XViewScene({
11865
11908
  onClearAncestryVisuals: handleClearAncestryVisuals,
11866
11909
  onUploadFile: upload_file_action,
11867
11910
  onOpenImageViewer: handleOpenImageViewer,
11868
- onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
11911
+ onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
11869
11912
  }
11870
11913
  ),
11871
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.3",
3
+ "version": "1.1.9-dev.6",
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",