@liquidcars/atlas 0.1.44 → 0.1.46

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.
@@ -11890,7 +11890,7 @@ var Qc = class {
11890
11890
  }
11891
11891
  }, $c = {
11892
11892
  name: "@liquidcars/atlas",
11893
- version: "0.1.44",
11893
+ version: "0.1.46",
11894
11894
  description: "Reusable 3D conceptual atlas Web Component for LiquidCars-style models",
11895
11895
  type: "module",
11896
11896
  scripts: {
@@ -12284,9 +12284,10 @@ var Fl = [":host{display:block;position:relative;height:var(--lc-height,680px);m
12284
12284
  view: Rl("<path d=\"M2.5 12s3.5-5 9.5-5 9.5 5 9.5 5-3.5 5-9.5 5-9.5-5-9.5-5Z\"/><circle cx=\"12\" cy=\"12\" r=\"2.5\"/>"),
12285
12285
  relations: Rl("<circle cx=\"5\" cy=\"6\" r=\"2\"/><circle cx=\"19\" cy=\"7\" r=\"2\"/><circle cx=\"12\" cy=\"18\" r=\"2\"/><path d=\"m6.8 6.3 10.2.5M6.2 7.7l4.6 8.6m6.8-7.5-4.4 7.5\"/>"),
12286
12286
  focus: Rl("<circle cx=\"12\" cy=\"12\" r=\"7\"/><circle cx=\"12\" cy=\"12\" r=\"2.5\"/><path d=\"M12 2v3M12 19v3M2 12h3M19 12h3\"/>"),
12287
+ copy: Rl("<rect x=\"8\" y=\"8\" width=\"11\" height=\"11\" rx=\"2\"/><path d=\"M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2\"/>"),
12287
12288
  chevron: Rl("<path d=\"m8 10 4 4 4-4\"/>")
12288
- }, Bl = (e, t, n = !1) => `<button class="toolbar-option${n ? " active" : ""}" data-action="${e}" aria-pressed="${n}"><span>${t}</span><span class="toolbar-option-check" aria-hidden="true">✓</span></button>`, Vl = (e, t, n, r, i) => `<details class="toolbar-menu" data-toolbar-menu="${e}"><summary aria-label="${n}" title="${n}">${t}<span class="toolbar-menu-status" data-toolbar-status="${e}">${r}</span>${zl.chevron}</summary><div class="toolbar-popover" role="menu"><div class="toolbar-popover-title">${n}</div>${i}</div></details>`, Hl = `<div class="atlas"><section class="viewport"><canvas tabindex="0" aria-label="Modelo 3D interactivo"></canvas><div class="toolbar" role="toolbar" aria-label="Controles de la vista"><div class="toolbar-group" data-toolbar-group="camera"><button class="toolbar-icon" data-action="minus" aria-label="Alejar" title="Alejar">${zl.minus}</button><button class="toolbar-icon" data-action="plus" aria-label="Acercar" title="Acercar">${zl.plus}</button><button class="toolbar-icon" data-action="fit" aria-label="Encuadrar todo el modelo" title="Encuadrar todo el modelo">${zl.fit}</button><button class="toolbar-icon" data-action="front" aria-label="Vista frontal" title="Vista frontal">${zl.front}</button></div><div class="toolbar-group" data-toolbar-group="view">${Vl("view", zl.view, "Vista", "Vista", Bl("labels", "Etiquetas", !0) + Bl("panel", "Información", !0) + Bl("item-facing", "Caras a cámara", !0) + "<div class=\"toolbar-option-separator\"></div>" + Bl("open-all", "Abrir todos") + Bl("close-all", "Cerrar todos"))}</div><div class="toolbar-group" data-toolbar-group="relations">${Vl("relations", zl.relations, "Relaciones", "Selección", Bl("relations-all", "Todas") + Bl("relations-selected", "Selección", !0) + Bl("relations-callers", "All callers") + Bl("relations-called", "All called") + Bl("relations-none", "Ocultar") + "<div data-relation-groups-section hidden><div class=\"toolbar-option-separator\"></div><div class=\"toolbar-popover-title\">Grupos</div><div data-relation-groups></div></div>")}</div><div class="toolbar-group" data-toolbar-group="focus">${Vl("focus", zl.focus, "Foco", "Todo", Bl("focus-all", "Todo", !0) + Bl("focus-dim", "Conectados") + Bl("focus-hide", "Aislar") + "<div class=\"toolbar-option-separator\"></div>" + Bl("focus-selection", "Enfocar selección") + Bl("focus-layout", "Reorganizar visibles"))}</div></div><div class="hint">Gira: arrastra · Pan: botón derecho / ⇧+arrastra / 2 dedos · Zoom: rueda o pellizco · Selecciona: clic · Enfoca: doble clic</div></section><aside class="panel" aria-live="polite"></aside></div>`;
12289
- function Ul(e) {
12289
+ }, Bl = (e, t, n = !1) => `<button class="toolbar-option${n ? " active" : ""}" data-action="${e}" aria-pressed="${n}"><span>${t}</span><span class="toolbar-option-check" aria-hidden="true">✓</span></button>`, Vl = (e, t) => `<button class="toolbar-option" data-action="${e}" role="menuitem"><span>${t}</span><span aria-hidden="true"></span></button>`, Hl = (e, t, n, r, i) => `<details class="toolbar-menu" data-toolbar-menu="${e}"><summary aria-label="${n}" title="${n}">${t}<span class="toolbar-menu-status" data-toolbar-status="${e}" aria-live="polite">${r}</span>${zl.chevron}</summary><div class="toolbar-popover" role="menu"><div class="toolbar-popover-title">${n}</div>${i}</div></details>`, Ul = `<div class="toolbar-group" data-toolbar-group="copy">${Hl("copy", zl.copy, "Copiar imagen", "PNG", Vl("copy-theme", "PNG con fondo · HD 2×") + Vl("copy-transparent", "PNG transparente · HD 2×"))}</div>`, Wl = `<div class="atlas"><section class="viewport"><canvas tabindex="0" aria-label="Modelo 3D interactivo"></canvas><div class="toolbar" role="toolbar" aria-label="Controles de la vista"><div class="toolbar-group" data-toolbar-group="camera"><button class="toolbar-icon" data-action="minus" aria-label="Alejar" title="Alejar">${zl.minus}</button><button class="toolbar-icon" data-action="plus" aria-label="Acercar" title="Acercar">${zl.plus}</button><button class="toolbar-icon" data-action="fit" aria-label="Encuadrar todo el modelo" title="Encuadrar todo el modelo">${zl.fit}</button><button class="toolbar-icon" data-action="front" aria-label="Vista frontal" title="Vista frontal">${zl.front}</button></div><div class="toolbar-group" data-toolbar-group="view">${Hl("view", zl.view, "Vista", "Vista", Bl("labels", "Etiquetas", !0) + Bl("panel", "Información", !0) + Bl("item-facing", "Caras a cámara", !0) + "<div class=\"toolbar-option-separator\"></div>" + Bl("open-all", "Abrir todos") + Bl("close-all", "Cerrar todos"))}</div><div class="toolbar-group" data-toolbar-group="relations">${Hl("relations", zl.relations, "Relaciones", "Selección", Bl("relations-all", "Todas") + Bl("relations-selected", "Selección", !0) + Bl("relations-callers", "All callers") + Bl("relations-called", "All called") + Bl("relations-none", "Ocultar") + "<div data-relation-groups-section hidden><div class=\"toolbar-option-separator\"></div><div class=\"toolbar-popover-title\">Grupos</div><div data-relation-groups></div></div>")}</div><div class="toolbar-group" data-toolbar-group="focus">${Hl("focus", zl.focus, "Foco", "Todo", Bl("focus-all", "Todo", !0) + Bl("focus-dim", "Conectados") + Bl("focus-hide", "Aislar") + "<div class=\"toolbar-option-separator\"></div>" + Bl("focus-selection", "Enfocar selección") + Bl("focus-layout", "Reorganizar visibles"))}</div></div><div class="hint">Gira: arrastra · Pan: botón derecho / ⇧+arrastra / 2 dedos · Zoom: rueda o pellizco · Selecciona: clic · Enfoca: doble clic</div></section><aside class="panel" aria-live="polite"></aside></div>`;
12290
+ function Gl(e) {
12290
12291
  return String(e ?? "").replace(/[&<>"']/g, (e) => ({
12291
12292
  "&": "&amp;",
12292
12293
  "<": "&lt;",
@@ -12295,20 +12296,20 @@ function Ul(e) {
12295
12296
  "'": "&#39;"
12296
12297
  })[e]);
12297
12298
  }
12298
- function Wl(e) {
12299
+ function Kl(e) {
12299
12300
  let t = String(e ?? "").trim();
12300
12301
  if (!t) return "";
12301
12302
  try {
12302
12303
  let e = new URL(t, globalThis.location?.href);
12303
- return ["http:", "https:"].includes(e.protocol) ? "<a class=\"external-link\" href=\"" + Ul(e.href) + "\" target=\"_blank\" rel=\"noopener noreferrer\">Open documentation ↗</a>" : "";
12304
+ return ["http:", "https:"].includes(e.protocol) ? "<a class=\"external-link\" href=\"" + Gl(e.href) + "\" target=\"_blank\" rel=\"noopener noreferrer\">Open documentation ↗</a>" : "";
12304
12305
  } catch {
12305
12306
  return "";
12306
12307
  }
12307
12308
  }
12308
- function Gl(e, t = "connection") {
12309
+ function ql(e, t = "connection") {
12309
12310
  return String(e || t).normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || t;
12310
12311
  }
12311
- function Kl(e) {
12312
+ function Jl(e) {
12312
12313
  let t = Array.isArray(e) ? e : e && typeof e == "object" ? Object.entries(e).map(([e, t]) => typeof t == "string" ? {
12313
12314
  id: e,
12314
12315
  label: t
@@ -12327,7 +12328,7 @@ function Kl(e) {
12327
12328
  }]);
12328
12329
  });
12329
12330
  }
12330
- function ql(e) {
12331
+ function Yl(e) {
12331
12332
  let t = e && typeof e == "object" ? e : {}, n = t.render && typeof t.render == "object" ? t.render : {}, r = Array.isArray(t.entities) ? t.entities.map((e) => ({
12332
12333
  ...e,
12333
12334
  p: Array.isArray(e.p) ? e.p : [
@@ -12343,9 +12344,9 @@ function ql(e) {
12343
12344
  })) : [], i = /* @__PURE__ */ new Set(), a = (e) => {
12344
12345
  let t = (e.id == null ? "" : String(e.id).trim()) || [
12345
12346
  "relation",
12346
- Gl(e.from, "source"),
12347
- Gl(e.to, "target"),
12348
- e.label ? Gl(e.label) : ""
12347
+ ql(e.from, "source"),
12348
+ ql(e.to, "target"),
12349
+ e.label ? ql(e.label) : ""
12349
12350
  ].filter(Boolean).join("-"), n = t || "relation", r = 2;
12350
12351
  for (; i.has(n);) n = `${t || "relation"}-${r++}`;
12351
12352
  return i.add(n), n;
@@ -12381,12 +12382,12 @@ function ql(e) {
12381
12382
  ...n,
12382
12383
  relationMarker: Ol(n.relationMarker)
12383
12384
  },
12384
- relationGroups: Kl(t.relationGroups),
12385
+ relationGroups: Jl(t.relationGroups),
12385
12386
  entities: r,
12386
12387
  relations: o
12387
12388
  };
12388
12389
  }
12389
- function Jl(e, t, n = [
12390
+ function Xl(e, t, n = [
12390
12391
  1,
12391
12392
  1,
12392
12393
  1
@@ -12405,7 +12406,7 @@ function Jl(e, t, n = [
12405
12406
  });
12406
12407
  return s.center(), s;
12407
12408
  }
12408
- function Yl(e, t, n) {
12409
+ function Zl(e, t, n) {
12409
12410
  let r = new ui();
12410
12411
  for (let t = 0; t < e; t++) {
12411
12412
  let n = Math.PI / 2 + t * Math.PI * 2 / e, i = new V(Math.cos(n) * .5, Math.sin(n) * .5);
@@ -12422,7 +12423,7 @@ function Yl(e, t, n) {
12422
12423
  });
12423
12424
  return i.rotateX(Math.PI / 2), i.center(), i;
12424
12425
  }
12425
- function Xl(e, t, n, r) {
12426
+ function Ql(e, t, n, r) {
12426
12427
  let i = Math.min(.22, Math.max(0, Number(n) || 0));
12427
12428
  if (!i) return new Er(t, e, 1, 32);
12428
12429
  let a = [new V(0, -.5)];
@@ -12439,7 +12440,7 @@ function Xl(e, t, n, r) {
12439
12440
  }
12440
12441
  return a.push(new V(0, .5)), new Qi(a, 32);
12441
12442
  }
12442
- function Zl(e, t) {
12443
+ function $l(e, t) {
12443
12444
  if (!t) return e;
12444
12445
  let n = Math.min(.72, Math.max(0, Number(t) * 3)), r = e.attributes.position;
12445
12446
  for (let e = 0; e < r.count; e++) {
@@ -12448,36 +12449,36 @@ function Zl(e, t) {
12448
12449
  }
12449
12450
  return r.needsUpdate = !0, e.computeVertexNormals(), e;
12450
12451
  }
12451
- function Ql(e, t = 0, n = 4, r = [
12452
+ function eu(e, t = 0, n = 4, r = [
12452
12453
  1,
12453
12454
  1,
12454
12455
  1
12455
12456
  ]) {
12456
12457
  let i = Number(t) || 0, a = Math.max(2, Math.round(Number(n) || 4));
12457
12458
  switch (e) {
12458
- case "cylinder": return i ? Xl(.5, .5, i, a) : new Er(.5, .5, 1, 32);
12459
- case "cone": return i ? Xl(0, .5, i, a) : new Dr(.5, 1, 32);
12459
+ case "cylinder": return i ? Ql(.5, .5, i, a) : new Er(.5, .5, 1, 32);
12460
+ case "cone": return i ? Ql(0, .5, i, a) : new Dr(.5, 1, 32);
12460
12461
  case "frustum-cone":
12461
- case "truncated-cone": return i ? Xl(.28, .5, i, a) : new Er(.28, .5, 1, 32);
12462
+ case "truncated-cone": return i ? Ql(.28, .5, i, a) : new Er(.28, .5, 1, 32);
12462
12463
  case "frustum-pyramid":
12463
12464
  case "truncated-pyramid": return new Er(.28, .5, 1, 4);
12464
12465
  case "frustum-triangle": return new Er(.28, .5, 1, 3);
12465
- case "prism": return i ? Yl(6, i, a) : new Er(.5, .5, 1, 6);
12466
- case "pyramid-square": return i ? Zl(new Dr(.5, 1, 4), i) : new Dr(.5, 1, 4);
12467
- case "pyramid-triangle": return i ? Zl(new Dr(.5, 1, 3), i) : new Dr(.5, 1, 3);
12466
+ case "prism": return i ? Zl(6, i, a) : new Er(.5, .5, 1, 6);
12467
+ case "pyramid-square": return i ? $l(new Dr(.5, 1, 4), i) : new Dr(.5, 1, 4);
12468
+ case "pyramid-triangle": return i ? $l(new Dr(.5, 1, 3), i) : new Dr(.5, 1, 3);
12468
12469
  case "sphere": return new ta(.5, 24, 16);
12469
- case "octahedron": return Zl(new $i(.5), i);
12470
- case "dodecahedron": return Zl(new kr(.5), i);
12471
- case "icosahedron": return Zl(new Zi(.5), i);
12472
- default: return i ? Jl(i, a, r) : new Nn(1, 1, 1);
12470
+ case "octahedron": return $l(new $i(.5), i);
12471
+ case "dodecahedron": return $l(new kr(.5), i);
12472
+ case "icosahedron": return $l(new Zi(.5), i);
12473
+ default: return i ? Xl(i, a, r) : new Nn(1, 1, 1);
12473
12474
  }
12474
12475
  }
12475
- function $l(e) {
12476
+ function tu(e) {
12476
12477
  e.computeBoundingBox();
12477
12478
  let t = e.boundingBox?.getSize(new U());
12478
12479
  return !t || !t.x || !t.y || !t.z ? e : (e.scale(1 / t.x, 1 / t.y, 1 / t.z), e.computeBoundingBox(), e);
12479
12480
  }
12480
- function eu(e, t) {
12481
+ function nu(e, t) {
12481
12482
  let n = e.geometryOptions || e.geometry_options || e.parameters || {}, r = {};
12482
12483
  for (let [e, n] of Object.entries(t?.parameters || {})) n && Object.hasOwn(n, "default") && (r[e] = n.default);
12483
12484
  return {
@@ -12485,10 +12486,10 @@ function eu(e, t) {
12485
12486
  ...n && typeof n == "object" ? n : {}
12486
12487
  };
12487
12488
  }
12488
- function tu(e, t, n) {
12489
+ function ru(e, t, n) {
12489
12490
  return typeof e != "string" || !e ? n : t[e] || e;
12490
12491
  }
12491
- function nu(e, t = "#ffffff", n = "transparent") {
12492
+ function iu(e, t = "#ffffff", n = "transparent") {
12492
12493
  let r = document.createElement("canvas");
12493
12494
  r.width = 256, r.height = 256;
12494
12495
  let i = r.getContext("2d");
@@ -12496,8 +12497,8 @@ function nu(e, t = "#ffffff", n = "transparent") {
12496
12497
  let a = new Cr(r);
12497
12498
  return a.colorSpace = y, a;
12498
12499
  }
12499
- var ru = /^[AaCcHhLlMmQqSsTtVvZz]$/, iu = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?|[AaCcHhLlMmQqSsTtVvZz]/g;
12500
- function au(e, t, n, r, i, a, o, s, c) {
12500
+ var au = /^[AaCcHhLlMmQqSsTtVvZz]$/, ou = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?|[AaCcHhLlMmQqSsTtVvZz]/g;
12501
+ function su(e, t, n, r, i, a, o, s, c) {
12501
12502
  let l = Math.abs(Number(n)), u = Math.abs(Number(r));
12502
12503
  if (!l || !u || e === s && t === c) return [[s, c]];
12503
12504
  let d = Number(i || 0) * Math.PI / 180, f = Math.cos(d), p = Math.sin(d), m = (e - s) / 2, h = (t - c) / 2, g = f * m + p * h, _ = -p * m + f * h, v = Math.sqrt(Math.max(1, g * g / (l * l) + _ * _ / (u * u)));
@@ -12513,12 +12514,12 @@ function au(e, t, n, r, i, a, o, s, c) {
12513
12514
  return [w + f * l * r - p * u * i, T + p * l * r + f * u * i];
12514
12515
  });
12515
12516
  }
12516
- function ou(e) {
12517
- let t = String(e || "").match(iu) || [], n = new qa(), r = 0, i = "", a = "", o = 0, s = 0, c = 0, l = 0, u = 0, d = 0, f = 0, p = 0, m = () => r < t.length && !ru.test(t[r]), h = () => Number(t[r++]), g = () => {
12517
+ function cu(e) {
12518
+ let t = String(e || "").match(ou) || [], n = new qa(), r = 0, i = "", a = "", o = 0, s = 0, c = 0, l = 0, u = 0, d = 0, f = 0, p = 0, m = () => r < t.length && !au.test(t[r]), h = () => Number(t[r++]), g = () => {
12518
12519
  let e = t[r];
12519
12520
  return /^[01].+/.test(e) ? (t[r] = e.slice(1), e[0] === "1") : h() !== 0;
12520
12521
  }, _ = (e, t, n) => [n ? o + e : e, n ? s + t : t];
12521
- for (; r < t.length && (ru.test(t[r]) && (i = t[r++]), i);) {
12522
+ for (; r < t.length && (au.test(t[r]) && (i = t[r++]), i);) {
12522
12523
  let e = i.toLowerCase(), t = i === e;
12523
12524
  if (e === "z") {
12524
12525
  n.currentPath?.closePath(), o = c, s = l, a = i, i = "";
@@ -12558,7 +12559,7 @@ function ou(e) {
12558
12559
  }
12559
12560
  else if (e === "a") for (; m();) {
12560
12561
  let e = h(), r = h(), c = h(), l = g(), u = g(), [d, f] = _(h(), h(), t);
12561
- for (let [t, i] of au(o, s, e, r, c, l, u, d, f)) n.lineTo(t, -i);
12562
+ for (let [t, i] of su(o, s, e, r, c, l, u, d, f)) n.lineTo(t, -i);
12562
12563
  o = d, s = f, a = i;
12563
12564
  }
12564
12565
  else break;
@@ -12566,12 +12567,12 @@ function ou(e) {
12566
12567
  }
12567
12568
  return n;
12568
12569
  }
12569
- function su(e, t = {}) {
12570
+ function lu(e, t = {}) {
12570
12571
  let n = String(e || "").match(/<path\b[^>]*>/gi) || [], r = [];
12571
12572
  for (let e of n) {
12572
12573
  let t = e.match(/\bd\s*=\s*(["'])([\s\S]*?)\1/i);
12573
12574
  if (!t) continue;
12574
- let n = ou(t[2]);
12575
+ let n = cu(t[2]);
12575
12576
  r.push(...n.toShapes(!0, !1));
12576
12577
  }
12577
12578
  if (!r.length) return new Nn(1, 1, .12);
@@ -12586,11 +12587,11 @@ function su(e, t = {}) {
12586
12587
  });
12587
12588
  return a.center(), a;
12588
12589
  }
12589
- function cu(e) {
12590
- return e.shape === "plane" ? new ea(1, 1) : e.shape === "svg-extrude" ? su(e.svg, e) : Ql(e.shape || e.geometry || "box", e.radius, e.segments, e.size);
12590
+ function uu(e) {
12591
+ return e.shape === "plane" ? new ea(1, 1) : e.shape === "svg-extrude" ? lu(e.svg, e) : eu(e.shape || e.geometry || "box", e.radius, e.segments, e.size);
12591
12592
  }
12592
- function lu(e, t, n, r, i) {
12593
- let a = eu(t, e), o = {
12593
+ function du(e, t, n, r, i) {
12594
+ let a = nu(t, e), o = {
12594
12595
  ...n,
12595
12596
  ...e.palette || {},
12596
12597
  ...t.geometryPalette || t.geometry_palette || {}
@@ -12605,11 +12606,11 @@ function lu(e, t, n, r, i) {
12605
12606
  if (!c.length) throw Error(`Geometry '${e.id}' did not produce any parts.`);
12606
12607
  let l = new Qn(), u = [], d = [];
12607
12608
  for (let a of c) {
12608
- let s = cu(a);
12609
- $l(s);
12610
- let c = a.color || "component", f = tu(c, o, n.component || el.component), p = a.emissive || "#000000", m = new ia({
12609
+ let s = uu(a);
12610
+ tu(s);
12611
+ let c = a.color || "component", f = ru(c, o, n.component || el.component), p = a.emissive || "#000000", m = new ia({
12611
12612
  color: f,
12612
- emissive: tu(p, o, "#000000"),
12613
+ emissive: ru(p, o, "#000000"),
12613
12614
  emissiveIntensity: Number.isFinite(Number(a.emissiveIntensity)) ? Math.max(0, Number(a.emissiveIntensity)) : 0,
12614
12615
  roughness: Number.isFinite(Number(a.roughness)) ? Number(a.roughness) : .72,
12615
12616
  metalness: Number.isFinite(Number(a.metalness)) ? Number(a.metalness) : .06,
@@ -12680,7 +12681,7 @@ function lu(e, t, n, r, i) {
12680
12681
  n.src = _;
12681
12682
  }
12682
12683
  })(), m.map.colorSpace = y, m.needsUpdate = !0;
12683
- } else g != null && g !== "" && (m.map = nu(g, tu(a.iconColor || "#ffffff", o, "#ffffff"), tu(a.iconBackground || "transparent", o, "transparent")), m.transparent = !0, m.needsUpdate = !0);
12684
+ } else g != null && g !== "" && (m.map = iu(g, ru(a.iconColor || "#ffffff", o, "#ffffff"), ru(a.iconBackground || "transparent", o, "transparent")), m.transparent = !0, m.needsUpdate = !0);
12684
12685
  if (h = new An(s, m), h.position.fromArray(Array.isArray(a.position) ? a.position : [
12685
12686
  0,
12686
12687
  0,
@@ -12717,23 +12718,23 @@ function lu(e, t, n, r, i) {
12717
12718
  descriptor: s
12718
12719
  };
12719
12720
  }
12720
- var uu = Object.freeze([
12721
+ var fu = Object.freeze([
12721
12722
  "auto",
12722
12723
  "top",
12723
12724
  "bottom",
12724
12725
  "left",
12725
12726
  "right"
12726
12727
  ]);
12727
- function du(e) {
12728
+ function pu(e) {
12728
12729
  let t = String(e || "auto").trim().toLowerCase();
12729
- return uu.includes(t) ? t : "auto";
12730
+ return fu.includes(t) ? t : "auto";
12730
12731
  }
12731
- function fu(e = {}, t = {}) {
12732
+ function mu(e = {}, t = {}) {
12732
12733
  let n = e.style?.label?.anchor ?? e.labelAnchor ?? e.label_anchor, r = wl(e.type) ? "auto" : t?.label?.anchor ?? "bottom";
12733
- return du(n ?? r);
12734
+ return pu(n ?? r);
12734
12735
  }
12735
- function pu(e, t, n, r, i = .025) {
12736
- let a = du(e);
12736
+ function hu(e, t, n, r, i = .025) {
12737
+ let a = pu(e);
12737
12738
  if (a === "auto") return null;
12738
12739
  let o = Math.max(0, Number(t?.x) || 0), s = Math.max(0, Number(t?.y) || 0);
12739
12740
  Math.max(0, Number(n) || 0);
@@ -12760,7 +12761,23 @@ function pu(e, t, n, r, i = .025) {
12760
12761
  backRotation: Math.PI / 2
12761
12762
  };
12762
12763
  }
12763
- function mu(e, t, n, r = "", i = !0) {
12764
+ function gu(e, t, n = null, r = .08) {
12765
+ let i = (Number(e?.x) || 0) - (Number(t?.x) || 0), a = (Number(e?.y) || 0) - (Number(t?.y) || 0), o = (Number(e?.z) || 0) - (Number(t?.z) || 0), s = Math.hypot(i, a, o), c = [
12766
+ "front",
12767
+ "back",
12768
+ "top"
12769
+ ];
12770
+ if (!s) return c.includes(n) ? n : "front";
12771
+ let l = {
12772
+ front: o / s,
12773
+ back: -o / s,
12774
+ top: a / s
12775
+ }, u = "front";
12776
+ for (let e of c.slice(1)) l[e] > l[u] && (u = e);
12777
+ let d = Math.max(0, Math.min(.5, Number(r) || 0));
12778
+ return c.includes(n) && l[n] > 0 && l[n] + d >= l[u] ? n : l[u] > 0 ? u : c.includes(n) ? n : "front";
12779
+ }
12780
+ function _u(e, t, n, r = "", i = !0) {
12764
12781
  let a = document.createElement("canvas"), o = a.getContext("2d"), s = n.x * .88, c = Math.min(.82, n.y * .64);
12765
12782
  a.width = Math.ceil(s * 320), a.height = Math.ceil(c * 320), o.imageSmoothingEnabled = !0, o.imageSmoothingQuality = "high", o.clearRect(0, 0, a.width, a.height);
12766
12783
  let l = a.height * .62;
@@ -12805,29 +12822,90 @@ function mu(e, t, n, r = "", i = !0) {
12805
12822
  ]) e.renderOrder = 20, e.frustumCulled = !1, e.material.depthTest = !0, e.material.depthWrite = !1, e.material.transparent = !0;
12806
12823
  return x.renderOrder = 20, x.frustumCulled = !1, x.userData.front = S, x.userData.back = C, x.userData.top = w, x.userData.height = c, x.userData.width = s, x.userData.textOffsetX = h, x.userData.textOffsetY = g, x.userData.nodeLabel = !0, x;
12807
12824
  }
12808
- function hu(e, t, n, r = globalThis.document) {
12825
+ function vu(e, t, n, r) {
12826
+ if (!r || r === "transparent" || !e?.fillRect) return;
12827
+ let i = typeof r == "string" ? { color: r } : r, a = i.fade || i.color || "#0a111a", o = i.glow || a;
12828
+ if (e.save?.(), e.globalCompositeOperation = "destination-over", o !== a && e.createRadialGradient && e.scale) {
12829
+ e.scale(t, n);
12830
+ let r = e.createRadialGradient(.5, .45, 0, .5, .45, .75);
12831
+ r.addColorStop(0, o), r.addColorStop(.82, a), r.addColorStop(1, a), e.fillStyle = r, e.fillRect(0, 0, 1, 1);
12832
+ } else e.fillStyle = a, e.fillRect(0, 0, t, n);
12833
+ e.restore?.();
12834
+ }
12835
+ function yu(e) {
12836
+ for (let t = 0; t < e.length; t += 4) {
12837
+ let n = e[t + 3];
12838
+ if (!n || n === 255) continue;
12839
+ let r = 255 / n;
12840
+ e[t] = Math.min(255, Math.round(e[t] * r)), e[t + 1] = Math.min(255, Math.round(e[t + 1] * r)), e[t + 2] = Math.min(255, Math.round(e[t + 2] * r));
12841
+ }
12842
+ }
12843
+ function bu(e, t, n, r = 8192) {
12844
+ let i = Math.max(1, Math.min(4, Number(n) || 1));
12845
+ if (i === 1 || !e?.getPixelRatio || !e?.getSize || !e?.setPixelRatio || !e?.setSize) return null;
12846
+ let a = e.getPixelRatio(), o = {
12847
+ x: 0,
12848
+ y: 0,
12849
+ set(e, t) {
12850
+ return this.x = e, this.y = t, this;
12851
+ }
12852
+ };
12853
+ if (e.getSize(o), !o.x || !o.y) return null;
12854
+ let s = t?.getParameter && t?.MAX_RENDERBUFFER_SIZE ? Number(t.getParameter(t.MAX_RENDERBUFFER_SIZE)) : 0, c = Math.max(1, Math.min(Number(r) || 8192, s || Infinity)), l = t?.drawingBufferWidth || o.x * a, u = t?.drawingBufferHeight || o.y * a, d = Math.max(1, Math.min(i, c / l, c / u));
12855
+ return d <= 1 ? null : (e.setPixelRatio(a * d), e.setSize(o.x, o.y, !1), () => {
12856
+ e.setPixelRatio(a), e.setSize(o.x, o.y, !1);
12857
+ });
12858
+ }
12859
+ function xu(e, t, n, r = globalThis.document, i = {}) {
12809
12860
  if (!e || !t || !n || !r?.createElement) return null;
12861
+ let a = null;
12810
12862
  try {
12811
- e.render(t, n);
12812
- let i = e.getContext?.(), a = i?.drawingBufferWidth || e.domElement?.width || 0, o = i?.drawingBufferHeight || e.domElement?.height || 0;
12813
- if (!i?.readPixels || !a || !o) return null;
12814
- let s = new Uint8Array(a * o * 4);
12815
- i.readPixels(0, 0, a, o, i.RGBA, i.UNSIGNED_BYTE, s);
12816
- let c = r.createElement("canvas");
12817
- c.className = "atlas-print-snapshot", c.width = a, c.height = o, c.setAttribute("aria-hidden", "true");
12818
- let l = c.getContext?.("2d");
12819
- if (!l) return null;
12820
- let u = l.createImageData(a, o), d = a * 4;
12821
- for (let e = 0; e < o; e += 1) {
12822
- let t = o - e - 1;
12823
- u.data.set(s.subarray(t * d, (t + 1) * d), e * d);
12824
- }
12825
- return l.putImageData(u, 0, 0), c;
12863
+ let o = e.getContext?.();
12864
+ a = bu(e, o, i.scale, i.maximumDimension), e.render(t, n);
12865
+ let s = e.getContext?.(), c = s?.drawingBufferWidth || e.domElement?.width || 0, l = s?.drawingBufferHeight || e.domElement?.height || 0;
12866
+ if (!s?.readPixels || !c || !l) return null;
12867
+ let u = new Uint8Array(c * l * 4);
12868
+ s.readPixels(0, 0, c, l, s.RGBA, s.UNSIGNED_BYTE, u);
12869
+ let d = r.createElement("canvas");
12870
+ d.className = "atlas-print-snapshot", d.width = c, d.height = l, d.setAttribute("aria-hidden", "true");
12871
+ let f = d.getContext?.("2d");
12872
+ if (!f) return null;
12873
+ let p = f.createImageData(c, l), m = c * 4;
12874
+ for (let e = 0; e < l; e += 1) {
12875
+ let t = l - e - 1;
12876
+ p.data.set(u.subarray(t * m, (t + 1) * m), e * m);
12877
+ }
12878
+ return s.getContextAttributes?.().premultipliedAlpha !== !1 && yu(p.data), f.putImageData(p, 0, 0), vu(f, c, l, i.background), d;
12826
12879
  } catch {
12827
12880
  return null;
12881
+ } finally {
12882
+ if (a) try {
12883
+ a(), e.render(t, n);
12884
+ } catch {}
12885
+ }
12886
+ }
12887
+ function Su(e) {
12888
+ return e?.toBlob ? new Promise((t, n) => {
12889
+ e.toBlob((e) => {
12890
+ e ? t(e) : n(/* @__PURE__ */ Error("Atlas could not encode the captured view as PNG."));
12891
+ }, "image/png");
12892
+ }) : Promise.reject(/* @__PURE__ */ Error("PNG capture is unavailable in this browser."));
12893
+ }
12894
+ function Cu(e, t = {}) {
12895
+ let n = Object.hasOwn(t, "documentRef") ? t.documentRef : globalThis.document, r = Object.hasOwn(t, "urlRef") ? t.urlRef : globalThis.URL;
12896
+ if (!n?.createElement || !r?.createObjectURL) throw Error("PNG download is unavailable in this browser.");
12897
+ let i = String(t.filename || "atlas-view.png"), a = r.createObjectURL(e), o = n.createElement("a");
12898
+ o.href = a, o.download = i, o.hidden = !0, n.body?.appendChild?.(o);
12899
+ try {
12900
+ o.click();
12901
+ } finally {
12902
+ o.remove?.();
12903
+ let e = () => r.revokeObjectURL?.(a), n = Object.hasOwn(t, "schedule") ? t.schedule : globalThis.setTimeout;
12904
+ typeof n == "function" ? n(e, 0) : e();
12828
12905
  }
12906
+ return i;
12829
12907
  }
12830
- var gu = class extends HTMLElement {
12908
+ var wu = class extends HTMLElement {
12831
12909
  static version = $c;
12832
12910
  static get observedAttributes() {
12833
12911
  return [
@@ -12858,11 +12936,11 @@ var gu = class extends HTMLElement {
12858
12936
  return Sl();
12859
12937
  }
12860
12938
  constructor() {
12861
- super(), this.attachShadow({ mode: "open" }), this.shadowRoot.innerHTML = "<style>" + Fl + Il + Ll + "</style>" + Hl, this.canvas = this.shadowRoot.querySelector("canvas"), this.panel = this.shadowRoot.querySelector(".panel"), this.scene = new tr(), this.camera = new Kn(30, 1, .1, 2e3), this.cameraPosition = new U(), this.cameraTarget = new U(), this.raycaster = new Wa(), this.pointer = new V(), this.nodes = /* @__PURE__ */ new Map(), this.open = /* @__PURE__ */ new Set(), this._initialOpenContainers = /* @__PURE__ */ new Set(), this.selected = null, this.selectedRelationIndex = null, this.modelData = null, this._loading = !1, this._pendingSelection = null, this._theme = Nl(), this.relationMode = kl(this.getAttribute("relation-mode")), this.relationMarker = Ol(this.getAttribute("relation-marker")), this.visibleRelationGroups = null, this.focusFilter = Tl({
12939
+ super(), this.attachShadow({ mode: "open" }), this.shadowRoot.innerHTML = "<style>" + Fl + Il + Ll + "</style>" + Wl, this.shadowRoot.querySelector("[data-toolbar-group=\"focus\"]")?.insertAdjacentHTML?.("afterend", Ul), this.canvas = this.shadowRoot.querySelector("canvas"), this.panel = this.shadowRoot.querySelector(".panel"), this.scene = new tr(), this.camera = new Kn(30, 1, .1, 2e3), this.cameraPosition = new U(), this.cameraTarget = new U(), this.raycaster = new Wa(), this.pointer = new V(), this.nodes = /* @__PURE__ */ new Map(), this.open = /* @__PURE__ */ new Set(), this._initialOpenContainers = /* @__PURE__ */ new Set(), this.selected = null, this.selectedRelationIndex = null, this.modelData = null, this._loading = !1, this._pendingSelection = null, this._theme = Nl(), this.relationMode = kl(this.getAttribute("relation-mode")), this.relationMarker = Ol(this.getAttribute("relation-marker")), this.visibleRelationGroups = null, this.focusFilter = Tl({
12862
12940
  mode: this.getAttribute("focus-mode"),
12863
12941
  effect: this.getAttribute("focus-effect"),
12864
12942
  layout: this.getAttribute("focus-layout")
12865
- }), this.selectionMode = ["internal", "event"].includes(this.getAttribute("selection-mode")) ? this.getAttribute("selection-mode") : "internal", this.selectionNavigation = El(this.getAttribute("selection-navigation")), this.itemFacing = Dl(this.getAttribute("item-facing")), this.showShellLabels = this.getAttribute("shell-labels") !== "false", this.yaw = .37, this.pitch = .22, this.zoom = 1, this.targetZoom = 1, this.focus = new U(), this.targetFocus = new U(), this.drag = null, this.pointers = /* @__PURE__ */ new Map(), this.relationGroup = new Qn(), this.scene.add(this.relationGroup), this.relations = [], this.animationFrame = 0, this.ready = !1, this._toolbarVisible = this.getAttribute("toolbar") !== "off", this._panelVisible = this.getAttribute("panel") !== "off", this.toolbar = this.shadowRoot.querySelector(".toolbar"), this._printState = null, this._beforePrintListener = () => this.prepareForPrint(), this._afterPrintListener = () => this.restoreAfterPrint(), this._printMedia = globalThis.matchMedia?.("print") || null, this._printMediaListener = (e) => e.matches ? this.prepareForPrint() : this.restoreAfterPrint(), this._geometryRegistryListener = () => {
12943
+ }), this.selectionMode = ["internal", "event"].includes(this.getAttribute("selection-mode")) ? this.getAttribute("selection-mode") : "internal", this.selectionNavigation = El(this.getAttribute("selection-navigation")), this.itemFacing = Dl(this.getAttribute("item-facing")), this.showShellLabels = this.getAttribute("shell-labels") !== "false", this.yaw = .37, this.pitch = .22, this.zoom = 1, this.targetZoom = 1, this.focus = new U(), this.targetFocus = new U(), this.drag = null, this.pointers = /* @__PURE__ */ new Map(), this.relationGroup = new Qn(), this.scene.add(this.relationGroup), this.relations = [], this.animationFrame = 0, this.ready = !1, this._toolbarVisible = this.getAttribute("toolbar") !== "off", this._panelVisible = this.getAttribute("panel") !== "off", this.toolbar = this.shadowRoot.querySelector(".toolbar"), this._copyStatusTimer = null, this._printState = null, this._beforePrintListener = () => this.prepareForPrint(), this._afterPrintListener = () => this.restoreAfterPrint(), this._printMedia = globalThis.matchMedia?.("print") || null, this._printMediaListener = (e) => e.matches ? this.prepareForPrint() : this.restoreAfterPrint(), this._geometryRegistryListener = () => {
12866
12944
  this.ready && this.modelData && this._build();
12867
12945
  }, this._bindControls(), this._syncFocusToolbar(), this._syncRelationToolbar(), this._syncLabelsToolbar(), this._syncPanelToolbar(), this._syncItemFacingToolbar(), this.resizeObserver = new ResizeObserver(() => this.resize()), this.resizeObserver.observe(this.canvas);
12868
12946
  }
@@ -12870,7 +12948,7 @@ var gu = class extends HTMLElement {
12870
12948
  globalThis.addEventListener?.("lc-geometry-registry-change", this._geometryRegistryListener), globalThis.addEventListener?.("beforeprint", this._beforePrintListener), globalThis.addEventListener?.("afterprint", this._afterPrintListener), typeof this._printMedia?.addEventListener == "function" ? this._printMedia.addEventListener("change", this._printMediaListener) : this._printMedia?.addListener?.(this._printMediaListener), this.resizeObserver.observe(this.canvas), this.hasAttribute("height") && this.style.setProperty("--lc-height", this.getAttribute("height")), this._loadInitial();
12871
12949
  }
12872
12950
  disconnectedCallback() {
12873
- globalThis.removeEventListener?.("lc-geometry-registry-change", this._geometryRegistryListener), globalThis.removeEventListener?.("beforeprint", this._beforePrintListener), globalThis.removeEventListener?.("afterprint", this._afterPrintListener), typeof this._printMedia?.removeEventListener == "function" ? this._printMedia.removeEventListener("change", this._printMediaListener) : this._printMedia?.removeListener?.(this._printMediaListener), this.restoreAfterPrint(), this.resizeObserver.disconnect(), this.animationFrame && cancelAnimationFrame(this.animationFrame), this._clearObjects(), this.renderer &&= (this.renderer.dispose(), this.renderer.forceContextLoss?.(), null), this.ready = !1, this.dispatchEvent(new CustomEvent("lc-disconnect"));
12951
+ globalThis.removeEventListener?.("lc-geometry-registry-change", this._geometryRegistryListener), globalThis.removeEventListener?.("beforeprint", this._beforePrintListener), globalThis.removeEventListener?.("afterprint", this._afterPrintListener), typeof this._printMedia?.removeEventListener == "function" ? this._printMedia.removeEventListener("change", this._printMediaListener) : this._printMedia?.removeListener?.(this._printMediaListener), this.restoreAfterPrint(), this._copyStatusTimer && globalThis.clearTimeout?.(this._copyStatusTimer), this.resizeObserver.disconnect(), this.animationFrame && cancelAnimationFrame(this.animationFrame), this._clearObjects(), this.renderer &&= (this.renderer.dispose(), this.renderer.forceContextLoss?.(), null), this.ready = !1, this.dispatchEvent(new CustomEvent("lc-disconnect"));
12874
12952
  }
12875
12953
  attributeChangedCallback(e, t, n) {
12876
12954
  if (t !== n) {
@@ -12916,8 +12994,56 @@ var gu = class extends HTMLElement {
12916
12994
  set palette(e) {
12917
12995
  this.setPalette(e);
12918
12996
  }
12919
- captureFrame() {
12920
- return hu(this.renderer, this.scene, this.camera, this.ownerDocument);
12997
+ captureFrame(e = {}) {
12998
+ let t = e.background === "theme" ? this.theme?.background || jl.background : e.background;
12999
+ return xu(this.renderer, this.scene, this.camera, this.ownerDocument, {
13000
+ ...e,
13001
+ background: t
13002
+ });
13003
+ }
13004
+ async copyFrame(e = {}) {
13005
+ let t = e.background === "transparent" ? "transparent" : "theme", n = Math.max(1, Math.min(4, Number(e.scale) || 2)), r = e.fallback === "download" ? "download" : "none", i = Object.hasOwn(e, "navigatorRef") ? e.navigatorRef : globalThis.navigator, a = Object.hasOwn(e, "ClipboardItemClass") ? e.ClipboardItemClass : globalThis.ClipboardItem, o = !!(i?.clipboard?.write && a), s = e.source || "api";
13006
+ try {
13007
+ if (!o && r !== "download") throw Error("Image clipboard access is unavailable. Use HTTPS or localhost in a compatible browser.");
13008
+ let c = this.captureFrame({
13009
+ background: t,
13010
+ scale: n
13011
+ });
13012
+ if (!c) throw Error("Atlas could not capture the current WebGL view.");
13013
+ let l = Su(c), u = "clipboard";
13014
+ if (o) try {
13015
+ await i.clipboard.write([new a({ "image/png": l })]);
13016
+ } catch (e) {
13017
+ if (r !== "download") throw e;
13018
+ u = "download";
13019
+ }
13020
+ else u = "download";
13021
+ let d = await l;
13022
+ u === "download" && Cu(d, e);
13023
+ let f = {
13024
+ blob: d,
13025
+ width: c.width,
13026
+ height: c.height,
13027
+ background: t,
13028
+ scale: n,
13029
+ method: u
13030
+ };
13031
+ return this._emit?.("lc-image-export", {
13032
+ width: f.width,
13033
+ height: f.height,
13034
+ background: t,
13035
+ scale: n,
13036
+ method: u,
13037
+ source: s
13038
+ }), f;
13039
+ } catch (e) {
13040
+ throw this._emit?.("lc-image-export-error", {
13041
+ message: e?.message || String(e),
13042
+ background: t,
13043
+ scale: n,
13044
+ source: s
13045
+ }), e;
13046
+ }
12921
13047
  }
12922
13048
  prepareForPrint() {
12923
13049
  if (this._printState) return this;
@@ -13092,7 +13218,7 @@ var gu = class extends HTMLElement {
13092
13218
  let t = this.modelData?.relationGroups || [], n = this.shadowRoot.querySelector("[data-relation-groups-section]"), r = this.shadowRoot.querySelector("[data-relation-groups]");
13093
13219
  n && (n.hidden = t.length === 0), r && (r.innerHTML = t.map((e) => {
13094
13220
  let t = !this.visibleRelationGroups || this.visibleRelationGroups.has(e.id);
13095
- return Bl("relation-group-toggle", Ul(e.label || e.id), t).replace("data-action=\"relation-group-toggle\"", `data-action="relation-group-toggle" data-relation-group="${Ul(e.id)}"`);
13221
+ return Bl("relation-group-toggle", Gl(e.label || e.id), t).replace("data-action=\"relation-group-toggle\"", `data-action="relation-group-toggle" data-relation-group="${Gl(e.id)}"`);
13096
13222
  }).join(""));
13097
13223
  }
13098
13224
  _syncPanelToolbar() {
@@ -13214,7 +13340,7 @@ var gu = class extends HTMLElement {
13214
13340
  }
13215
13341
  _commitModelChange(e, t = {}, n = {}) {
13216
13342
  let r = n.preserveSelection === !1 ? null : this.selected?.id, i = n.preserveSelection === !1 ? null : this._publicRelation(this.selectedRelationIndex), a = i?.id ?? i?.index ?? null;
13217
- this.modelData = ql(this.modelData);
13343
+ this.modelData = Yl(this.modelData);
13218
13344
  let o = this._syncInitialContainerState({
13219
13345
  refresh: !1,
13220
13346
  emit: !1,
@@ -13231,7 +13357,7 @@ var gu = class extends HTMLElement {
13231
13357
  }
13232
13358
  updateModel(e = {}, t = {}) {
13233
13359
  if (!e || typeof e != "object" || Array.isArray(e)) throw TypeError("El parche del modelo debe ser un objeto.");
13234
- let n = this.modelData || ql({}), r = JSON.stringify(n.render?.camera || null), i = {
13360
+ let n = this.modelData || Yl({}), r = JSON.stringify(n.render?.camera || null), i = {
13235
13361
  ...n,
13236
13362
  ...e,
13237
13363
  palette: e.palette ? {
@@ -13242,11 +13368,11 @@ var gu = class extends HTMLElement {
13242
13368
  entities: Array.isArray(e.entities) ? e.entities : n.entities,
13243
13369
  relations: Array.isArray(e.relations) ? e.relations : n.relations
13244
13370
  };
13245
- return this.modelData = ql(i), this.theme = this.modelData.theme, this._commitModelChange("model-update", { patch: e }, t), this._applyModelRenderOptions(), JSON.stringify(this.modelData.render?.camera || null) !== r && this.modelData.render?.camera && this.setCameraView(this.modelData.render.camera, { animate: t.animateCamera !== !1 }), this;
13371
+ return this.modelData = Yl(i), this.theme = this.modelData.theme, this._commitModelChange("model-update", { patch: e }, t), this._applyModelRenderOptions(), JSON.stringify(this.modelData.render?.camera || null) !== r && this.modelData.render?.camera && this.setCameraView(this.modelData.render.camera, { animate: t.animateCamera !== !1 }), this;
13246
13372
  }
13247
13373
  addEntity(e, t = {}) {
13248
13374
  if (!e || typeof e != "object" || !e.id) throw TypeError("La entidad debe incluir un id.");
13249
- if (this.modelData ||= ql({}), this.modelData.entities.some((t) => t.id === e.id)) throw Error(`Ya existe una entidad con id "${e.id}".`);
13375
+ if (this.modelData ||= Yl({}), this.modelData.entities.some((t) => t.id === e.id)) throw Error(`Ya existe una entidad con id "${e.id}".`);
13250
13376
  if (e.parent && !this.modelData.entities.some((t) => t.id === e.parent)) throw Error(`No existe el contenedor padre "${e.parent}".`);
13251
13377
  return this.modelData.entities = [...this.modelData.entities, { ...e }], this._commitModelChange("entity-add", { entity: this._publicEntity(e.id) }, t);
13252
13378
  }
@@ -13517,7 +13643,7 @@ var gu = class extends HTMLElement {
13517
13643
  this._loading = !0, this._pendingSelection = null;
13518
13644
  try {
13519
13645
  let t = typeof e == "string" ? await fetch(e).then((e) => e.json()) : e;
13520
- this.modelData = ql(t), this.selected = null, this.selectedRelationIndex = null, this.open.clear(), this._initialOpenContainers.clear(), this._pendingPalette &&= (this.modelData.palette = {
13646
+ this.modelData = Yl(t), this.selected = null, this.selectedRelationIndex = null, this.open.clear(), this._initialOpenContainers.clear(), this._pendingPalette &&= (this.modelData.palette = {
13521
13647
  ...this.modelData.palette,
13522
13648
  ...this._pendingPalette
13523
13649
  }, null), this.theme = this.modelData.theme, this._applyTheme(), this._syncInitialContainerState({
@@ -13587,7 +13713,7 @@ var gu = class extends HTMLElement {
13587
13713
  ...e.geometryPalette || {},
13588
13714
  ...e.geometryPaletteOverrides || {}
13589
13715
  };
13590
- n.material.color.set(tu(n.value, r, t)), n.material.emissive && n.emissiveValue && n.material.emissive.set(tu(n.emissiveValue, r, "#000000"));
13716
+ n.material.color.set(ru(n.value, r, t)), n.material.emissive && n.emissiveValue && n.material.emissive.set(ru(n.emissiveValue, r, "#000000"));
13591
13717
  }
13592
13718
  }
13593
13719
  }
@@ -13612,7 +13738,7 @@ var gu = class extends HTMLElement {
13612
13738
  ...e.ports || {}
13613
13739
  }, s) {
13614
13740
  try {
13615
- let n = lu(r, e, this.modelData.palette, () => this.invalidate(), (e) => this.dispatchEvent(new CustomEvent("lc-warning", { detail: e })));
13741
+ let n = du(r, e, this.modelData.palette, () => this.invalidate(), (e) => this.dispatchEvent(new CustomEvent("lc-warning", { detail: e })));
13616
13742
  n.root.scale.multiply(new U().fromArray(e.s)), t.appearanceMaterials = [], n.root.traverse((e) => {
13617
13743
  if (!(e.isMesh || e.isLine || e.isLineSegments || e.isSprite)) return;
13618
13744
  e.userData.node = t;
@@ -13633,7 +13759,7 @@ var gu = class extends HTMLElement {
13633
13759
  entityId: e.id,
13634
13760
  error: r
13635
13761
  } }));
13636
- let i = $l(Ql("box"));
13762
+ let i = tu(eu("box"));
13637
13763
  t.material = new ia({
13638
13764
  color: "#ed8f98",
13639
13765
  roughness: .72,
@@ -13642,8 +13768,8 @@ var gu = class extends HTMLElement {
13642
13768
  }
13643
13769
  t.labelSize = new U().fromArray(e.s);
13644
13770
  } else {
13645
- let n = o === "box" && Number(e.radius) > 0, r = Ql(o, e.radius, e.segments, e.s);
13646
- n || $l(r), t.material = new ia({
13771
+ let n = o === "box" && Number(e.radius) > 0, r = eu(o, e.radius, e.segments, e.s);
13772
+ n || tu(r), t.material = new ia({
13647
13773
  color: a,
13648
13774
  roughness: .72,
13649
13775
  metalness: .06,
@@ -13663,7 +13789,7 @@ var gu = class extends HTMLElement {
13663
13789
  1
13664
13790
  ] : e.s), t.group.add(t.edge);
13665
13791
  }
13666
- t.label = mu(e.name, a, t.labelSize, e.type, this.showShellLabels), t.labelAnchor = fu(e, this.modelData.style), t.label.userData.node = t, t.label.traverse((e) => {
13792
+ t.label = _u(e.name, a, t.labelSize, e.type, this.showShellLabels), t.labelAnchor = mu(e, this.modelData.style), t.label.userData.node = t, t.label.traverse((e) => {
13667
13793
  e.userData.node = t;
13668
13794
  }), t.group.add(t.label), this.scene.add(t.group);
13669
13795
  }
@@ -13835,11 +13961,11 @@ var gu = class extends HTMLElement {
13835
13961
  if (!this.modelData) return;
13836
13962
  let e = this.selectedRelationIndex === null ? null : this.relations[this.selectedRelationIndex];
13837
13963
  if (e) {
13838
- let t = Pl(e), n = (this.modelData.relationGroups || []).find((t) => t.id === e.group), r = new Map((this.modelData.relationGroups || []).map((e) => [e.id, e])), i = this.getRelationBundle(this.selectedRelationIndex), a = e.text ? "<p>" + Ul(e.text) + "</p>" : "", o = Wl(e.url), s = n ? "<h3>GRUPO</h3><p>" + Ul(n.label || n.id) + "</p>" : "", c = i.map(({ index: e, relation: t }) => {
13964
+ let t = Pl(e), n = (this.modelData.relationGroups || []).find((t) => t.id === e.group), r = new Map((this.modelData.relationGroups || []).map((e) => [e.id, e])), i = this.getRelationBundle(this.selectedRelationIndex), a = e.text ? "<p>" + Gl(e.text) + "</p>" : "", o = Kl(e.url), s = n ? "<h3>GRUPO</h3><p>" + Gl(n.label || n.id) + "</p>" : "", c = i.map(({ index: e, relation: t }) => {
13839
13965
  let n = r.get(t.group), i = [n?.label || n?.id || "Sin grupo", Pl(t)].join(" · ");
13840
- return "<button class=\"relation" + (e === this.selectedRelationIndex ? " selected" : "") + "\" data-action=\"relation\" data-relation-index=\"" + e + "\"><strong>" + Ul(t.label || `${t.from} → ${t.to}`) + "</strong><small>" + Ul(i) + "</small></button>";
13966
+ return "<button class=\"relation" + (e === this.selectedRelationIndex ? " selected" : "") + "\" data-action=\"relation\" data-relation-index=\"" + e + "\"><strong>" + Gl(t.label || `${t.from} → ${t.to}`) + "</strong><small>" + Gl(i) + "</small></button>";
13841
13967
  }).join(""), l = i.length === 1 ? "1 conexión" : `${i.length} conexiones`;
13842
- this.panel.innerHTML = "<button class=\"back\" data-action=\"overview\">← Vista de conjunto</button><button data-action=\"focus-selection\">◎ Enfocar selección</button><div class=\"eyebrow\">RELACIÓN</div><h2>" + Ul(e.label || `${e.from} → ${e.to}`) + "</h2><div class=\"sub\">" + Ul(e.from) + " → " + Ul(e.to) + "</div>" + a + o + s + "<h3>MODO</h3><p>" + Ul(t) + "</p><h3>TUBO VIRTUAL</h3><p>" + Ul(`${e.from} ↔ ${e.to} · ${l}`) + "</p>" + c, this.panel.querySelector("[data-action=\"overview\"]")?.addEventListener("click", () => this.reset()), this.panel.querySelector("[data-action=\"focus-selection\"]")?.addEventListener("click", () => this.focusSelection()), this.panel.querySelectorAll("[data-action=\"relation\"]").forEach((e) => e.addEventListener("click", () => this.selectRelation(Number(e.dataset.relationIndex), { source: "panel" }))), this._applyTheme();
13968
+ this.panel.innerHTML = "<button class=\"back\" data-action=\"overview\">← Vista de conjunto</button><button data-action=\"focus-selection\">◎ Enfocar selección</button><div class=\"eyebrow\">RELACIÓN</div><h2>" + Gl(e.label || `${e.from} → ${e.to}`) + "</h2><div class=\"sub\">" + Gl(e.from) + " → " + Gl(e.to) + "</div>" + a + o + s + "<h3>MODO</h3><p>" + Gl(t) + "</p><h3>TUBO VIRTUAL</h3><p>" + Gl(`${e.from} ↔ ${e.to} · ${l}`) + "</p>" + c, this.panel.querySelector("[data-action=\"overview\"]")?.addEventListener("click", () => this.reset()), this.panel.querySelector("[data-action=\"focus-selection\"]")?.addEventListener("click", () => this.focusSelection()), this.panel.querySelectorAll("[data-action=\"relation\"]").forEach((e) => e.addEventListener("click", () => this.selectRelation(Number(e.dataset.relationIndex), { source: "panel" }))), this._applyTheme();
13843
13969
  return;
13844
13970
  }
13845
13971
  let t = this.selected;
@@ -13849,11 +13975,11 @@ var gu = class extends HTMLElement {
13849
13975
  }
13850
13976
  let n = this.relations.filter((e) => e.from === t.id || e.to === t.id), r = this.modelData.entities.filter((e) => e.parent === t.id), i = [], a = /* @__PURE__ */ new Set(), o = t;
13851
13977
  for (; o && !a.has(o.id);) a.add(o.id), i.unshift(o), o = o.parent ? this.nodes.get(o.parent) : null;
13852
- let s = "<nav class=\"crumbs\" aria-label=\"Ruta del modelo\"><button data-action=\"overview\">Modelo</button>" + i.map((e, t) => "<span>/</span><button data-action=\"path\" data-id=\"" + Ul(e.id) + "\" class=\"" + (t === i.length - 1 ? "current" : "") + "\">" + Ul(e.name) + "</button>").join("") + "</nav>", c = n.map((e) => {
13853
- let n = this.relations.indexOf(e), r = e.text ? "<small>" + Ul(e.text) + "</small>" : "";
13854
- return "<button class=\"relation\" data-action=\"relation\" data-relation-index=\"" + n + "\"><strong>" + Ul(e.label || (e.from === t.id ? e.to : e.from)) + "</strong><small>" + Ul(e.from) + " → " + Ul(e.to) + "</small>" + r + "</button>";
13978
+ let s = "<nav class=\"crumbs\" aria-label=\"Ruta del modelo\"><button data-action=\"overview\">Modelo</button>" + i.map((e, t) => "<span>/</span><button data-action=\"path\" data-id=\"" + Gl(e.id) + "\" class=\"" + (t === i.length - 1 ? "current" : "") + "\">" + Gl(e.name) + "</button>").join("") + "</nav>", c = n.map((e) => {
13979
+ let n = this.relations.indexOf(e), r = e.text ? "<small>" + Gl(e.text) + "</small>" : "";
13980
+ return "<button class=\"relation\" data-action=\"relation\" data-relation-index=\"" + n + "\"><strong>" + Gl(e.label || (e.from === t.id ? e.to : e.from)) + "</strong><small>" + Gl(e.from) + " → " + Gl(e.to) + "</small>" + r + "</button>";
13855
13981
  }).join("");
13856
- this.panel.innerHTML = "<button class=\"back\" data-action=\"overview\">← Vista de conjunto</button>" + s + "<button data-action=\"focus-selection\">◎ Enfocar selección</button><div class=\"eyebrow\">" + Ul(wl(t.type) ? "CONTENEDOR" : t.type === "actor" ? "ACTOR EXTERNO" : "COMPONENTE") + "</div><h2>" + Ul(t.name) + "</h2><div class=\"sub\">" + Ul(t.sub || "") + "</div><p>" + Ul(t.text || "") + "</p>" + Wl(t.url) + (wl(t.type) ? "<button data-action=\"toggle-shell\">" + (this.open.has(t.id) ? "Cerrar bloque" : "Abrir bloque") + "</button>" : "") + (r.length ? "<h3>CONTIENE</h3><p>" + r.length + " pieza(s) interna(s).</p>" : "") + "<h3>RELACIONES</h3>" + (c || "<p>No hay relaciones directas.</p>"), this.panel.querySelectorAll("[data-action=\"overview\"]").forEach((e) => e.addEventListener("click", () => this.reset())), this.panel.querySelectorAll("[data-action=\"path\"]").forEach((e) => e.addEventListener("click", () => this.select(e.dataset.id))), this.panel.querySelectorAll("[data-action=\"relation\"]").forEach((e) => e.addEventListener("click", () => this.selectRelation(Number(e.dataset.relationIndex), { source: "panel" }))), this.panel.querySelector("[data-action=\"focus-selection\"]")?.addEventListener("click", () => this.focusSelection()), this.panel.querySelector("[data-action=\"toggle-shell\"]")?.addEventListener("click", () => {
13982
+ this.panel.innerHTML = "<button class=\"back\" data-action=\"overview\">← Vista de conjunto</button>" + s + "<button data-action=\"focus-selection\">◎ Enfocar selección</button><div class=\"eyebrow\">" + Gl(wl(t.type) ? "CONTENEDOR" : t.type === "actor" ? "ACTOR EXTERNO" : "COMPONENTE") + "</div><h2>" + Gl(t.name) + "</h2><div class=\"sub\">" + Gl(t.sub || "") + "</div><p>" + Gl(t.text || "") + "</p>" + Kl(t.url) + (wl(t.type) ? "<button data-action=\"toggle-shell\">" + (this.open.has(t.id) ? "Cerrar bloque" : "Abrir bloque") + "</button>" : "") + (r.length ? "<h3>CONTIENE</h3><p>" + r.length + " pieza(s) interna(s).</p>" : "") + "<h3>RELACIONES</h3>" + (c || "<p>No hay relaciones directas.</p>"), this.panel.querySelectorAll("[data-action=\"overview\"]").forEach((e) => e.addEventListener("click", () => this.reset())), this.panel.querySelectorAll("[data-action=\"path\"]").forEach((e) => e.addEventListener("click", () => this.select(e.dataset.id))), this.panel.querySelectorAll("[data-action=\"relation\"]").forEach((e) => e.addEventListener("click", () => this.selectRelation(Number(e.dataset.relationIndex), { source: "panel" }))), this.panel.querySelector("[data-action=\"focus-selection\"]")?.addEventListener("click", () => this.focusSelection()), this.panel.querySelector("[data-action=\"toggle-shell\"]")?.addEventListener("click", () => {
13857
13983
  this.toggleContainer(t.id, { source: "panel" });
13858
13984
  }), this._applyTheme();
13859
13985
  }
@@ -13951,12 +14077,12 @@ var gu = class extends HTMLElement {
13951
14077
  e.edge?.material && (e.edge.material.opacity = (e === this.selected ? 1 : .65) * t);
13952
14078
  let o = wl(e.type) && r, s = o, c = e.label.userData.front, l = e.label.userData.back, u = e.label.userData.top, d = e.label.userData.height, f = e.label.userData.width, p = e.label.userData.textOffsetX || 0;
13953
14079
  e.label.userData.textOffsetY;
13954
- let m = e.labelSize || new U().fromArray(e.s), h = pu(e.labelAnchor, m, f, d);
14080
+ let m = e.labelSize || new U().fromArray(e.s), h = hu(e.labelAnchor, m, f, d);
13955
14081
  e.label.visible = n;
13956
- let g = this._worldPosition(e), _ = this.itemFacing === "camera" && !wl(e.type) || this.camera.position.z >= g.z, v = this.camera.position.y > g.y + .25;
13957
- if (h) c.visible = _, l.visible = !_, u.visible = !1, c.scale.setScalar(1), l.scale.setScalar(1), c.position.set(h.x, h.y, m.z / 2 + .025), l.position.set(h.x, h.y, -m.z / 2 - .025), c.rotation.z = h.frontRotation, l.rotation.z = h.backRotation, c.material.color.set(15923964), l.material.color.set(15923964), c.material.opacity = t, l.material.opacity = t;
14082
+ let g = this._worldPosition(e), _ = this.itemFacing === "camera" && !wl(e.type) || this.camera.position.z >= g.z, v = e.label.userData.visibleFace || (_ ? "front" : "back"), y = o ? gu(this.camera.position, g, v) : null;
14083
+ if (y && (e.label.userData.visibleFace = y), h) c.visible = _, l.visible = !_, u.visible = !1, c.scale.setScalar(1), l.scale.setScalar(1), c.position.set(h.x, h.y, m.z / 2 + .025), l.position.set(h.x, h.y, -m.z / 2 - .025), c.rotation.z = h.frontRotation, l.rotation.z = h.backRotation, c.material.color.set(15923964), l.material.color.set(15923964), c.material.opacity = t, l.material.opacity = t;
13958
14084
  else if (wl(e.type)) {
13959
- c.rotation.z = 0, l.rotation.z = 0, c.visible = _ && (!o || s), l.visible = !_ && (!o || s), u.visible = s && v;
14085
+ c.rotation.z = 0, l.rotation.z = 0, c.visible = o ? y === "front" : _, l.visible = o ? y === "back" : !_, u.visible = s && y === "top";
13960
14086
  let e = s ? .52 : 1;
13961
14087
  c.scale.setScalar(e), c.position.x = s ? -m.x / 2 + .18 + f * e / 2 - p * e : 0;
13962
14088
  let n = .18;
@@ -14007,6 +14133,28 @@ var gu = class extends HTMLElement {
14007
14133
  node: r.object.userData.node
14008
14134
  } : null;
14009
14135
  }
14136
+ _setCopyToolbarStatus(e, t = "idle") {
14137
+ let n = this.shadowRoot?.querySelector("[data-toolbar-status=\"copy\"]");
14138
+ n && (n.textContent = e, n.style.color = t === "error" ? "#ffaaa0" : t === "success" ? "#9ff0df" : "", this._copyStatusTimer && globalThis.clearTimeout?.(this._copyStatusTimer), t !== "idle" && (this._copyStatusTimer = globalThis.setTimeout?.(() => {
14139
+ n.textContent = "PNG", n.style.color = "", this._copyStatusTimer = null;
14140
+ }, t === "error" ? 4200 : 2400)));
14141
+ }
14142
+ async _copyFromToolbar(e, t) {
14143
+ t && (t.disabled = !0), this._setCopyToolbarStatus("Copiando…");
14144
+ try {
14145
+ let t = await this.copyFrame({
14146
+ background: e,
14147
+ scale: 2,
14148
+ fallback: "download",
14149
+ source: "toolbar"
14150
+ });
14151
+ return this._setCopyToolbarStatus(t.method === "clipboard" ? "Copiado" : "Descargado", "success"), t;
14152
+ } catch (e) {
14153
+ return this._setCopyToolbarStatus("Error", "error"), globalThis.console?.error?.("Atlas PNG export failed.", e), null;
14154
+ } finally {
14155
+ t && (t.disabled = !1);
14156
+ }
14157
+ }
14010
14158
  _bindControls() {
14011
14159
  this.toolbar?.querySelectorAll(".toolbar-menu").forEach((e) => e.addEventListener("toggle", () => {
14012
14160
  e.open && this._closeToolbarMenus(e);
@@ -14022,7 +14170,7 @@ var gu = class extends HTMLElement {
14022
14170
  }, { source: "toolbar" }), n === "focus-hide" && this.setFocusFilter({
14023
14171
  mode: "connected",
14024
14172
  effect: "hide"
14025
- }, { source: "toolbar" }), n === "focus-selection" && this.focusSelection(), n === "focus-layout" && this.setFocusFilter({ layout: this.focusFilter.layout === "reflow" ? "preserve" : "reflow" }, { source: "toolbar" }), t?.closest?.(".toolbar-popover") && n !== "relation-group-toggle" && this._closeToolbarMenus(), n && this.invalidate();
14173
+ }, { source: "toolbar" }), n === "focus-selection" && this.focusSelection(), n === "focus-layout" && this.setFocusFilter({ layout: this.focusFilter.layout === "reflow" ? "preserve" : "reflow" }, { source: "toolbar" }), n === "copy-theme" && this._copyFromToolbar("theme", t), n === "copy-transparent" && this._copyFromToolbar("transparent", t), t?.closest?.(".toolbar-popover") && n !== "relation-group-toggle" && this._closeToolbarMenus(), n && this.invalidate();
14026
14174
  }), this.canvas.addEventListener("contextmenu", (e) => e.preventDefault()), this.canvas.addEventListener("pointerdown", (e) => {
14027
14175
  if (e.pointerType !== "touch" && ![
14028
14176
  0,
@@ -14136,11 +14284,11 @@ var gu = class extends HTMLElement {
14136
14284
  }
14137
14285
  _showError(e) {
14138
14286
  let t = this.shadowRoot.querySelector(".viewport"), n = t.querySelector(".error");
14139
- n ? n.textContent = e : t.insertAdjacentHTML("beforeend", "<div class=\"error\" role=\"alert\">" + Ul(e) + "</div>");
14287
+ n ? n.textContent = e : t.insertAdjacentHTML("beforeend", "<div class=\"error\" role=\"alert\">" + Gl(e) + "</div>");
14140
14288
  }
14141
14289
  };
14142
- customElements.get("liquidcars-atlas") || customElements.define("liquidcars-atlas", gu);
14290
+ customElements.get("liquidcars-atlas") || customElements.define("liquidcars-atlas", wu);
14143
14291
  //#endregion
14144
- export { $c as ATLAS_VERSION, tl as DEFAULT_RELATION_MARKER, gu as LiquidCarsAtlas, nl as RELATION_DISPLAY_MODES, hu as captureRendererFrame, su as createSvgExtrudeGeometry, xl as getGeometryCatalog, Sl as getGeometryPackCatalog, pu as labelPlacementForAnchor, du as normalizeLabelAnchor, ql as normalizeModel, yl as registerGeometryPack, fu as resolveEntityLabelAnchor, bl as unregisterGeometryPack };
14292
+ export { $c as ATLAS_VERSION, tl as DEFAULT_RELATION_MARKER, wu as LiquidCarsAtlas, nl as RELATION_DISPLAY_MODES, Su as canvasToPngBlob, xu as captureRendererFrame, lu as createSvgExtrudeGeometry, Cu as downloadPngBlob, xl as getGeometryCatalog, Sl as getGeometryPackCatalog, hu as labelPlacementForAnchor, pu as normalizeLabelAnchor, Yl as normalizeModel, gu as preferredContainerLabelFace, yl as registerGeometryPack, mu as resolveEntityLabelAnchor, bl as unregisterGeometryPack };
14145
14293
 
14146
14294
  //# sourceMappingURL=liquidcars-atlas.js.map