react-muscle-stats 1.0.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 +73 -0
- package/dist/components/MuscleRadar/index.cjs.js +84 -0
- package/dist/components/MuscleRadar/index.cjs.js.map +1 -0
- package/dist/components/MuscleRadar/index.d.ts +43 -0
- package/dist/components/MuscleRadar/index.d.ts.map +1 -0
- package/dist/components/MuscleRadar/index.es.js +83 -0
- package/dist/components/MuscleRadar/index.es.js.map +1 -0
- package/dist/components/MuscleRadar/normalization.cjs.js +100 -0
- package/dist/components/MuscleRadar/normalization.cjs.js.map +1 -0
- package/dist/components/MuscleRadar/normalization.d.ts +21 -0
- package/dist/components/MuscleRadar/normalization.d.ts.map +1 -0
- package/dist/components/MuscleRadar/normalization.es.js +99 -0
- package/dist/components/MuscleRadar/normalization.es.js.map +1 -0
- package/dist/components/MuscleVisualizer/index.cjs.js +49 -0
- package/dist/components/MuscleVisualizer/index.cjs.js.map +1 -0
- package/dist/components/MuscleVisualizer/index.d.ts +32 -0
- package/dist/components/MuscleVisualizer/index.d.ts.map +1 -0
- package/dist/components/MuscleVisualizer/index.es.js +48 -0
- package/dist/components/MuscleVisualizer/index.es.js.map +1 -0
- package/dist/components/MuscleVisualizer/svgs.cjs.js +2274 -0
- package/dist/components/MuscleVisualizer/svgs.cjs.js.map +1 -0
- package/dist/components/MuscleVisualizer/svgs.d.ts +2 -0
- package/dist/components/MuscleVisualizer/svgs.d.ts.map +1 -0
- package/dist/components/MuscleVisualizer/svgs.es.js +2274 -0
- package/dist/components/MuscleVisualizer/svgs.es.js.map +1 -0
- package/dist/components/OneRepMaxChart/index.cjs.js +132 -0
- package/dist/components/OneRepMaxChart/index.cjs.js.map +1 -0
- package/dist/components/OneRepMaxChart/index.d.ts +30 -0
- package/dist/components/OneRepMaxChart/index.d.ts.map +1 -0
- package/dist/components/OneRepMaxChart/index.es.js +127 -0
- package/dist/components/OneRepMaxChart/index.es.js.map +1 -0
- package/dist/components/VolumeChart/index.cjs.js +155 -0
- package/dist/components/VolumeChart/index.cjs.js.map +1 -0
- package/dist/components/VolumeChart/index.d.ts +30 -0
- package/dist/components/VolumeChart/index.d.ts.map +1 -0
- package/dist/components/VolumeChart/index.es.js +150 -0
- package/dist/components/VolumeChart/index.es.js.map +1 -0
- package/dist/index.cjs.js +16 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.es.js +8 -0
- package/dist/utils/math.cjs.js +16 -0
- package/dist/utils/math.cjs.js.map +1 -0
- package/dist/utils/math.d.ts +11 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.es.js +16 -0
- package/dist/utils/math.es.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MUSCLE_SVGS } from "./svgs.es.js";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
* Renders an interactive SVG body diagram.
|
|
6
|
+
*
|
|
7
|
+
* Muscle groups inside the SVG carry `class="muscle"` and can be
|
|
8
|
+
* highlighted by passing their `id` values through the `activeMuscles`
|
|
9
|
+
* prop. The component uses `dangerouslySetInnerHTML` to inject the SVG
|
|
10
|
+
* markup and `useEffect` to imperatively toggle the `active` class on
|
|
11
|
+
* the matching `<g>` elements.
|
|
12
|
+
*/
|
|
13
|
+
function MuscleVisualizer({ gender, view = "front", activeMuscles = [], onMuscleClick, style, className, width = "100%", height = "auto" }) {
|
|
14
|
+
const containerRef = useRef(null);
|
|
15
|
+
const svgKey = `${gender} ${view}`;
|
|
16
|
+
const svgMarkup = MUSCLE_SVGS[svgKey] ?? "";
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const container = containerRef.current;
|
|
19
|
+
if (!container) return;
|
|
20
|
+
container.querySelectorAll("g.muscle").forEach((g) => {
|
|
21
|
+
if (activeMuscles.includes(g.id)) g.classList.add("active");
|
|
22
|
+
else g.classList.remove("active");
|
|
23
|
+
});
|
|
24
|
+
}, [activeMuscles, svgKey]);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const container = containerRef.current;
|
|
27
|
+
if (!container || !onMuscleClick) return;
|
|
28
|
+
const handler = (e) => {
|
|
29
|
+
const target = e.target.closest("g.muscle");
|
|
30
|
+
if (target?.id) onMuscleClick(target.id);
|
|
31
|
+
};
|
|
32
|
+
container.addEventListener("click", handler);
|
|
33
|
+
return () => container.removeEventListener("click", handler);
|
|
34
|
+
}, [onMuscleClick, svgKey]);
|
|
35
|
+
return /* @__PURE__ */ jsx("div", {
|
|
36
|
+
ref: containerRef,
|
|
37
|
+
className,
|
|
38
|
+
style: {
|
|
39
|
+
width,
|
|
40
|
+
height,
|
|
41
|
+
...style
|
|
42
|
+
},
|
|
43
|
+
dangerouslySetInnerHTML: { __html: svgMarkup }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export { MuscleVisualizer };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=index.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.es.js","names":[],"sources":["../../../src/components/MuscleVisualizer/index.tsx"],"sourcesContent":["import { useEffect, useRef, type CSSProperties } from 'react';\r\nimport { MUSCLE_SVGS } from './svgs';\r\n\r\nexport type Gender = 'male' | 'female';\r\nexport type View = 'front' | 'back';\r\n\r\nexport interface MuscleVisualizerProps {\r\n /** Gender to display – determines the body silhouette. */\r\n gender: Gender;\r\n /** Which side of the body to show. */\r\n view?: View;\r\n /** Muscle IDs that should be highlighted (given the `.active` CSS class). */\r\n activeMuscles?: string[];\r\n /** Optional callback fired when a muscle group `<g>` element is clicked. */\r\n onMuscleClick?: (muscleId: string) => void;\r\n /** Optional inline styles applied to the wrapper `<div>`. */\r\n style?: CSSProperties;\r\n /** Optional CSS class name for the wrapper `<div>`. */\r\n className?: string;\r\n /** Width applied to the SVG wrapper (default: `'100%'`). */\r\n width?: string | number;\r\n /** Height applied to the SVG wrapper (default: `'auto'`). */\r\n height?: string | number;\r\n}\r\n\r\n/**\r\n * Renders an interactive SVG body diagram.\r\n *\r\n * Muscle groups inside the SVG carry `class=\"muscle\"` and can be\r\n * highlighted by passing their `id` values through the `activeMuscles`\r\n * prop. The component uses `dangerouslySetInnerHTML` to inject the SVG\r\n * markup and `useEffect` to imperatively toggle the `active` class on\r\n * the matching `<g>` elements.\r\n */\r\nexport function MuscleVisualizer({\r\n gender,\r\n view = 'front',\r\n activeMuscles = [],\r\n onMuscleClick,\r\n style,\r\n className,\r\n width = '100%',\r\n height = 'auto',\r\n}: MuscleVisualizerProps) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n\r\n const svgKey = `${gender} ${view}` as keyof typeof MUSCLE_SVGS;\r\n const svgMarkup = MUSCLE_SVGS[svgKey] ?? '';\r\n\r\n // Toggle the `active` class on `<g class=\"muscle\">` elements whose\r\n // `id` is listed in `activeMuscles`.\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n\r\n const muscleGroups = container.querySelectorAll<SVGGElement>('g.muscle');\r\n muscleGroups.forEach((g) => {\r\n if (activeMuscles.includes(g.id)) {\r\n g.classList.add('active');\r\n } else {\r\n g.classList.remove('active');\r\n }\r\n });\r\n }, [activeMuscles, svgKey]);\r\n\r\n // Attach click listeners to every `<g class=\"muscle\">` element.\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container || !onMuscleClick) return;\r\n\r\n const handler = (e: Event) => {\r\n const target = (e.target as SVGElement).closest<SVGGElement>('g.muscle');\r\n if (target?.id) {\r\n onMuscleClick(target.id);\r\n }\r\n };\r\n\r\n container.addEventListener('click', handler);\r\n return () => container.removeEventListener('click', handler);\r\n }, [onMuscleClick, svgKey]);\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={className}\r\n style={{ width, height, ...style }}\r\n dangerouslySetInnerHTML={{ __html: svgMarkup }}\r\n />\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAkCA,SAAgB,iBAAiB,EAC/B,QACA,OAAO,SACP,gBAAgB,EAAE,EAClB,eACA,OACA,WACA,QAAQ,QACR,SAAS,UACe;CACxB,MAAM,eAAe,OAAuB,KAAK;CAEjD,MAAM,SAAS,GAAG,OAAO,GAAG;CAC5B,MAAM,YAAY,YAAY,WAAW;AAIzC,iBAAgB;EACd,MAAM,YAAY,aAAa;AAC/B,MAAI,CAAC,UAAW;AAEK,YAAU,iBAA8B,WAAW,CAC3D,SAAS,MAAM;AAC1B,OAAI,cAAc,SAAS,EAAE,GAAG,CAC9B,GAAE,UAAU,IAAI,SAAS;OAEzB,GAAE,UAAU,OAAO,SAAS;IAE9B;IACD,CAAC,eAAe,OAAO,CAAC;AAG3B,iBAAgB;EACd,MAAM,YAAY,aAAa;AAC/B,MAAI,CAAC,aAAa,CAAC,cAAe;EAElC,MAAM,WAAW,MAAa;GAC5B,MAAM,SAAU,EAAE,OAAsB,QAAqB,WAAW;AACxE,OAAI,QAAQ,GACV,eAAc,OAAO,GAAG;;AAI5B,YAAU,iBAAiB,SAAS,QAAQ;AAC5C,eAAa,UAAU,oBAAoB,SAAS,QAAQ;IAC3D,CAAC,eAAe,OAAO,CAAC;AAE3B,QACE,oBAAC,OAAD;EACE,KAAK;EACM;EACX,OAAO;GAAE;GAAO;GAAQ,GAAG;GAAO;EAClC,yBAAyB,EAAE,QAAQ,WAAW;EAC9C,CAAA"}
|