@broberg/bodymap 0.7.0 → 0.8.0

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.
package/dist/three.cjs CHANGED
@@ -103,10 +103,12 @@ function emitFeedback(outcome, region, opts = {}) {
103
103
  if (opts.haptics === false) return "skipped";
104
104
  return requestVibration(VIBRATION_PATTERNS[outcome], opts.nav);
105
105
  }
106
+ var STAGE_BG = "#0e1424";
106
107
  var defaultUi = {
107
108
  text: "#1e293b",
108
109
  mutedText: "#475569",
109
110
  panelBg: "#fff",
111
+ stageBg: STAGE_BG,
110
112
  border: "#e2e8f0",
111
113
  badgeBg: "#f1f5f9",
112
114
  danger: "#dc2626"
@@ -268,6 +270,14 @@ function seamBlend(nearestSq, secondSq) {
268
270
  if (t >= 1) return 0.5;
269
271
  return t * t * (3 - 2 * t) * 0.5;
270
272
  }
273
+ function seamWeight(seamEnabled, blend) {
274
+ return seamEnabled ? blend : 0;
275
+ }
276
+ function ensureNormals(geo) {
277
+ if (geo.getAttribute("normal")) return false;
278
+ geo.computeVertexNormals();
279
+ return true;
280
+ }
271
281
  var ANCHOR_KEYS = Object.keys(ANCHORS);
272
282
  for (const k of ANCHOR_KEYS) ANCHORS[k][0] = -ANCHORS[k][0];
273
283
  function mergeLabels(locale, overrides) {
@@ -353,6 +363,8 @@ function BodyMap3D(props) {
353
363
  setReadyRef.current = setReady;
354
364
  const seamRef = react.useRef(seam);
355
365
  seamRef.current = seam;
366
+ const stageRef = react.useRef(chrome.stageBg);
367
+ stageRef.current = chrome.stageBg;
356
368
  const [internalFs, setInternalFs] = react.useState(false);
357
369
  const isFullscreen = fullscreenProp ?? internalFs;
358
370
  const setFullscreen = (v) => {
@@ -369,7 +381,7 @@ function BodyMap3D(props) {
369
381
  if (!el) return;
370
382
  let W = el.clientWidth || 520, H = el.clientHeight || 600;
371
383
  const scene = new THREE__namespace.Scene();
372
- scene.background = new THREE__namespace.Color(922660);
384
+ scene.background = new THREE__namespace.Color(stageRef.current);
373
385
  const camera = new THREE__namespace.PerspectiveCamera(32, W / H, 0.1, 100);
374
386
  camera.position.set(0, 1.05, 4.4);
375
387
  let renderer;
@@ -452,7 +464,7 @@ function BodyMap3D(props) {
452
464
  };
453
465
  for (let i = 0; i < vertexRegion.length; i++) {
454
466
  tmp.copy(col(vertexRegion[i]));
455
- const w = seamRef.current ? vertexBlend[i] : 0;
467
+ const w = seamWeight(seamRef.current, vertexBlend[i]);
456
468
  if (w > 0) {
457
469
  tmp2.copy(col(vertexNeighbour[i]));
458
470
  tmp.lerp(tmp2, w);
@@ -462,6 +474,7 @@ function BodyMap3D(props) {
462
474
  colorAttr.needsUpdate = true;
463
475
  };
464
476
  const refresh = () => {
477
+ scene.background = new THREE__namespace.Color(stageRef.current);
465
478
  paint();
466
479
  renderFrame();
467
480
  };
@@ -486,7 +499,7 @@ function BodyMap3D(props) {
486
499
  });
487
500
  if (bodyMesh) {
488
501
  const geo = bodyMesh.geometry;
489
- if (!geo.getAttribute("normal")) geo.computeVertexNormals();
502
+ ensureNormals(geo);
490
503
  const pos = geo.getAttribute("position");
491
504
  const n = pos.count;
492
505
  const cols = new Float32Array(n * 3);
@@ -684,8 +697,23 @@ function BodyMap3D(props) {
684
697
  position: "fixed",
685
698
  inset: 0,
686
699
  zIndex: 2147483e3,
687
- background: chrome.panelBg,
688
- padding: 12,
700
+ // THE STAGE, not the panel. This used to be `chrome.panelBg`,
701
+ // the same field that paints the picker card — so a consumer with
702
+ // a dark canvas got a white void around a dark body in fullscreen,
703
+ // and could not fix it: darkening panelBg hid the 0-10 buttons.
704
+ // One field, two surfaces, opposite needs. (F052.29)
705
+ background: chrome.stageBg,
706
+ // F052.27 — a fixed inset:0 surface in a standalone/Capacitor
707
+ // webview covers the STATUS BAR too, so a control laid out at the
708
+ // top lands on the clock and the battery. Measured by fd-sundhed
709
+ // on a real iPhone: the owner could not read the button or get
710
+ // out, and Escape does not exist on a phone. Every side gets its
711
+ // safe-area inset, bottom included — the home indicator covers
712
+ // content just as effectively.
713
+ paddingTop: "calc(12px + env(safe-area-inset-top))",
714
+ paddingBottom: "calc(12px + env(safe-area-inset-bottom))",
715
+ paddingLeft: "calc(12px + env(safe-area-inset-left))",
716
+ paddingRight: "calc(12px + env(safe-area-inset-right))",
689
717
  display: "flex",
690
718
  flexDirection: "column",
691
719
  overflow: "auto"
@@ -706,12 +734,25 @@ function BodyMap3D(props) {
706
734
  "aria-pressed": isFullscreen,
707
735
  "aria-label": isFullscreen ? UI.collapse ?? "Close" : UI.expand ?? "Expand",
708
736
  onClick: () => setFullscreen(!isFullscreen),
709
- style: { ...btn, color: chrome.text, borderColor: chrome.border, background: chrome.panelBg },
710
- children: isFullscreen ? UI.collapse ?? "Close" : UI.expand ?? "Expand"
737
+ style: {
738
+ ...btn,
739
+ color: chrome.text,
740
+ borderColor: chrome.border,
741
+ background: chrome.panelBg,
742
+ ...isFullscreen ? { width: 40, height: 40, padding: 0, fontSize: 22, lineHeight: 1 } : null
743
+ },
744
+ children: isFullscreen ? "\xD7" : UI.expand ?? "Expand"
711
745
  }
712
746
  ) }),
713
747
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 18, alignItems: "flex-start", flexWrap: "wrap", ...isFullscreen ? { flex: "1 1 auto", minHeight: 0 } : null }, children: [
714
- unsupported ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "bodymap3d-unsupported", style: { flex: "1 1 520px", minWidth: 320, height: canvasH, borderRadius: 16, background: "#0e1424", color: "#cbd5e1", display: "flex", alignItems: "center", justifyContent: "center", padding: 24, textAlign: "center", fontSize: 14 }, children: "3D kr\xE6ver WebGL, som ikke er tilg\xE6ngeligt her." }) : /* @__PURE__ */ jsxRuntime.jsx(
748
+ unsupported ? /* @__PURE__ */ jsxRuntime.jsx(
749
+ "div",
750
+ {
751
+ "data-testid": "bodymap3d-unsupported",
752
+ style: { flex: "1 1 520px", minWidth: 320, height: canvasH, borderRadius: 16, background: chrome.panelBg, color: chrome.mutedText, border: `1px solid ${chrome.border}`, display: "flex", alignItems: "center", justifyContent: "center", padding: 24, textAlign: "center", fontSize: 14 },
753
+ children: "3D kr\xE6ver WebGL, som ikke er tilg\xE6ngeligt her."
754
+ }
755
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
715
756
  "div",
716
757
  {
717
758
  ref: mountRef,
@@ -726,7 +767,7 @@ function BodyMap3D(props) {
726
767
  minHeight: isFullscreen ? 0 : void 0,
727
768
  borderRadius: 16,
728
769
  overflow: "hidden",
729
- background: "#0e1424",
770
+ background: chrome.stageBg,
730
771
  touchAction: "none"
731
772
  }
732
773
  }
@@ -763,7 +804,9 @@ function BodyMap3D(props) {
763
804
  }
764
805
 
765
806
  exports.BodyMap3D = BodyMap3D;
807
+ exports.ensureNormals = ensureNormals;
766
808
  exports.seamBlend = seamBlend;
809
+ exports.seamWeight = seamWeight;
767
810
  exports.serializeReport = serializeReport;
768
811
  //# sourceMappingURL=three.cjs.map
769
812
  //# sourceMappingURL=three.cjs.map