@lv-x-software-house/x_view 1.2.3-dev.2 → 1.2.3-dev.4
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.
- package/dist/index.js +113 -57
- package/dist/index.mjs +113 -57
- 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
|
-
|
|
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
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,9 +2951,15 @@ 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 (
|
|
2920
|
-
tooltipEl.
|
|
2958
|
+
if (positionTarget) {
|
|
2959
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2960
|
+
tooltipEl.innerHTML = content;
|
|
2961
|
+
tooltipEl.dataset.currentId = currentId;
|
|
2962
|
+
}
|
|
2921
2963
|
const screenPosition = new THREE2.Vector3();
|
|
2922
2964
|
if (isLink) screenPosition.copy(positionTarget);
|
|
2923
2965
|
else positionTarget.getWorldPosition(screenPosition);
|
|
@@ -2937,7 +2979,10 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2937
2979
|
tooltipEl.style.left = `${x}px`;
|
|
2938
2980
|
tooltipEl.style.top = `${y}px`;
|
|
2939
2981
|
} else {
|
|
2940
|
-
tooltipEl.style.display
|
|
2982
|
+
if (tooltipEl.style.display !== "none") {
|
|
2983
|
+
tooltipEl.style.display = "none";
|
|
2984
|
+
tooltipEl.dataset.currentId = "";
|
|
2985
|
+
}
|
|
2941
2986
|
}
|
|
2942
2987
|
}
|
|
2943
2988
|
var processDescriptionForSave = (text, existingSections = []) => {
|
|
@@ -4550,7 +4595,6 @@ function DescriptionDisplay({
|
|
|
4550
4595
|
currentBranchDirection = null,
|
|
4551
4596
|
onSaveDescription,
|
|
4552
4597
|
onStepChange
|
|
4553
|
-
// 1. Adicione a nova prop aqui
|
|
4554
4598
|
}) {
|
|
4555
4599
|
const [localDescription, setLocalDescription] = (0, import_react7.useState)(description || "");
|
|
4556
4600
|
(0, import_react7.useEffect)(() => {
|
|
@@ -4744,7 +4788,8 @@ function DescriptionDisplay({
|
|
|
4744
4788
|
const resolved = resolveDescriptionReference(trimmed, availableNodes, availableAncestries);
|
|
4745
4789
|
if (!resolved) return null;
|
|
4746
4790
|
if (resolved.error) return null;
|
|
4747
|
-
|
|
4791
|
+
const cleanContent = resolved.content.trim();
|
|
4792
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "my-1 group relative" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
4748
4793
|
"div",
|
|
4749
4794
|
{
|
|
4750
4795
|
className: "flex items-center gap-1.5 mb-1 select-none opacity-50 hover:opacity-100 transition-opacity pl-1 cursor-pointer w-fit",
|
|
@@ -4760,7 +4805,7 @@ function DescriptionDisplay({
|
|
|
4760
4805
|
), /* @__PURE__ */ import_react7.default.createElement("div", { className: `
|
|
4761
4806
|
pl-3 border-l border-white/10 group-hover:border-indigo-500/30 transition-colors
|
|
4762
4807
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4763
|
-
` }, renderMixedContent(
|
|
4808
|
+
` }, renderMixedContent(cleanContent, index, isActiveSection, -1, setRef)));
|
|
4764
4809
|
};
|
|
4765
4810
|
globalCheckboxCounterRef.current = 0;
|
|
4766
4811
|
const hasUnsavedChanges = localDescription !== (description || "");
|
|
@@ -10907,7 +10952,18 @@ function XViewScene({
|
|
|
10907
10952
|
ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
|
|
10908
10953
|
}
|
|
10909
10954
|
updateSceneHighlights(stateRef.current);
|
|
10910
|
-
updateTooltip({
|
|
10955
|
+
updateTooltip({
|
|
10956
|
+
tooltipEl: tooltipRef.current,
|
|
10957
|
+
hoveredNode: stateRef.current.hoveredNode,
|
|
10958
|
+
hoveredLink: stateRef.current.hoveredLink,
|
|
10959
|
+
camera,
|
|
10960
|
+
mountEl: currentMount,
|
|
10961
|
+
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10962
|
+
parentData: parentDataRef.current,
|
|
10963
|
+
// <--- ADICIONADO AQUI
|
|
10964
|
+
ancestryData: ancestryDataRef.current
|
|
10965
|
+
// <--- ADICIONADO AQUI
|
|
10966
|
+
});
|
|
10911
10967
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10912
10968
|
stateRef.current.controls.update();
|
|
10913
10969
|
renderer.autoClear = false;
|
package/dist/index.mjs
CHANGED
|
@@ -2556,7 +2556,54 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2556
2556
|
isEditing: true
|
|
2557
2557
|
};
|
|
2558
2558
|
}
|
|
2559
|
-
|
|
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
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,9 +2907,15 @@ 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 (
|
|
2876
|
-
tooltipEl.
|
|
2914
|
+
if (positionTarget) {
|
|
2915
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2916
|
+
tooltipEl.innerHTML = content;
|
|
2917
|
+
tooltipEl.dataset.currentId = currentId;
|
|
2918
|
+
}
|
|
2877
2919
|
const screenPosition = new THREE2.Vector3();
|
|
2878
2920
|
if (isLink) screenPosition.copy(positionTarget);
|
|
2879
2921
|
else positionTarget.getWorldPosition(screenPosition);
|
|
@@ -2893,7 +2935,10 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2893
2935
|
tooltipEl.style.left = `${x}px`;
|
|
2894
2936
|
tooltipEl.style.top = `${y}px`;
|
|
2895
2937
|
} else {
|
|
2896
|
-
tooltipEl.style.display
|
|
2938
|
+
if (tooltipEl.style.display !== "none") {
|
|
2939
|
+
tooltipEl.style.display = "none";
|
|
2940
|
+
tooltipEl.dataset.currentId = "";
|
|
2941
|
+
}
|
|
2897
2942
|
}
|
|
2898
2943
|
}
|
|
2899
2944
|
var processDescriptionForSave = (text, existingSections = []) => {
|
|
@@ -4506,7 +4551,6 @@ function DescriptionDisplay({
|
|
|
4506
4551
|
currentBranchDirection = null,
|
|
4507
4552
|
onSaveDescription,
|
|
4508
4553
|
onStepChange
|
|
4509
|
-
// 1. Adicione a nova prop aqui
|
|
4510
4554
|
}) {
|
|
4511
4555
|
const [localDescription, setLocalDescription] = useState7(description || "");
|
|
4512
4556
|
useEffect6(() => {
|
|
@@ -4700,7 +4744,8 @@ function DescriptionDisplay({
|
|
|
4700
4744
|
const resolved = resolveDescriptionReference(trimmed, availableNodes, availableAncestries);
|
|
4701
4745
|
if (!resolved) return null;
|
|
4702
4746
|
if (resolved.error) return null;
|
|
4703
|
-
|
|
4747
|
+
const cleanContent = resolved.content.trim();
|
|
4748
|
+
return /* @__PURE__ */ React6.createElement("div", { className: "my-1 group relative" }, /* @__PURE__ */ React6.createElement(
|
|
4704
4749
|
"div",
|
|
4705
4750
|
{
|
|
4706
4751
|
className: "flex items-center gap-1.5 mb-1 select-none opacity-50 hover:opacity-100 transition-opacity pl-1 cursor-pointer w-fit",
|
|
@@ -4716,7 +4761,7 @@ function DescriptionDisplay({
|
|
|
4716
4761
|
), /* @__PURE__ */ React6.createElement("div", { className: `
|
|
4717
4762
|
pl-3 border-l border-white/10 group-hover:border-indigo-500/30 transition-colors
|
|
4718
4763
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4719
|
-
` }, renderMixedContent(
|
|
4764
|
+
` }, renderMixedContent(cleanContent, index, isActiveSection, -1, setRef)));
|
|
4720
4765
|
};
|
|
4721
4766
|
globalCheckboxCounterRef.current = 0;
|
|
4722
4767
|
const hasUnsavedChanges = localDescription !== (description || "");
|
|
@@ -10907,7 +10952,18 @@ function XViewScene({
|
|
|
10907
10952
|
ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
|
|
10908
10953
|
}
|
|
10909
10954
|
updateSceneHighlights(stateRef.current);
|
|
10910
|
-
updateTooltip({
|
|
10955
|
+
updateTooltip({
|
|
10956
|
+
tooltipEl: tooltipRef.current,
|
|
10957
|
+
hoveredNode: stateRef.current.hoveredNode,
|
|
10958
|
+
hoveredLink: stateRef.current.hoveredLink,
|
|
10959
|
+
camera,
|
|
10960
|
+
mountEl: currentMount,
|
|
10961
|
+
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10962
|
+
parentData: parentDataRef.current,
|
|
10963
|
+
// <--- ADICIONADO AQUI
|
|
10964
|
+
ancestryData: ancestryDataRef.current
|
|
10965
|
+
// <--- ADICIONADO AQUI
|
|
10966
|
+
});
|
|
10911
10967
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10912
10968
|
stateRef.current.controls.update();
|
|
10913
10969
|
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
|
+
"version": "1.2.3-dev.4",
|
|
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",
|