@lv-x-software-house/x_view 1.2.3-dev.3 → 1.2.3-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 +119 -57
  2. package/dist/index.mjs +119 -57
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2600,7 +2600,54 @@ function createNewCustomProperty(existingProps = []) {
2600
2600
  isEditing: true
2601
2601
  };
2602
2602
  }
2603
- function generateTooltipHtml(data) {
2603
+ var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
2604
+ const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
2605
+ if (!match) return null;
2606
+ const [_, type, itemId, sectionId] = match;
2607
+ let sourceItem = null;
2608
+ if (type === "node") {
2609
+ sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
2610
+ } else {
2611
+ sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
2612
+ }
2613
+ if (!sourceItem) return null;
2614
+ const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
2615
+ const targetSection = sections.find((s) => String(s.id) === String(sectionId));
2616
+ if (!targetSection) return null;
2617
+ return {
2618
+ content: targetSection.content,
2619
+ sourceName: sourceItem.name,
2620
+ sourceId: itemId,
2621
+ type
2622
+ };
2623
+ };
2624
+ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
2625
+ if (!rawText) return "";
2626
+ let text = rawText;
2627
+ const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
2628
+ const allAncestries = ancestryData || [];
2629
+ text = text.replace(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g, (match, type, itemId, sectionId) => {
2630
+ const resolved = resolveDescriptionReference(match, allNodes, allAncestries);
2631
+ if (resolved && !resolved.error) {
2632
+ return resolved.content;
2633
+ }
2634
+ return "[Refer\xEAncia indispon\xEDvel]";
2635
+ });
2636
+ text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
2637
+ text = text.replace(/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g, (match, nodeId) => {
2638
+ const node = allNodes.find((n) => String(n.id) === String(nodeId));
2639
+ return node ? `@${node.name}` : `@Men\xE7\xE3o`;
2640
+ });
2641
+ text = text.replace(/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g, (match, url, name) => {
2642
+ return name ? `[Imagem: ${name}]` : `[Imagem]`;
2643
+ });
2644
+ text = text.replace(/^#+\s*/gm, "");
2645
+ text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
2646
+ text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
2647
+ text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g, "$1");
2648
+ return text.trim();
2649
+ }
2650
+ function generateTooltipHtml(data, parentData, ancestryData) {
2604
2651
  const ignoredKeys = ["id", "name", "type", "color", "_baseEmissiveIntensity", "description"];
2605
2652
  const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
2606
2653
  const extras = customKeys.length;
@@ -2616,20 +2663,23 @@ function generateTooltipHtml(data) {
2616
2663
  <div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
2617
2664
  <div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
2618
2665
  if (data.description) {
2619
- html += `<div style="
2620
- margin-top: 6px;
2621
- padding-top: 6px;
2622
- border-top: 1px solid rgba(255,255,255,0.1);
2623
- opacity: 0.85;
2624
- font-size: 13px;
2625
- display: -webkit-box;
2626
- -webkit-line-clamp: 4;
2627
- -webkit-box-orient: vertical;
2628
- overflow: hidden;
2629
- text-overflow: ellipsis;
2630
- word-break: break-word;
2631
- white-space: normal;
2632
- ">${data.description}</div>`;
2666
+ const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
2667
+ if (cleanDesc) {
2668
+ html += `<div style="
2669
+ margin-top: 6px;
2670
+ padding-top: 6px;
2671
+ border-top: 1px solid rgba(255,255,255,0.1);
2672
+ opacity: 0.85;
2673
+ font-size: 13px;
2674
+ display: -webkit-box;
2675
+ -webkit-line-clamp: 4;
2676
+ -webkit-box-orient: vertical;
2677
+ overflow: hidden;
2678
+ text-overflow: ellipsis;
2679
+ word-break: break-word;
2680
+ white-space: normal;
2681
+ ">${cleanDesc}</div>`;
2682
+ }
2633
2683
  }
2634
2684
  if (extras > 0) {
2635
2685
  html += `<div style="margin-top:8px; opacity:0.7; font-size:12px; font-style: italic;">
@@ -2639,28 +2689,7 @@ function generateTooltipHtml(data) {
2639
2689
  html += `</div>`;
2640
2690
  return html;
2641
2691
  }
2642
- var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
2643
- const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
2644
- if (!match) return null;
2645
- const [_, type, itemId, sectionId] = match;
2646
- let sourceItem = null;
2647
- if (type === "node") {
2648
- sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
2649
- } else {
2650
- sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
2651
- }
2652
- if (!sourceItem) return null;
2653
- const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
2654
- const targetSection = sections.find((s) => String(s.id) === String(sectionId));
2655
- if (!targetSection) return null;
2656
- return {
2657
- content: targetSection.content,
2658
- sourceName: sourceItem.name,
2659
- sourceId: itemId,
2660
- type
2661
- };
2662
- };
2663
- function generateLinkTooltipHtml(data) {
2692
+ function generateLinkTooltipHtml(data, parentData, ancestryData) {
2664
2693
  var _a, _b;
2665
2694
  const hasName = (_a = data == null ? void 0 : data.name) == null ? void 0 : _a.trim();
2666
2695
  const hasDescription = (_b = data == null ? void 0 : data.description) == null ? void 0 : _b.trim();
@@ -2672,16 +2701,19 @@ function generateLinkTooltipHtml(data) {
2672
2701
  html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
2673
2702
  }
2674
2703
  if (hasDescription) {
2675
- html += `<div style="
2676
- display: -webkit-box;
2677
- -webkit-line-clamp: 4;
2678
- -webkit-box-orient: vertical;
2679
- overflow: hidden;
2680
- text-overflow: ellipsis;
2681
- word-break: break-word;
2682
- white-space: normal;
2683
- opacity: 0.9;
2684
- ">${data.description}</div>`;
2704
+ const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
2705
+ if (cleanDesc) {
2706
+ html += `<div style="
2707
+ display: -webkit-box;
2708
+ -webkit-line-clamp: 4;
2709
+ -webkit-box-orient: vertical;
2710
+ overflow: hidden;
2711
+ text-overflow: ellipsis;
2712
+ word-break: break-word;
2713
+ white-space: normal;
2714
+ opacity: 0.9;
2715
+ ">${cleanDesc}</div>`;
2716
+ }
2685
2717
  }
2686
2718
  html += `</div>`;
2687
2719
  return html;
@@ -2897,16 +2929,20 @@ function calculateNodePositions(nodes) {
2897
2929
  }
2898
2930
  return positions;
2899
2931
  }
2900
- function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy }) {
2932
+ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy, parentData, ancestryData }) {
2901
2933
  if (!tooltipEl || !camera || !mountEl) return;
2902
2934
  let content = "";
2903
2935
  let positionTarget = null;
2904
2936
  let isLink = false;
2937
+ let currentId = "";
2905
2938
  if (hoveredNode && !isSceneBusy) {
2906
- content = generateTooltipHtml(hoveredNode.userData);
2939
+ currentId = `node_${hoveredNode.userData.id}`;
2907
2940
  positionTarget = hoveredNode;
2941
+ if (tooltipEl.dataset.currentId !== currentId) {
2942
+ content = generateTooltipHtml(hoveredNode.userData, parentData, ancestryData);
2943
+ }
2908
2944
  } else if (hoveredLink && !isSceneBusy) {
2909
- content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}) : generateLinkTooltipHtml(hoveredLink.userData);
2945
+ currentId = `link_${hoveredLink.userData.id}`;
2910
2946
  if (hoveredLink.userData.isCurved) {
2911
2947
  const positions = hoveredLink.geometry.attributes.position.array;
2912
2948
  const midIndex = Math.floor(positions.length / 2 / 3) * 3;
@@ -2915,12 +2951,23 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
2915
2951
  positionTarget = new THREE2.Vector3().addVectors(hoveredLink.userData.sourceNode.position, hoveredLink.userData.targetNode.position).multiplyScalar(0.5);
2916
2952
  }
