@lv-x-software-house/x_view 1.2.4 → 1.2.5-dev.2

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 +1684 -815
  2. package/dist/index.mjs +1691 -816
  3. package/package.json +52 -43
package/dist/index.js CHANGED
@@ -446,11 +446,18 @@ function ContextMenu({
446
446
  ))));
447
447
  };
448
448
  const renderAncestryActionsView = () => {
449
+ var _a2, _b2;
449
450
  const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
450
- return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
451
- onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry);
451
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
452
+ onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "full");
453
+ onClose();
454
+ }, className: baseButtonClass, title: "Renderizar Ancestralidade Completa" }, /* @__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: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Renderizar Ancestralidade")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
455
+ onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "ancestry_only");
452
456
  onClose();
453
- }, className: baseButtonClass, title: "Renderizar 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: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Renderizar Ancestralidade")), ability.can("update", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
457
+ }, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Ancestralidade (Radial)" }, /* @__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: "M12 2v3m0 14v3m10-10h-3m-14 0H2m15.66-6.34-2.12 2.12m-9.08 9.08-2.12 2.12m13.32 0-2.12-2.12m-9.08-9.08-2.12-2.12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "\xC1rvore de Ancestralidade")), ((_b2 = (_a2 = selectedAncestry == null ? void 0 : selectedAncestry.abstraction_tree) == null ? void 0 : _a2.children) == null ? void 0 : _b2.length) > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
458
+ onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "abstraction_only");
459
+ onClose();
460
+ }, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Abstra\xE7\xE3o (Vertical)" }, /* @__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("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 6.5h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 17.5h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.5 10v4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17.5 10v4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "\xC1rvore de Abstra\xE7\xE3o"))), ability.can("update", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
454
461
  onEditAncestry == null ? void 0 : onEditAncestry(selectedAncestry);
455
462
  onClose();
456
463
  }, className: baseButtonClass, title: "Editar 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: "M12 20h9" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Editar Ancestralidade")), (ability.can("update", "Ancestry") || ability.can("delete", "Ancestry")) && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), ability.can("delete", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
@@ -9890,7 +9897,6 @@ var GroupItem = ({
9890
9897
  onPlayAncestry,
9891
9898
  availableIds,
9892
9899
  canEdit
9893
- // [NOVO] Recebe permissão de edição
9894
9900
  }) => {
9895
9901
  const canIndent = index > 0;
9896
9902
  const isPickingForThisGroup = pickingGroupId === group.id;
@@ -9905,107 +9911,126 @@ var GroupItem = ({
9905
9911
  (0, import_react25.useEffect)(() => {
9906
9912
  adjustHeight();
9907
9913
  }, [group.text]);
9908
- return /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react25.default.createElement("div", { className: `
9914
+ return /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react25.default.createElement(
9915
+ "div",
9916
+ {
9917
+ className: `
9909
9918
  flex flex-col gap-2 py-2 px-3 transition-all duration-200
9910
9919
  ${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
9911
- ` }, /* @__PURE__ */ import_react25.default.createElement(
9912
- "textarea",
9913
- {
9914
- ref: textareaRef,
9915
- className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
9916
- rows: 1,
9917
- style: {
9918
- minHeight: "1.5rem",
9919
- maxHeight: "250px"
9920
- },
9921
- placeholder: canEdit ? "Escreva sobre este grupo..." : "",
9922
- value: group.text,
9923
- readOnly: !canEdit,
9924
- onChange: (e) => {
9925
- if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
9926
- }
9927
- }
9928
- ), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
9929
- const isValid = availableIds.has(String(anc.ancestry_id));
9930
- return /* @__PURE__ */ import_react25.default.createElement(
9931
- "div",
9920
+ `
9921
+ },
9922
+ /* @__PURE__ */ import_react25.default.createElement(
9923
+ "textarea",
9932
9924
  {
9933
- key: anc.ancestry_id,
9934
- className: `
9925
+ ref: textareaRef,
9926
+ className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
9927
+ rows: 1,
9928
+ style: {
9929
+ minHeight: "1.5rem",
9930
+ maxHeight: "250px"
9931
+ },
9932
+ placeholder: canEdit ? "Escreva sobre este grupo..." : "",
9933
+ value: group.text,
9934
+ readOnly: !canEdit,
9935
+ onChange: (e) => {
9936
+ if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
9937
+ }
9938
+ }
9939
+ ),
9940
+ group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
9941
+ const isValid = availableIds.has(String(anc.ancestry_id));
9942
+ return /* @__PURE__ */ import_react25.default.createElement(
9943
+ "div",
9944
+ {
9945
+ key: anc.ancestry_id,
9946
+ className: `
9935
9947
  flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
9936
9948
  ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
9937
9949
  `,
9938
- title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
9939
- },
9940
- isValid ? (
9941
- // [MANTIDO] Botão Play visível para todos
9950
+ title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
9951
+ },
9952
+ isValid ? (
9953
+ // [MANTIDO] Botão Play visível para todos
9954
+ /* @__PURE__ */ import_react25.default.createElement(
9955
+ "button",
9956
+ {
9957
+ onClick: () => onPlayAncestry(anc.ancestry_id),
9958
+ className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
9959
+ title: "Renderizar no cen\xE1rio"
9960
+ },
9961
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9962
+ )
9963
+ ) : /* @__PURE__ */ import_react25.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiAlertTriangle, { size: 10 })),
9942
9964
  /* @__PURE__ */ import_react25.default.createElement(
9965
+ "span",
9966
+ {
9967
+ className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}`
9968
+ },
9969
+ anc.name
9970
+ ),
9971
+ canEdit && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(
9972
+ "div",
9973
+ {
9974
+ className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}`
9975
+ }
9976
+ ), /* @__PURE__ */ import_react25.default.createElement(
9943
9977
  "button",
9944
9978
  {
9945
- onClick: () => onPlayAncestry(anc.ancestry_id),
9946
- className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
9947
- title: "Renderizar no cen\xE1rio"
9979
+ onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
9980
+ className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
9981
+ title: "Remover men\xE7\xE3o"
9948
9982
  },
9949
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9950
- )
9951
- ) : /* @__PURE__ */ import_react25.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiAlertTriangle, { size: 10 })),
9952
- /* @__PURE__ */ import_react25.default.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
9953
- canEdit && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ import_react25.default.createElement(
9954
- "button",
9955
- {
9956
- onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
9957
- className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
9958
- title: "Remover men\xE7\xE3o"
9959
- },
9960
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiX, { size: 12 })
9961
- ))
9962
- );
9963
- })), canEdit && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.createElement(
9964
- "button",
9965
- {
9966
- onClick: () => onRequestPickAncestry(group.id),
9967
- className: `
9983
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiX, { size: 12 })
9984
+ ))
9985
+ );
9986
+ })),
9987
+ canEdit && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.createElement(
9988
+ "button",
9989
+ {
9990
+ onClick: () => onRequestPickAncestry(group.id),
9991
+ className: `
9968
9992
  flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
9969
9993
  ${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
9970
9994
  `,
9971
- title: "Adicionar Ancestralidade a este grupo"
9972
- },
9973
- isPickingForThisGroup ? /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiSearch, { size: 12 }),
9974
- isPickingForThisGroup ? "Selecionando..." : "Adicionar"
9975
- ), /* @__PURE__ */ import_react25.default.createElement(
9976
- "button",
9977
- {
9978
- onClick: () => onAddSubgroup(group.id),
9979
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
9980
- title: "Criar Subgrupo"
9981
- },
9982
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 14 })
9983
- )), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.createElement(
9984
- "button",
9985
- {
9986
- onClick: () => onIndent(group.id),
9987
- disabled: !canIndent,
9988
- className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
9989
- title: "Aninhar no grupo acima"
9990
- },
9991
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiArrowRight, { size: 14 })
9992
- ), /* @__PURE__ */ import_react25.default.createElement(
9993
- "button",
9994
- {
9995
- onClick: () => onOutdent(group.id),
9996
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
9997
- title: "Desaninhar"
9998
- },
9999
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiArrowLeft, { size: 14 })
10000
- ), /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.createElement(
10001
- "button",
10002
- {
10003
- onClick: () => onDelete(group.id),
10004
- className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
10005
- title: "Remover Grupo"
10006
- },
10007
- /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiTrash2, { size: 14 })
10008
- )))), group.children && group.children.length > 0 && /* @__PURE__ */ import_react25.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react25.default.createElement(
9995
+ title: "Adicionar Ancestralidade a este grupo"
9996
+ },
9997
+ isPickingForThisGroup ? /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiSearch, { size: 12 }),
9998
+ isPickingForThisGroup ? "Selecionando..." : "Adicionar"
9999
+ ), /* @__PURE__ */ import_react25.default.createElement(
10000
+ "button",
10001
+ {
10002
+ onClick: () => onAddSubgroup(group.id),
10003
+ className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
10004
+ title: "Criar Subgrupo"
10005
+ },
10006
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 14 })
10007
+ )), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.createElement(
10008
+ "button",
10009
+ {
10010
+ onClick: () => onIndent(group.id),
10011
+ disabled: !canIndent,
10012
+ className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
10013
+ title: "Aninhar no grupo acima"
10014
+ },
10015
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiArrowRight, { size: 14 })
10016
+ ), /* @__PURE__ */ import_react25.default.createElement(
10017
+ "button",
10018
+ {
10019
+ onClick: () => onOutdent(group.id),
10020
+ className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
10021
+ title: "Desaninhar"
10022
+ },
10023
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiArrowLeft, { size: 14 })
10024
+ ), /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.createElement(
10025
+ "button",
10026
+ {
10027
+ onClick: () => onDelete(group.id),
10028
+ className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
10029
+ title: "Remover Grupo"
10030
+ },
10031
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiTrash2, { size: 14 })
10032
+ )))
10033
+ ), group.children && group.children.length > 0 && /* @__PURE__ */ import_react25.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react25.default.createElement(
10009
10034
  GroupItem,
10010
10035
  {
10011
10036
  key: childGroup.id,
@@ -10214,7 +10239,9 @@ function AncestryBoard({
10214
10239
  const addRecursive = (list) => {
10215
10240
  return list.map((g) => {
10216
10241
  if (g.id === pickingGroupId) {
10217
- const exists = g.ancestries.some((a) => a.ancestry_id === ancestry.ancestry_id);
10242
+ const exists = g.ancestries.some(
10243
+ (a) => a.ancestry_id === ancestry.ancestry_id
10244
+ );
10218
10245
  if (exists) return g;
10219
10246
  return { ...g, ancestries: [...g.ancestries, ancestry] };
10220
10247
  }
@@ -10225,12 +10252,16 @@ function AncestryBoard({
10225
10252
  });
10226
10253
  setPickingGroupId(null);
10227
10254
  } else {
10228
- const fullAncestry = availableAncestries.find((a) => a.ancestry_id === ancestry.ancestry_id) || ancestry;
10255
+ const fullAncestry = availableAncestries.find(
10256
+ (a) => a.ancestry_id === ancestry.ancestry_id
10257
+ ) || ancestry;
10229
10258
  onSelect(fullAncestry);
10230
10259
  }
10231
10260
  };
10232
10261
  const handlePlayFromGroup = (ancestryId) => {
10233
- const fullAncestry = availableAncestries.find((a) => a.ancestry_id === ancestryId);
10262
+ const fullAncestry = availableAncestries.find(
10263
+ (a) => a.ancestry_id === ancestryId
10264
+ );
10234
10265
  if (fullAncestry && onSelect) {
10235
10266
  onSelect(fullAncestry);
10236
10267
  }
@@ -10240,7 +10271,12 @@ function AncestryBoard({
10240
10271
  const removeRecursive = (list) => {
10241
10272
  return list.map((g) => {
10242
10273
  if (g.id === groupId) {
10243
- return { ...g, ancestries: g.ancestries.filter((a) => a.ancestry_id !== ancestryId) };
10274
+ return {
10275
+ ...g,
10276
+ ancestries: g.ancestries.filter(
10277
+ (a) => a.ancestry_id !== ancestryId
10278
+ )
10279
+ };
10244
10280
  }
10245
10281
  return { ...g, children: removeRecursive(g.children) };
10246
10282
  });
@@ -10261,7 +10297,13 @@ function AncestryBoard({
10261
10297
  className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
10262
10298
  onClick: (e) => e.stopPropagation()
10263
10299
  },
10264
- /* @__PURE__ */ import_react25.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react25.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLoader, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ import_react25.default.createElement(
10300
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react25.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(
10301
+ import_fi19.FiLoader,
10302
+ {
10303
+ className: "animate-spin text-indigo-400",
10304
+ size: 12
10305
+ }
10306
+ ), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ import_react25.default.createElement(
10265
10307
  "button",
10266
10308
  {
10267
10309
  onClick: handleAddRootGroup,
@@ -10277,57 +10319,75 @@ function AncestryBoard({
10277
10319
  },
10278
10320
  "\xD7"
10279
10321
  ))),
10280
- /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: `
10322
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react25.default.createElement(
10323
+ "div",
10324
+ {
10325
+ className: `
10281
10326
  flex flex-col border-r border-white/10 transition-all duration-300 flex-none
10282
10327
  ${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
10283
10328
  min-w-[280px] max-w-[500px] bg-slate-900
10284
- ` }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiSearch, { className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}` }), /* @__PURE__ */ import_react25.default.createElement(
10285
- "input",
10286
- {
10287
- type: "text",
10288
- placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
10289
- className: `
10329
+ `
10330
+ },
10331
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react25.default.createElement(
10332
+ import_fi19.FiSearch,
10333
+ {
10334
+ className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}`
10335
+ }
10336
+ ), /* @__PURE__ */ import_react25.default.createElement(
10337
+ "input",
10338
+ {
10339
+ type: "text",
10340
+ placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
10341
+ className: `
10290
10342
  w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
10291
10343
  ${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
10292
10344
  `,
10293
- value: searchTerm,
10294
- onChange: (e) => setSearchTerm(e.target.value),
10295
- autoFocus: !pickingGroupId
10296
- }
10297
- ))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
10298
- const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
10299
- const isPicking = !!pickingGroupId;
10300
- return /* @__PURE__ */ import_react25.default.createElement(
10301
- "div",
10302
- {
10303
- key: anc.ancestry_id,
10304
- onClick: () => {
10305
- if (isPicking) handleSelectAncestry(anc);
10306
- },
10307
- className: `
10345
+ value: searchTerm,
10346
+ onChange: (e) => setSearchTerm(e.target.value),
10347
+ autoFocus: !pickingGroupId
10348
+ }
10349
+ ))),
10350
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
10351
+ const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
10352
+ const isPicking = !!pickingGroupId;
10353
+ return /* @__PURE__ */ import_react25.default.createElement(
10354
+ "div",
10355
+ {
10356
+ key: anc.ancestry_id,
10357
+ onClick: () => {
10358
+ if (isPicking) handleSelectAncestry(anc);
10359
+ },
10360
+ className: `
10308
10361
  group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
10309
10362
  ${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
10310
10363
  `
10311
- },
10312
- /* @__PURE__ */ import_react25.default.createElement("div", { className: `
10364
+ },
10365
+ /* @__PURE__ */ import_react25.default.createElement(
10366
+ "div",
10367
+ {
10368
+ className: `
10313
10369
  mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
10314
10370
  ${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
10315
- ` }, isPicking ? /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 14 })),
10316
- /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react25.default.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ import_react25.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
10317
- !isPicking && /* @__PURE__ */ import_react25.default.createElement(
10318
- "button",
10319
- {
10320
- onClick: (e) => {
10321
- e.stopPropagation();
10322
- handleSelectAncestry(anc);
10371
+ `
10323
10372
  },
10324
- className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
10325
- title: "Renderizar Ancestralidade"
10326
- },
10327
- /* @__PURE__ */ import_react25.default.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 14, className: "ml-0.5" }))
10328
- )
10329
- );
10330
- }))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react25.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react25.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react25.default.createElement(
10373
+ isPicking ? /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 14 })
10374
+ ),
10375
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react25.default.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ import_react25.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
10376
+ !isPicking && /* @__PURE__ */ import_react25.default.createElement(
10377
+ "button",
10378
+ {
10379
+ onClick: (e) => {
10380
+ e.stopPropagation();
10381
+ handleSelectAncestry(anc);
10382
+ },
10383
+ className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
10384
+ title: "Renderizar Ancestralidade"
10385
+ },
10386
+ /* @__PURE__ */ import_react25.default.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 14, className: "ml-0.5" }))
10387
+ )
10388
+ );
10389
+ }))
10390
+ ), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react25.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react25.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react25.default.createElement(
10331
10391
  GroupItem,
10332
10392
  {
10333
10393
  key: group.id,
@@ -10406,7 +10466,10 @@ var findNodePath3 = (tree, targetNodeId, currentPath = []) => {
10406
10466
  }
10407
10467
  if (tree.children) {
10408
10468
  for (let i = 0; i < tree.children.length; i++) {
10409
- const res = findNodePath3(tree.children[i], targetNodeId, [...currentPath, i]);
10469
+ const res = findNodePath3(tree.children[i], targetNodeId, [
10470
+ ...currentPath,
10471
+ i
10472
+ ]);
10410
10473
  if (res) return res;
10411
10474
  }
10412
10475
  }
@@ -10499,27 +10562,70 @@ function XViewScene({
10499
10562
  const [userPermissionRole, setUserPermissionRole] = (0, import_react26.useState)(null);
10500
10563
  const [isInitialized, setIsInitialized] = (0, import_react26.useState)(false);
10501
10564
  const [sceneVersion, setSceneVersion] = (0, import_react26.useState)(0);
10502
- const [contextMenu, setContextMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, nodeData: null });
10503
- const [multiContextMenu, setMultiContextMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, nodeIds: null });
10504
- const [relationshipMenu, setRelationshipMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, linkObject: null });
10505
- const [creationMode, setCreationMode] = (0, import_react26.useState)({ isActive: false, sourceNodeData: null });
10506
- const [versionMode, setVersionMode] = (0, import_react26.useState)({ isActive: false, sourceNodeData: null });
10565
+ const [contextMenu, setContextMenu] = (0, import_react26.useState)({
10566
+ visible: false,
10567
+ x: 0,
10568
+ y: 0,
10569
+ nodeData: null
10570
+ });
10571
+ const [multiContextMenu, setMultiContextMenu] = (0, import_react26.useState)({
10572
+ visible: false,
10573
+ x: 0,
10574
+ y: 0,
10575
+ nodeIds: null
10576
+ });
10577
+ const [relationshipMenu, setRelationshipMenu] = (0, import_react26.useState)({
10578
+ visible: false,
10579
+ x: 0,
10580
+ y: 0,
10581
+ linkObject: null
10582
+ });
10583
+ const [creationMode, setCreationMode] = (0, import_react26.useState)({
10584
+ isActive: false,
10585
+ sourceNodeData: null
10586
+ });
10587
+ const [versionMode, setVersionMode] = (0, import_react26.useState)({
10588
+ isActive: false,
10589
+ sourceNodeData: null
10590
+ });
10507
10591
  const [questMode, setQuestMode] = (0, import_react26.useState)({ isActive: false });
10508
10592
  const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react26.useState)(false);
10509
10593
  const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react26.useState)(false);
10510
- const [ancestryMode, setAncestryMode] = (0, import_react26.useState)({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
10594
+ const [ancestryMode, setAncestryMode] = (0, import_react26.useState)({
10595
+ isActive: false,
10596
+ tree: null,
10597
+ selectedParentId: null,
10598
+ isEditMode: false,
10599
+ currentAncestryId: null,
10600
+ ancestryName: "",
10601
+ ancestryDescription: "",
10602
+ ancestryDescriptionSections: [],
10603
+ isAddingNodes: false
10604
+ });
10511
10605
  const [readingMode, setReadingMode] = (0, import_react26.useState)({
10512
10606
  isActive: false,
10513
10607
  ancestry: null,
10514
10608
  branchStack: [],
10515
10609
  autoAbstraction: false
10516
10610
  });
10517
- const [formPosition, setFormPosition] = (0, import_react26.useState)({ left: 16, top: 16, opacity: 0 });
10611
+ const [formPosition, setFormPosition] = (0, import_react26.useState)({
10612
+ left: 16,
10613
+ top: 16,
10614
+ opacity: 0
10615
+ });
10518
10616
  const [detailsNode, setDetailsNode] = (0, import_react26.useState)(null);
10519
10617
  const [detailsLink, setDetailsLink] = (0, import_react26.useState)(null);
10520
10618
  const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react26.useState)(null);
10521
- const [imageViewer, setImageViewer] = (0, import_react26.useState)({ visible: false, images: [], startIndex: 0 });
10522
- const [editingAncestryRel, setEditingAncestryRel] = (0, import_react26.useState)({ visible: false, data: null, path: null });
10619
+ const [imageViewer, setImageViewer] = (0, import_react26.useState)({
10620
+ visible: false,
10621
+ images: [],
10622
+ startIndex: 0
10623
+ });
10624
+ const [editingAncestryRel, setEditingAncestryRel] = (0, import_react26.useState)({
10625
+ visible: false,
10626
+ data: null,
10627
+ path: null
10628
+ });
10523
10629
  const [isImportModalOpen, setIsImportModalOpen] = (0, import_react26.useState)(false);
10524
10630
  const [importSuccessMessage, setImportSuccessMessage] = (0, import_react26.useState)("");
10525
10631
  const [highlightedNodeId, setHighlightedNodeId] = (0, import_react26.useState)(null);
@@ -10559,8 +10665,23 @@ function XViewScene({
10559
10665
  ghostElements: { node: null, line: null, aura: null },
10560
10666
  creation: { isActive: false, sourceNodeData: null },
10561
10667
  connection: { isActive: false, sourceNodeData: null, line: null },
10562
- relink: { isActive: false, end: null, fixedNodeId: null, originalLine: null, line: null },
10563
- ancestry: { isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", isAddingNodes: false },
10668
+ relink: {
10669
+ isActive: false,
10670
+ end: null,
10671
+ fixedNodeId: null,
10672
+ originalLine: null,
10673
+ line: null
10674
+ },
10675
+ ancestry: {
10676
+ isActive: false,
10677
+ tree: null,
10678
+ selectedParentId: null,
10679
+ isEditMode: false,
10680
+ currentAncestryId: null,
10681
+ ancestryName: "",
10682
+ ancestryDescription: "",
10683
+ isAddingNodes: false
10684
+ },
10564
10685
  glowTexture: null,
10565
10686
  nodeIdToParentFileMap: null,
10566
10687
  maxAncestryRenderIndex: 0,
@@ -10569,7 +10690,11 @@ function XViewScene({
10569
10690
  highlightedNodeId: null
10570
10691
  });
10571
10692
  const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
10572
- const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
10693
+ const {
10694
+ width: readModeWidth,
10695
+ isResizing: isReadModeResizing,
10696
+ handlePointerDown: handleReadModeResize
10697
+ } = useResizablePanel({
10573
10698
  initialWidth: 700,
10574
10699
  minWidth: 320,
10575
10700
  maxWidth: maxReadPanelW
@@ -10586,7 +10711,9 @@ function XViewScene({
10586
10711
  for (const parentFileId in allParentData) {
10587
10712
  if (allParentData.hasOwnProperty(parentFileId)) {
10588
10713
  const parentFile = allParentData[parentFileId];
10589
- const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
10714
+ const parentDbInfo = parentDbsArray.find(
10715
+ (db) => String(db.db_id) === String(parentFileId)
10716
+ );
10590
10717
  const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
10591
10718
  const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
10592
10719
  if (parentFile.nodes && ownerId2) {
@@ -10622,7 +10749,10 @@ function XViewScene({
10622
10749
  if (files.length > 0 && get_single_parent_file && save_view_data) {
10623
10750
  for (const file of files) {
10624
10751
  try {
10625
- const parentFileData = await get_single_parent_file(file.id, session);
10752
+ const parentFileData = await get_single_parent_file(
10753
+ file.id,
10754
+ session
10755
+ );
10626
10756
  if (parentFileData.success && parentFileData.data) {
10627
10757
  parentDataRef.current = {
10628
10758
  ...parentDataRef.current,
@@ -10633,7 +10763,11 @@ function XViewScene({
10633
10763
  owner_id: session.user.id
10634
10764
  };
10635
10765
  updatedParentDbs.push(newParentDbObject);
10636
- await add_new_parent_file_to_scene_at_firebase_action(sceneConfigId, session, file.id);
10766
+ await add_new_parent_file_to_scene_at_firebase_action(
10767
+ sceneConfigId,
10768
+ session,
10769
+ file.id
10770
+ );
10637
10771
  importedIds.push(file.id);
10638
10772
  successCount++;
10639
10773
  }
@@ -10645,7 +10779,10 @@ function XViewScene({
10645
10779
  if (viewToImport && get_ancestry_file) {
10646
10780
  try {
10647
10781
  const targetViewOwnerId = ((_b2 = (_a2 = viewToImport.members) == null ? void 0 : _a2.find((m) => m.permission === "owner")) == null ? void 0 : _b2.id) || session.user.id;
10648
- const ancestryResponse = await get_ancestry_file(viewToImport.id, targetViewOwnerId);
10782
+ const ancestryResponse = await get_ancestry_file(
10783
+ viewToImport.id,
10784
+ targetViewOwnerId
10785
+ );
10649
10786
  if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
10650
10787
  const viewSpecificAncestries = ancestryResponse.data.filter(
10651
10788
  (anc) => anc._source_file_id === viewToImport.id && !anc.is_private
@@ -10656,14 +10793,21 @@ function XViewScene({
10656
10793
  _imported_from_view_owner_id: targetViewOwnerId,
10657
10794
  _source_file_id: viewToImport.id,
10658
10795
  _source_owner_id: targetViewOwnerId,
10659
- _origin_db_ids: (viewToImport.selected_databases || []).map((db) => db.db_id)
10796
+ _origin_db_ids: (viewToImport.selected_databases || []).map(
10797
+ (db) => db.db_id
10798
+ )
10660
10799
  }));
10661
10800
  const currentAncestries = ancestryDataRef.current || [];
10662
10801
  const newAncestries = processedAncestries.filter(
10663
- (newAnc) => !currentAncestries.some((curr) => String(curr.ancestry_id) === String(newAnc.ancestry_id))
10802
+ (newAnc) => !currentAncestries.some(
10803
+ (curr) => String(curr.ancestry_id) === String(newAnc.ancestry_id)
10804
+ )
10664
10805
  );
10665
10806
  if (newAncestries.length > 0) {
10666
- ancestryDataRef.current = [...currentAncestries, ...newAncestries];
10807
+ ancestryDataRef.current = [
10808
+ ...currentAncestries,
10809
+ ...newAncestries
10810
+ ];
10667
10811
  ancestriesWereImported = true;
10668
10812
  }
10669
10813
  }
@@ -10683,7 +10827,9 @@ function XViewScene({
10683
10827
  if (ancestry_save_url) {
10684
10828
  await save_view_data(ancestry_save_url, ancestryDataRef.current);
10685
10829
  } else {
10686
- console.error("Erro: URL de salvamento de ancestralidade n\xE3o definida.");
10830
+ console.error(
10831
+ "Erro: URL de salvamento de ancestralidade n\xE3o definida."
10832
+ );
10687
10833
  }
10688
10834
  }
10689
10835
  setSceneVersion((v) => v + 1);
@@ -10691,113 +10837,136 @@ function XViewScene({
10691
10837
  setImportSuccessMessage("Importa\xE7\xE3o conclu\xEDda com sucesso.");
10692
10838
  setTimeout(() => setImportSuccessMessage(""), 5e3);
10693
10839
  } else if (viewToImport && !ancestriesWereImported) {
10694
- console.warn("Importa\xE7\xE3o finalizada, mas nenhum dado novo foi adicionado.");
10840
+ console.warn(
10841
+ "Importa\xE7\xE3o finalizada, mas nenhum dado novo foi adicionado."
10842
+ );
10695
10843
  }
10696
10844
  },
10697
- [get_single_parent_file, get_ancestry_file, save_view_data, session, sceneSaveUrl, ancestry_save_url, sceneConfigId, add_new_parent_file_to_scene_at_firebase_action]
10845
+ [
10846
+ get_single_parent_file,
10847
+ get_ancestry_file,
10848
+ save_view_data,
10849
+ session,
10850
+ sceneSaveUrl,
10851
+ ancestry_save_url,
10852
+ sceneConfigId,
10853
+ add_new_parent_file_to_scene_at_firebase_action
10854
+ ]
10698
10855
  );
10699
10856
  const handleOpenImageViewer = (images, startIndex) => {
10700
10857
  setImageViewer({ visible: true, images, startIndex });
10701
10858
  };
10702
- const tweenToTarget = (0, import_react26.useCallback)((target, zoomFactor = 1, forcedDirection = null) => {
10703
- const { camera, controls, tweenGroup } = stateRef.current;
10704
- if (!camera || !controls || !tweenGroup) return;
10705
- const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
10706
- const controlsTween = new import_tween2.Tween(controls.target).to(targetPos, 1500).easing(import_tween2.Easing.Cubic.Out);
10707
- tweenGroup.add(controlsTween);
10708
- controlsTween.start();
10709
- let offset;
10710
- if (forcedDirection) {
10711
- offset = forcedDirection.clone().normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
10712
- } else {
10713
- offset = camera.position.clone().sub(controls.target).normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
10714
- }
10715
- const targetCameraPos = targetPos.clone().add(offset);
10716
- const cameraTween = new import_tween2.Tween(camera.position).to(targetCameraPos, 1500).easing(import_tween2.Easing.Cubic.Out);
10717
- tweenGroup.add(cameraTween);
10718
- cameraTween.start();
10719
- }, []);
10859
+ const tweenToTarget = (0, import_react26.useCallback)(
10860
+ (target, zoomFactor = 1, forcedDirection = null) => {
10861
+ const { camera, controls, tweenGroup } = stateRef.current;
10862
+ if (!camera || !controls || !tweenGroup) return;
10863
+ const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
10864
+ const controlsTween = new import_tween2.Tween(controls.target).to(targetPos, 1500).easing(import_tween2.Easing.Cubic.Out);
10865
+ tweenGroup.add(controlsTween);
10866
+ controlsTween.start();
10867
+ let offset;
10868
+ if (forcedDirection) {
10869
+ offset = forcedDirection.clone().normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
10870
+ } else {
10871
+ offset = camera.position.clone().sub(controls.target).normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
10872
+ }
10873
+ const targetCameraPos = targetPos.clone().add(offset);
10874
+ const cameraTween = new import_tween2.Tween(camera.position).to(targetCameraPos, 1500).easing(import_tween2.Easing.Cubic.Out);
10875
+ tweenGroup.add(cameraTween);
10876
+ cameraTween.start();
10877
+ },
10878
+ []
10879
+ );
10720
10880
  const isFromUiOverlay = (event) => {
10721
10881
  const t = event == null ? void 0 : event.target;
10722
10882
  if (!t || typeof t.closest !== "function") return false;
10723
10883
  return !!t.closest(".ui-overlay");
10724
10884
  };
10725
- const buildFullAncestryTree = (0, import_react26.useCallback)((idTree, nodes, ancestries = []) => {
10726
- if (!idTree) return null;
10727
- const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
10728
- const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
10729
- const recursiveBuild = (treeItem) => {
10730
- if (!treeItem) return null;
10731
- if (treeItem.is_section) {
10732
- return {
10733
- ...treeItem,
10734
- children: (treeItem.children || []).map(recursiveBuild).filter(Boolean)
10735
- };
10736
- }
10737
- let nodeId = treeItem.node_id;
10738
- if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
10739
- const fullNode = nodeMap.get(String(nodeId));
10740
- const effectiveNode = fullNode || treeItem.node;
10741
- let processedBranches = [];
10742
- if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
10743
- processedBranches = treeItem.parallel_branches.map((branch) => {
10744
- if (branch.linked_ancestry_id) {
10745
- const linkedAncestry = ancestryMap.get(String(branch.linked_ancestry_id));
10746
- if (linkedAncestry && linkedAncestry.tree) {
10747
- const graftedTree = recursiveBuild(linkedAncestry.tree);
10748
- return {
10749
- ...branch,
10750
- name: linkedAncestry.name,
10751
- description: linkedAncestry.description,
10752
- description_sections: linkedAncestry.description_sections,
10753
- tree: graftedTree,
10754
- isLinked: true
10755
- };
10756
- }
10757
- }
10885
+ const buildFullAncestryTree = (0, import_react26.useCallback)(
10886
+ (idTree, nodes, ancestries = []) => {
10887
+ if (!idTree) return null;
10888
+ const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
10889
+ const ancestryMap = new Map(
10890
+ ancestries.map((a) => [String(a.ancestry_id), a])
10891
+ );
10892
+ const recursiveBuild = (treeItem) => {
10893
+ if (!treeItem) return null;
10894
+ if (treeItem.is_section) {
10758
10895
  return {
10759
- ...branch,
10760
- tree: recursiveBuild(branch.tree)
10896
+ ...treeItem,
10897
+ children: (treeItem.children || []).map(recursiveBuild).filter(Boolean)
10761
10898
  };
10762
- });
10763
- }
10764
- return {
10765
- ...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
10766
- relationship: treeItem.relationship || {},
10767
- children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
10768
- parallel_branches: processedBranches
10769
- };
10770
- };
10771
- let rootId = idTree.node_id;
10772
- if (!rootId && idTree.node) rootId = idTree.node.id;
10773
- if (rootId) {
10774
- const rootNode = nodeMap.get(String(rootId));
10775
- const effectiveRoot = rootNode || idTree.node;
10776
- if (!effectiveRoot) return null;
10777
- return {
10778
- node: effectiveRoot,
10779
- relationship: idTree.relationship || {},
10780
- children: (idTree.children || []).map(recursiveBuild).filter(Boolean),
10781
- parallel_branches: (idTree.parallel_branches || []).map((branch) => {
10782
- if (branch.linked_ancestry_id) {
10783
- const linkedAncestry = ancestryMap.get(String(branch.linked_ancestry_id));
10784
- if (linkedAncestry && linkedAncestry.tree) {
10785
- return {
10786
- ...branch,
10787
- name: linkedAncestry.name,
10788
- description: linkedAncestry.description,
10789
- description_sections: linkedAncestry.description_sections,
10790
- tree: recursiveBuild(linkedAncestry.tree),
10791
- isLinked: true
10792
- };
10899
+ }
10900
+ let nodeId = treeItem.node_id;
10901
+ if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
10902
+ const fullNode = nodeMap.get(String(nodeId));
10903
+ const effectiveNode = fullNode || treeItem.node;
10904
+ let processedBranches = [];
10905
+ if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
10906
+ processedBranches = treeItem.parallel_branches.map((branch) => {
10907
+ if (branch.linked_ancestry_id) {
10908
+ const linkedAncestry = ancestryMap.get(
10909
+ String(branch.linked_ancestry_id)
10910
+ );
10911
+ if (linkedAncestry && linkedAncestry.tree) {
10912
+ const graftedTree = recursiveBuild(linkedAncestry.tree);
10913
+ return {
10914
+ ...branch,
10915
+ name: linkedAncestry.name,
10916
+ description: linkedAncestry.description,
10917
+ description_sections: linkedAncestry.description_sections,
10918
+ tree: graftedTree,
10919
+ isLinked: true
10920
+ };
10921
+ }
10793
10922
  }
10794
- }
10795
- return { ...branch, tree: recursiveBuild(branch.tree) };
10796
- })
10923
+ return {
10924
+ ...branch,
10925
+ tree: recursiveBuild(branch.tree)
10926
+ };
10927
+ });
10928
+ }
10929
+ return {
10930
+ ...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
10931
+ relationship: treeItem.relationship || {},
10932
+ children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
10933
+ parallel_branches: processedBranches
10934
+ };
10797
10935
  };
10798
- }
10799
- return recursiveBuild(idTree);
10800
- }, []);
10936
+ let rootId = idTree.node_id;
10937
+ if (!rootId && idTree.node) rootId = idTree.node.id;
10938
+ if (rootId) {
10939
+ const rootNode = nodeMap.get(String(rootId));
10940
+ const effectiveRoot = rootNode || idTree.node;
10941
+ if (!effectiveRoot) return null;
10942
+ return {
10943
+ node: effectiveRoot,
10944
+ relationship: idTree.relationship || {},
10945
+ children: (idTree.children || []).map(recursiveBuild).filter(Boolean),
10946
+ parallel_branches: (idTree.parallel_branches || []).map((branch) => {
10947
+ if (branch.linked_ancestry_id) {
10948
+ const linkedAncestry = ancestryMap.get(
10949
+ String(branch.linked_ancestry_id)
10950
+ );
10951
+ if (linkedAncestry && linkedAncestry.tree) {
10952
+ return {
10953
+ ...branch,
10954
+ name: linkedAncestry.name,
10955
+ description: linkedAncestry.description,
10956
+ description_sections: linkedAncestry.description_sections,
10957
+ tree: recursiveBuild(linkedAncestry.tree),
10958
+ isLinked: true
10959
+ };
10960
+ }
10961
+ }
10962
+ return { ...branch, tree: recursiveBuild(branch.tree) };
10963
+ })
10964
+ };
10965
+ }
10966
+ return recursiveBuild(idTree);
10967
+ },
10968
+ []
10969
+ );
10801
10970
  const handleActivateTimeline = (0, import_react26.useCallback)(() => {
10802
10971
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
10803
10972
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
@@ -10878,10 +11047,12 @@ function XViewScene({
10878
11047
  if (timelineNodes.length === 0) return;
10879
11048
  const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
10880
11049
  const maxTimeIndex = sortedTimePoints.length - 1;
10881
- const timeToYMap = new Map(sortedTimePoints.map((time, index) => [
10882
- time,
10883
- (index - maxTimeIndex) * TIMELINE_LAYER_SPACING_Y
10884
- ]));
11050
+ const timeToYMap = new Map(
11051
+ sortedTimePoints.map((time, index) => [
11052
+ time,
11053
+ (index - maxTimeIndex) * TIMELINE_LAYER_SPACING_Y
11054
+ ])
11055
+ );
10885
11056
  timelineNodes.sort((a, b) => {
10886
11057
  if (a.isUndated && b.isUndated) return 0;
10887
11058
  if (a.isUndated) return 1;
@@ -10924,7 +11095,12 @@ function XViewScene({
10924
11095
  if (type === "interval") {
10925
11096
  const endY = timeToYMap.get(endDate.getTime());
10926
11097
  if (endY > y) {
10927
- const barGeometry = new THREE3.CylinderGeometry(TIMELINE_INTERVAL_BAR_RADIUS, TIMELINE_INTERVAL_BAR_RADIUS, 1, 16);
11098
+ const barGeometry = new THREE3.CylinderGeometry(
11099
+ TIMELINE_INTERVAL_BAR_RADIUS,
11100
+ TIMELINE_INTERVAL_BAR_RADIUS,
11101
+ 1,
11102
+ 16
11103
+ );
10928
11104
  const barMaterial = new THREE3.MeshStandardMaterial({
10929
11105
  color: TIMELINE_GOLD_COLOR,
10930
11106
  emissive: 12092939,
@@ -10953,7 +11129,8 @@ function XViewScene({
10953
11129
  }, []);
10954
11130
  const handleVersionTimeline = (0, import_react26.useCallback)((sourceMesh, versionMeshes) => {
10955
11131
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
10956
- if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
11132
+ if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
11133
+ return;
10957
11134
  versionMeshes.forEach((mesh) => {
10958
11135
  const oldLabel = mesh.getObjectByName("timelineLabel");
10959
11136
  if (oldLabel) {
@@ -10969,7 +11146,8 @@ function XViewScene({
10969
11146
  }
10970
11147
  if (mesh.userData.timelineEndLabel) {
10971
11148
  timelineIntervalsGroup.remove(mesh.userData.timelineEndLabel);
10972
- if (mesh.userData.timelineEndLabel.material.map) mesh.userData.timelineEndLabel.material.map.dispose();
11149
+ if (mesh.userData.timelineEndLabel.material.map)
11150
+ mesh.userData.timelineEndLabel.material.map.dispose();
10973
11151
  mesh.userData.timelineEndLabel.material.dispose();
10974
11152
  delete mesh.userData.timelineEndLabel;
10975
11153
  }
@@ -11029,8 +11207,15 @@ function XViewScene({
11029
11207
  });
11030
11208
  if (timelineNodes.length === 0) return;
11031
11209
  const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
11032
- const timeToYMap = new Map(sortedTimePoints.map((time, index) => [time, index * TIMELINE_LAYER_SPACING_Y]));
11033
- timelineNodes.sort((a, b) => a.startDate - b.startDate || a.endDate - b.endDate);
11210
+ const timeToYMap = new Map(
11211
+ sortedTimePoints.map((time, index) => [
11212
+ time,
11213
+ index * TIMELINE_LAYER_SPACING_Y
11214
+ ])
11215
+ );
11216
+ timelineNodes.sort(
11217
+ (a, b) => a.startDate - b.startDate || a.endDate - b.endDate
11218
+ );
11034
11219
  const baseX = sourceMesh.position.x + TIMELINE_NODE_SPACING_X;
11035
11220
  const baseY = sourceMesh.position.y;
11036
11221
  const maxNodeIndex = timelineNodes.length - 1;
@@ -11048,7 +11233,12 @@ function XViewScene({
11048
11233
  if (type === "interval") {
11049
11234
  const relativeEndY = timeToYMap.get(endDate.getTime()) - timeToYMap.get(startDate.getTime());
11050
11235
  if (relativeEndY > 0) {
11051
- const barGeometry = new THREE3.CylinderGeometry(TIMELINE_INTERVAL_BAR_RADIUS, TIMELINE_INTERVAL_BAR_RADIUS, 1, 16);
11236
+ const barGeometry = new THREE3.CylinderGeometry(
11237
+ TIMELINE_INTERVAL_BAR_RADIUS,
11238
+ TIMELINE_INTERVAL_BAR_RADIUS,
11239
+ 1,
11240
+ 16
11241
+ );
11052
11242
  const barMaterial = new THREE3.MeshStandardMaterial({
11053
11243
  color: TIMELINE_GOLD_COLOR,
11054
11244
  emissive: 12092939,
@@ -11085,15 +11275,31 @@ function XViewScene({
11085
11275
  try {
11086
11276
  const typeStr = (viewParams == null ? void 0 : viewParams.type) || "";
11087
11277
  const sceneType = typeStr.toLowerCase().includes("database") ? "database" : "view";
11088
- const scenePromise = get_scene_view_data(configPath, ownerId2, typeStr, session, focusNodeId, focusAncestryId);
11278
+ const scenePromise = get_scene_view_data(
11279
+ configPath,
11280
+ ownerId2,
11281
+ typeStr,
11282
+ session,
11283
+ focusNodeId,
11284
+ focusAncestryId
11285
+ );
11089
11286
  const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
11090
- const [sceneResponse, boardResponse] = await Promise.all([scenePromise, boardPromise]);
11287
+ const [sceneResponse, boardResponse] = await Promise.all([
11288
+ scenePromise,
11289
+ boardPromise
11290
+ ]);
11091
11291
  if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
11092
11292
  if (focusNodeId) {
11093
- let targetNode = sceneResponse.data.scene.nodes.find((n) => String(n.id) === String(focusNodeId));
11293
+ let targetNode = sceneResponse.data.scene.nodes.find(
11294
+ (n) => String(n.id) === String(focusNodeId)
11295
+ );
11094
11296
  if (!targetNode) {
11095
- const allParentNodes = Object.values(sceneResponse.data.parent).flatMap((f) => f.nodes || []);
11096
- targetNode = allParentNodes.find((n) => String(n.id) === String(focusNodeId));
11297
+ const allParentNodes = Object.values(
11298
+ sceneResponse.data.parent
11299
+ ).flatMap((f) => f.nodes || []);
11300
+ targetNode = allParentNodes.find(
11301
+ (n) => String(n.id) === String(focusNodeId)
11302
+ );
11097
11303
  }
11098
11304
  if (targetNode) {
11099
11305
  sceneResponse.data.scene.nodes = [targetNode];
@@ -11106,12 +11312,24 @@ function XViewScene({
11106
11312
  sceneDataRef.current = sceneResponse.data.scene;
11107
11313
  parentDataRef.current = sceneResponse.data.parent;
11108
11314
  ancestryDataRef.current = sceneResponse.data.ancestry;
11109
- console.log("Console de sceneResponse.data.scene:", sceneResponse.data.scene);
11110
- console.log("Console de sceneResponse.data.parent:", sceneResponse.data.parent);
11111
- console.log("Console de sceneResponse.data.ancestry:", sceneResponse.data.ancestry);
11315
+ console.log(
11316
+ "Console de sceneResponse.data.scene:",
11317
+ sceneResponse.data.scene
11318
+ );
11319
+ console.log(
11320
+ "Console de sceneResponse.data.parent:",
11321
+ sceneResponse.data.parent
11322
+ );
11323
+ console.log(
11324
+ "Console de sceneResponse.data.ancestry:",
11325
+ sceneResponse.data.ancestry
11326
+ );
11112
11327
  setIsInitialized(true);
11113
11328
  } else {
11114
- console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
11329
+ console.error(
11330
+ "Falha ao buscar dados da cena:",
11331
+ (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida."
11332
+ );
11115
11333
  }
11116
11334
  if (boardResponse == null ? void 0 : boardResponse.success) {
11117
11335
  setAncestryBoardData(boardResponse.data);
@@ -11130,7 +11348,9 @@ function XViewScene({
11130
11348
  console.error("Usu\xE1rio n\xE3o autenticado. Acesso negado.");
11131
11349
  setIsLoading(false);
11132
11350
  } else if (!sceneConfigId && status !== "loading") {
11133
- console.warn("Nenhum par\xE2metro de cena encontrado na URL ou falha na decripta\xE7\xE3o.");
11351
+ console.warn(
11352
+ "Nenhum par\xE2metro de cena encontrado na URL ou falha na decripta\xE7\xE3o."
11353
+ );
11134
11354
  setIsLoading(false);
11135
11355
  }
11136
11356
  }, [
@@ -11151,33 +11371,46 @@ function XViewScene({
11151
11371
  const objs = stateRef.current.nodeObjects || {};
11152
11372
  return !!objs[key];
11153
11373
  }, []);
11154
- const addOrUpdateNodeMesh = (0, import_react26.useCallback)((nodeData, position, suppressVersionUpdate = false) => {
11155
- const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
11156
- const nodeId = String(nodeData.id);
11157
- if (nodeObjects[nodeId]) {
11158
- const existingMesh = nodeObjects[nodeId];
11159
- if (position) {
11160
- const updateTween = new import_tween2.Tween(existingMesh.position).to(position, 800).easing(import_tween2.Easing.Cubic.Out);
11161
- tweenGroup.add(updateTween);
11162
- updateTween.start();
11163
- }
11164
- return existingMesh;
11165
- }
11166
- const mesh = createNodeMesh(nodeData, position || new THREE3.Vector3(), glowTexture);
11167
- graphGroup.add(mesh);
11168
- if (mesh.userData.labelObject) {
11169
- if (mesh.userData.labelOffset) {
11170
- mesh.userData.labelObject.position.copy(mesh.position).add(mesh.userData.labelOffset);
11374
+ const addOrUpdateNodeMesh = (0, import_react26.useCallback)(
11375
+ (nodeData, position, suppressVersionUpdate = false) => {
11376
+ const {
11377
+ graphGroup,
11378
+ nodeObjects,
11379
+ clickableNodes,
11380
+ glowTexture,
11381
+ tweenGroup
11382
+ } = stateRef.current;
11383
+ const nodeId = String(nodeData.id);
11384
+ if (nodeObjects[nodeId]) {
11385
+ const existingMesh = nodeObjects[nodeId];
11386
+ if (position) {
11387
+ const updateTween = new import_tween2.Tween(existingMesh.position).to(position, 800).easing(import_tween2.Easing.Cubic.Out);
11388
+ tweenGroup.add(updateTween);
11389
+ updateTween.start();
11390
+ }
11391
+ return existingMesh;
11392
+ }
11393
+ const mesh = createNodeMesh(
11394
+ nodeData,
11395
+ position || new THREE3.Vector3(),
11396
+ glowTexture
11397
+ );
11398
+ graphGroup.add(mesh);
11399
+ if (mesh.userData.labelObject) {
11400
+ if (mesh.userData.labelOffset) {
11401
+ mesh.userData.labelObject.position.copy(mesh.position).add(mesh.userData.labelOffset);
11402
+ }
11403
+ graphGroup.add(mesh.userData.labelObject);
11171
11404
  }
11172
- graphGroup.add(mesh.userData.labelObject);
11173
- }
11174
- nodeObjects[nodeId] = mesh;
11175
- clickableNodes.push(mesh);
11176
- if (!suppressVersionUpdate) {
11177
- setSceneVersion((v) => v + 1);
11178
- }
11179
- return mesh;
11180
- }, []);
11405
+ nodeObjects[nodeId] = mesh;
11406
+ clickableNodes.push(mesh);
11407
+ if (!suppressVersionUpdate) {
11408
+ setSceneVersion((v) => v + 1);
11409
+ }
11410
+ return mesh;
11411
+ },
11412
+ []
11413
+ );
11181
11414
  (0, import_react26.useEffect)(() => {
11182
11415
  if (!isInitialized || !sceneDataRef.current) return;
11183
11416
  const currentMount = mountRef.current;
@@ -11192,7 +11425,12 @@ function XViewScene({
11192
11425
  const scene = new THREE3.Scene();
11193
11426
  scene.background = new THREE3.Color(0);
11194
11427
  stateRef.current.scene = scene;
11195
- const camera = new THREE3.PerspectiveCamera(75, currentMount.clientWidth / currentMount.clientHeight, 0.1, 2e3);
11428
+ const camera = new THREE3.PerspectiveCamera(
11429
+ 75,
11430
+ currentMount.clientWidth / currentMount.clientHeight,
11431
+ 0.1,
11432
+ 2e3
11433
+ );
11196
11434
  camera.position.set(0, 60, 120);
11197
11435
  stateRef.current.camera = camera;
11198
11436
  const renderer = new THREE3.WebGLRenderer({ antialias: true });
@@ -11213,7 +11451,12 @@ function XViewScene({
11213
11451
  directionalLight.position.set(50, 50, 50);
11214
11452
  scene.add(directionalLight);
11215
11453
  const renderScene = new import_RenderPass.RenderPass(scene, camera);
11216
- const bloomPass = new import_UnrealBloomPass.UnrealBloomPass(new THREE3.Vector2(currentMount.clientWidth, currentMount.clientHeight), x_view_config.BLOOM_EFFECT.strength, x_view_config.BLOOM_EFFECT.radius, x_view_config.BLOOM_EFFECT.threshold);
11454
+ const bloomPass = new import_UnrealBloomPass.UnrealBloomPass(
11455
+ new THREE3.Vector2(currentMount.clientWidth, currentMount.clientHeight),
11456
+ x_view_config.BLOOM_EFFECT.strength,
11457
+ x_view_config.BLOOM_EFFECT.radius,
11458
+ x_view_config.BLOOM_EFFECT.threshold
11459
+ );
11217
11460
  const composer = new import_EffectComposer.EffectComposer(renderer);
11218
11461
  composer.addPass(renderScene);
11219
11462
  composer.addPass(bloomPass);
@@ -11256,8 +11499,16 @@ function XViewScene({
11256
11499
  const sourceNode = nodeObjects[String(linksArray[0].source)];
11257
11500
  const targetNode = nodeObjects[String(linksArray[0].target)];
11258
11501
  if (sourceNode && targetNode) {
11259
- const resolution = new THREE3.Vector2(currentMount.clientWidth, currentMount.clientHeight);
11260
- const newLinks = createMultipleLinkLines(linksArray, sourceNode, targetNode, resolution);
11502
+ const resolution = new THREE3.Vector2(
11503
+ currentMount.clientWidth,
11504
+ currentMount.clientHeight
11505
+ );
11506
+ const newLinks = createMultipleLinkLines(
11507
+ linksArray,
11508
+ sourceNode,
11509
+ targetNode,
11510
+ resolution
11511
+ );
11261
11512
  newLinks.forEach((line, idx) => {
11262
11513
  const meta = linksArray[idx];
11263
11514
  if (meta) {
@@ -11298,7 +11549,10 @@ function XViewScene({
11298
11549
  function tryPickNode() {
11299
11550
  raycaster.setFromCamera(mouse, camera);
11300
11551
  raycaster.layers.enable(GHOST_BLOOM_LAYER);
11301
- const intersects = raycaster.intersectObjects(stateRef.current.clickableNodes, false);
11552
+ const intersects = raycaster.intersectObjects(
11553
+ stateRef.current.clickableNodes,
11554
+ false
11555
+ );
11302
11556
  return intersects.length > 0 ? intersects[0].object : null;
11303
11557
  }
11304
11558
  function findClosestLinkToRay() {
@@ -11310,7 +11564,10 @@ function XViewScene({
11310
11564
  x: (mouse.x * 0.5 + 0.5) * clientWidth,
11311
11565
  y: (-mouse.y * 0.5 + 0.5) * clientHeight
11312
11566
  };
11313
- const allVisibleLinks = [...stateRef.current.allLinks, ...stateRef.current.ancestryLinks];
11567
+ const allVisibleLinks = [
11568
+ ...stateRef.current.allLinks,
11569
+ ...stateRef.current.ancestryLinks
11570
+ ];
11314
11571
  const THRESH = x_view_config.LINE_HOVER_THRESHOLD_PX + 4;
11315
11572
  const tmpP1 = new THREE3.Vector3();
11316
11573
  const tmpP2 = new THREE3.Vector3();
@@ -11325,19 +11582,35 @@ function XViewScene({
11325
11582
  const up = new THREE3.Vector3(0, 1, 0);
11326
11583
  const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
11327
11584
  const controlPoint = mid.add(normal.multiplyScalar(curveOffset || 0));
11328
- const curve = new THREE3.QuadraticBezierCurve3(start, controlPoint, end);
11585
+ const curve = new THREE3.QuadraticBezierCurve3(
11586
+ start,
11587
+ controlPoint,
11588
+ end
11589
+ );
11329
11590
  const points = curve.getPoints(x_view_config.CURVE_SEGMENTS || 32);
11330
11591
  for (let i = 0; i < points.length - 1; i++) {
11331
11592
  tmpP1.copy(points[i]).project(camera);
11332
11593
  tmpP2.copy(points[i + 1]).project(camera);
11333
- const p1_px = { x: (tmpP1.x * 0.5 + 0.5) * clientWidth, y: (-tmpP1.y * 0.5 + 0.5) * clientHeight };
11334
- const p2_px = { x: (tmpP2.x * 0.5 + 0.5) * clientWidth, y: (-tmpP2.y * 0.5 + 0.5) * clientHeight };
11594
+ const p1_px = {
11595
+ x: (tmpP1.x * 0.5 + 0.5) * clientWidth,
11596
+ y: (-tmpP1.y * 0.5 + 0.5) * clientHeight
11597
+ };
11598
+ const p2_px = {
11599
+ x: (tmpP2.x * 0.5 + 0.5) * clientWidth,
11600
+ y: (-tmpP2.y * 0.5 + 0.5) * clientHeight
11601
+ };
11335
11602
  const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
11336
11603
  if (L2 === 0) continue;
11337
11604
  let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
11338
11605
  t = Math.max(0, Math.min(1, t));
11339
- const closestPoint = { x: p1_px.x + t * (p2_px.x - p1_px.x), y: p1_px.y + t * (p2_px.y - p1_px.y) };
11340
- const dist = Math.hypot(mousePixels.x - closestPoint.x, mousePixels.y - closestPoint.y);
11606
+ const closestPoint = {
11607
+ x: p1_px.x + t * (p2_px.x - p1_px.x),
11608
+ y: p1_px.y + t * (p2_px.y - p1_px.y)
11609
+ };
11610
+ const dist = Math.hypot(
11611
+ mousePixels.x - closestPoint.x,
11612
+ mousePixels.y - closestPoint.y
11613
+ );
11341
11614
  if (dist < THRESH && dist < minDistance) {
11342
11615
  minDistance = dist;
11343
11616
  closestLink = link;
@@ -11346,14 +11619,26 @@ function XViewScene({
11346
11619
  } else {
11347
11620
  const p1 = new THREE3.Vector3().copy(sourceNode.position).project(camera);
11348
11621
  const p2 = new THREE3.Vector3().copy(targetNode.position).project(camera);
11349
- const p1_px = { x: (p1.x * 0.5 + 0.5) * clientWidth, y: (-p1.y * 0.5 + 0.5) * clientHeight };
11350
- const p2_px = { x: (p2.x * 0.5 + 0.5) * clientWidth, y: (-p2.y * 0.5 + 0.5) * clientHeight };
11622
+ const p1_px = {
11623
+ x: (p1.x * 0.5 + 0.5) * clientWidth,
11624
+ y: (-p1.y * 0.5 + 0.5) * clientHeight
11625
+ };
11626
+ const p2_px = {
11627
+ x: (p2.x * 0.5 + 0.5) * clientWidth,
11628
+ y: (-p2.y * 0.5 + 0.5) * clientHeight
11629
+ };
11351
11630
  const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
11352
11631
  if (L2 === 0) return;
11353
11632
  let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
11354
11633
  t = Math.max(0, Math.min(1, t));
11355
- const closestPoint = { x: p1_px.x + t * (p2_px.x - p1_px.x), y: p1_px.y + t * (p2_px.y - p1_px.y) };
11356
- const dist = Math.hypot(mousePixels.x - closestPoint.x, mousePixels.y - closestPoint.y);
11634
+ const closestPoint = {
11635
+ x: p1_px.x + t * (p2_px.x - p1_px.x),
11636
+ y: p1_px.y + t * (p2_px.y - p1_px.y)
11637
+ };
11638
+ const dist = Math.hypot(
11639
+ mousePixels.x - closestPoint.x,
11640
+ mousePixels.y - closestPoint.y
11641
+ );
11357
11642
  if (dist < THRESH && dist < minDistance) {
11358
11643
  minDistance = dist;
11359
11644
  closestLink = link;
@@ -11388,7 +11673,11 @@ function XViewScene({
11388
11673
  if (picked && !stateRef.current.ancestry.isActive) {
11389
11674
  stateRef.current.controls.enabled = false;
11390
11675
  }
11391
- stateRef.current.pointerDown = { isDown: true, x: event.clientX, y: event.clientY };
11676
+ stateRef.current.pointerDown = {
11677
+ isDown: true,
11678
+ x: event.clientX,
11679
+ y: event.clientY
11680
+ };
11392
11681
  stateRef.current.dragCandidate = picked;
11393
11682
  }
11394
11683
  function onPointerMove(event) {
@@ -11399,7 +11688,10 @@ function XViewScene({
11399
11688
  const raycaster2 = new THREE3.Raycaster();
11400
11689
  raycaster2.setFromCamera(mouse, camera);
11401
11690
  camera.getWorldDirection(plane.normal);
11402
- plane.setFromNormalAndCoplanarPoint(plane.normal, stateRef.current.draggedNode.position);
11691
+ plane.setFromNormalAndCoplanarPoint(
11692
+ plane.normal,
11693
+ stateRef.current.draggedNode.position
11694
+ );
11403
11695
  if (raycaster2.ray.intersectPlane(plane, intersectionPoint)) {
11404
11696
  const draggedNode = stateRef.current.draggedNode;
11405
11697
  draggedNode.position.copy(intersectionPoint);
@@ -11408,7 +11700,8 @@ function XViewScene({
11408
11700
  }
11409
11701
  if (stateRef.current.connection.isActive || stateRef.current.relink.isActive || stateRef.current.ancestry.isActive) {
11410
11702
  const newHoveredNode2 = tryPickNode();
11411
- if (stateRef.current.hoveredNode !== newHoveredNode2) stateRef.current.hoveredNode = newHoveredNode2;
11703
+ if (stateRef.current.hoveredNode !== newHoveredNode2)
11704
+ stateRef.current.hoveredNode = newHoveredNode2;
11412
11705
  if (currentMount) {
11413
11706
  let fixedId = null;
11414
11707
  if (stateRef.current.connection.isActive) {
@@ -11439,14 +11732,20 @@ function XViewScene({
11439
11732
  stateRef.current.controls.enabled = false;
11440
11733
  if (currentMount) currentMount.style.cursor = "grabbing";
11441
11734
  camera.getWorldDirection(plane.normal);
11442
- plane.setFromNormalAndCoplanarPoint(plane.normal, stateRef.current.draggedNode.position);
11735
+ plane.setFromNormalAndCoplanarPoint(
11736
+ plane.normal,
11737
+ stateRef.current.draggedNode.position
11738
+ );
11443
11739
  }
11444
11740
  }
11445
11741
  const newHoveredNode = tryPickNode();
11446
11742
  const newHoveredLink = !newHoveredNode ? findClosestLinkToRay() : null;
11447
- if (stateRef.current.hoveredNode !== newHoveredNode) stateRef.current.hoveredNode = newHoveredNode;
11448
- if (stateRef.current.hoveredLink !== newHoveredLink) stateRef.current.hoveredLink = newHoveredLink;
11449
- if (currentMount) currentMount.style.cursor = newHoveredNode || newHoveredLink ? "pointer" : "grab";
11743
+ if (stateRef.current.hoveredNode !== newHoveredNode)
11744
+ stateRef.current.hoveredNode = newHoveredNode;
11745
+ if (stateRef.current.hoveredLink !== newHoveredLink)
11746
+ stateRef.current.hoveredLink = newHoveredLink;
11747
+ if (currentMount)
11748
+ currentMount.style.cursor = newHoveredNode || newHoveredLink ? "pointer" : "grab";
11450
11749
  }
11451
11750
  const isNodeInTree = (tree, nodeId) => {
11452
11751
  if (!tree) return false;
@@ -11461,7 +11760,10 @@ function XViewScene({
11461
11760
  const context = actionHandlerContext;
11462
11761
  if (connection.isActive) {
11463
11762
  if (hoveredNode && String(hoveredNode.userData.id) !== String(connection.sourceNodeData.id)) {
11464
- await userActionHandlers.handleCompleteConnection(context, hoveredNode.userData);
11763
+ await userActionHandlers.handleCompleteConnection(
11764
+ context,
11765
+ hoveredNode.userData
11766
+ );
11465
11767
  } else {
11466
11768
  userActionHandlers.handleCancelConnection(context);
11467
11769
  }
@@ -11469,7 +11771,10 @@ function XViewScene({
11469
11771
  }
11470
11772
  if (relink.isActive) {
11471
11773
  if (hoveredNode && String(hoveredNode.userData.id) !== String(relink.fixedNodeId)) {
11472
- await userActionHandlers.handleCompleteRelink(context, hoveredNode.userData);
11774
+ await userActionHandlers.handleCompleteRelink(
11775
+ context,
11776
+ hoveredNode.userData
11777
+ );
11473
11778
  } else {
11474
11779
  userActionHandlers.handleCancelRelink(context);
11475
11780
  }
@@ -11487,7 +11792,9 @@ function XViewScene({
11487
11792
  const clickedNodeId = String(clickedNode.userData.id);
11488
11793
  const parentId = String(currentSelectedParent);
11489
11794
  if (clickedNodeId === parentId) {
11490
- alert("Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo.");
11795
+ alert(
11796
+ "Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo."
11797
+ );
11491
11798
  return;
11492
11799
  }
11493
11800
  const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
@@ -11497,16 +11804,33 @@ function XViewScene({
11497
11804
  const addChildToNode = (current, targetParentId, childNode) => {
11498
11805
  const currentId = current.is_section ? current.id || current.section_id : String(current.node.id);
11499
11806
  if (String(currentId) === String(targetParentId)) {
11500
- const alreadyExists = current.children.some((child) => !child.is_section && String(child.node.id) === String(childNode.id));
11807
+ const alreadyExists = current.children.some(
11808
+ (child) => !child.is_section && String(child.node.id) === String(childNode.id)
11809
+ );
11501
11810
  if (alreadyExists) return current;
11502
- return { ...current, children: [...current.children, { node: childNode, children: [], relationship: {} }] };
11811
+ return {
11812
+ ...current,
11813
+ children: [
11814
+ ...current.children,
11815
+ { node: childNode, children: [], relationship: {} }
11816
+ ]
11817
+ };
11503
11818
  }
11504
- return { ...current, children: current.children.map((c) => addChildToNode(c, targetParentId, childNode)) };
11819
+ return {
11820
+ ...current,
11821
+ children: current.children.map(
11822
+ (c) => addChildToNode(c, targetParentId, childNode)
11823
+ )
11824
+ };
11505
11825
  };
11506
11826
  setAncestryMode((prev) => {
11507
11827
  const treeKey = isAbstraction ? "abstraction_tree" : "tree";
11508
11828
  if (!prev[treeKey]) return prev;
11509
- const newTree = addChildToNode(prev[treeKey], parentId, fullNodeData);
11829
+ const newTree = addChildToNode(
11830
+ prev[treeKey],
11831
+ parentId,
11832
+ fullNodeData
11833
+ );
11510
11834
  return { ...prev, [treeKey]: newTree };
11511
11835
  });
11512
11836
  }
@@ -11520,7 +11844,8 @@ function XViewScene({
11520
11844
  stateRef.current.dragCandidate = null;
11521
11845
  stateRef.current.pointerDown.isDown = false;
11522
11846
  stateRef.current.controls.enabled = true;
11523
- if (currentMount) currentMount.style.cursor = stateRef.current.hoveredNode || stateRef.current.hoveredLink ? "pointer" : "grab";
11847
+ if (currentMount)
11848
+ currentMount.style.cursor = stateRef.current.hoveredNode || stateRef.current.hoveredLink ? "pointer" : "grab";
11524
11849
  return;
11525
11850
  }
11526
11851
  const dragDistance = Math.hypot(
@@ -11568,16 +11893,21 @@ function XViewScene({
11568
11893
  }
11569
11894
  function handleDoubleClick(event) {
11570
11895
  if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
11571
- if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive) return;
11572
- if (stateRef.current.hoveredNode) tweenToTarget(stateRef.current.hoveredNode);
11896
+ if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
11897
+ return;
11898
+ if (stateRef.current.hoveredNode)
11899
+ tweenToTarget(stateRef.current.hoveredNode);
11573
11900
  }
11574
11901
  function handleContextMenu(event) {
11575
11902
  if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
11576
11903
  if (isFromUiOverlay(event)) return;
11577
11904
  event.preventDefault();
11578
- if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive) return;
11905
+ if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
11906
+ return;
11579
11907
  setMouseFromEvent(event);
11580
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11908
+ setContextMenu(
11909
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
11910
+ );
11581
11911
  setMultiContextMenu((prev) => ({ ...prev, visible: false }));
11582
11912
  setRelationshipMenu((prev) => ({ ...prev, visible: false }));
11583
11913
  const pickedNode = tryPickNode();
@@ -11608,7 +11938,12 @@ function XViewScene({
11608
11938
  return;
11609
11939
  }
11610
11940
  stateRef.current.selectedNodes.clear();
11611
- setRelationshipMenu({ visible: true, x: event.clientX, y: event.clientY, linkObject: pickedLink });
11941
+ setRelationshipMenu({
11942
+ visible: true,
11943
+ x: event.clientX,
11944
+ y: event.clientY,
11945
+ linkObject: pickedLink
11946
+ });
11612
11947
  return;
11613
11948
  }
11614
11949
  stateRef.current.selectedNodes.clear();
@@ -11640,7 +11975,10 @@ function XViewScene({
11640
11975
  }
11641
11976
  });
11642
11977
  }
11643
- const allRenderedLinks = [...stateRef.current.allLinks, ...stateRef.current.ancestryLinks];
11978
+ const allRenderedLinks = [
11979
+ ...stateRef.current.allLinks,
11980
+ ...stateRef.current.ancestryLinks
11981
+ ];
11644
11982
  allRenderedLinks.forEach((line) => {
11645
11983
  const { sourceNode, targetNode, isCurved, curveOffset } = line.userData;
11646
11984
  if (sourceNode && targetNode) {
@@ -11652,13 +11990,20 @@ function XViewScene({
11652
11990
  const up = new THREE3.Vector3(0, 1, 0);
11653
11991
  const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
11654
11992
  const controlPoint = mid.add(normal.multiplyScalar(curveOffset));
11655
- const curve = new THREE3.QuadraticBezierCurve3(start, controlPoint, end);
11993
+ const curve = new THREE3.QuadraticBezierCurve3(
11994
+ start,
11995
+ controlPoint,
11996
+ end
11997
+ );
11656
11998
  const points = curve.getPoints(x_view_config.CURVE_SEGMENTS);
11657
11999
  const positions = [];
11658
12000
  points.forEach((p) => positions.push(p.x, p.y, p.z));
11659
12001
  line.geometry.setPositions(positions);
11660
12002
  } else {
11661
- line.geometry.setPositions([...sourceNode.position.toArray(), ...targetNode.position.toArray()]);
12003
+ line.geometry.setPositions([
12004
+ ...sourceNode.position.toArray(),
12005
+ ...targetNode.position.toArray()
12006
+ ]);
11662
12007
  }
11663
12008
  }
11664
12009
  });
@@ -11671,7 +12016,11 @@ function XViewScene({
11671
12016
  const startPos = node.position;
11672
12017
  const distance = startPos.distanceTo(endPos);
11673
12018
  bar.scale.y = distance;
11674
- const midpoint = new THREE3.Vector3().lerpVectors(startPos, endPos, 0.5);
12019
+ const midpoint = new THREE3.Vector3().lerpVectors(
12020
+ startPos,
12021
+ endPos,
12022
+ 0.5
12023
+ );
11675
12024
  bar.position.copy(midpoint);
11676
12025
  const direction = new THREE3.Vector3().subVectors(endPos, startPos).normalize();
11677
12026
  const upVector = new THREE3.Vector3(0, 1, 0);
@@ -11682,7 +12031,11 @@ function XViewScene({
11682
12031
  const { ghostElements, creation, connection, relink } = stateRef.current;
11683
12032
  if (creation.isActive && ghostElements.node && ghostElements.line) {
11684
12033
  const srcMesh = stateRef.current.nodeObjects[String(creation.sourceNodeData.id)];
11685
- if (srcMesh) ghostElements.line.geometry.setPositions([...srcMesh.position.toArray(), ...ghostElements.node.position.toArray()]);
12034
+ if (srcMesh)
12035
+ ghostElements.line.geometry.setPositions([
12036
+ ...srcMesh.position.toArray(),
12037
+ ...ghostElements.node.position.toArray()
12038
+ ]);
11686
12039
  }
11687
12040
  if (connection.isActive && connection.line) {
11688
12041
  const srcMesh = stateRef.current.nodeObjects[String(connection.sourceNodeData.id)];
@@ -11691,7 +12044,11 @@ function XViewScene({
11691
12044
  raycaster2.setFromCamera(mouse, camera);
11692
12045
  camera.getWorldDirection(plane.normal);
11693
12046
  plane.setFromNormalAndCoplanarPoint(plane.normal, srcMesh.position);
11694
- if (raycaster2.ray.intersectPlane(plane, intersectionPoint)) connection.line.geometry.setPositions([...srcMesh.position.toArray(), ...intersectionPoint.toArray()]);
12047
+ if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
12048
+ connection.line.geometry.setPositions([
12049
+ ...srcMesh.position.toArray(),
12050
+ ...intersectionPoint.toArray()
12051
+ ]);
11695
12052
  }
11696
12053
  }
11697
12054
  if (relink.isActive && relink.line) {
@@ -11701,7 +12058,11 @@ function XViewScene({
11701
12058
  raycaster2.setFromCamera(mouse, camera);
11702
12059
  camera.getWorldDirection(plane.normal);
11703
12060
  plane.setFromNormalAndCoplanarPoint(plane.normal, fixedMesh.position);
11704
- if (raycaster2.ray.intersectPlane(plane, intersectionPoint)) relink.line.geometry.setPositions([...fixedMesh.position.toArray(), ...intersectionPoint.toArray()]);
12061
+ if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
12062
+ relink.line.geometry.setPositions([
12063
+ ...fixedMesh.position.toArray(),
12064
+ ...intersectionPoint.toArray()
12065
+ ]);
11705
12066
  }
11706
12067
  }
11707
12068
  Object.values(stateRef.current.nodeObjects).forEach((node) => {
@@ -11745,11 +12106,18 @@ function XViewScene({
11745
12106
  renderer.setSize(clientWidth, clientHeight);
11746
12107
  composer.setSize(clientWidth, clientHeight);
11747
12108
  const resVec = new THREE3.Vector2(clientWidth, clientHeight);
11748
- stateRef.current.allLinks.forEach((line) => line.material.resolution.copy(resVec));
11749
- stateRef.current.ancestryLinks.forEach((line) => line.material.resolution.copy(resVec));
11750
- if (stateRef.current.ghostElements.line) stateRef.current.ghostElements.line.material.resolution.copy(resVec);
11751
- if (stateRef.current.connection.line) stateRef.current.connection.line.material.resolution.copy(resVec);
11752
- if (stateRef.current.relink.line) stateRef.current.relink.line.material.resolution.copy(resVec);
12109
+ stateRef.current.allLinks.forEach(
12110
+ (line) => line.material.resolution.copy(resVec)
12111
+ );
12112
+ stateRef.current.ancestryLinks.forEach(
12113
+ (line) => line.material.resolution.copy(resVec)
12114
+ );
12115
+ if (stateRef.current.ghostElements.line)
12116
+ stateRef.current.ghostElements.line.material.resolution.copy(resVec);
12117
+ if (stateRef.current.connection.line)
12118
+ stateRef.current.connection.line.material.resolution.copy(resVec);
12119
+ if (stateRef.current.relink.line)
12120
+ stateRef.current.relink.line.material.resolution.copy(resVec);
11753
12121
  }
11754
12122
  window.addEventListener("resize", handleResize);
11755
12123
  return () => {
@@ -11769,14 +12137,16 @@ function XViewScene({
11769
12137
  ancestryGroup.traverse((obj) => {
11770
12138
  if (obj.geometry) obj.geometry.dispose();
11771
12139
  if (obj.material) {
11772
- if (Array.isArray(obj.material)) obj.material.forEach((m) => m.dispose());
12140
+ if (Array.isArray(obj.material))
12141
+ obj.material.forEach((m) => m.dispose());
11773
12142
  else obj.material.dispose();
11774
12143
  }
11775
12144
  });
11776
12145
  graphGroup.traverse((obj) => {
11777
12146
  if (obj.geometry) obj.geometry.dispose();
11778
12147
  if (obj.material) {
11779
- if (Array.isArray(obj.material)) obj.material.forEach((m) => m.dispose());
12148
+ if (Array.isArray(obj.material))
12149
+ obj.material.forEach((m) => m.dispose());
11780
12150
  else obj.material.dispose();
11781
12151
  }
11782
12152
  });
@@ -11787,9 +12157,22 @@ function XViewScene({
11787
12157
  currentMount.removeChild(renderer.domElement);
11788
12158
  }
11789
12159
  };
11790
- }, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
12160
+ }, [
12161
+ isInitialized,
12162
+ tweenToTarget,
12163
+ dbSaveUrl,
12164
+ isNodeInView,
12165
+ addOrUpdateNodeMesh,
12166
+ handleActivateTimeline,
12167
+ get_scene_view_data,
12168
+ save_view_data
12169
+ ]);
11791
12170
  const handleGhostNodeImageChange = (0, import_react26.useCallback)((useImage, imageUrl) => {
11792
- const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
12171
+ const {
12172
+ node: ghostNode,
12173
+ line: ghostLine,
12174
+ aura: ghostAura
12175
+ } = stateRef.current.ghostElements;
11793
12176
  const { graphGroup, glowTexture } = stateRef.current;
11794
12177
  if (!ghostNode || !graphGroup) return;
11795
12178
  const currentData = {
@@ -11800,13 +12183,15 @@ function XViewScene({
11800
12183
  const position = ghostNode.position.clone();
11801
12184
  if (ghostNode.userData.labelObject) {
11802
12185
  graphGroup.remove(ghostNode.userData.labelObject);
11803
- if (ghostNode.userData.labelObject.material.map) ghostNode.userData.labelObject.material.map.dispose();
12186
+ if (ghostNode.userData.labelObject.material.map)
12187
+ ghostNode.userData.labelObject.material.map.dispose();
11804
12188
  ghostNode.userData.labelObject.material.dispose();
11805
12189
  }
11806
12190
  graphGroup.remove(ghostNode);
11807
12191
  if (ghostNode.geometry) ghostNode.geometry.dispose();
11808
12192
  if (ghostNode.material) {
11809
- if (Array.isArray(ghostNode.material)) ghostNode.material.forEach((m) => m.dispose());
12193
+ if (Array.isArray(ghostNode.material))
12194
+ ghostNode.material.forEach((m) => m.dispose());
11810
12195
  else ghostNode.material.dispose();
11811
12196
  }
11812
12197
  const newGhostNode = createNodeMesh(currentData, position, glowTexture);
@@ -11851,28 +12236,31 @@ function XViewScene({
11851
12236
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
11852
12237
  }
11853
12238
  }, []);
11854
- const handleDetailNodeIntensityChange = (0, import_react26.useCallback)((nodeId, newIntensity) => {
11855
- const mesh = stateRef.current.nodeObjects[String(nodeId)];
11856
- if (!mesh) return;
11857
- const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
11858
- mesh.userData.intensity = newIntensity;
11859
- mesh.userData._baseEmissiveIntensity = adjustedIntensity;
11860
- const isImageNode = mesh.userData.useImageAsTexture === true;
11861
- if (isImageNode) {
11862
- const borderMesh = mesh.getObjectByName("borderRing");
11863
- if (borderMesh && borderMesh.material) {
11864
- borderMesh.material.emissiveIntensity = adjustedIntensity;
12239
+ const handleDetailNodeIntensityChange = (0, import_react26.useCallback)(
12240
+ (nodeId, newIntensity) => {
12241
+ const mesh = stateRef.current.nodeObjects[String(nodeId)];
12242
+ if (!mesh) return;
12243
+ const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
12244
+ mesh.userData.intensity = newIntensity;
12245
+ mesh.userData._baseEmissiveIntensity = adjustedIntensity;
12246
+ const isImageNode = mesh.userData.useImageAsTexture === true;
12247
+ if (isImageNode) {
12248
+ const borderMesh = mesh.getObjectByName("borderRing");
12249
+ if (borderMesh && borderMesh.material) {
12250
+ borderMesh.material.emissiveIntensity = adjustedIntensity;
12251
+ }
12252
+ } else {
12253
+ if (mesh.material) {
12254
+ mesh.material.emissiveIntensity = adjustedIntensity;
12255
+ }
11865
12256
  }
11866
- } else {
11867
- if (mesh.material) {
11868
- mesh.material.emissiveIntensity = adjustedIntensity;
12257
+ const aura = mesh.getObjectByName("aura");
12258
+ if (aura && aura.material) {
12259
+ aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
11869
12260
  }
11870
- }
11871
- const aura = mesh.getObjectByName("aura");
11872
- if (aura && aura.material) {
11873
- aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
11874
- }
11875
- }, []);
12261
+ },
12262
+ []
12263
+ );
11876
12264
  const handleGhostNodeColorChange = (newColor) => {
11877
12265
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
11878
12266
  if (!ghostNode) return;
@@ -11983,7 +12371,9 @@ function XViewScene({
11983
12371
  mesh.userData.size = newSize;
11984
12372
  };
11985
12373
  const handleStartAncestryCreation = (nodeData) => {
11986
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12374
+ setContextMenu(
12375
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
12376
+ );
11987
12377
  stateRef.current.maxAncestryRenderIndex = 0;
11988
12378
  setAncestryMode({
11989
12379
  isActive: true,
@@ -12008,9 +12398,12 @@ function XViewScene({
12008
12398
  const newTreeStr = JSON.stringify(newTree);
12009
12399
  let metaChanged = false;
12010
12400
  if (extraData) {
12011
- if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName) metaChanged = true;
12012
- if (extraData.ancestryDescription !== void 0 && extraData.ancestryDescription !== prev.ancestryDescription) metaChanged = true;
12013
- if (extraData.ancestryDescriptionSections !== void 0 && JSON.stringify(extraData.ancestryDescriptionSections) !== JSON.stringify(prev.ancestryDescriptionSections)) metaChanged = true;
12401
+ if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName)
12402
+ metaChanged = true;
12403
+ if (extraData.ancestryDescription !== void 0 && extraData.ancestryDescription !== prev.ancestryDescription)
12404
+ metaChanged = true;
12405
+ if (extraData.ancestryDescriptionSections !== void 0 && JSON.stringify(extraData.ancestryDescriptionSections) !== JSON.stringify(prev.ancestryDescriptionSections))
12406
+ metaChanged = true;
12014
12407
  }
12015
12408
  if (prevTreeStr === newTreeStr && !metaChanged) {
12016
12409
  return prev;
@@ -12088,13 +12481,15 @@ function XViewScene({
12088
12481
  if (ghostElements.node && graphGroup) {
12089
12482
  if (ghostElements.node.userData.labelObject) {
12090
12483
  graphGroup.remove(ghostElements.node.userData.labelObject);
12091
- if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
12484
+ if (ghostElements.node.userData.labelObject.material.map)
12485
+ ghostElements.node.userData.labelObject.material.map.dispose();
12092
12486
  ghostElements.node.userData.labelObject.material.dispose();
12093
12487
  }
12094
12488
  graphGroup.remove(ghostElements.node);
12095
12489
  ghostElements.node.traverse((child) => {
12096
12490
  if (child.material) {
12097
- if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
12491
+ if (Array.isArray(child.material))
12492
+ child.material.forEach((m) => m.dispose());
12098
12493
  else child.material.dispose();
12099
12494
  }
12100
12495
  if (child.geometry) child.geometry.dispose();
@@ -12104,7 +12499,17 @@ function XViewScene({
12104
12499
  setQuestMode({ isActive: false });
12105
12500
  }, []);
12106
12501
  const handleSaveQuestNode = async (context, newQuestData) => {
12107
- const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
12502
+ const {
12503
+ graphDataRef,
12504
+ sceneDataRef: sceneDataRef2,
12505
+ stateRef: stateRef2,
12506
+ setters,
12507
+ actions,
12508
+ sceneSaveUrl: sceneSaveUrl2,
12509
+ viewType,
12510
+ sceneConfigId: sceneConfigId2,
12511
+ ownerId: ownerId2
12512
+ } = context;
12108
12513
  if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
12109
12514
  const currentCounter = sceneDataRef2.current.quest_counter || 1;
12110
12515
  const newNode = {
@@ -12137,7 +12542,8 @@ function XViewScene({
12137
12542
  const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
12138
12543
  const { graphGroup, ghostElements } = stateRef2.current;
12139
12544
  if (ghostElements.node && graphGroup) {
12140
- if (ghostElements.node.userData.labelObject) graphGroup.remove(ghostElements.node.userData.labelObject);
12545
+ if (ghostElements.node.userData.labelObject)
12546
+ graphGroup.remove(ghostElements.node.userData.labelObject);
12141
12547
  graphGroup.remove(ghostElements.node);
12142
12548
  }
12143
12549
  stateRef2.current.ghostElements = { node: null, line: null, aura: null };
@@ -12151,14 +12557,33 @@ function XViewScene({
12151
12557
  }
12152
12558
  };
12153
12559
  userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
12154
- const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2, ownerId: ownerId2 } = context;
12560
+ const {
12561
+ stateRef: stateRef2,
12562
+ graphDataRef,
12563
+ sceneDataRef: sceneDataRef2,
12564
+ sceneConfigId: sceneConfigId2,
12565
+ sceneSaveUrl: sceneSaveUrl2,
12566
+ ownerId: ownerId2
12567
+ } = context;
12155
12568
  const { sourceNodeData } = stateRef2.current.connection;
12156
12569
  if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
12157
12570
  userActionHandlers.handleCancelConnection(context);
12158
12571
  return;
12159
12572
  }
12160
- const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
12161
- const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
12573
+ const sourceParentInfo = getParentFileInfoForNode(
12574
+ graphDataRef.current,
12575
+ sceneDataRef2.current,
12576
+ sourceNodeData.id,
12577
+ sceneConfigId2,
12578
+ ownerId2
12579
+ );
12580
+ const targetParentInfo = getParentFileInfoForNode(
12581
+ graphDataRef.current,
12582
+ sceneDataRef2.current,
12583
+ targetNodeData.id,
12584
+ sceneConfigId2,
12585
+ ownerId2
12586
+ );
12162
12587
  let parentInfoToSave = sourceParentInfo;
12163
12588
  const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
12164
12589
  const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
@@ -12184,10 +12609,15 @@ function XViewScene({
12184
12609
  };
12185
12610
  await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
12186
12611
  } else {
12187
- const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
12612
+ const specificParentData = JSON.parse(
12613
+ JSON.stringify(graphDataRef.current[parentFileIdToSave])
12614
+ );
12188
12615
  specificParentData.links.push(newLink);
12189
12616
  const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
12190
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
12617
+ await context.actions.save_view_data(
12618
+ filenameForSpecificParent,
12619
+ specificParentData
12620
+ );
12191
12621
  graphDataRef.current[parentFileIdToSave] = specificParentData;
12192
12622
  }
12193
12623
  addNewLinkToScene(stateRef2.current, newLink);
@@ -12199,7 +12629,9 @@ function XViewScene({
12199
12629
  };
12200
12630
  const handleClearAncestryVisuals = (0, import_react26.useCallback)((ancestryId) => {
12201
12631
  const { renderedAncestries, ancestryGroup } = stateRef.current;
12202
- const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
12632
+ const renderIndex = renderedAncestries.findIndex(
12633
+ (a) => String(a.id) === String(ancestryId)
12634
+ );
12203
12635
  if (renderIndex !== -1) {
12204
12636
  const toRemove = renderedAncestries[renderIndex];
12205
12637
  toRemove.lines.forEach((line) => {
@@ -12208,12 +12640,16 @@ function XViewScene({
12208
12640
  if (line.material) line.material.dispose();
12209
12641
  });
12210
12642
  renderedAncestries.splice(renderIndex, 1);
12211
- stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
12643
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
12644
+ (a) => a.lines
12645
+ );
12212
12646
  }
12213
12647
  }, []);
12214
12648
  const handleRenderAncestry = (0, import_react26.useCallback)(
12215
12649
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
12216
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12650
+ setContextMenu(
12651
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
12652
+ );
12217
12653
  if (!ancestryObject || !ancestryObject.tree) {
12218
12654
  return;
12219
12655
  }
@@ -12240,14 +12676,16 @@ function XViewScene({
12240
12676
  if (numId !== void 0 && normalizedAllowedIds.has(numId)) return true;
12241
12677
  if (strId && normalizedAllowedIds.has(strId)) return true;
12242
12678
  if (strSecId && normalizedAllowedIds.has(strSecId)) return true;
12243
- if (numId !== void 0 && normalizedAllowedIds.has(String(numId))) return true;
12679
+ if (numId !== void 0 && normalizedAllowedIds.has(String(numId)))
12680
+ return true;
12244
12681
  return false;
12245
12682
  };
12246
12683
  const checkIsActive = (section, targetId) => {
12247
12684
  if (targetId === null || targetId === void 0) return false;
12248
12685
  const sTarget = String(targetId);
12249
12686
  if (section.id && String(section.id) === sTarget) return true;
12250
- if (section.section_id && String(section.section_id) === sTarget) return true;
12687
+ if (section.section_id && String(section.section_id) === sTarget)
12688
+ return true;
12251
12689
  if (section.section_numeric_id !== void 0) {
12252
12690
  if (String(section.section_numeric_id) === sTarget) return true;
12253
12691
  }
@@ -12263,7 +12701,9 @@ function XViewScene({
12263
12701
  traverse(sectionTree);
12264
12702
  return ids;
12265
12703
  };
12266
- const existingIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryObject.ancestry_id));
12704
+ const existingIndex = renderedAncestries.findIndex(
12705
+ (a) => String(a.id) === String(ancestryObject.ancestry_id)
12706
+ );
12267
12707
  let skipGeneration = false;
12268
12708
  let ancestryEntry = null;
12269
12709
  if (existingIndex !== -1) {
@@ -12318,9 +12758,15 @@ function XViewScene({
12318
12758
  if (line.material) line.material.dispose();
12319
12759
  });
12320
12760
  }
12321
- const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes);
12761
+ const allParentNodes = Object.values(parentDataRef.current).flatMap(
12762
+ (fileData) => fileData.nodes
12763
+ );
12322
12764
  const allAncestries = ancestryDataRef.current || [];
12323
- const fullTree = buildFullAncestryTree(ancestryObject.tree, allParentNodes, allAncestries);
12765
+ const fullTree = buildFullAncestryTree(
12766
+ ancestryObject.tree,
12767
+ allParentNodes,
12768
+ allAncestries
12769
+ );
12324
12770
  if (!fullTree) return;
12325
12771
  const rootNodeId = String(ancestryObject.ancestral_node);
12326
12772
  let rootNodeMesh = nodeObjects[rootNodeId];
@@ -12363,7 +12809,10 @@ function XViewScene({
12363
12809
  const colorIndex = stateRef.current.ancestryRenderCounter % 3;
12364
12810
  colorHex = ANCESTRY_COLORS[colorIndex];
12365
12811
  }
12366
- const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
12812
+ const resolution = new THREE3.Vector2(
12813
+ renderer.domElement.clientWidth,
12814
+ renderer.domElement.clientHeight
12815
+ );
12367
12816
  const cleanupLinesForNode = (nodeId) => {
12368
12817
  if (!ancestryEntry || !ancestryEntry.lines) return;
12369
12818
  const linesKeep = [];
@@ -12403,7 +12852,13 @@ function XViewScene({
12403
12852
  }
12404
12853
  if (originMesh && rootNodeMesh) {
12405
12854
  cleanupLinesForNode(rootNodeId);
12406
- const branchLine = createAncestryLinkLine(originMesh, rootNodeMesh, resolution, {}, colorHex);
12855
+ const branchLine = createAncestryLinkLine(
12856
+ originMesh,
12857
+ rootNodeMesh,
12858
+ resolution,
12859
+ {},
12860
+ colorHex
12861
+ );
12407
12862
  ancestryGroup.add(branchLine);
12408
12863
  ancestryEntry.lines.push(branchLine);
12409
12864
  }
@@ -12414,8 +12869,14 @@ function XViewScene({
12414
12869
  if (!children || children.length === 0) return null;
12415
12870
  let lastRenderedMesh = null;
12416
12871
  const numChildren = children.length;
12417
- const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(new THREE3.Vector3(0, 1, 0), currentAngle);
12418
- const rightVec = new THREE3.Vector3(1, 0, 0).applyAxisAngle(new THREE3.Vector3(0, 1, 0), currentAngle);
12872
+ const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(
12873
+ new THREE3.Vector3(0, 1, 0),
12874
+ currentAngle
12875
+ );
12876
+ const rightVec = new THREE3.Vector3(1, 0, 0).applyAxisAngle(
12877
+ new THREE3.Vector3(0, 1, 0),
12878
+ currentAngle
12879
+ );
12419
12880
  const angleRange = numChildren > 3 ? Math.PI : Math.PI / 1.5;
12420
12881
  children.forEach((childItem, index) => {
12421
12882
  if (childItem.is_section) return;
@@ -12436,14 +12897,30 @@ function XViewScene({
12436
12897
  targetPositionsCache.set(sNodeId, childPosition.clone());
12437
12898
  cleanupLinesForNode(sNodeId);
12438
12899
  }
12439
- const childMesh = addOrUpdateNodeMesh(childItem.node, childPosition, true);
12900
+ const childMesh = addOrUpdateNodeMesh(
12901
+ childItem.node,
12902
+ childPosition,
12903
+ true
12904
+ );
12440
12905
  allRenderedNodePositions.push(childPosition);
12441
- const line = createAncestryLinkLine(parentMesh, childMesh, resolution, childItem.relationship, colorHex);
12906
+ const line = createAncestryLinkLine(
12907
+ parentMesh,
12908
+ childMesh,
12909
+ resolution,
12910
+ childItem.relationship,
12911
+ colorHex
12912
+ );
12442
12913
  ancestryGroup.add(line);
12443
12914
  ancestryEntry.lines.push(line);
12444
12915
  lastRenderedMesh = childMesh;
12445
12916
  if (childItem.children && childItem.children.length > 0) {
12446
- const lastDescendant = renderCluster(childItem.children, childMesh, childPosition, level + 1, currentAngle);
12917
+ const lastDescendant = renderCluster(
12918
+ childItem.children,
12919
+ childMesh,
12920
+ childPosition,
12921
+ level + 1,
12922
+ currentAngle
12923
+ );
12447
12924
  if (lastDescendant) lastRenderedMesh = lastDescendant;
12448
12925
  }
12449
12926
  });
@@ -12457,9 +12934,13 @@ function XViewScene({
12457
12934
  else looseNodes.push(child);
12458
12935
  });
12459
12936
  }
12460
- sections.sort((a, b) => (a.section_numeric_id || 0) - (b.section_numeric_id || 0));
12937
+ sections.sort(
12938
+ (a, b) => (a.section_numeric_id || 0) - (b.section_numeric_id || 0)
12939
+ );
12461
12940
  let combinedStartNodes = [...looseNodes];
12462
- let session0Index = sections.findIndex((s) => s.section_numeric_id === 0 || s.name === "Sess\xE3o 0");
12941
+ let session0Index = sections.findIndex(
12942
+ (s) => s.section_numeric_id === 0 || s.name === "Sess\xE3o 0"
12943
+ );
12463
12944
  if (session0Index !== -1) {
12464
12945
  const session0 = sections[session0Index];
12465
12946
  if (checkShouldRender(session0) && session0.children) {
@@ -12468,7 +12949,13 @@ function XViewScene({
12468
12949
  sections.splice(session0Index, 1);
12469
12950
  }
12470
12951
  const rootTargetPos2 = targetPositionsCache.get(rootNodeId) || rootNodeMesh.position;
12471
- const lastStartMesh = renderCluster(combinedStartNodes, rootNodeMesh, rootTargetPos2, 1, baseRotation);
12952
+ const lastStartMesh = renderCluster(
12953
+ combinedStartNodes,
12954
+ rootNodeMesh,
12955
+ rootTargetPos2,
12956
+ 1,
12957
+ baseRotation
12958
+ );
12472
12959
  if (lastStartMesh) {
12473
12960
  currentAnchorMesh = lastStartMesh;
12474
12961
  }
@@ -12479,10 +12966,18 @@ function XViewScene({
12479
12966
  const sectionNodes = section.children || [];
12480
12967
  if (sectionNodes.length > 0) {
12481
12968
  const parentAngle = nodeRotationMap.get(String(currentAnchorMesh.userData.id)) ?? baseRotation;
12482
- const lastMeshOfThisSection = renderCluster(sectionNodes, currentAnchorMesh, currentAnchorPosition, 1, parentAngle);
12969
+ const lastMeshOfThisSection = renderCluster(
12970
+ sectionNodes,
12971
+ currentAnchorMesh,
12972
+ currentAnchorPosition,
12973
+ 1,
12974
+ parentAngle
12975
+ );
12483
12976
  if (lastMeshOfThisSection) {
12484
12977
  currentAnchorMesh = lastMeshOfThisSection;
12485
- currentAnchorPosition = targetPositionsCache.get(String(lastMeshOfThisSection.userData.id)) || lastMeshOfThisSection.position;
12978
+ currentAnchorPosition = targetPositionsCache.get(
12979
+ String(lastMeshOfThisSection.userData.id)
12980
+ ) || lastMeshOfThisSection.position;
12486
12981
  }
12487
12982
  }
12488
12983
  }
@@ -12511,7 +13006,10 @@ function XViewScene({
12511
13006
  } else {
12512
13007
  const directChildren = fullTree.children ? fullTree.children.filter((c) => !c.is_section) : [];
12513
13008
  if (directChildren.length > 0) {
12514
- targetSectionForZone = { name: "In\xEDcio", children: directChildren };
13009
+ targetSectionForZone = {
13010
+ name: "In\xEDcio",
13011
+ children: directChildren
13012
+ };
12515
13013
  }
12516
13014
  }
12517
13015
  } else {
@@ -12585,7 +13083,10 @@ function XViewScene({
12585
13083
  stateRef.current.ancestryLinks = stateRef.current.renderedAncestries.flatMap((a) => a.lines);
12586
13084
  focusTargetPosition = center;
12587
13085
  focusTargetRotation = baseRotation;
12588
- const desiredDistance = Math.max(x_view_config.CAMERA_ZOOM_DISTANCE, radius * 2.8);
13086
+ const desiredDistance = Math.max(
13087
+ x_view_config.CAMERA_ZOOM_DISTANCE,
13088
+ radius * 2.8
13089
+ );
12589
13090
  focusZoomFactor = x_view_config.CAMERA_ZOOM_DISTANCE / desiredDistance;
12590
13091
  } else {
12591
13092
  const anchorId = String(currentAnchorMesh.userData.id);
@@ -12600,13 +13101,18 @@ function XViewScene({
12600
13101
  }
12601
13102
  if (!focusTargetPosition && !allowedSectionIds) {
12602
13103
  if (allRenderedNodePositions.length > 0) {
12603
- const boundingBox = new THREE3.Box3().setFromPoints(allRenderedNodePositions);
13104
+ const boundingBox = new THREE3.Box3().setFromPoints(
13105
+ allRenderedNodePositions
13106
+ );
12604
13107
  const center = new THREE3.Vector3();
12605
13108
  boundingBox.getCenter(center);
12606
13109
  const size = new THREE3.Vector3();
12607
13110
  boundingBox.getSize(size);
12608
13111
  const maxDim = Math.max(size.x, size.y, size.z);
12609
- const fitZoom = Math.min(1, x_view_config.CAMERA_ZOOM_DISTANCE / (maxDim * 1.5));
13112
+ const fitZoom = Math.min(
13113
+ 1,
13114
+ x_view_config.CAMERA_ZOOM_DISTANCE / (maxDim * 1.5)
13115
+ );
12610
13116
  const defaultBase = new THREE3.Vector3(-50, 40, 20);
12611
13117
  const rotatedCinematicAngle = defaultBase.clone().applyAxisAngle(new THREE3.Vector3(0, 1, 0), baseRotation);
12612
13118
  tweenToTarget(center, fitZoom, rotatedCinematicAngle);
@@ -12625,210 +13131,280 @@ function XViewScene({
12625
13131
  tweenToTarget(targetPos, focusZoomFactor, rotatedCinematicAngle);
12626
13132
  }
12627
13133
  },
12628
- [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
13134
+ [
13135
+ addOrUpdateNodeMesh,
13136
+ tweenToTarget,
13137
+ buildFullAncestryTree,
13138
+ readingMode.isActive,
13139
+ ancestryMode.isActive
13140
+ ]
12629
13141
  );
12630
- const handleRenderAbstractionTree = (0, import_react26.useCallback)((ancestryObject, targetNodeId = null) => {
12631
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12632
- if (!ancestryObject || !ancestryObject.abstraction_tree) return;
12633
- const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
12634
- const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
12635
- let fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
12636
- if (!fullTree || !fullTree.node) return;
12637
- if (targetNodeId) {
12638
- const pruneTreeToPath = (treeNode, targetId) => {
12639
- var _a2;
12640
- if (!treeNode) return null;
12641
- const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
12642
- if (String(currentId) === String(targetId)) {
12643
- return { ...treeNode, children: [] };
12644
- }
12645
- if (treeNode.children && treeNode.children.length > 0) {
12646
- for (let child of treeNode.children) {
12647
- const prunedChild = pruneTreeToPath(child, targetId);
12648
- if (prunedChild) {
12649
- return { ...treeNode, children: [prunedChild] };
12650
- }
13142
+ const handleRenderAbstractionTree = (0, import_react26.useCallback)(
13143
+ (ancestryObject, targetNodeId = null) => {
13144
+ setContextMenu(
13145
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
13146
+ );
13147
+ if (!ancestryObject || !ancestryObject.abstraction_tree) return;
13148
+ const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
13149
+ const allParentNodes = Object.values(parentDataRef.current).flatMap(
13150
+ (f) => f.nodes
13151
+ );
13152
+ let fullTree = buildFullAncestryTree(
13153
+ ancestryObject.abstraction_tree,
13154
+ allParentNodes,
13155
+ ancestryDataRef.current
13156
+ );
13157
+ if (!fullTree || !fullTree.node) return;
13158
+ if (targetNodeId) {
13159
+ const pruneTreeToPath = (treeNode, targetId) => {
13160
+ var _a2;
13161
+ if (!treeNode) return null;
13162
+ const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
13163
+ if (String(currentId) === String(targetId)) {
13164
+ return { ...treeNode, children: [] };
12651
13165
  }
12652
- }
12653
- return null;
12654
- };
12655
- const pruned = pruneTreeToPath(fullTree, targetNodeId);
12656
- if (pruned) fullTree = pruned;
12657
- }
12658
- const absId = ancestryObject.ancestry_id + "_abs";
12659
- handleClearAncestryVisuals(absId);
12660
- const colorHex = 9133302;
12661
- const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
12662
- const ancestryEntry = { id: absId, lines: [], isFullRender: true };
12663
- renderedAncestries.push(ancestryEntry);
12664
- const rootNodeId = String(fullTree.node.id);
12665
- let rootNodeMesh = nodeObjects[rootNodeId];
12666
- let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
12667
- if (!rootNodeMesh) {
12668
- rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
12669
- }
12670
- const SPACING_Y = -40;
12671
- const SPACING_X = 55;
12672
- const renderVertical = (treeNode, parentMesh, parentPos, level) => {
12673
- if (!treeNode.children || treeNode.children.length === 0) return;
12674
- const totalSiblings = treeNode.children.length;
12675
- treeNode.children.forEach((childItem, i) => {
12676
- if (!childItem.node) return;
12677
- const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
12678
- const childY = parentPos.y + SPACING_Y;
12679
- const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
12680
- const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
12681
- const line = createAncestryLinkLine(parentMesh, childMesh, resolution, {}, colorHex);
12682
- ancestryGroup.add(line);
12683
- ancestryEntry.lines.push(line);
12684
- renderVertical(childItem, childMesh, childPos, level + 1);
12685
- });
12686
- };
12687
- renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
12688
- stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
12689
- tweenToTarget(rootTargetPos, 0.7);
12690
- }, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
12691
- const handleReadModeBranchNav = (0, import_react26.useCallback)((nodeId, action, direction = "right") => {
12692
- const { ancestry, branchStack } = readingMode;
12693
- if (!ancestry || !ancestry.tree) return;
12694
- const allAncestries = ancestryDataRef.current || [];
12695
- const fullTree = buildFullAncestryTree(ancestry.tree, Object.values(parentDataRef.current).flatMap((f) => f.nodes), allAncestries);
12696
- if (action === "open") {
12697
- let currentPtr = fullTree;
12698
- for (const step of branchStack) {
12699
- const found = findNodePath3(currentPtr, step.nodeId);
12700
- if (found && found.node.parallel_branches) {
12701
- const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
12702
- if (branch) currentPtr = branch.tree;
12703
- }
12704
- }
12705
- const foundTarget = findNodePath3(currentPtr, nodeId);
12706
- if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
12707
- const branchToOpen = foundTarget.node.parallel_branches.find((b) => (b.direction || "right") === direction);
12708
- if (!branchToOpen) return;
12709
- if (branchToOpen && branchToOpen.tree) {
12710
- const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
12711
- const savedBranchProgress = 0;
12712
- stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
12713
- stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
12714
- const newStack = [...branchStack, {
12715
- nodeId,
12716
- branchId: branchToOpen.id,
12717
- savedMaxIndex: parentIndexToSave,
12718
- entryDirection: direction
12719
- }];
12720
- setReadingMode((prev) => ({ ...prev, branchStack: newStack, initialSectionId: null }));
12721
- const branchAncestryObj = {
12722
- ancestry_id: branchToOpen.id,
12723
- ancestral_node: branchToOpen.tree.node.id,
12724
- name: branchToOpen.name,
12725
- description: branchToOpen.description,
12726
- description_sections: branchToOpen.description_sections,
12727
- tree: branchToOpen.tree,
12728
- _originNodeId: nodeId,
12729
- _branchDirection: direction
12730
- };
12731
- const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
12732
- const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
12733
- for (let i = 0; i <= savedBranchProgress; i++) {
12734
- if (branchSections[i]) {
12735
- if (branchSections[i].id) allowedIds.add(String(branchSections[i].id));
12736
- if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
12737
- allowedIds.add(branchSections[i].numericId);
12738
- allowedIds.add(String(branchSections[i].numericId));
13166
+ if (treeNode.children && treeNode.children.length > 0) {
13167
+ for (let child of treeNode.children) {
13168
+ const prunedChild = pruneTreeToPath(child, targetId);
13169
+ if (prunedChild) {
13170
+ return { ...treeNode, children: [prunedChild] };
12739
13171
  }
12740
13172
  }
12741
13173
  }
12742
- const rotation = newStack.reduce((acc, step) => {
12743
- return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
12744
- }, 0);
12745
- const initialFocusId = "preamble";
12746
- handleRenderAncestry(
12747
- branchAncestryObj,
12748
- allowedIds,
12749
- initialFocusId,
12750
- rotation,
12751
- false
12752
- );
12753
- }
13174
+ return null;
13175
+ };
13176
+ const pruned = pruneTreeToPath(fullTree, targetNodeId);
13177
+ if (pruned) fullTree = pruned;
13178
+ }
13179
+ const absId = ancestryObject.ancestry_id + "_abs";
13180
+ handleClearAncestryVisuals(absId);
13181
+ const colorHex = 9133302;
13182
+ const resolution = new THREE3.Vector2(
13183
+ renderer.domElement.clientWidth,
13184
+ renderer.domElement.clientHeight
13185
+ );
13186
+ const ancestryEntry = { id: absId, lines: [], isFullRender: true };
13187
+ renderedAncestries.push(ancestryEntry);
13188
+ const rootNodeId = String(fullTree.node.id);
13189
+ let rootNodeMesh = nodeObjects[rootNodeId];
13190
+ let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
13191
+ if (!rootNodeMesh) {
13192
+ rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
12754
13193
  }
12755
- } else if (action === "back") {
12756
- if (branchStack.length === 0) return;
12757
- const newStack = [...branchStack];
12758
- const popped = newStack.pop();
12759
- if (popped && popped.branchId) {
12760
- stateRef.current.readMode.progressMap[popped.branchId] = stateRef.current.readMode.currentMaxIndex;
12761
- }
12762
- const parentSavedIndex = popped.savedMaxIndex !== void 0 ? popped.savedMaxIndex : 0;
12763
- stateRef.current.readMode.currentMaxIndex = parentSavedIndex;
12764
- stateRef.current.maxAncestryRenderIndex = parentSavedIndex;
12765
- let targetTreeToRender = fullTree;
12766
- let targetAncestryInfo = ancestry;
12767
- if (newStack.length > 0) {
12768
- let ptr = fullTree;
12769
- for (const step of newStack) {
12770
- const found = findNodePath3(ptr, step.nodeId);
13194
+ const SPACING_Y = -40;
13195
+ const SPACING_X = 55;
13196
+ const renderVertical = (treeNode, parentMesh, parentPos, level) => {
13197
+ if (!treeNode.children || treeNode.children.length === 0) return;
13198
+ const totalSiblings = treeNode.children.length;
13199
+ treeNode.children.forEach((childItem, i) => {
13200
+ if (!childItem.node) return;
13201
+ const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
13202
+ const childY = parentPos.y + SPACING_Y;
13203
+ const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
13204
+ const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
13205
+ const line = createAncestryLinkLine(
13206
+ parentMesh,
13207
+ childMesh,
13208
+ resolution,
13209
+ {},
13210
+ colorHex
13211
+ );
13212
+ ancestryGroup.add(line);
13213
+ ancestryEntry.lines.push(line);
13214
+ renderVertical(childItem, childMesh, childPos, level + 1);
13215
+ });
13216
+ };
13217
+ renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
13218
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
13219
+ (a) => a.lines
13220
+ );
13221
+ tweenToTarget(rootTargetPos, 0.7);
13222
+ },
13223
+ [
13224
+ addOrUpdateNodeMesh,
13225
+ tweenToTarget,
13226
+ buildFullAncestryTree,
13227
+ handleClearAncestryVisuals
13228
+ ]
13229
+ );
13230
+ const handleReadModeBranchNav = (0, import_react26.useCallback)(
13231
+ (nodeId, action, direction = "right") => {
13232
+ const { ancestry, branchStack } = readingMode;
13233
+ if (!ancestry || !ancestry.tree) return;
13234
+ const allAncestries = ancestryDataRef.current || [];
13235
+ const fullTree = buildFullAncestryTree(
13236
+ ancestry.tree,
13237
+ Object.values(parentDataRef.current).flatMap((f) => f.nodes),
13238
+ allAncestries
13239
+ );
13240
+ if (action === "open") {
13241
+ let currentPtr = fullTree;
13242
+ for (const step of branchStack) {
13243
+ const found = findNodePath3(currentPtr, step.nodeId);
12771
13244
  if (found && found.node.parallel_branches) {
12772
- const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
12773
- if (branch) {
12774
- ptr = branch.tree;
12775
- targetAncestryInfo = { ...branch, ancestry_id: branch.id, ancestral_node: branch.tree.node.id };
13245
+ const branch = found.node.parallel_branches.find(
13246
+ (b) => b.id === step.branchId
13247
+ );
13248
+ if (branch) currentPtr = branch.tree;
13249
+ }
13250
+ }
13251
+ const foundTarget = findNodePath3(currentPtr, nodeId);
13252
+ if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
13253
+ const branchToOpen = foundTarget.node.parallel_branches.find(
13254
+ (b) => (b.direction || "right") === direction
13255
+ );
13256
+ if (!branchToOpen) return;
13257
+ if (branchToOpen && branchToOpen.tree) {
13258
+ const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
13259
+ const savedBranchProgress = 0;
13260
+ stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
13261
+ stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
13262
+ const newStack = [
13263
+ ...branchStack,
13264
+ {
13265
+ nodeId,
13266
+ branchId: branchToOpen.id,
13267
+ savedMaxIndex: parentIndexToSave,
13268
+ entryDirection: direction
13269
+ }
13270
+ ];
13271
+ setReadingMode((prev) => ({
13272
+ ...prev,
13273
+ branchStack: newStack,
13274
+ initialSectionId: null
13275
+ }));
13276
+ const branchAncestryObj = {
13277
+ ancestry_id: branchToOpen.id,
13278
+ ancestral_node: branchToOpen.tree.node.id,
13279
+ name: branchToOpen.name,
13280
+ description: branchToOpen.description,
13281
+ description_sections: branchToOpen.description_sections,
13282
+ tree: branchToOpen.tree,
13283
+ _originNodeId: nodeId,
13284
+ _branchDirection: direction
13285
+ };
13286
+ const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
13287
+ const branchSections = parseDescriptionSections(
13288
+ branchToOpen.description || "",
13289
+ branchToOpen.description_sections || []
13290
+ );
13291
+ for (let i = 0; i <= savedBranchProgress; i++) {
13292
+ if (branchSections[i]) {
13293
+ if (branchSections[i].id)
13294
+ allowedIds.add(String(branchSections[i].id));
13295
+ if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
13296
+ allowedIds.add(branchSections[i].numericId);
13297
+ allowedIds.add(String(branchSections[i].numericId));
13298
+ }
13299
+ }
12776
13300
  }
13301
+ const rotation = newStack.reduce((acc, step) => {
13302
+ return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
13303
+ }, 0);
13304
+ const initialFocusId = "preamble";
13305
+ handleRenderAncestry(
13306
+ branchAncestryObj,
13307
+ allowedIds,
13308
+ initialFocusId,
13309
+ rotation,
13310
+ false
13311
+ );
12777
13312
  }
12778
13313
  }
12779
- targetTreeToRender = ptr;
12780
- }
12781
- const activeParentStackItem = newStack.length > 0 ? newStack[newStack.length - 1] : null;
12782
- const parentAncestryObj = {
12783
- ...targetAncestryInfo,
12784
- tree: targetTreeToRender,
12785
- _originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
12786
- _branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
12787
- };
12788
- const descriptionText = targetAncestryInfo.description || "";
12789
- const savedSections = targetAncestryInfo.description_sections || [];
12790
- const sections = parseDescriptionSections(descriptionText, savedSections);
12791
- let focusTargetId = null;
12792
- if (popped && popped.nodeId) {
12793
- const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
12794
- for (let i = 0; i < sections.length; i++) {
12795
- if (sections[i].content && sections[i].content.includes(mentionTag)) {
12796
- const section = sections[i];
12797
- focusTargetId = section.numericId !== void 0 ? section.numericId : section.id;
12798
- break;
13314
+ } else if (action === "back") {
13315
+ if (branchStack.length === 0) return;
13316
+ const newStack = [...branchStack];
13317
+ const popped = newStack.pop();
13318
+ if (popped && popped.branchId) {
13319
+ stateRef.current.readMode.progressMap[popped.branchId] = stateRef.current.readMode.currentMaxIndex;
13320
+ }
13321
+ const parentSavedIndex = popped.savedMaxIndex !== void 0 ? popped.savedMaxIndex : 0;
13322
+ stateRef.current.readMode.currentMaxIndex = parentSavedIndex;
13323
+ stateRef.current.maxAncestryRenderIndex = parentSavedIndex;
13324
+ let targetTreeToRender = fullTree;
13325
+ let targetAncestryInfo = ancestry;
13326
+ if (newStack.length > 0) {
13327
+ let ptr = fullTree;
13328
+ for (const step of newStack) {
13329
+ const found = findNodePath3(ptr, step.nodeId);
13330
+ if (found && found.node.parallel_branches) {
13331
+ const branch = found.node.parallel_branches.find(
13332
+ (b) => b.id === step.branchId
13333
+ );
13334
+ if (branch) {
13335
+ ptr = branch.tree;
13336
+ targetAncestryInfo = {
13337
+ ...branch,
13338
+ ancestry_id: branch.id,
13339
+ ancestral_node: branch.tree.node.id
13340
+ };
13341
+ }
13342
+ }
13343
+ }
13344
+ targetTreeToRender = ptr;
13345
+ }
13346
+ const activeParentStackItem = newStack.length > 0 ? newStack[newStack.length - 1] : null;
13347
+ const parentAncestryObj = {
13348
+ ...targetAncestryInfo,
13349
+ tree: targetTreeToRender,
13350
+ _originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
13351
+ _branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
13352
+ };
13353
+ const descriptionText = targetAncestryInfo.description || "";
13354
+ const savedSections = targetAncestryInfo.description_sections || [];
13355
+ const sections = parseDescriptionSections(
13356
+ descriptionText,
13357
+ savedSections
13358
+ );
13359
+ let focusTargetId = null;
13360
+ if (popped && popped.nodeId) {
13361
+ const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
13362
+ for (let i = 0; i < sections.length; i++) {
13363
+ if (sections[i].content && sections[i].content.includes(mentionTag)) {
13364
+ const section = sections[i];
13365
+ focusTargetId = section.numericId !== void 0 ? section.numericId : section.id;
13366
+ break;
13367
+ }
12799
13368
  }
12800
13369
  }
12801
- }
12802
- const allowedIds = /* @__PURE__ */ new Set();
12803
- allowedIds.add("preamble");
12804
- allowedIds.add(0);
12805
- allowedIds.add("0");
12806
- for (let i = 0; i <= parentSavedIndex; i++) {
12807
- if (sections[i]) {
12808
- if (sections[i].id) allowedIds.add(String(sections[i].id));
12809
- if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
12810
- allowedIds.add(sections[i].numericId);
12811
- allowedIds.add(String(sections[i].numericId));
13370
+ const allowedIds = /* @__PURE__ */ new Set();
13371
+ allowedIds.add("preamble");
13372
+ allowedIds.add(0);
13373
+ allowedIds.add("0");
13374
+ for (let i = 0; i <= parentSavedIndex; i++) {
13375
+ if (sections[i]) {
13376
+ if (sections[i].id) allowedIds.add(String(sections[i].id));
13377
+ if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
13378
+ allowedIds.add(sections[i].numericId);
13379
+ allowedIds.add(String(sections[i].numericId));
13380
+ }
12812
13381
  }
12813
13382
  }
12814
- }
12815
- const rotation = newStack.reduce((acc, step) => {
12816
- return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
12817
- }, 0);
12818
- handleRenderAncestry(parentAncestryObj, allowedIds, focusTargetId, rotation, false);
12819
- if (popped && popped.nodeId) {
12820
- const nodeMesh = stateRef.current.nodeObjects[String(popped.nodeId)];
12821
- if (nodeMesh) {
12822
- tweenToTarget(nodeMesh);
13383
+ const rotation = newStack.reduce((acc, step) => {
13384
+ return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
13385
+ }, 0);
13386
+ handleRenderAncestry(
13387
+ parentAncestryObj,
13388
+ allowedIds,
13389
+ focusTargetId,
13390
+ rotation,
13391
+ false
13392
+ );
13393
+ if (popped && popped.nodeId) {
13394
+ const nodeMesh = stateRef.current.nodeObjects[String(popped.nodeId)];
13395
+ if (nodeMesh) {
13396
+ tweenToTarget(nodeMesh);
13397
+ }
12823
13398
  }
13399
+ setReadingMode((prev) => ({
13400
+ ...prev,
13401
+ branchStack: newStack,
13402
+ initialSectionId: focusTargetId
13403
+ }));
12824
13404
  }
12825
- setReadingMode((prev) => ({
12826
- ...prev,
12827
- branchStack: newStack,
12828
- initialSectionId: focusTargetId
12829
- }));
12830
- }
12831
- }, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
13405
+ },
13406
+ [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
13407
+ );
12832
13408
  const handleReadModeHighlight = (0, import_react26.useCallback)((nodeId) => {
12833
13409
  if (stateRef.current.highlightedNodeId !== nodeId) {
12834
13410
  stateRef.current.highlightedNodeId = nodeId;
@@ -12836,7 +13412,8 @@ function XViewScene({
12836
13412
  setHighlightedNodeId(nodeId);
12837
13413
  }, []);
12838
13414
  const activeNodeBranches = (0, import_react26.useMemo)(() => {
12839
- if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree) return null;
13415
+ if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
13416
+ return null;
12840
13417
  const fullTree = buildFullAncestryTree(
12841
13418
  readingMode.ancestry.tree,
12842
13419
  Object.values(parentDataRef.current).flatMap((f) => f.nodes),
@@ -12871,7 +13448,13 @@ function XViewScene({
12871
13448
  };
12872
13449
  }
12873
13450
  return null;
12874
- }, [highlightedNodeId, readingMode.ancestry, buildFullAncestryTree, readingMode.branchStack, ancestryDataRef.current]);
13451
+ }, [
13452
+ highlightedNodeId,
13453
+ readingMode.ancestry,
13454
+ buildFullAncestryTree,
13455
+ readingMode.branchStack,
13456
+ ancestryDataRef.current
13457
+ ]);
12875
13458
  const backNavigationInfo = (0, import_react26.useMemo)(() => {
12876
13459
  const { branchStack } = readingMode;
12877
13460
  if (!branchStack || branchStack.length === 0) return null;
@@ -12907,7 +13490,9 @@ function XViewScene({
12907
13490
  for (const step of branchStack) {
12908
13491
  const found = findNodePath3(currentPtr, step.nodeId);
12909
13492
  if (found && found.node.parallel_branches) {
12910
- const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
13493
+ const branch = found.node.parallel_branches.find(
13494
+ (b) => b.id === step.branchId
13495
+ );
12911
13496
  if (branch) {
12912
13497
  currentPtr = branch.tree;
12913
13498
  currentMeta = branch;
@@ -12928,17 +13513,26 @@ function XViewScene({
12928
13513
  if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
12929
13514
  return null;
12930
13515
  }
12931
- const allNodes = Object.values(parentDataRef.current || {}).flatMap((f) => f.nodes || []);
13516
+ const allNodes = Object.values(parentDataRef.current || {}).flatMap(
13517
+ (f) => f.nodes || []
13518
+ );
12932
13519
  const allAncestries = ancestryDataRef.current || [];
12933
13520
  return buildFullAncestryTree(
12934
13521
  readingMode.ancestry.abstraction_tree,
12935
13522
  allNodes,
12936
13523
  allAncestries
12937
13524
  );
12938
- }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
13525
+ }, [
13526
+ readingMode.isActive,
13527
+ readingMode.ancestry,
13528
+ buildFullAncestryTree,
13529
+ sceneVersion
13530
+ ]);
12939
13531
  const handleStartReadingAncestry = (0, import_react26.useCallback)(
12940
- async (ancestryObject) => {
12941
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
13532
+ async (ancestryObject, renderMode = "full") => {
13533
+ setContextMenu(
13534
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
13535
+ );
12942
13536
  if (!ancestryObject || !ancestryObject.tree) {
12943
13537
  console.warn("Ancestralidade inv\xE1lida para leitura.");
12944
13538
  return;
@@ -12951,14 +13545,20 @@ function XViewScene({
12951
13545
  const hasDescription = ancestryObject.description && ancestryObject.description.trim() !== "";
12952
13546
  const hasMainTreeNodes = ancestryObject.tree.children && ancestryObject.tree.children.length > 0;
12953
13547
  const hasAbstractionNodes = ancestryObject.abstraction_tree && ancestryObject.abstraction_tree.children && ancestryObject.abstraction_tree.children.length > 0;
12954
- const shouldAutoRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
13548
+ const isFull = renderMode === "full";
13549
+ const isAncestryOnly = renderMode === "ancestry_only";
13550
+ const isAbstractionOnly = renderMode === "abstraction_only";
13551
+ let shouldRenderAbstraction = isAbstractionOnly;
13552
+ if (isFull) {
13553
+ shouldRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
13554
+ }
12955
13555
  setReadingMode({
12956
- isActive: true,
13556
+ isActive: isFull ? hasDescription : false,
12957
13557
  ancestry: ancestryObject,
12958
13558
  branchStack: [],
12959
- autoAbstraction: shouldAutoRenderAbstraction
13559
+ autoAbstraction: shouldRenderAbstraction
12960
13560
  });
12961
- if (shouldAutoRenderAbstraction) {
13561
+ if (shouldRenderAbstraction) {
12962
13562
  handleRenderAbstractionTree(ancestryObject, null);
12963
13563
  } else {
12964
13564
  const initialSections = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
@@ -12971,148 +13571,190 @@ function XViewScene({
12971
13571
  },
12972
13572
  [handleRenderAncestry, handleRenderAbstractionTree]
12973
13573
  );
12974
- const handleReadModeSectionChange = (0, import_react26.useCallback)((activeSectionId) => {
12975
- const { ancestry, branchStack } = readingMode;
12976
- if (!ancestry || !readingMode.isActive) return;
12977
- let targetObj = ancestry;
12978
- let targetTree = ancestry.tree;
12979
- if (branchStack.length > 0) {
12980
- const allNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
12981
- const fullTree = buildFullAncestryTree(
12982
- ancestry.tree,
12983
- allNodes,
12984
- ancestryDataRef.current
12985
- );
12986
- let currentPtr = fullTree;
12987
- for (const step of branchStack) {
12988
- const found = findNodePath3(currentPtr, step.nodeId);
12989
- if (found && found.node && found.node.parallel_branches) {
12990
- const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
12991
- if (branch) {
12992
- targetObj = branch;
12993
- targetTree = branch.tree;
12994
- currentPtr = branch.tree;
13574
+ const handleReadModeSectionChange = (0, import_react26.useCallback)(
13575
+ (activeSectionId) => {
13576
+ const { ancestry, branchStack } = readingMode;
13577
+ if (!ancestry || !readingMode.isActive) return;
13578
+ let targetObj = ancestry;
13579
+ let targetTree = ancestry.tree;
13580
+ if (branchStack.length > 0) {
13581
+ const allNodes = Object.values(parentDataRef.current).flatMap(
13582
+ (f) => f.nodes
13583
+ );
13584
+ const fullTree = buildFullAncestryTree(
13585
+ ancestry.tree,
13586
+ allNodes,
13587
+ ancestryDataRef.current
13588
+ );
13589
+ let currentPtr = fullTree;
13590
+ for (const step of branchStack) {
13591
+ const found = findNodePath3(currentPtr, step.nodeId);
13592
+ if (found && found.node && found.node.parallel_branches) {
13593
+ const branch = found.node.parallel_branches.find(
13594
+ (b) => b.id === step.branchId
13595
+ );
13596
+ if (branch) {
13597
+ targetObj = branch;
13598
+ targetTree = branch.tree;
13599
+ currentPtr = branch.tree;
13600
+ }
12995
13601
  }
12996
13602
  }
12997
13603
  }
12998
- }
12999
- const descriptionText = targetObj.description || "";
13000
- const savedSections = targetObj.description_sections || [];
13001
- const sections = parseDescriptionSections(descriptionText, savedSections);
13002
- let activeIndex = sections.findIndex((s) => String(s.id) === String(activeSectionId));
13003
- if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
13004
- activeIndex = sections.findIndex((s) => s.numericId === parseInt(activeSectionId));
13005
- }
13006
- if (activeIndex === -1) activeIndex = 0;
13007
- stateRef.current.readMode.currentMaxIndex = activeIndex;
13008
- stateRef.current.maxAncestryRenderIndex = activeIndex;
13009
- const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
13010
- const allowedIds = /* @__PURE__ */ new Set();
13011
- allowedIds.add("preamble");
13012
- allowedIds.add(0);
13013
- allowedIds.add("0");
13014
- for (let i = 0; i <= renderLimitIndex; i++) {
13015
- if (sections[i]) {
13016
- if (sections[i].id) allowedIds.add(String(sections[i].id));
13017
- if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
13018
- allowedIds.add(sections[i].numericId);
13019
- allowedIds.add(String(sections[i].numericId));
13604
+ const descriptionText = targetObj.description || "";
13605
+ const savedSections = targetObj.description_sections || [];
13606
+ const sections = parseDescriptionSections(descriptionText, savedSections);
13607
+ let activeIndex = sections.findIndex(
13608
+ (s) => String(s.id) === String(activeSectionId)
13609
+ );
13610
+ if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
13611
+ activeIndex = sections.findIndex(
13612
+ (s) => s.numericId === parseInt(activeSectionId)
13613
+ );
13614
+ }
13615
+ if (activeIndex === -1) activeIndex = 0;
13616
+ stateRef.current.readMode.currentMaxIndex = activeIndex;
13617
+ stateRef.current.maxAncestryRenderIndex = activeIndex;
13618
+ const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
13619
+ const allowedIds = /* @__PURE__ */ new Set();
13620
+ allowedIds.add("preamble");
13621
+ allowedIds.add(0);
13622
+ allowedIds.add("0");
13623
+ for (let i = 0; i <= renderLimitIndex; i++) {
13624
+ if (sections[i]) {
13625
+ if (sections[i].id) allowedIds.add(String(sections[i].id));
13626
+ if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
13627
+ allowedIds.add(sections[i].numericId);
13628
+ allowedIds.add(String(sections[i].numericId));
13629
+ }
13020
13630
  }
13021
13631
  }
13022
- }
13023
- const activeSection = sections[activeIndex];
13024
- let focusTargetId = activeSectionId;
13025
- if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
13026
- focusTargetId = activeSection.numericId;
13027
- }
13028
- const currentStackItem = branchStack.length > 0 ? branchStack[branchStack.length - 1] : null;
13029
- const renderPayload = {
13030
- ...targetObj,
13031
- ancestry_id: targetObj.ancestry_id || targetObj.id,
13032
- ancestral_node: targetTree.node ? targetTree.node.id : targetTree.node_id,
13033
- tree: targetTree,
13034
- _originNodeId: currentStackItem ? currentStackItem.nodeId : null,
13035
- _branchDirection: currentStackItem ? currentStackItem.entryDirection : null,
13036
- _forceUpdate: true
13037
- };
13038
- const rotation = branchStack.reduce((acc, step) => {
13039
- return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
13040
- }, 0);
13041
- handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
13042
- }, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
13632
+ const activeSection = sections[activeIndex];
13633
+ let focusTargetId = activeSectionId;
13634
+ if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
13635
+ focusTargetId = activeSection.numericId;
13636
+ }
13637
+ const currentStackItem = branchStack.length > 0 ? branchStack[branchStack.length - 1] : null;
13638
+ const renderPayload = {
13639
+ ...targetObj,
13640
+ ancestry_id: targetObj.ancestry_id || targetObj.id,
13641
+ ancestral_node: targetTree.node ? targetTree.node.id : targetTree.node_id,
13642
+ tree: targetTree,
13643
+ _originNodeId: currentStackItem ? currentStackItem.nodeId : null,
13644
+ _branchDirection: currentStackItem ? currentStackItem.entryDirection : null,
13645
+ _forceUpdate: true
13646
+ };
13647
+ const rotation = branchStack.reduce((acc, step) => {
13648
+ return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
13649
+ }, 0);
13650
+ handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
13651
+ },
13652
+ [
13653
+ readingMode,
13654
+ handleRenderAncestry,
13655
+ buildFullAncestryTree,
13656
+ ancestryDataRef.current
13657
+ ]
13658
+ );
13043
13659
  const handleCloseReadMode = (0, import_react26.useCallback)(() => {
13044
13660
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
13045
13661
  }, []);
13046
- const handleAncestrySectionChange = (0, import_react26.useCallback)((activeSectionId, ancestryOverride = null, rotation = 0) => {
13047
- var _a2, _b2;
13048
- const currentMode = stateRef.current.ancestry;
13049
- let targetObj = ancestryOverride;
13050
- if (!targetObj) {
13051
- const currentAncestryId = currentMode.currentAncestryId;
13052
- const ancestryObj = (ancestryDataRef.current || []).find((a) => String(a.ancestry_id) === String(currentAncestryId));
13053
- targetObj = ancestryObj || (currentMode.isActive ? {
13054
- ...currentMode,
13055
- ancestry_id: "temp_creating",
13056
- ancestral_node: (_b2 = (_a2 = currentMode.tree) == null ? void 0 : _a2.node) == null ? void 0 : _b2.id
13057
- } : null);
13058
- }
13059
- if (!targetObj) return;
13060
- const targetId = targetObj.ancestry_id || targetObj.id;
13061
- if (stateRef.current.lastRenderedAncestryId !== targetId) {
13062
- stateRef.current.maxAncestryRenderIndex = 0;
13063
- stateRef.current.lastRenderedAncestryId = targetId;
13064
- }
13065
- const descriptionText = (ancestryOverride ? targetObj.description : currentMode.ancestryDescription) || targetObj.description || "";
13066
- const savedSections = (ancestryOverride ? targetObj.description_sections : currentMode.ancestryDescriptionSections) || targetObj.description_sections || [];
13067
- const sections = parseDescriptionSections(descriptionText, savedSections);
13068
- let activeIndex = sections.findIndex((s) => String(s.id) === String(activeSectionId));
13069
- if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
13070
- activeIndex = sections.findIndex((s) => s.numericId === parseInt(activeSectionId));
13071
- }
13072
- if (activeIndex === -1) activeIndex = 0;
13073
- if (stateRef.current.maxAncestryRenderIndex === void 0) stateRef.current.maxAncestryRenderIndex = 0;
13074
- stateRef.current.maxAncestryRenderIndex = activeIndex;
13075
- const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
13076
- const allowedIds = /* @__PURE__ */ new Set();
13077
- allowedIds.add("preamble");
13078
- allowedIds.add(0);
13079
- allowedIds.add("0");
13080
- for (let i = 0; i <= renderLimitIndex; i++) {
13081
- if (sections[i]) {
13082
- if (sections[i].id) allowedIds.add(String(sections[i].id));
13083
- if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
13084
- allowedIds.add(sections[i].numericId);
13085
- allowedIds.add(String(sections[i].numericId));
13662
+ const handleAncestrySectionChange = (0, import_react26.useCallback)(
13663
+ (activeSectionId, ancestryOverride = null, rotation = 0) => {
13664
+ var _a2, _b2;
13665
+ const currentMode = stateRef.current.ancestry;
13666
+ let targetObj = ancestryOverride;
13667
+ if (!targetObj) {
13668
+ const currentAncestryId = currentMode.currentAncestryId;
13669
+ const ancestryObj = (ancestryDataRef.current || []).find(
13670
+ (a) => String(a.ancestry_id) === String(currentAncestryId)
13671
+ );
13672
+ targetObj = ancestryObj || (currentMode.isActive ? {
13673
+ ...currentMode,
13674
+ ancestry_id: "temp_creating",
13675
+ ancestral_node: (_b2 = (_a2 = currentMode.tree) == null ? void 0 : _a2.node) == null ? void 0 : _b2.id
13676
+ } : null);
13677
+ }
13678
+ if (!targetObj) return;
13679
+ const targetId = targetObj.ancestry_id || targetObj.id;
13680
+ if (stateRef.current.lastRenderedAncestryId !== targetId) {
13681
+ stateRef.current.maxAncestryRenderIndex = 0;
13682
+ stateRef.current.lastRenderedAncestryId = targetId;
13683
+ }
13684
+ const descriptionText = (ancestryOverride ? targetObj.description : currentMode.ancestryDescription) || targetObj.description || "";
13685
+ const savedSections = (ancestryOverride ? targetObj.description_sections : currentMode.ancestryDescriptionSections) || targetObj.description_sections || [];
13686
+ const sections = parseDescriptionSections(descriptionText, savedSections);
13687
+ let activeIndex = sections.findIndex(
13688
+ (s) => String(s.id) === String(activeSectionId)
13689
+ );
13690
+ if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
13691
+ activeIndex = sections.findIndex(
13692
+ (s) => s.numericId === parseInt(activeSectionId)
13693
+ );
13694
+ }
13695
+ if (activeIndex === -1) activeIndex = 0;
13696
+ if (stateRef.current.maxAncestryRenderIndex === void 0)
13697
+ stateRef.current.maxAncestryRenderIndex = 0;
13698
+ stateRef.current.maxAncestryRenderIndex = activeIndex;
13699
+ const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
13700
+ const allowedIds = /* @__PURE__ */ new Set();
13701
+ allowedIds.add("preamble");
13702
+ allowedIds.add(0);
13703
+ allowedIds.add("0");
13704
+ for (let i = 0; i <= renderLimitIndex; i++) {
13705
+ if (sections[i]) {
13706
+ if (sections[i].id) allowedIds.add(String(sections[i].id));
13707
+ if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
13708
+ allowedIds.add(sections[i].numericId);
13709
+ allowedIds.add(String(sections[i].numericId));
13710
+ }
13086
13711
  }
13087
13712
  }
13088
- }
13089
- const activeSection = sections[activeIndex];
13090
- let focusTargetId = activeSectionId;
13091
- if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
13092
- focusTargetId = activeSection.numericId;
13093
- }
13094
- const treeToRender = ancestryOverride ? ancestryOverride.tree : currentMode.isActive && currentMode.tree ? currentMode.tree : targetObj.tree;
13095
- const renderPayload = { ...targetObj, tree: treeToRender };
13096
- handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
13097
- }, [handleRenderAncestry]);
13713
+ const activeSection = sections[activeIndex];
13714
+ let focusTargetId = activeSectionId;
13715
+ if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
13716
+ focusTargetId = activeSection.numericId;
13717
+ }
13718
+ const treeToRender = ancestryOverride ? ancestryOverride.tree : currentMode.isActive && currentMode.tree ? currentMode.tree : targetObj.tree;
13719
+ const renderPayload = { ...targetObj, tree: treeToRender };
13720
+ handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
13721
+ },
13722
+ [handleRenderAncestry]
13723
+ );
13098
13724
  const handleEditAncestry = (0, import_react26.useCallback)(
13099
13725
  async (ancestryObject) => {
13100
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
13726
+ setContextMenu(
13727
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
13728
+ );
13101
13729
  if (!ancestryObject || !ancestryObject.tree) {
13102
- alert("N\xE3o foi poss\xEDvel carregar os dados desta ancestralidade para edi\xE7\xE3o.");
13730
+ alert(
13731
+ "N\xE3o foi poss\xEDvel carregar os dados desta ancestralidade para edi\xE7\xE3o."
13732
+ );
13103
13733
  return;
13104
13734
  }
13105
13735
  stateRef.current.maxAncestryRenderIndex = 0;
13106
13736
  const initialSections = /* @__PURE__ */ new Set(["preamble", 0]);
13107
13737
  await handleRenderAncestry(ancestryObject, initialSections);
13108
- const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes);
13738
+ const allParentNodes = Object.values(parentDataRef.current).flatMap(
13739
+ (fileData) => fileData.nodes
13740
+ );
13109
13741
  const allAncestries = ancestryDataRef.current || [];
13110
- const fullTree = buildFullAncestryTree(ancestryObject.tree, allParentNodes, allAncestries);
13742
+ const fullTree = buildFullAncestryTree(
13743
+ ancestryObject.tree,
13744
+ allParentNodes,
13745
+ allAncestries
13746
+ );
13111
13747
  if (!fullTree) {
13112
- alert("Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando.");
13748
+ alert(
13749
+ "Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando."
13750
+ );
13113
13751
  return;
13114
13752
  }
13115
- const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, allAncestries) : { node: fullTree.node, children: [] };
13753
+ const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(
13754
+ ancestryObject.abstraction_tree,
13755
+ allParentNodes,
13756
+ allAncestries
13757
+ ) : { node: fullTree.node, children: [] };
13116
13758
  setAncestryMode({
13117
13759
  isActive: true,
13118
13760
  ...ancestryObject,
@@ -13164,7 +13806,9 @@ function XViewScene({
13164
13806
  const treeToUse = treeOverride || ancestryMode.tree;
13165
13807
  const { isEditMode, currentAncestryId } = ancestryMode;
13166
13808
  if (!treeToUse || !treeToUse.node) {
13167
- alert("Erro: A estrutura da ancestralidade \xE9 inv\xE1lida (Node raiz ausente).");
13809
+ alert(
13810
+ "Erro: A estrutura da ancestralidade \xE9 inv\xE1lida (Node raiz ausente)."
13811
+ );
13168
13812
  return;
13169
13813
  }
13170
13814
  if (!save_view_data || !stateRef.current.nodeIdToParentFileMap) return;
@@ -13197,14 +13841,18 @@ function XViewScene({
13197
13841
  };
13198
13842
  };
13199
13843
  const treeWithIds = convertTreeToIds(treeToUse);
13200
- const abstractionTreeWithIds = convertTreeToIds(ancestryMode.abstraction_tree);
13844
+ const abstractionTreeWithIds = convertTreeToIds(
13845
+ ancestryMode.abstraction_tree
13846
+ );
13201
13847
  if (!treeWithIds) {
13202
13848
  alert("Erro ao processar a \xE1rvore da ancestralidade.");
13203
13849
  return;
13204
13850
  }
13205
13851
  let originalAncestryObj = null;
13206
13852
  if (isEditMode && currentAncestryId) {
13207
- originalAncestryObj = (ancestryDataRef.current || []).find((anc) => String(anc.ancestry_id) === String(currentAncestryId));
13853
+ originalAncestryObj = (ancestryDataRef.current || []).find(
13854
+ (anc) => String(anc.ancestry_id) === String(currentAncestryId)
13855
+ );
13208
13856
  }
13209
13857
  const ancestryObjectToSave = {
13210
13858
  ancestry_id: isEditMode && currentAncestryId ? currentAncestryId : `${import_short_uuid2.default.generate()}`,
@@ -13287,14 +13935,20 @@ function XViewScene({
13287
13935
  try {
13288
13936
  if (isExternalSave) {
13289
13937
  try {
13290
- const remoteResponse = await get_ancestry_file(targetFileIdForCache, targetOwnerIdForCache);
13938
+ const remoteResponse = await get_ancestry_file(
13939
+ targetFileIdForCache,
13940
+ targetOwnerIdForCache
13941
+ );
13291
13942
  if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
13292
13943
  masterAncestryList = remoteResponse.data;
13293
13944
  } else {
13294
13945
  masterAncestryList = [];
13295
13946
  }
13296
13947
  } catch (fetchErr) {
13297
- console.warn("Arquivo de destino n\xE3o existe ou erro ao buscar, criando novo:", fetchErr);
13948
+ console.warn(
13949
+ "Arquivo de destino n\xE3o existe ou erro ao buscar, criando novo:",
13950
+ fetchErr
13951
+ );
13298
13952
  masterAncestryList = [];
13299
13953
  }
13300
13954
  } else {
@@ -13314,7 +13968,9 @@ function XViewScene({
13314
13968
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
13315
13969
  if (result.success) {
13316
13970
  const localList = [...ancestryDataRef.current || []];
13317
- const localIndex = localList.findIndex((a) => String(a.ancestry_id) === String(ancestryObjectToSave.ancestry_id));
13971
+ const localIndex = localList.findIndex(
13972
+ (a) => String(a.ancestry_id) === String(ancestryObjectToSave.ancestry_id)
13973
+ );
13318
13974
  if (localIndex !== -1) {
13319
13975
  localList[localIndex] = ancestryObjectToSave;
13320
13976
  } else {
@@ -13342,11 +13998,29 @@ function XViewScene({
13342
13998
  return;
13343
13999
  }
13344
14000
  if (!keepOpen) {
13345
- setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
14001
+ setAncestryMode({
14002
+ isActive: false,
14003
+ tree: null,
14004
+ selectedParentId: null,
14005
+ isEditMode: false,
14006
+ currentAncestryId: null,
14007
+ ancestryName: "",
14008
+ ancestryDescription: "",
14009
+ ancestryDescriptionSections: [],
14010
+ isAddingNodes: false
14011
+ });
13346
14012
  if (mountRef.current) mountRef.current.style.cursor = "grab";
13347
14013
  }
13348
14014
  },
13349
- [ancestryMode, ancestry_save_url, handleRenderAncestry, save_view_data, sceneConfigId, ownerId, get_ancestry_file]
14015
+ [
14016
+ ancestryMode,
14017
+ ancestry_save_url,
14018
+ handleRenderAncestry,
14019
+ save_view_data,
14020
+ sceneConfigId,
14021
+ ownerId,
14022
+ get_ancestry_file
14023
+ ]
13350
14024
  );
13351
14025
  const handleOpenAncestryRelEditor = (path, currentData) => {
13352
14026
  setEditingAncestryRel({ visible: true, data: currentData, path });
@@ -13376,7 +14050,9 @@ function XViewScene({
13376
14050
  if (ancestryToDelete && delete_file_action) {
13377
14051
  const urls = extractFileUrlsFromProperties(ancestryToDelete);
13378
14052
  if (urls.length > 0) {
13379
- Promise.all(urls.map((url) => delete_file_action(url))).catch((err) => console.error("Erro ao deletar arquivos da ancestralidade:", err));
14053
+ Promise.all(urls.map((url) => delete_file_action(url))).catch(
14054
+ (err) => console.error("Erro ao deletar arquivos da ancestralidade:", err)
14055
+ );
13380
14056
  }
13381
14057
  }
13382
14058
  if (!ancestryToDelete) {
@@ -13386,7 +14062,9 @@ function XViewScene({
13386
14062
  const sourceFileId = ancestryToDelete._source_file_id;
13387
14063
  const sourceOwnerId = ancestryToDelete._source_owner_id;
13388
14064
  if (!sourceFileId || !sourceOwnerId) {
13389
- alert("N\xE3o foi poss\xEDvel identificar o arquivo de origem desta ancestralidade.");
14065
+ alert(
14066
+ "N\xE3o foi poss\xEDvel identificar o arquivo de origem desta ancestralidade."
14067
+ );
13390
14068
  return;
13391
14069
  }
13392
14070
  const finalSaveUrl = `x_view_ancestry/${sourceOwnerId}/${sourceFileId}`;
@@ -13394,13 +14072,18 @@ function XViewScene({
13394
14072
  (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
13395
14073
  );
13396
14074
  try {
13397
- const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
14075
+ const result = await save_view_data(
14076
+ finalSaveUrl,
14077
+ updatedAncestriesForFile
14078
+ );
13398
14079
  if (result.success) {
13399
14080
  ancestryDataRef.current = (ancestryDataRef.current || []).filter(
13400
14081
  (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
13401
14082
  );
13402
14083
  const { renderedAncestries, ancestryGroup } = stateRef.current;
13403
- const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryIdToDelete));
14084
+ const renderIndex = renderedAncestries.findIndex(
14085
+ (a) => String(a.id) === String(ancestryIdToDelete)
14086
+ );
13404
14087
  if (renderIndex !== -1) {
13405
14088
  const toRemove = renderedAncestries[renderIndex];
13406
14089
  toRemove.lines.forEach((line) => {
@@ -13409,18 +14092,29 @@ function XViewScene({
13409
14092
  if (line.material) line.material.dispose();
13410
14093
  });
13411
14094
  renderedAncestries.splice(renderIndex, 1);
13412
- stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
14095
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
14096
+ (a) => a.lines
14097
+ );
13413
14098
  }
13414
14099
  setSceneVersion((v) => v + 1);
13415
14100
  } else {
13416
- throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
14101
+ throw new Error(
14102
+ result.error || "Ocorreu um erro desconhecido ao excluir."
14103
+ );
13417
14104
  }
13418
14105
  } catch (error) {
13419
14106
  console.error("Falha ao excluir a ancestralidade:", error);
13420
14107
  alert(`Erro ao excluir a ancestralidade: ${error.message}`);
13421
14108
  return;
13422
14109
  }
13423
- setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "" });
14110
+ setAncestryMode({
14111
+ isActive: false,
14112
+ tree: null,
14113
+ selectedParentId: null,
14114
+ isEditMode: false,
14115
+ currentAncestryId: null,
14116
+ ancestryName: ""
14117
+ });
13424
14118
  if (mountRef.current) mountRef.current.style.cursor = "grab";
13425
14119
  },
13426
14120
  [save_view_data, delete_file_action]
@@ -13428,24 +14122,38 @@ function XViewScene({
13428
14122
  const handleOpenAncestryBoard = (0, import_react26.useCallback)(() => {
13429
14123
  setIsAncestryBoardOpen(true);
13430
14124
  }, []);
13431
- const handleSelectAncestryFromBoard = (0, import_react26.useCallback)((ancestry) => {
13432
- setIsAncestryBoardOpen(false);
13433
- setIsSidebarOpen(false);
13434
- handleStartReadingAncestry(ancestry);
13435
- }, [handleStartReadingAncestry]);
13436
- const handleSaveAncestryBoard = (0, import_react26.useCallback)(async (groups) => {
13437
- if (!sceneConfigId || !viewParams || !session) return;
13438
- const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
13439
- await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
13440
- }, [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]);
14125
+ const handleSelectAncestryFromBoard = (0, import_react26.useCallback)(
14126
+ (ancestry) => {
14127
+ setIsAncestryBoardOpen(false);
14128
+ setIsSidebarOpen(false);
14129
+ handleStartReadingAncestry(ancestry);
14130
+ },
14131
+ [handleStartReadingAncestry]
14132
+ );
14133
+ const handleSaveAncestryBoard = (0, import_react26.useCallback)(
14134
+ async (groups) => {
14135
+ if (!sceneConfigId || !viewParams || !session) return;
14136
+ const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
14137
+ await save_ancestry_board_action(
14138
+ sceneConfigId,
14139
+ sceneType,
14140
+ groups,
14141
+ session,
14142
+ ownerId
14143
+ );
14144
+ },
14145
+ [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
14146
+ );
13441
14147
  const existingNodeTypes = (0, import_react26.useMemo)(() => {
13442
14148
  if (!parentDataRef.current) {
13443
14149
  return [];
13444
14150
  }
13445
- const allTypes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes.flatMap((node) => {
13446
- if (Array.isArray(node.type)) return node.type;
13447
- return [node.type];
13448
- })).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
14151
+ const allTypes = Object.values(parentDataRef.current).flatMap(
14152
+ (fileData) => fileData.nodes.flatMap((node) => {
14153
+ if (Array.isArray(node.type)) return node.type;
14154
+ return [node.type];
14155
+ })
14156
+ ).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
13449
14157
  return [...new Set(allTypes)];
13450
14158
  }, [parentDataRef.current, sceneVersion]);
13451
14159
  const searchableDbNodes = (0, import_react26.useMemo)(() => {
@@ -13459,7 +14167,10 @@ function XViewScene({
13459
14167
  }, [parentDataRef.current, sceneVersion]);
13460
14168
  const handleAddExistingNode = (0, import_react26.useCallback)(
13461
14169
  (nodeId) => {
13462
- return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
14170
+ return userActionHandlers.handleAddExistingNodeById(
14171
+ actionHandlerContext,
14172
+ nodeId
14173
+ );
13463
14174
  },
13464
14175
  [actionHandlerContext]
13465
14176
  );
@@ -13467,7 +14178,9 @@ function XViewScene({
13467
14178
  var _a2, _b2, _c2;
13468
14179
  const { nodeObjects, allLinks } = stateRef.current;
13469
14180
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
13470
- console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
14181
+ console.warn(
14182
+ "N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente."
14183
+ );
13471
14184
  return;
13472
14185
  }
13473
14186
  if (!save_view_data) return;
@@ -13504,48 +14217,68 @@ function XViewScene({
13504
14217
  }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
13505
14218
  const allAvailableNodes = (0, import_react26.useMemo)(() => {
13506
14219
  if (!parentDataRef.current) return [];
13507
- return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
14220
+ return Object.values(parentDataRef.current).flatMap(
14221
+ (fileData) => fileData.nodes || []
14222
+ );
13508
14223
  }, [sceneVersion, isInitialized]);
13509
14224
  const allAvailableAncestries = (0, import_react26.useMemo)(() => {
13510
14225
  return ancestryDataRef.current || [];
13511
14226
  }, [sceneVersion, isInitialized]);
13512
- const handleOpenReference = (0, import_react26.useCallback)((referenceData) => {
13513
- const { type, id } = referenceData;
13514
- if (type === "node") {
13515
- const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
13516
- if (targetNode) {
13517
- setAncestryLinkDetails(null);
13518
- setDetailsLink(null);
13519
- setDetailsNode(targetNode);
13520
- const sceneMesh = stateRef.current.nodeObjects[String(id)];
13521
- if (sceneMesh) {
13522
- tweenToTarget(sceneMesh);
14227
+ const handleOpenReference = (0, import_react26.useCallback)(
14228
+ (referenceData) => {
14229
+ const { type, id } = referenceData;
14230
+ if (type === "node") {
14231
+ const targetNode = allAvailableNodes.find(
14232
+ (n) => String(n.id) === String(id)
14233
+ );
14234
+ if (targetNode) {
14235
+ setAncestryLinkDetails(null);
14236
+ setDetailsLink(null);
14237
+ setDetailsNode(targetNode);
14238
+ const sceneMesh = stateRef.current.nodeObjects[String(id)];
14239
+ if (sceneMesh) {
14240
+ tweenToTarget(sceneMesh);
14241
+ }
14242
+ } else {
14243
+ alert("Node original n\xE3o encontrado neste contexto.");
14244
+ }
14245
+ } else if (type === "ancestry") {
14246
+ const targetAncestry = allAvailableAncestries.find(
14247
+ (a) => String(a.ancestry_id) === String(id)
14248
+ );
14249
+ if (targetAncestry) {
14250
+ setDetailsNode(null);
14251
+ setDetailsLink(null);
14252
+ setAncestryLinkDetails(null);
14253
+ handleEditAncestry(targetAncestry);
14254
+ } else {
14255
+ alert("Ancestralidade original n\xE3o encontrada neste contexto.");
13523
14256
  }
13524
- } else {
13525
- alert("Node original n\xE3o encontrado neste contexto.");
13526
- }
13527
- } else if (type === "ancestry") {
13528
- const targetAncestry = allAvailableAncestries.find((a) => String(a.ancestry_id) === String(id));
13529
- if (targetAncestry) {
13530
- setDetailsNode(null);
13531
- setDetailsLink(null);
13532
- setAncestryLinkDetails(null);
13533
- handleEditAncestry(targetAncestry);
13534
- } else {
13535
- alert("Ancestralidade original n\xE3o encontrada neste contexto.");
13536
14257
  }
13537
- }
13538
- }, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
14258
+ },
14259
+ [
14260
+ allAvailableNodes,
14261
+ allAvailableAncestries,
14262
+ handleEditAncestry,
14263
+ tweenToTarget
14264
+ ]
14265
+ );
13539
14266
  const handleToggleAncestryAddMode = (0, import_react26.useCallback)(() => {
13540
- setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
14267
+ setAncestryMode((prev) => ({
14268
+ ...prev,
14269
+ isAddingNodes: !prev.isAddingNodes
14270
+ }));
13541
14271
  }, []);
13542
- const handleFocusNode = (0, import_react26.useCallback)((nodeData) => {
13543
- if (!nodeData) return;
13544
- const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
13545
- if (nodeMesh) {
13546
- tweenToTarget(nodeMesh, 1.2);
13547
- }
13548
- }, [tweenToTarget]);
14272
+ const handleFocusNode = (0, import_react26.useCallback)(
14273
+ (nodeData) => {
14274
+ if (!nodeData) return;
14275
+ const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
14276
+ if (nodeMesh) {
14277
+ tweenToTarget(nodeMesh, 1.2);
14278
+ }
14279
+ },
14280
+ [tweenToTarget]
14281
+ );
13549
14282
  const availableDatasets = (0, import_react26.useMemo)(() => {
13550
14283
  if (!sceneDataRef.current || !parentDataRef.current) return [];
13551
14284
  return sceneDataRef.current.parent_dbs.map((db) => {
@@ -13556,7 +14289,9 @@ function XViewScene({
13556
14289
  };
13557
14290
  });
13558
14291
  }, [sceneVersion, isInitialized]);
13559
- const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
14292
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
14293
+ String(creationMode.sourceNodeData.id)
14294
+ )) == null ? void 0 : _b.parentFileId : null;
13560
14295
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
13561
14296
  (0, import_react26.useEffect)(() => {
13562
14297
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
@@ -13571,11 +14306,19 @@ function XViewScene({
13571
14306
  setHasFocusedInitial(true);
13572
14307
  }
13573
14308
  }
13574
- }, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
14309
+ }, [
14310
+ isInitialized,
14311
+ sceneVersion,
14312
+ focusNodeId,
14313
+ hasFocusedInitial,
14314
+ tweenToTarget
14315
+ ]);
13575
14316
  (0, import_react26.useEffect)(() => {
13576
14317
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
13577
14318
  const ancestries = ancestryDataRef.current || [];
13578
- const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
14319
+ const targetAncestry = ancestries.find(
14320
+ (a) => String(a.ancestry_id) === String(focusAncestryId)
14321
+ );
13579
14322
  if (targetAncestry) {
13580
14323
  setTimeout(() => {
13581
14324
  handleStartReadingAncestry(targetAncestry);
@@ -13585,18 +14328,38 @@ function XViewScene({
13585
14328
  setHasOpenedInitialAncestry(true);
13586
14329
  }
13587
14330
  }
13588
- }, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
14331
+ }, [
14332
+ isInitialized,
14333
+ sceneVersion,
14334
+ focusAncestryId,
14335
+ hasOpenedInitialAncestry,
14336
+ handleStartReadingAncestry
14337
+ ]);
13589
14338
  (0, import_react26.useEffect)(() => {
13590
14339
  function handleKeyDown(event) {
13591
14340
  var _a2, _b2, _c2;
13592
14341
  const context = actionHandlerContext;
13593
14342
  if (event.key === "Escape") {
13594
- if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
13595
- if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
13596
- if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
13597
- if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
14343
+ if (stateRef.current.connection.isActive)
14344
+ userActionHandlers.handleCancelConnection(context);
14345
+ if (stateRef.current.relink.isActive)
14346
+ userActionHandlers.handleCancelRelink(context);
14347
+ if (stateRef.current.creation.isActive)
14348
+ userActionHandlers.handleCancelCreation(context);
14349
+ if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive)
14350
+ userActionHandlers.handleCancelVersioning(context);
13598
14351
  if (stateRef.current.ancestry.isActive) {
13599
- setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
14352
+ setAncestryMode({
14353
+ isActive: false,
14354
+ tree: null,
14355
+ selectedParentId: null,
14356
+ isEditMode: false,
14357
+ currentAncestryId: null,
14358
+ ancestryName: "",
14359
+ ancestryDescription: "",
14360
+ ancestryDescriptionSections: [],
14361
+ isAddingNodes: false
14362
+ });
13600
14363
  if (mountRef.current) mountRef.current.style.cursor = "grab";
13601
14364
  }
13602
14365
  if (questMode.isActive) {
@@ -13605,7 +14368,9 @@ function XViewScene({
13605
14368
  if (stateRef.current.selectedNodes.size > 0) {
13606
14369
  stateRef.current.selectedNodes.clear();
13607
14370
  }
13608
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
14371
+ setContextMenu(
14372
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
14373
+ );
13609
14374
  setMultiContextMenu((prev) => ({ ...prev, visible: false }));
13610
14375
  setRelationshipMenu((prev) => ({ ...prev, visible: false }));
13611
14376
  }
@@ -13624,7 +14389,9 @@ function XViewScene({
13624
14389
  let attempts = 0;
13625
14390
  const MIN_CLEARANCE = 15;
13626
14391
  while (isOccupied && attempts < 30) {
13627
- isOccupied = existingNodes.some((mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE);
14392
+ isOccupied = existingNodes.some(
14393
+ (mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE
14394
+ );
13628
14395
  if (isOccupied) {
13629
14396
  ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
13630
14397
  ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
@@ -13643,7 +14410,11 @@ function XViewScene({
13643
14410
  intensity: 0,
13644
14411
  type: ["quest"]
13645
14412
  };
13646
- const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
14413
+ const ghostNode = createNodeMesh(
14414
+ ghostData,
14415
+ ghostPosition,
14416
+ glowTexture
14417
+ );
13647
14418
  ghostNode.traverse((child) => {
13648
14419
  if (child.isMesh) {
13649
14420
  child.material.transparent = true;
@@ -13690,13 +14461,49 @@ function XViewScene({
13690
14461
  return /* @__PURE__ */ import_react26.default.createElement(LoadingScreen, null);
13691
14462
  }
13692
14463
  if (permissionStatus === "denied") {
13693
- return /* @__PURE__ */ import_react26.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react26.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "w-16 h-16 mx-auto" }, /* @__PURE__ */ import_react26.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" }))), /* @__PURE__ */ import_react26.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react26.default.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ import_react26.default.createElement(
14464
+ return /* @__PURE__ */ import_react26.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react26.default.createElement(
14465
+ "svg",
14466
+ {
14467
+ xmlns: "http://www.w3.org/2000/svg",
14468
+ fill: "none",
14469
+ viewBox: "0 0 24 24",
14470
+ strokeWidth: 1.5,
14471
+ stroke: "currentColor",
14472
+ className: "w-16 h-16 mx-auto"
14473
+ },
14474
+ /* @__PURE__ */ import_react26.default.createElement(
14475
+ "path",
14476
+ {
14477
+ strokeLinecap: "round",
14478
+ strokeLinejoin: "round",
14479
+ d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
14480
+ }
14481
+ )
14482
+ )), /* @__PURE__ */ import_react26.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react26.default.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ import_react26.default.createElement(
13694
14483
  "button",
13695
14484
  {
13696
14485
  onClick: () => router.push("/dashboard/scenes"),
13697
14486
  className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
13698
14487
  },
13699
- /* @__PURE__ */ import_react26.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-5 h-5" }, /* @__PURE__ */ import_react26.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
14488
+ /* @__PURE__ */ import_react26.default.createElement(
14489
+ "svg",
14490
+ {
14491
+ xmlns: "http://www.w3.org/2000/svg",
14492
+ fill: "none",
14493
+ viewBox: "0 0 24 24",
14494
+ strokeWidth: 2,
14495
+ stroke: "currentColor",
14496
+ className: "w-5 h-5"
14497
+ },
14498
+ /* @__PURE__ */ import_react26.default.createElement(
14499
+ "path",
14500
+ {
14501
+ strokeLinecap: "round",
14502
+ strokeLinejoin: "round",
14503
+ d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"
14504
+ }
14505
+ )
14506
+ ),
13700
14507
  "Voltar para Scenes"
13701
14508
  )));
13702
14509
  }
@@ -13743,7 +14550,14 @@ function XViewScene({
13743
14550
  onImageChange: handleGhostNodeImageChange,
13744
14551
  onOpenImageViewer: handleOpenImageViewer,
13745
14552
  onMentionClick: handleAddExistingNode,
13746
- style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
14553
+ style: {
14554
+ position: "absolute",
14555
+ left: `${formPosition.left}px`,
14556
+ top: `${formPosition.top}px`,
14557
+ opacity: formPosition.opacity,
14558
+ zIndex: 20,
14559
+ transition: "opacity 200ms ease-out"
14560
+ },
13747
14561
  refEl: formRef,
13748
14562
  existingTypes: existingNodeTypes,
13749
14563
  initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
@@ -13767,7 +14581,14 @@ function XViewScene({
13767
14581
  onImageChange: handleGhostNodeImageChange,
13768
14582
  onOpenImageViewer: handleOpenImageViewer,
13769
14583
  onMentionClick: handleAddExistingNode,
13770
- style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
14584
+ style: {
14585
+ position: "absolute",
14586
+ left: `${formPosition.left}px`,
14587
+ top: `${formPosition.top}px`,
14588
+ opacity: formPosition.opacity,
14589
+ zIndex: 20,
14590
+ transition: "opacity 200ms ease-out"
14591
+ },
13771
14592
  refEl: formRef,
13772
14593
  fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
13773
14594
  fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
@@ -13784,7 +14605,13 @@ function XViewScene({
13784
14605
  onNameChange: handleGhostNodeNameChange,
13785
14606
  onColorChange: handleGhostNodeColorChange,
13786
14607
  onSizeChange: handleGhostNodeSizeChange,
13787
- style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
14608
+ style: {
14609
+ position: "absolute",
14610
+ left: `16px`,
14611
+ top: `16px`,
14612
+ zIndex: 20,
14613
+ transition: "opacity 200ms ease-out"
14614
+ },
13788
14615
  refEl: formRef,
13789
14616
  onOpenImageViewer: handleOpenImageViewer,
13790
14617
  onMentionClick: handleAddExistingNode,
@@ -13799,7 +14626,14 @@ function XViewScene({
13799
14626
  "div",
13800
14627
  {
13801
14628
  className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
13802
- style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
14629
+ style: {
14630
+ top: 16,
14631
+ right: 16,
14632
+ zIndex: 1100,
14633
+ maxHeight: "calc(100vh - 32px)",
14634
+ width: `${readModeWidth}px`,
14635
+ maxWidth: "92vw"
14636
+ }
13803
14637
  },
13804
14638
  /* @__PURE__ */ import_react26.default.createElement(
13805
14639
  "div",
@@ -13857,7 +14691,16 @@ function XViewScene({
13857
14691
  onSave: handleSaveAncestry,
13858
14692
  onEditRelationship: handleOpenAncestryRelEditor,
13859
14693
  onClose: () => {
13860
- setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", isAddingNodes: false });
14694
+ setAncestryMode({
14695
+ isActive: false,
14696
+ tree: null,
14697
+ selectedParentId: null,
14698
+ isEditMode: false,
14699
+ currentAncestryId: null,
14700
+ ancestryName: "",
14701
+ ancestryDescription: "",
14702
+ isAddingNodes: false
14703
+ });
13861
14704
  if (mountRef.current) mountRef.current.style.cursor = "grab";
13862
14705
  },
13863
14706
  availableNodes: allAvailableNodes,
@@ -13922,7 +14765,12 @@ function XViewScene({
13922
14765
  onOpenImageViewer: handleOpenImageViewer,
13923
14766
  existingTypes: existingNodeTypes,
13924
14767
  onImageChange: (useImage, url, currentColorOverride) => {
13925
- const updatedNode = { ...detailsNode, useImageAsTexture: useImage, textureImageUrl: url, color: currentColorOverride || detailsNode.color };
14768
+ const updatedNode = {
14769
+ ...detailsNode,
14770
+ useImageAsTexture: useImage,
14771
+ textureImageUrl: url,
14772
+ color: currentColorOverride || detailsNode.color
14773
+ };
13926
14774
  updateExistingNodeVisuals(stateRef.current, updatedNode);
13927
14775
  setDetailsNode(updatedNode);
13928
14776
  },
@@ -13996,7 +14844,9 @@ function XViewScene({
13996
14844
  parentData: parentDataRef.current,
13997
14845
  sceneData: sceneDataRef.current,
13998
14846
  ancestryData: ancestryDataRef.current,
13999
- onClose: () => setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev),
14847
+ onClose: () => setContextMenu(
14848
+ (prev) => prev.visible ? { ...prev, visible: false } : prev
14849
+ ),
14000
14850
  onStartCreation: (data) => userActionHandlers.handleStartCreation(actionHandlerContext, data),
14001
14851
  onStartConnection: (data) => userActionHandlers.handleStartConnection(actionHandlerContext, data),
14002
14852
  onStartVersioning: handleStartVersioning,
@@ -14004,7 +14854,11 @@ function XViewScene({
14004
14854
  onDeleteNode: (data) => userActionHandlers.handleDeleteNode(actionHandlerContext, data),
14005
14855
  onDismissNode: (data) => userActionHandlers.handleDismissNode(actionHandlerContext, data),
14006
14856
  onDismissOtherNodes: (data) => userActionHandlers.handleDismissOtherNodes(actionHandlerContext, data),
14007
- onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(actionHandlerContext, sourceNode, links),
14857
+ onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(
14858
+ actionHandlerContext,
14859
+ sourceNode,
14860
+ links
14861
+ ),
14008
14862
  onRenderAncestry: handleStartReadingAncestry,
14009
14863
  onEditAncestry: handleEditAncestry,
14010
14864
  onDeleteAncestry: (ancestryId) => handleDeleteAncestry(ancestryId),
@@ -14017,9 +14871,18 @@ function XViewScene({
14017
14871
  data: multiContextMenu,
14018
14872
  userRole: userPermissionRole,
14019
14873
  onClose: () => setMultiContextMenu((prev) => ({ ...prev, visible: false })),
14020
- onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(actionHandlerContext, ids),
14021
- onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(actionHandlerContext, ids),
14022
- onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
14874
+ onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
14875
+ actionHandlerContext,
14876
+ ids
14877
+ ),
14878
+ onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(
14879
+ actionHandlerContext,
14880
+ ids
14881
+ ),
14882
+ onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(
14883
+ actionHandlerContext,
14884
+ ids
14885
+ )
14023
14886
  }
14024
14887
  ),
14025
14888
  /* @__PURE__ */ import_react26.default.createElement(
@@ -14040,7 +14903,13 @@ function XViewScene({
14040
14903
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
14041
14904
  }
14042
14905
  ),
14043
- /* @__PURE__ */ import_react26.default.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
14906
+ /* @__PURE__ */ import_react26.default.createElement(
14907
+ ImageViewer,
14908
+ {
14909
+ data: imageViewer,
14910
+ onClose: () => setImageViewer({ ...imageViewer, visible: false })
14911
+ }
14912
+ ),
14044
14913
  /* @__PURE__ */ import_react26.default.createElement(
14045
14914
  AncestryBoard,
14046
14915
  {