@broberg/bodymap 0.8.0 → 0.10.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/README.md +59 -0
- package/dist/index.cjs +10 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +3 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +13 -0
- package/dist/react.d.ts +13 -0
- package/dist/react.js +3 -3
- package/dist/react.js.map +1 -1
- package/dist/three.cjs +65 -16
- package/dist/three.cjs.map +1 -1
- package/dist/three.d.cts +42 -1
- package/dist/three.d.ts +42 -1
- package/dist/three.js +65 -16
- package/dist/three.js.map +1 -1
- package/package.json +1 -1
package/dist/three.cjs
CHANGED
|
@@ -111,7 +111,16 @@ var defaultUi = {
|
|
|
111
111
|
stageBg: STAGE_BG,
|
|
112
112
|
border: "#e2e8f0",
|
|
113
113
|
badgeBg: "#f1f5f9",
|
|
114
|
-
danger: "#dc2626"
|
|
114
|
+
danger: "#dc2626",
|
|
115
|
+
dangerBorder: "#f6c9c9",
|
|
116
|
+
// F052.30 — was #0e8f8a, which measured 3.95:1 against white. AA needs 4.5,
|
|
117
|
+
// and this is the SELECTED intensity button on a surface where AA is a legal
|
|
118
|
+
// duty. It shipped from 0.2.0 and no check could see it: the colour was an
|
|
119
|
+
// inline literal, and the F052.19 contrast sweep only read this object.
|
|
120
|
+
// #0c7d77 is the same teal a shade deeper — 4.98:1, with headroom rather than
|
|
121
|
+
// sitting on the 4.5 boundary where any later tweak reopens it.
|
|
122
|
+
accent: "#0c7d77",
|
|
123
|
+
accentText: "#fff"
|
|
115
124
|
};
|
|
116
125
|
function uiColors(palette) {
|
|
117
126
|
return { ...defaultUi, ...palette?.ui ?? {} };
|
|
@@ -225,8 +234,8 @@ var LABELS_EN = {
|
|
|
225
234
|
zoomOut: "Zoom out",
|
|
226
235
|
zoomReset: "Reset zoom"
|
|
227
236
|
};
|
|
228
|
-
var UI_DA = { male: "Mand", female: "Kvinde", hoverHint: "
|
|
229
|
-
var UI_EN = { male: "Male", female: "Female", hoverHint: "
|
|
237
|
+
var UI_DA = { male: "Mand", female: "Kvinde", hoverHint: "Tr\xE6k for at dreje \xB7 tryk en kropsdel for at markere smerte.", expand: "Vis stor", collapse: "Luk stor visning" };
|
|
238
|
+
var UI_EN = { male: "Male", female: "Female", hoverHint: "Drag to rotate \xB7 tap a body part to mark pain.", expand: "Expand", collapse: "Close" };
|
|
230
239
|
var ANCHORS = {
|
|
231
240
|
head: [0, 1.79, 0.02],
|
|
232
241
|
neck: [0, 1.57, 0],
|
|
@@ -298,8 +307,20 @@ function webglAvailable() {
|
|
|
298
307
|
return false;
|
|
299
308
|
}
|
|
300
309
|
}
|
|
301
|
-
var btn =
|
|
302
|
-
|
|
310
|
+
var btn = (c) => ({
|
|
311
|
+
font: "inherit",
|
|
312
|
+
cursor: "pointer",
|
|
313
|
+
borderRadius: 8,
|
|
314
|
+
border: `1px solid ${c.border}`,
|
|
315
|
+
background: c.panelBg,
|
|
316
|
+
padding: "6px 9px"
|
|
317
|
+
});
|
|
318
|
+
var seg = (c, on) => ({
|
|
319
|
+
...btn(c),
|
|
320
|
+
background: on ? c.accent : c.panelBg,
|
|
321
|
+
color: on ? c.accentText : c.text,
|
|
322
|
+
fontWeight: 600
|
|
323
|
+
});
|
|
303
324
|
function BodyMap3D(props) {
|
|
304
325
|
const {
|
|
305
326
|
models,
|
|
@@ -321,6 +342,7 @@ function BodyMap3D(props) {
|
|
|
321
342
|
onFeedback,
|
|
322
343
|
haptics,
|
|
323
344
|
seam = false,
|
|
345
|
+
hint,
|
|
324
346
|
fullscreen: fullscreenProp,
|
|
325
347
|
onFullscreenChange,
|
|
326
348
|
showFullscreenButton = true,
|
|
@@ -680,7 +702,9 @@ function BodyMap3D(props) {
|
|
|
680
702
|
const region = selected ? REGIONS.find((r) => r.key === selected) : null;
|
|
681
703
|
const current = selected ? pointOf(selected) : void 0;
|
|
682
704
|
const anySelectable = REGIONS.some((r) => isSelectable(r.key, config ?? {}));
|
|
683
|
-
const showEmptyHint = anySelectable || ui?.hoverHint !== void 0;
|
|
705
|
+
const showEmptyHint = hint === false ? false : anySelectable || ui?.hoverHint !== void 0;
|
|
706
|
+
const hintText = (hint ? hint.text : void 0) ?? UI.hoverHint;
|
|
707
|
+
const hintAtStage = isFullscreen && !!hint && hint.placement === "stage-bottom";
|
|
684
708
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
685
709
|
"div",
|
|
686
710
|
{
|
|
@@ -689,7 +713,7 @@ function BodyMap3D(props) {
|
|
|
689
713
|
"data-fullscreen": isFullscreen ? "true" : void 0,
|
|
690
714
|
style: {
|
|
691
715
|
fontFamily: "system-ui, sans-serif",
|
|
692
|
-
color:
|
|
716
|
+
color: chrome.text,
|
|
693
717
|
// A viewport fill, not the Fullscreen API — see the `fullscreen` prop.
|
|
694
718
|
// `fixed`+`inset:0` behaves the same on iOS Safari, where element
|
|
695
719
|
// fullscreen does not exist at all, as it does everywhere else.
|
|
@@ -721,8 +745,8 @@ function BodyMap3D(props) {
|
|
|
721
745
|
},
|
|
722
746
|
children: [
|
|
723
747
|
showSexToggle && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginBottom: 12, fontSize: 13 }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
724
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-sex-male", onClick: () => changeSex("male"), style: seg(sex === "male"), children: UI.male }),
|
|
725
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-sex-female", onClick: () => changeSex("female"), style: seg(sex === "female"), children: UI.female })
|
|
748
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-sex-male", onClick: () => changeSex("male"), style: seg(chrome, sex === "male"), children: UI.male }),
|
|
749
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-sex-female", onClick: () => changeSex("female"), style: seg(chrome, sex === "female"), children: UI.female })
|
|
726
750
|
] }) }),
|
|
727
751
|
/* @__PURE__ */ jsxRuntime.jsx("span", { ref: loadedRef, "data-testid": "bodymap3d-loaded", style: { display: "none" } }),
|
|
728
752
|
ready && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "bodymap3d-ready", style: { position: "absolute", width: 1, height: 1, opacity: 0, pointerEvents: "none" } }),
|
|
@@ -735,7 +759,7 @@ function BodyMap3D(props) {
|
|
|
735
759
|
"aria-label": isFullscreen ? UI.collapse ?? "Close" : UI.expand ?? "Expand",
|
|
736
760
|
onClick: () => setFullscreen(!isFullscreen),
|
|
737
761
|
style: {
|
|
738
|
-
...btn,
|
|
762
|
+
...btn(chrome),
|
|
739
763
|
color: chrome.text,
|
|
740
764
|
borderColor: chrome.border,
|
|
741
765
|
background: chrome.panelBg,
|
|
@@ -786,18 +810,43 @@ function BodyMap3D(props) {
|
|
|
786
810
|
"data-testid": "bodymap3d-close",
|
|
787
811
|
"aria-label": L.close,
|
|
788
812
|
onClick: () => setSelected(null),
|
|
789
|
-
style: { ...btn, width: 32, height: 32, padding: 0, fontSize: 20, lineHeight: 1, color: chrome.mutedText, borderColor: chrome.border, background: chrome.panelBg },
|
|
813
|
+
style: { ...btn(chrome), width: 32, height: 32, padding: 0, fontSize: 20, lineHeight: 1, color: chrome.mutedText, borderColor: chrome.border, background: chrome.panelBg },
|
|
790
814
|
children: "\xD7"
|
|
791
815
|
}
|
|
792
816
|
)
|
|
793
817
|
] }),
|
|
794
818
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, letterSpacing: ".06em", textTransform: "uppercase", color: chrome.mutedText, marginBottom: 7 }, children: L.intensity }),
|
|
795
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 12 }, children: Array.from({ length: 11 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": `bodymap3d-intensity-${i}`, onClick: () => setPain(region.key, i, current?.type), style: { ...btn, display: "inline-flex", alignItems: "center", justifyContent: "center", minWidth: 30, height: 30, padding: 0, background: current?.intensity === i ?
|
|
819
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 12 }, children: Array.from({ length: 11 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": `bodymap3d-intensity-${i}`, onClick: () => setPain(region.key, i, current?.type), style: { ...btn(chrome), display: "inline-flex", alignItems: "center", justifyContent: "center", minWidth: 30, height: 30, padding: 0, background: current?.intensity === i ? chrome.accent : chrome.panelBg, color: current?.intensity === i ? chrome.accentText : chrome.text }, children: i }, i)) }),
|
|
796
820
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, letterSpacing: ".06em", textTransform: "uppercase", color: chrome.mutedText, marginBottom: 7 }, children: L.quality }),
|
|
797
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 14 }, children: PAIN_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": `bodymap3d-type-${t}`, onClick: () => setPain(region.key, current?.intensity ?? 5, t), style: { ...btn, borderRadius: 999, padding: "6px 12px", background: current?.type === t ?
|
|
798
|
-
current && /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-remove", onClick: () => removePain(region.key), style: { ...btn, color: chrome.danger, borderColor:
|
|
799
|
-
] }) : showEmptyHint ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "bodymap3d-empty", style: { border: `1px solid ${chrome.border}`, borderRadius: 14, padding: 16, background: chrome.panelBg, color: chrome.mutedText, fontSize: 13.5 }, children:
|
|
800
|
-
] })
|
|
821
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 14 }, children: PAIN_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": `bodymap3d-type-${t}`, onClick: () => setPain(region.key, current?.intensity ?? 5, t), style: { ...btn(chrome), borderRadius: 999, padding: "6px 12px", background: current?.type === t ? chrome.text : chrome.panelBg, color: current?.type === t ? chrome.panelBg : chrome.mutedText }, children: L.qualities[t] ?? t }, t)) }),
|
|
822
|
+
current && /* @__PURE__ */ jsxRuntime.jsx("button", { "data-testid": "bodymap3d-remove", onClick: () => removePain(region.key), style: { ...btn(chrome), color: chrome.danger, borderColor: chrome.dangerBorder }, children: L.remove })
|
|
823
|
+
] }) : showEmptyHint && !hintAtStage ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "bodymap3d-empty", style: { border: `1px solid ${chrome.border}`, borderRadius: 14, padding: 16, background: chrome.panelBg, color: chrome.mutedText, fontSize: 13.5 }, children: hintText }) : null })
|
|
824
|
+
] }),
|
|
825
|
+
showEmptyHint && hintAtStage && /* F052.31 — pinned INSIDE the fullscreen surface, not in the column that
|
|
826
|
+
wraps beneath a full-height canvas. That wrap is what put the note at
|
|
827
|
+
858-912 in an 852px window on a real iPhone: entirely offscreen, and
|
|
828
|
+
it reads as a bug in the consumer's app rather than in ours.
|
|
829
|
+
The bottom inset clears the home indicator, exactly as the exit
|
|
830
|
+
control's does (F052.27). */
|
|
831
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
832
|
+
"div",
|
|
833
|
+
{
|
|
834
|
+
"data-testid": "bodymap3d-empty",
|
|
835
|
+
"data-placement": "stage-bottom",
|
|
836
|
+
style: {
|
|
837
|
+
flex: "0 0 auto",
|
|
838
|
+
marginTop: 12,
|
|
839
|
+
marginBottom: "env(safe-area-inset-bottom)",
|
|
840
|
+
border: `1px solid ${chrome.border}`,
|
|
841
|
+
borderRadius: 14,
|
|
842
|
+
padding: 16,
|
|
843
|
+
background: chrome.panelBg,
|
|
844
|
+
color: chrome.mutedText,
|
|
845
|
+
fontSize: 13.5
|
|
846
|
+
},
|
|
847
|
+
children: hintText
|
|
848
|
+
}
|
|
849
|
+
)
|
|
801
850
|
]
|
|
802
851
|
}
|
|
803
852
|
);
|