2917
2953
  isLink = true;
2954
+ if (tooltipEl.dataset.currentId !== currentId) {
2955
+ content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}, parentData, ancestryData) : generateLinkTooltipHtml(hoveredLink.userData, parentData, ancestryData);
2956
+ }
2918
2957
  }
2919
- if (content && positionTarget) {
2920
- tooltipEl.innerHTML = content;
2921
- const screenPosition = new THREE2.Vector3();
2922
- if (isLink) screenPosition.copy(positionTarget);
2923
- else positionTarget.getWorldPosition(screenPosition);
2958
+ if (positionTarget) {
2959
+ if (tooltipEl.dataset.currentId !== currentId) {
2960
+ tooltipEl.innerHTML = content;
2961
+ tooltipEl.dataset.currentId = currentId;
2962
+ const anchor3D = new THREE2.Vector3();
2963
+ if (isLink) {
2964
+ anchor3D.copy(positionTarget);
2965
+ } else {
2966
+ positionTarget.getWorldPosition(anchor3D);
2967
+ }
2968
+ tooltipEl._fixedAnchor3D = anchor3D;
2969
+ }
2970
+ const screenPosition = tooltipEl._fixedAnchor3D.clone();
2924
2971
  screenPosition.project(camera);
2925
2972
  const clientWidth = mountEl.clientWidth;
2926
2973
  const clientHeight = mountEl.clientHeight;
@@ -2937,7 +2984,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
2937
2984
  tooltipEl.style.left = `${x}px`;
2938
2985
  tooltipEl.style.top = `${y}px`;
2939
2986
  } else {
2940
- tooltipEl.style.display = "none";
2987
+ if (tooltipEl.style.display !== "none") {
2988
+ tooltipEl.style.display = "none";
2989
+ tooltipEl.dataset.currentId = "";
2990
+ tooltipEl._fixedAnchor3D = null;
2991
+ }
2941
2992
  }
2942
2993
  }
