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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +171 -24
  2. package/dist/index.mjs +237 -87
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -131,6 +131,7 @@ function ContextMenu({
131
131
  const [menuView, setMenuView] = (0, import_react.useState)("main");
132
132
  const [selectedAncestry, setSelectedAncestry] = (0, import_react.useState)(null);
133
133
  const [versionSubMenu, setVersionSubMenu] = (0, import_react.useState)(null);
134
+ const [isLinkCopied, setIsLinkCopied] = (0, import_react.useState)(false);
134
135
  const ability = (0, import_react.useMemo)(() => defineAbilityFor(userRole), [userRole]);
135
136
  (0, import_react.useEffect)(() => {
136
137
  if (data.visible) {
@@ -267,6 +268,20 @@ function ContextMenu({
267
268
  return ((_a2 = node.version_node) == null ? void 0 : _a2.is_version) && String(node.version_node.parent_node) === String(data.nodeData.id);
268
269
  }
269
270
  ).sort((a, b) => getYearFromDate(b.Date) - getYearFromDate(a.Date));
271
+ const handleCopyLink = (e, nodeData) => {
272
+ e.stopPropagation();
273
+ const baseUrl = window.location.origin + window.location.pathname;
274
+ const fullUrl = `${baseUrl}?focus=${nodeData.id}`;
275
+ navigator.clipboard.writeText(fullUrl).then(() => {
276
+ setIsLinkCopied(true);
277
+ setTimeout(() => {
278
+ setIsLinkCopied(false);
279
+ onClose();
280
+ }, 1500);
281
+ }).catch((err) => {
282
+ console.error("Erro ao copiar link:", err);
283
+ });
284
+ };
270
285
  const renderMainView = () => {
271
286
  const hasVersions = computedVersions.length > 0;
272
287
  const canCreateVersion = ability.can("create", "Versioning");
@@ -275,7 +290,7 @@ function ContextMenu({
275
290
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
276
291
  onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
277
292
  onClose();
278
- }, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Focar neste Node")), ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), ability.can("dismiss", "Node") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDeleteNode == null ? void 0 : onDeleteNode(data.nodeData), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Excluir Node"))));
293
+ }, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Focar neste Node")), ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDeleteNode == null ? void 0 : onDeleteNode(data.nodeData), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ import_react.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" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Excluir Node"))));
279
294
  };
280
295
  const renderVersionSubMenuView = () => {
281
296
  const group = versionSubMenu;
@@ -4533,6 +4548,8 @@ var ReadOnlyNodeItem = ({ nodeData, onViewSelect, highlightedPathIds = [], targe
4533
4548
  function DescriptionReadModePanel({
4534
4549
  title,
4535
4550
  description,
4551
+ ancestryId,
4552
+ // <-- NOVO: Prop recebida do XViewScene
4536
4553
  savedSections,
4537
4554
  onBack,
4538
4555
  onEdit,
@@ -4552,13 +4569,32 @@ function DescriptionReadModePanel({
4552
4569
  customProperties = [],
4553
4570
  onImageClick,
4554
4571
  userRole,
4555
- // --- NOVAS PROPS PARA ABSTRAÇÃO ---
4556
4572
  abstractionTree = null,
4557
- onRenderAbstractionTree = null
4573
+ onRenderAbstractionTree = null,
4574
+ initialShowAbstraction = false
4558
4575
  }) {
4559
4576
  const [showProperties, setShowProperties] = (0, import_react7.useState)(false);
4560
4577
  const [showAbstraction, setShowAbstraction] = (0, import_react7.useState)(false);
4561
4578
  const [targetRenderNodeId, setTargetRenderNodeId] = (0, import_react7.useState)(null);
4579
+ const [isLinkCopied, setIsLinkCopied] = (0, import_react7.useState)(false);
4580
+ const handleCopyLink = (e) => {
4581
+ e.stopPropagation();
4582
+ if (!ancestryId) return;
4583
+ const baseUrl = window.location.origin + window.location.pathname;
4584
+ const fullUrl = `${baseUrl}?ancestry=${ancestryId}`;
4585
+ navigator.clipboard.writeText(fullUrl).then(() => {
4586
+ setIsLinkCopied(true);
4587
+ setTimeout(() => setIsLinkCopied(false), 2e3);
4588
+ }).catch((err) => {
4589
+ console.error("Erro ao copiar link:", err);
4590
+ });
4591
+ };
4592
+ (0, import_react7.useEffect)(() => {
4593
+ setShowAbstraction(initialShowAbstraction);
4594
+ if (initialShowAbstraction) {
4595
+ setShowProperties(false);
4596
+ }
4597
+ }, [initialShowAbstraction]);
4562
4598
  const swallow = (e) => e.stopPropagation();
4563
4599
  const hasCustomProps = customProperties && customProperties.length > 0;
4564
4600
  const hasAbstraction = Boolean(abstractionTree && (abstractionTree.node || abstractionTree.children && abstractionTree.children.length > 0));
@@ -4642,7 +4678,15 @@ function DescriptionReadModePanel({
4642
4678
  title: "Voltar"
4643
4679
  },
4644
4680
  /* @__PURE__ */ import_react7.default.createElement(import_fi6.FiArrowLeft, { size: 16 })
4645
- ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-xs/relaxed text-slate-400 uppercase tracking-wider font-semibold" }, showAbstraction ? "Tree de Abstra\xE7\xE3o" : showProperties ? "Propriedades Adicionais" : "Modo de Leitura"), /* @__PURE__ */ import_react7.default.createElement("h2", { className: "text-lg sm:text-xl font-semibold tracking-tight text-white truncate", title }, title || "Sem T\xEDtulo"))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" }, hasCustomProps && /* @__PURE__ */ import_react7.default.createElement(
4681
+ ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-xs/relaxed text-slate-400 uppercase tracking-wider font-semibold" }, showAbstraction ? "Tree de Abstra\xE7\xE3o" : showProperties ? "Propriedades Adicionais" : "Modo de Leitura"), ancestryId && /* @__PURE__ */ import_react7.default.createElement(
4682
+ "button",
4683
+ {
4684
+ onClick: handleCopyLink,
4685
+ className: `p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-indigo-400"}`,
4686
+ title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Ancestralidade"
4687
+ },
4688
+ isLinkCopied ? /* @__PURE__ */ import_react7.default.createElement(import_fi6.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react7.default.createElement(import_fi6.FiLink, { size: 12 })
4689
+ )), /* @__PURE__ */ import_react7.default.createElement("h2", { className: "text-lg sm:text-xl font-semibold tracking-tight text-white truncate", title }, title || "Sem T\xEDtulo"))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" }, hasCustomProps && /* @__PURE__ */ import_react7.default.createElement(
4646
4690
  "button",
4647
4691
  {
4648
4692
  onClick: handleToggleProperties,
@@ -5169,6 +5213,20 @@ function CreateAncestryPanel({
5169
5213
  currentAncestryId
5170
5214
  } = ancestryMode;
5171
5215
  const [isSaving, setIsSaving] = (0, import_react10.useState)(false);
5216
+ const [isLinkCopied, setIsLinkCopied] = (0, import_react10.useState)(false);
5217
+ const handleCopyLink = (e) => {
5218
+ e.stopPropagation();
5219
+ if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
5220
+ alert("Salve a ancestralidade primeiro para gerar um link.");
5221
+ return;
5222
+ }
5223
+ const baseUrl = window.location.origin + window.location.pathname;
5224
+ const fullUrl = `${baseUrl}?ancestry=${currentAncestryId}`;
5225
+ navigator.clipboard.writeText(fullUrl).then(() => {
5226
+ setIsLinkCopied(true);
5227
+ setTimeout(() => setIsLinkCopied(false), 2e3);
5228
+ }).catch((err) => console.error("Erro ao copiar link:", err));
5229
+ };
5172
5230
  const [isPickerOpen, setIsPickerOpen] = (0, import_react10.useState)(false);
5173
5231
  const [customProps, setCustomProps] = (0, import_react10.useState)([]);
5174
5232
  const propsEndRef = (0, import_react10.useRef)(null);
@@ -6198,7 +6256,15 @@ function CreateAncestryPanel({
6198
6256
  onHighlightNode,
6199
6257
  onImageClick: handleImageClickFromText
6200
6258
  }
6201
- ) : /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 flex-shrink-0" }), /* @__PURE__ */ import_react10.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 flex-shrink-0" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react10.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, branchStack.length > 0 ? `Ramifica\xE7\xE3o (N\xEDvel ${branchStack.length})` : isEditMode ? "Editar Ancestralidade" : "Criar Ancestralidade")), /* @__PURE__ */ import_react10.default.createElement(
6259
+ ) : /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 flex-shrink-0" }), /* @__PURE__ */ import_react10.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 flex-shrink-0" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react10.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, branchStack.length > 0 ? `Ramifica\xE7\xE3o (N\xEDvel ${branchStack.length})` : isEditMode ? "Editar Ancestralidade" : "Criar Ancestralidade"), currentAncestryId && currentAncestryId !== "temp_creating" && currentAncestryId !== "temp_root" && /* @__PURE__ */ import_react10.default.createElement(
6260
+ "button",
6261
+ {
6262
+ onClick: handleCopyLink,
6263
+ className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-indigo-400"}`,
6264
+ title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Ancestralidade"
6265
+ },
6266
+ isLinkCopied ? /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLink, { size: 12 })
6267
+ )), /* @__PURE__ */ import_react10.default.createElement(
6202
6268
  "input",
6203
6269
  {
6204
6270
  type: "text",
@@ -7252,7 +7318,6 @@ function NodeDetailsPanel({
7252
7318
  onIntensityChange,
7253
7319
  onUploadFile,
7254
7320
  userRole
7255
- // <--- ADIÇÃO: Recebendo a prop userRole
7256
7321
  }) {
7257
7322
  const [name, setName] = (0, import_react15.useState)((node == null ? void 0 : node.name) ?? "");
7258
7323
  const [types, setTypes] = (0, import_react15.useState)([]);
@@ -7268,6 +7333,7 @@ function NodeDetailsPanel({
7268
7333
  const [isReadMode, setIsReadMode] = (0, import_react15.useState)(false);
7269
7334
  const [existingSections, setExistingSections] = (0, import_react15.useState)((node == null ? void 0 : node.description_sections) || []);
7270
7335
  const [isSaving, setIsSaving] = (0, import_react15.useState)(false);
7336
+ const [isLinkCopied, setIsLinkCopied] = (0, import_react15.useState)(false);
7271
7337
  const [useImageAsTexture, setUseImageAsTexture] = (0, import_react15.useState)(() => {
7272
7338
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
7273
7339
  if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
@@ -7329,6 +7395,17 @@ function NodeDetailsPanel({
7329
7395
  onIntensityChange == null ? void 0 : onIntensityChange(node.id, val);
7330
7396
  onDataUpdate == null ? void 0 : onDataUpdate({ ...node, intensity: val });
7331
7397
  };
7398
+ const handleCopyLink = () => {
7399
+ if (!(node == null ? void 0 : node.id)) return;
7400
+ const baseUrl = window.location.origin + window.location.pathname;
7401
+ const fullUrl = `${baseUrl}?focus=${node.id}`;
7402
+ navigator.clipboard.writeText(fullUrl).then(() => {
7403
+ setIsLinkCopied(true);
7404
+ setTimeout(() => setIsLinkCopied(false), 2e3);
7405
+ }).catch((err) => {
7406
+ console.error("Erro ao copiar link:", err);
7407
+ });
7408
+ };
7332
7409
  const swallow = (e) => e.stopPropagation();
7333
7410
  const handleNameChange = (e) => {
7334
7411
  const v = e.target.value;
@@ -7502,7 +7579,15 @@ function NodeDetailsPanel({
7502
7579
  onMentionClick,
7503
7580
  onImageClick: handleImageClickFromText
7504
7581
  }
7505
- ) : /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react15.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react15.default.createElement("div", null, /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react15.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react15.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node")), /* @__PURE__ */ import_react15.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react15.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ import_react15.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react15.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react15.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react15.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react15.default.createElement(
7582
+ ) : /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react15.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react15.default.createElement("div", null, /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react15.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react15.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ import_react15.default.createElement(
7583
+ "button",
7584
+ {
7585
+ onClick: handleCopyLink,
7586
+ className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-indigo-400"}`,
7587
+ title: isLinkCopied ? "Link Copiado!" : "Copiar link para este Node"
7588
+ },
7589
+ isLinkCopied ? /* @__PURE__ */ import_react15.default.createElement(import_fi14.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react15.default.createElement(import_fi14.FiLink, { size: 12 })
7590
+ )), /* @__PURE__ */ import_react15.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react15.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ import_react15.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react15.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react15.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react15.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react15.default.createElement(
7506
7591
  "button",
7507
7592
  {
7508
7593
  type: "button",
@@ -7655,8 +7740,7 @@ function NodeDetailsPanel({
7655
7740
  isSaving && /* @__PURE__ */ import_react15.default.createElement(import_fi14.FiLoader, { className: "animate-spin" }),
7656
7741
  isSaving ? "Salvando..." : "Salvar"
7657
7742
  )))
7658
- ), isDescriptionModalOpen && canEdit && // MODIFICAÇÃO: Modal de edição só abre se canEdit
7659
- /* @__PURE__ */ import_react15.default.createElement(
7743
+ ), isDescriptionModalOpen && canEdit && /* @__PURE__ */ import_react15.default.createElement(
7660
7744
  DescriptionEditModal,
7661
7745
  {
7662
7746
  isOpen: isDescriptionModalOpen,
@@ -8968,6 +9052,9 @@ function XViewScene({
8968
9052
  var _a, _b, _c, _d, _e, _f;
8969
9053
  const { data: session, status } = (0, import_react24.useSession)();
8970
9054
  const router = (0, import_navigation.useRouter)();
9055
+ const searchParams = (0, import_navigation.useSearchParams)();
9056
+ const focusNodeId = searchParams == null ? void 0 : searchParams.get("focus");
9057
+ const focusAncestryId = searchParams == null ? void 0 : searchParams.get("ancestry");
8971
9058
  const viewParams = (0, import_react23.useMemo)(() => {
8972
9059
  if (encryptedConfig) {
8973
9060
  const data = decryptData(encryptedConfig);
@@ -8999,6 +9086,9 @@ function XViewScene({
8999
9086
  }
9000
9087
  if (viewParams && session && status === "authenticated") {
9001
9088
  verifyPermission();
9089
+ } else if (status === "unauthenticated") {
9090
+ setPermissionStatus("denied");
9091
+ setIsLoading(false);
9002
9092
  }
9003
9093
  }, [viewParams, session, status, check_user_permission]);
9004
9094
  const sceneConfigId = (0, import_react23.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
@@ -9034,11 +9124,14 @@ function XViewScene({
9034
9124
  const [relationshipMenu, setRelationshipMenu] = (0, import_react23.useState)({ visible: false, x: 0, y: 0, linkObject: null });
9035
9125
  const [creationMode, setCreationMode] = (0, import_react23.useState)({ isActive: false, sourceNodeData: null });
9036
9126
  const [versionMode, setVersionMode] = (0, import_react23.useState)({ isActive: false, sourceNodeData: null });
9127
+ const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react23.useState)(false);
9128
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react23.useState)(false);
9037
9129
  const [ancestryMode, setAncestryMode] = (0, import_react23.useState)({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9038
9130
  const [readingMode, setReadingMode] = (0, import_react23.useState)({
9039
9131
  isActive: false,
9040
9132
  ancestry: null,
9041
- branchStack: []
9133
+ branchStack: [],
9134
+ autoAbstraction: false
9042
9135
  });
9043
9136
  const [formPosition, setFormPosition] = (0, import_react23.useState)({ left: 16, top: 16, opacity: 0 });
9044
9137
  const [detailsNode, setDetailsNode] = (0, import_react23.useState)(null);
@@ -9613,12 +9706,23 @@ function XViewScene({
9613
9706
  const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
9614
9707
  const [sceneResponse, boardResponse] = await Promise.all([scenePromise, boardPromise]);
9615
9708
  if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
9709
+ if (focusNodeId) {
9710
+ let targetNode = sceneResponse.data.scene.nodes.find((n) => String(n.id) === String(focusNodeId));
9711
+ if (!targetNode) {
9712
+ const allParentNodes = Object.values(sceneResponse.data.parent).flatMap((f) => f.nodes || []);
9713
+ targetNode = allParentNodes.find((n) => String(n.id) === String(focusNodeId));
9714
+ }
9715
+ if (targetNode) {
9716
+ sceneResponse.data.scene.nodes = [targetNode];
9717
+ sceneResponse.data.scene.links = [];
9718
+ }
9719
+ } else if (focusAncestryId) {
9720
+ sceneResponse.data.scene.nodes = [];
9721
+ sceneResponse.data.scene.links = [];
9722
+ }
9616
9723
  sceneDataRef.current = sceneResponse.data.scene;
9617
9724
  parentDataRef.current = sceneResponse.data.parent;
9618
9725
  ancestryDataRef.current = sceneResponse.data.ancestry;
9619
- console.log("Console de sceneDataRef.current no useEffect inicial:", sceneDataRef.current);
9620
- console.log("Console de parentDataRef.current no useEffect inicial:", parentDataRef.current);
9621
- console.log("Console de ancestryDataRef.current no useEffect inicial:", ancestryDataRef.current);
9622
9726
  setIsInitialized(true);
9623
9727
  } else {
9624
9728
  console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
@@ -9626,7 +9730,6 @@ function XViewScene({
9626
9730
  if (boardResponse == null ? void 0 : boardResponse.success) {
9627
9731
  setAncestryBoardData(boardResponse.data);
9628
9732
  } else {
9629
- console.warn("Ancestry Board n\xE3o carregado ou vazio:", boardResponse == null ? void 0 : boardResponse.error);
9630
9733
  setAncestryBoardData([]);
9631
9734
  }
9632
9735
  } catch (error) {
@@ -9650,11 +9753,14 @@ function XViewScene({
9650
9753
  status,
9651
9754
  ownerId,
9652
9755
  viewParams,
9653
- // Importante incluir viewParams nas dependências
9654
9756
  get_scene_view_data,
9655
9757
  get_ancestry_board_action,
9656
9758
  isInitialized,
9657
- permissionStatus
9759
+ permissionStatus,
9760
+ focusNodeId,
9761
+ // <-- MANTIDO
9762
+ focusAncestryId
9763
+ // <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
9658
9764
  ]);
9659
9765
  const isNodeInView = (0, import_react23.useCallback)((id) => {
9660
9766
  const key = String(id);
@@ -11341,19 +11447,30 @@ function XViewScene({
11341
11447
  currentMaxIndex: 0,
11342
11448
  progressMap: {}
11343
11449
  };
11450
+ const hasDescription = ancestryObject.description && ancestryObject.description.trim() !== "";
11451
+ const hasMainTreeNodes = ancestryObject.tree.children && ancestryObject.tree.children.length > 0;
11452
+ const hasAbstractionNodes = ancestryObject.abstraction_tree && ancestryObject.abstraction_tree.children && ancestryObject.abstraction_tree.children.length > 0;
11453
+ const shouldAutoRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
11344
11454
  setReadingMode({
11345
11455
  isActive: true,
11346
11456
  ancestry: ancestryObject,
11347
- branchStack: []
11457
+ branchStack: [],
11458
+ autoAbstraction: shouldAutoRenderAbstraction
11459
+ // <--- FLAG ENVIADA PARA A UI
11348
11460
  });
11349
- const initialSections = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
11350
- const ancestryWithForceUpdate = {
11351
- ...ancestryObject,
11352
- _forceUpdate: true
11353
- };
11354
- await handleRenderAncestry(ancestryWithForceUpdate, initialSections);
11461
+ if (shouldAutoRenderAbstraction) {
11462
+ handleRenderAbstractionTree(ancestryObject, null);
11463
+ } else {
11464
+ const initialSections = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
11465
+ const ancestryWithForceUpdate = {
11466
+ ...ancestryObject,
11467
+ _forceUpdate: true
11468
+ };
11469
+ await handleRenderAncestry(ancestryWithForceUpdate, initialSections);
11470
+ }
11355
11471
  },
11356
- [handleRenderAncestry]
11472
+ [handleRenderAncestry, handleRenderAbstractionTree]
11473
+ // <--- DEPENDÊNCIA ADICIONADA
11357
11474
  );
11358
11475
  const handleReadModeSectionChange = (0, import_react23.useCallback)((activeSectionId) => {
11359
11476
  const { ancestry, branchStack } = readingMode;
@@ -11927,6 +12044,34 @@ function XViewScene({
11927
12044
  tweenToTarget(nodeMesh, 1.2);
11928
12045
  }
11929
12046
  }, [tweenToTarget]);
12047
+ (0, import_react23.useEffect)(() => {
12048
+ if (isInitialized && focusNodeId && !hasFocusedInitial) {
12049
+ const nodeObjects = stateRef.current.nodeObjects || {};
12050
+ const targetMesh = nodeObjects[String(focusNodeId)];
12051
+ if (targetMesh) {
12052
+ setTimeout(() => {
12053
+ tweenToTarget(targetMesh, 1.2);
12054
+ setHasFocusedInitial(true);
12055
+ }, 300);
12056
+ } else {
12057
+ setHasFocusedInitial(true);
12058
+ }
12059
+ }
12060
+ }, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
12061
+ (0, import_react23.useEffect)(() => {
12062
+ if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
12063
+ const ancestries = ancestryDataRef.current || [];
12064
+ const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
12065
+ if (targetAncestry) {
12066
+ setTimeout(() => {
12067
+ handleStartReadingAncestry(targetAncestry);
12068
+ setHasOpenedInitialAncestry(true);
12069
+ }, 300);
12070
+ } else {
12071
+ setHasOpenedInitialAncestry(true);
12072
+ }
12073
+ }
12074
+ }, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
11930
12075
  if (isLoading || status === "loading" || permissionStatus === "loading") {
11931
12076
  return /* @__PURE__ */ import_react23.default.createElement(LoadingScreen, null);
11932
12077
  }
@@ -12021,11 +12166,13 @@ function XViewScene({
12021
12166
  DescriptionReadModePanel,
12022
12167
  {
12023
12168
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
12169
+ ancestryId: readingMode.ancestry.ancestry_id,
12024
12170
  title: (getReadModeDisplayContext == null ? void 0 : getReadModeDisplayContext.name) || readingMode.ancestry.name || "Ancestralidade",
12025
12171
  initialSectionId: readingMode.initialSectionId,
12026
12172
  description: getReadModeDisplayContext == null ? void 0 : getReadModeDisplayContext.description,
12027
12173
  savedSections: getReadModeDisplayContext == null ? void 0 : getReadModeDisplayContext.description_sections,
12028
12174
  customProperties: (getReadModeDisplayContext == null ? void 0 : getReadModeDisplayContext.customProperties) || [],
12175
+ initialShowAbstraction: readingMode.autoAbstraction,
12029
12176
  onBack: null,
12030
12177
  onEdit: () => {
12031
12178
  handleCloseReadMode();