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

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