2943
2994
  var processDescriptionForSave = (text, existingSections = []) => {
@@ -10907,7 +10958,18 @@ function XViewScene({
10907
10958
  ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
10908
10959
  }
10909
10960
  updateSceneHighlights(stateRef.current);
10910
- updateTooltip({ tooltipEl: tooltipRef.current, hoveredNode: stateRef.current.hoveredNode, hoveredLink: stateRef.current.hoveredLink, camera, mountEl: currentMount, isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive });
10961
+ updateTooltip({
10962
+ tooltipEl: tooltipRef.current,
10963
+ hoveredNode: stateRef.current.hoveredNode,
10964
+ hoveredLink: stateRef.current.hoveredLink,
10965
+ camera,
10966
+ mountEl: currentMount,
10967
+ isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
10968
+ parentData: parentDataRef.current,
10969
+ // <--- ADICIONADO AQUI
10970
+ ancestryData: ancestryDataRef.current
10971
+ // <--- ADICIONADO AQUI
10972
+ });
10911
10973
  (_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
10912
10974
  stateRef.current.controls.update();
10913
10975
  renderer.autoClear = false;
package/dist/index.mjs CHANGED
@@ -2556,7 +2556,54 @@ function createNewCustomProperty(existingProps = []) {
2556
2556
  isEditing: true
2557
2557
  };
2558
2558
  }
2559
- function generateTooltipHtml(data) {
2559
+ var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
2560
+ const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
2561
+ if (!match) return null;
2562
+ const [_, type, itemId, sectionId] = match;
2563
+ let sourceItem = null;
2564
+ if (type === "node") {
2565
+ sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
2566
+ } else {
2567
+ sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
2568
+ }
2569
+ if (!sourceItem) return null;
2570
+ const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
2571
+ const targetSection = sections.find((s) => String(s.id) === String(sectionId));
2572
+ if (!targetSection) return null;
2573
+ return {
2574
+ content: targetSection.content,
2575
+ sourceName: sourceItem.name,
2576
+ sourceId: itemId,
2577
+ type
2578
+ };
2579
+ };
2580
+ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
2581
+ if (!rawText) return "";
2582
+ let text = rawText;
2583
+ const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
2584
+ const allAncestries = ancestryData || [];
2585
+ text = text.replace(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g, (match, type, itemId, sectionId) => {
2586
+ const resolved = resolveDescriptionReference(match, allNodes, allAncestries);
2587
+ if (resolved && !resolved.error) {
2588
+ return resolved.content;
2589
+ }
2590
+ return "[Refer\xEAncia indispon\xEDvel]";
2591
+ });
2592
+ text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
2593
+ text = text.replace(/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g, (match, nodeId) => {
2594
+ const node = allNodes.find((n) => String(n.id) === String(nodeId));
2595
+ return node ? `@${node.name}` : `@Men\xE7\xE3o`;
2596
+ });
2597
+ text = text.replace(/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g, (match, url, name) => {
2598
+ return name ? `[Imagem: ${name}]` : `[Imagem]`;
2599
+ });
2600
+ text = text.replace(/^#+\s*/gm, "");
2601
+ text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
2602
+ text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
2603
+ text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g, "$1");
2604
+ return text.trim();
2605
+ }
2606
+ function generateTooltipHtml(data, parentData, ancestryData) {
2560
2607
  const ignoredKeys = ["id", "name", "type", "color", "_baseEmissiveIntensity", "description"];
2561
2608
  const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
2562
2609
  const extras = customKeys.length;
@@ -2572,20 +2619,23 @@ function generateTooltipHtml(data) {
2572
2619
  <div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
2573
2620
  <div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
2574
2621
  if (data.description) {
2575
- html += `<div style="
2576
- margin-top: 6px;
2577
- padding-top: 6px;
2578
- border-top: 1px solid rgba(255,255,255,0.1);
2579
- opacity: 0.85;
2580
- font-size: 13px;
2581
- display: -webkit-box;
2582
- -webkit-line-clamp: 4;
2583
- -webkit-box-orient: vertical;
2584
- overflow: hidden;
2585
- text-overflow: ellipsis;
2586
- word-break: break-word;
2587
- white-space: normal;
2588
- ">${data.description}</div>`;
2622
+ const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
2623
+ if (cleanDesc) {
2624
+ html += `<div style="
2625
+ margin-top: 6px;
2626
+ padding-top: 6px;
2627
+ border-top: 1px solid rgba(255,255,255,0.1);
2628
+ opacity: 0.85;
2629
+ font-size: 13px;
2630
+ display: -webkit-box;
2631
+ -webkit-line-clamp: 4;
2632
+ -webkit-box-orient: vertical;
2633
+ overflow: hidden;
2634
+ text-overflow: ellipsis;
2635
+ word-break: break-word;
2636
+ white-space: normal;
2637
+ ">${cleanDesc}</div>`;
2638
+ }
2589
2639
  }
2590
2640
  if (extras > 0) {
2591
2641
  html += `<div style="margin-top:8px; opacity:0.7; font-size:12px; font-style: italic;">
@@ -2595,28 +2645,7 @@ function generateTooltipHtml(data) {
2595
2645
  html += `</div>`;
2596
2646
  return html;
2597
2647
  }
2598
- var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
2599
- const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
2600
- if (!match) return null;
2601
- const [_, type, itemId, sectionId] = match;
2602
- let sourceItem = null;
2603
- if (type === "node") {
2604
- sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
2605
- } else {
2606
- sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
2607
- }
2608
- if (!sourceItem) return null;
2609
- const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
2610
- const targetSection = sections.find((s) => String(s.id) === String(sectionId));
2611
- if (!targetSection) return null;
2612
- return {
2613
- content: targetSection.content,
2614
- sourceName: sourceItem.name,
2615
- sourceId: itemId,
2616
- type
2617
- };
2618
- };
2619
- function generateLinkTooltipHtml(data) {
2648
+ function generateLinkTooltipHtml(data, parentData, ancestryData) {
2620
2649
  var _a, _b;
2621
2650
  const hasName = (_a = data == null ? void 0 : data.name) == null ? void 0 : _a.trim();
2622
2651
  const hasDescription = (_b = data == null ? void 0 : data.description) == null ? void 0 : _b.trim();
@@ -2628,16 +2657,19 @@ function generateLinkTooltipHtml(data) {
2628
2657
  html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
2629
2658
  }
2630
2659
  if (hasDescription) {
2631
- html += `<div style="
2632
- display: -webkit-box;
2633
- -webkit-line-clamp: 4;
2634
- -webkit-box-orient: vertical;
2635
- overflow: hidden;
2636
- text-overflow: ellipsis;
2637
- word-break: break-word;
2638
- white-space: normal;
2639
- opacity: 0.9;
2640
- ">${data.description}</div>`;
2660
+ const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
2661
+ if (cleanDesc) {
2662
+ html += `<div style="
2663
+ display: -webkit-box;
2664
+ -webkit-line-clamp: 4;
2665
+ -webkit-box-orient: vertical;
2666
+ overflow: hidden;
2667
+ text-overflow: ellipsis;
2668
+ word-break: break-word;
2669
+ white-space: normal;
2670
+ opacity: 0.9;
2671
+ ">${cleanDesc}</div>`;
2672
+ }
2641
2673
  }
2642
2674
  html += `</div>`;
2643
2675
  return html;
@@ -2853,16 +2885,20 @@ function calculateNodePositions(nodes) {
2853
2885
  }
2854
2886
  return positions;
2855
2887
  }
2856
- function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy }) {
2888
+ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy, parentData, ancestryData }) {
2857
2889
  if (!tooltipEl || !camera || !mountEl) return;
2858
2890
  let content = "";
2859
2891
  let positionTarget = null;
2860
2892
  let isLink = false;
2893
+ let currentId = "";
2861
2894
  if (hoveredNode && !isSceneBusy) {
2862
- content = generateTooltipHtml(hoveredNode.userData);
2895
+ currentId = `node_${hoveredNode.userData.id}`;
2863
2896
  positionTarget = hoveredNode;
2897
+ if (tooltipEl.dataset.currentId !== currentId) {
2898
+ content = generateTooltipHtml(hoveredNode.userData, parentData, ancestryData);
2899
+ }
2864
2900
  } else if (hoveredLink && !isSceneBusy) {
2865
- content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}) : generateLinkTooltipHtml(hoveredLink.userData);
2901
+ currentId = `link_${hoveredLink.userData.id}`;
2866
2902
  if (hoveredLink.userData.isCurved) {
2867
2903
  const positions = hoveredLink.geometry.attributes.position.array;
2868
2904
  const midIndex = Math.floor(positions.length / 2 / 3) * 3;
@@ -2871,12 +2907,23 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
2871
2907
  positionTarget = new THREE2.Vector3().addVectors(hoveredLink.userData.sourceNode.position, hoveredLink.userData.targetNode.position).multiplyScalar(0.5);
2872
2908
  }
