@liquidcars/atlas 0.1.45 → 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.45",
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,7 @@ function pu(e, t, n, r, i = .025) {
12760
12761
  backRotation: Math.PI / 2
12761
12762
  };
12762
12763
  }
12763
- function mu(e, t, n = null, r = .08) {
12764
+ function gu(e, t, n = null, r = .08) {
12764
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 = [
12765
12766
  "front",
12766
12767
  "back",
@@ -12776,7 +12777,7 @@ function mu(e, t, n = null, r = .08) {
12776
12777
  let d = Math.max(0, Math.min(.5, Number(r) || 0));
12777
12778
  return c.includes(n) && l[n] > 0 && l[n] + d >= l[u] ? n : l[u] > 0 ? u : c.includes(n) ? n : "front";
12778
12779
  }
12779
- function hu(e, t, n, r = "", i = !0) {
12780
+ function _u(e, t, n, r = "", i = !0) {
12780
12781
  let a = document.createElement("canvas"), o = a.getContext("2d"), s = n.x * .88, c = Math.min(.82, n.y * .64);
12781
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);
12782
12783
  let l = a.height * .62;
@@ -12821,7 +12822,7 @@ function hu(e, t, n, r = "", i = !0) {
12821
12822
  ]) e.renderOrder = 20, e.frustumCulled = !1, e.material.depthTest = !0, e.material.depthWrite = !1, e.material.transparent = !0;
12822
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;
12823
12824
  }
12824
- function gu(e, t, n, r) {
12825
+ function vu(e, t, n, r) {
12825
12826
  if (!r || r === "transparent" || !e?.fillRect) return;
12826
12827
  let i = typeof r == "string" ? { color: r } : r, a = i.fade || i.color || "#0a111a", o = i.glow || a;
12827
12828
  if (e.save?.(), e.globalCompositeOperation = "destination-over", o !== a && e.createRadialGradient && e.scale) {
@@ -12831,7 +12832,7 @@ function gu(e, t, n, r) {
12831
12832
  } else e.fillStyle = a, e.fillRect(0, 0, t, n);
12832
12833
  e.restore?.();
12833
12834
  }
12834
- function _u(e) {
12835
+ function yu(e) {
12835
12836
  for (let t = 0; t < e.length; t += 4) {
12836
12837
  let n = e[t + 3];
12837
12838
  if (!n || n === 255) continue;
@@ -12839,7 +12840,7 @@ function _u(e) {
12839
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));
12840
12841
  }
12841
12842
  }
12842
- function vu(e, t, n, r = 8192) {
12843
+ function bu(e, t, n, r = 8192) {
12843
12844
  let i = Math.max(1, Math.min(4, Number(n) || 1));
12844
12845
  if (i === 1 || !e?.getPixelRatio || !e?.getSize || !e?.setPixelRatio || !e?.setSize) return null;
12845
12846
  let a = e.getPixelRatio(), o = {
@@ -12855,12 +12856,12 @@ function vu(e, t, n, r = 8192) {
12855
12856
  e.setPixelRatio(a), e.setSize(o.x, o.y, !1);
12856
12857
  });
12857
12858
  }
12858
- function yu(e, t, n, r = globalThis.document, i = {}) {
12859
+ function xu(e, t, n, r = globalThis.document, i = {}) {
12859
12860
  if (!e || !t || !n || !r?.createElement) return null;
12860
12861
  let a = null;
12861
12862
  try {
12862
12863
  let o = e.getContext?.();
12863
- a = vu(e, o, i.scale, i.maximumDimension), e.render(t, n);
12864
+ a = bu(e, o, i.scale, i.maximumDimension), e.render(t, n);
12864
12865
  let s = e.getContext?.(), c = s?.drawingBufferWidth || e.domElement?.width || 0, l = s?.drawingBufferHeight || e.domElement?.height || 0;
12865
12866
  if (!s?.readPixels || !c || !l) return null;
12866
12867
  let u = new Uint8Array(c * l * 4);
@@ -12874,7 +12875,7 @@ function yu(e, t, n, r = globalThis.document, i = {}) {
12874
12875
  let t = l - e - 1;
12875
12876
  p.data.set(u.subarray(t * m, (t + 1) * m), e * m);
12876
12877
  }
12877
- return s.getContextAttributes?.().premultipliedAlpha !== !1 && _u(p.data), f.putImageData(p, 0, 0), gu(f, c, l, i.background), d;
12878
+ return s.getContextAttributes?.().premultipliedAlpha !== !1 && yu(p.data), f.putImageData(p, 0, 0), vu(f, c, l, i.background), d;
12878
12879
  } catch {
12879
12880
  return null;
12880
12881
  } finally {
@@ -12883,7 +12884,28 @@ function yu(e, t, n, r = globalThis.document, i = {}) {
12883
12884
  } catch {}
12884
12885
  }
12885
12886
  }
12886
- var bu = class extends HTMLElement {
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();
12905
+ }
12906
+ return i;
12907
+ }
12908
+ var wu = class extends HTMLElement {
12887
12909
  static version = $c;
12888
12910
  static get observedAttributes() {
12889
12911
  return [
@@ -12914,11 +12936,11 @@ var bu = class extends HTMLElement {
12914
12936
  return Sl();
12915
12937
  }
12916
12938
  constructor() {
12917
- 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({
12918
12940
  mode: this.getAttribute("focus-mode"),
12919
12941
  effect: this.getAttribute("focus-effect"),
12920
12942
  layout: this.getAttribute("focus-layout")
12921
- }), 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 = () => {
12922
12944
  this.ready && this.modelData && this._build();
12923
12945
  }, this._bindControls(), this._syncFocusToolbar(), this._syncRelationToolbar(), this._syncLabelsToolbar(), this._syncPanelToolbar(), this._syncItemFacingToolbar(), this.resizeObserver = new ResizeObserver(() => this.resize()), this.resizeObserver.observe(this.canvas);
12924
12946
  }
@@ -12926,7 +12948,7 @@ var bu = class extends HTMLElement {
12926
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();
12927
12949
  }
12928
12950
  disconnectedCallback() {
12929
- 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"));
12930
12952
  }
12931
12953
  attributeChangedCallback(e, t, n) {
12932
12954
  if (t !== n) {
@@ -12974,11 +12996,55 @@ var bu = class extends HTMLElement {
12974
12996
  }
12975
12997
  captureFrame(e = {}) {
12976
12998
  let t = e.background === "theme" ? this.theme?.background || jl.background : e.background;
12977
- return yu(this.renderer, this.scene, this.camera, this.ownerDocument, {
12999
+ return xu(this.renderer, this.scene, this.camera, this.ownerDocument, {
12978
13000
  ...e,
12979
13001
  background: t
12980
13002
  });
12981
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
+ }
13047
+ }
12982
13048
  prepareForPrint() {
12983
13049
  if (this._printState) return this;
12984
13050
  let e = this.captureFrame(), t = Object.fromEntries([
@@ -13152,7 +13218,7 @@ var bu = class extends HTMLElement {
13152
13218
  let t = this.modelData?.relationGroups || [], n = this.shadowRoot.querySelector("[data-relation-groups-section]"), r = this.shadowRoot.querySelector("[data-relation-groups]");
13153
13219
  n && (n.hidden = t.length === 0), r && (r.innerHTML = t.map((e) => {
13154
13220
  let t = !this.visibleRelationGroups || this.visibleRelationGroups.has(e.id);
13155
- 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)}"`);
13156
13222
  }).join(""));
13157
13223
  }
13158
13224
  _syncPanelToolbar() {
@@ -13274,7 +13340,7 @@ var bu = class extends HTMLElement {
13274
13340
  }
13275
13341
  _commitModelChange(e, t = {}, n = {}) {
13276
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;
13277
- this.modelData = ql(this.modelData);
13343
+ this.modelData = Yl(this.modelData);
13278
13344
  let o = this._syncInitialContainerState({
13279
13345
  refresh: !1,
13280
13346
  emit: !1,
@@ -13291,7 +13357,7 @@ var bu = class extends HTMLElement {
13291
13357
  }
13292
13358
  updateModel(e = {}, t = {}) {
13293
13359
  if (!e || typeof e != "object" || Array.isArray(e)) throw TypeError("El parche del modelo debe ser un objeto.");
13294
- 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 = {
13295
13361
  ...n,
13296
13362
  ...e,
13297
13363
  palette: e.palette ? {
@@ -13302,11 +13368,11 @@ var bu = class extends HTMLElement {
13302
13368
  entities: Array.isArray(e.entities) ? e.entities : n.entities,
13303
13369
  relations: Array.isArray(e.relations) ? e.relations : n.relations
13304
13370
  };
13305
- 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;
13306
13372
  }
13307
13373
  addEntity(e, t = {}) {
13308
13374
  if (!e || typeof e != "object" || !e.id) throw TypeError("La entidad debe incluir un id.");
13309
- 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}".`);
13310
13376
  if (e.parent && !this.modelData.entities.some((t) => t.id === e.parent)) throw Error(`No existe el contenedor padre "${e.parent}".`);
13311
13377
  return this.modelData.entities = [...this.modelData.entities, { ...e }], this._commitModelChange("entity-add", { entity: this._publicEntity(e.id) }, t);
13312
13378
  }
@@ -13577,7 +13643,7 @@ var bu = class extends HTMLElement {
13577
13643
  this._loading = !0, this._pendingSelection = null;
13578
13644
  try {
13579
13645
  let t = typeof e == "string" ? await fetch(e).then((e) => e.json()) : e;
13580
- 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 = {
13581
13647
  ...this.modelData.palette,
13582
13648
  ...this._pendingPalette
13583
13649
  }, null), this.theme = this.modelData.theme, this._applyTheme(), this._syncInitialContainerState({
@@ -13647,7 +13713,7 @@ var bu = class extends HTMLElement {
13647
13713
  ...e.geometryPalette || {},
13648
13714
  ...e.geometryPaletteOverrides || {}
13649
13715
  };
13650
- 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"));
13651
13717
  }
13652
13718
  }
13653
13719
  }
@@ -13672,7 +13738,7 @@ var bu = class extends HTMLElement {
13672
13738
  ...e.ports || {}
13673
13739
  }, s) {
13674
13740
  try {
13675
- 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 })));
13676
13742
  n.root.scale.multiply(new U().fromArray(e.s)), t.appearanceMaterials = [], n.root.traverse((e) => {
13677
13743
  if (!(e.isMesh || e.isLine || e.isLineSegments || e.isSprite)) return;
13678
13744
  e.userData.node = t;
@@ -13693,7 +13759,7 @@ var bu = class extends HTMLElement {
13693
13759
  entityId: e.id,
13694
13760
  error: r
13695
13761
  } }));
13696
- let i = $l(Ql("box"));
13762
+ let i = tu(eu("box"));
13697
13763
  t.material = new ia({
13698
13764
  color: "#ed8f98",
13699
13765
  roughness: .72,
@@ -13702,8 +13768,8 @@ var bu = class extends HTMLElement {
13702
13768
  }
13703
13769
  t.labelSize = new U().fromArray(e.s);
13704
13770
  } else {
13705
- let n = o === "box" && Number(e.radius) > 0, r = Ql(o, e.radius, e.segments, e.s);
13706
- 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({
13707
13773
  color: a,
13708
13774
  roughness: .72,
13709
13775
  metalness: .06,
@@ -13723,7 +13789,7 @@ var bu = class extends HTMLElement {
13723
13789
  1
13724
13790
  ] : e.s), t.group.add(t.edge);
13725
13791
  }
13726
- t.label = hu(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) => {
13727
13793
  e.userData.node = t;
13728
13794
  }), t.group.add(t.label), this.scene.add(t.group);
13729
13795
  }
@@ -13895,11 +13961,11 @@ var bu = class extends HTMLElement {
13895
13961
  if (!this.modelData) return;
13896
13962
  let e = this.selectedRelationIndex === null ? null : this.relations[this.selectedRelationIndex];
13897
13963
  if (e) {
13898
- 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 }) => {
13899
13965
  let n = r.get(t.group), i = [n?.label || n?.id || "Sin grupo", Pl(t)].join(" · ");
13900
- 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>";
13901
13967
  }).join(""), l = i.length === 1 ? "1 conexión" : `${i.length} conexiones`;
13902
- 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();
13903
13969
  return;
13904
13970
  }
13905
13971
  let t = this.selected;
@@ -13909,11 +13975,11 @@ var bu = class extends HTMLElement {
13909
13975
  }
13910
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;
13911
13977
  for (; o && !a.has(o.id);) a.add(o.id), i.unshift(o), o = o.parent ? this.nodes.get(o.parent) : null;
13912
- 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) => {
13913
- let n = this.relations.indexOf(e), r = e.text ? "<small>" + Ul(e.text) + "</small>" : "";
13914
- 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>";
13915
13981
  }).join("");
13916
- 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", () => {
13917
13983
  this.toggleContainer(t.id, { source: "panel" });
13918
13984
  }), this._applyTheme();
13919
13985
  }
@@ -14011,9 +14077,9 @@ var bu = class extends HTMLElement {
14011
14077
  e.edge?.material && (e.edge.material.opacity = (e === this.selected ? 1 : .65) * t);
14012
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;
14013
14079
  e.label.userData.textOffsetY;
14014
- 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);
14015
14081
  e.label.visible = n;
14016
- 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 ? mu(this.camera.position, g, v) : null;
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;
14017
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;
14018
14084
  else if (wl(e.type)) {
14019
14085
  c.rotation.z = 0, l.rotation.z = 0, c.visible = o ? y === "front" : _, l.visible = o ? y === "back" : !_, u.visible = s && y === "top";
@@ -14067,6 +14133,28 @@ var bu = class extends HTMLElement {
14067
14133
  node: r.object.userData.node
14068
14134
  } : null;
14069
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
+ }
14070
14158
  _bindControls() {
14071
14159
  this.toolbar?.querySelectorAll(".toolbar-menu").forEach((e) => e.addEventListener("toggle", () => {
14072
14160
  e.open && this._closeToolbarMenus(e);
@@ -14082,7 +14170,7 @@ var bu = class extends HTMLElement {
14082
14170
  }, { source: "toolbar" }), n === "focus-hide" && this.setFocusFilter({
14083
14171
  mode: "connected",
14084
14172
  effect: "hide"
14085
- }, { 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();
14086
14174
  }), this.canvas.addEventListener("contextmenu", (e) => e.preventDefault()), this.canvas.addEventListener("pointerdown", (e) => {
14087
14175
  if (e.pointerType !== "touch" && ![
14088
14176
  0,
@@ -14196,11 +14284,11 @@ var bu = class extends HTMLElement {
14196
14284
  }
14197
14285
  _showError(e) {
14198
14286
  let t = this.shadowRoot.querySelector(".viewport"), n = t.querySelector(".error");
14199
- 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>");
14200
14288
  }
14201
14289
  };
14202
- customElements.get("liquidcars-atlas") || customElements.define("liquidcars-atlas", bu);
14290
+ customElements.get("liquidcars-atlas") || customElements.define("liquidcars-atlas", wu);
14203
14291
  //#endregion
14204
- export { $c as ATLAS_VERSION, tl as DEFAULT_RELATION_MARKER, bu as LiquidCarsAtlas, nl as RELATION_DISPLAY_MODES, yu as captureRendererFrame, su as createSvgExtrudeGeometry, xl as getGeometryCatalog, Sl as getGeometryPackCatalog, pu as labelPlacementForAnchor, du as normalizeLabelAnchor, ql as normalizeModel, mu as preferredContainerLabelFace, 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 };
14205
14293
 
14206
14294
  //# sourceMappingURL=liquidcars-atlas.js.map