2873
2909
  isLink = true;
2910
+ if (tooltipEl.dataset.currentId !== currentId) {
2911
+ content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}, parentData, ancestryData) : generateLinkTooltipHtml(hoveredLink.userData, parentData, ancestryData);
2912
+ }
2874
2913
  }
2875
- if (content && positionTarget) {
2876
- tooltipEl.innerHTML = content;
2877
- const screenPosition = new THREE2.Vector3();
2878
- if (isLink) screenPosition.copy(positionTarget);
2879
- else positionTarget.getWorldPosition(screenPosition);
2914
+ if (positionTarget) {
2915
+ if (tooltipEl.dataset.currentId !== currentId) {
2916
+ tooltipEl.innerHTML = content;
2917
+ tooltipEl.dataset.currentId = currentId;
2918
+ const anchor3D = new THREE2.Vector3();
2919
+ if (isLink) {
2920
+ anchor3D.copy(positionTarget);
2921
+ } else {
2922
+ positionTarget.getWorldPosition(anchor3D);
2923
+ }
2924
+ tooltipEl._fixedAnchor3D = anchor3D;
2925
+ }
2926
+ const screenPosition = tooltipEl._fixedAnchor3D.clone();
2880
2927
  screenPosition.project(camera);
2881
2928
  const clientWidth = mountEl.clientWidth;
2882
2929
  const clientHeight = mountEl.clientHeight;
@@ -2893,7 +2940,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
2893
2940
  tooltipEl.style.left = `${x}px`;
2894
2941
  tooltipEl.style.top = `${y}px`;
2895
2942
  } else {
2896
- tooltipEl.style.display = "none";
2943
+ if (tooltipEl.style.display !== "none") {
2944
+ tooltipEl.style.display = "none";
2945
+ tooltipEl.dataset.currentId = "";
2946
+ tooltipEl._fixedAnchor3D = null;
2947
+ }
2897
2948
  }
2898
2949
  }
2899
2950
  var processDescriptionForSave = (text, existingSections = []) => {
@@ -10907,7 +10958,18 @@ function XViewScene({
10907
10958
  ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
10908
10959
  }
10909
10960
  updateSceneHighlights(stateRef.current);
10910
- updateTooltip({ tooltipEl: tooltipRef.current, hoveredNode: stateRef.current.hoveredNode, hoveredLink: stateRef.current.hoveredLink, camera, mountEl: currentMount, isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive });
10961
+ updateTooltip({
10962
+ tooltipEl: tooltipRef.current,
10963
+ hoveredNode: stateRef.current.hoveredNode,
10964
+ hoveredLink: stateRef.current.hoveredLink,
10965
+ camera,
10966
+ mountEl: currentMount,
10967
+ isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
10968
+ parentData: parentDataRef.current,
10969
+ // <--- ADICIONADO AQUI
10970
+ ancestryData: ancestryDataRef.current
10971
+ // <--- ADICIONADO AQUI
10972
+ });
10911
10973
  (_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
10912
10974
  stateRef.current.controls.update();
10913
10975
  renderer.autoClear = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.3-dev.3",
3
+ "version": "1.2.3-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",