@titan-design/react-ui 0.2.6 → 0.3.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.
Files changed (191) hide show
  1. package/dist/bodymap-BhG55xHM.d.mts +318 -0
  2. package/dist/bodymap-BhG55xHM.d.ts +318 -0
  3. package/dist/bodymap.d.mts +3 -0
  4. package/dist/bodymap.d.ts +3 -0
  5. package/dist/bodymap.js +2670 -0
  6. package/dist/bodymap.js.map +1 -0
  7. package/dist/bodymap.mjs +1101 -0
  8. package/dist/bodymap.mjs.map +1 -0
  9. package/dist/{chunk-UXVRPOME.mjs → chunk-7XPB4NAO.mjs} +125 -785
  10. package/dist/chunk-7XPB4NAO.mjs.map +1 -0
  11. package/dist/chunk-P7TSQUN6.mjs +846 -0
  12. package/dist/chunk-P7TSQUN6.mjs.map +1 -0
  13. package/dist/chunk-TOD2WQBG.mjs +1048 -0
  14. package/dist/chunk-TOD2WQBG.mjs.map +1 -0
  15. package/dist/index.d.mts +1131 -4
  16. package/dist/index.d.ts +1131 -4
  17. package/dist/index.js +6396 -225
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +5572 -641
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/theme/index.d.mts +317 -1
  22. package/dist/theme/index.d.ts +317 -1
  23. package/dist/theme/index.js +185 -2
  24. package/dist/theme/index.js.map +1 -1
  25. package/dist/theme/index.mjs +2 -1
  26. package/dist/theme/tokens-css.d.mts +20 -0
  27. package/dist/theme/tokens-css.d.ts +20 -0
  28. package/dist/theme/tokens-css.js +598 -0
  29. package/dist/theme/tokens-css.js.map +1 -0
  30. package/dist/theme/tokens-css.mjs +24 -0
  31. package/dist/theme/tokens-css.mjs.map +1 -0
  32. package/package.json +25 -5
  33. package/src/bodymap.ts +37 -0
  34. package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
  35. package/src/components/custom/Gauge/Gauge.stories.tsx +45 -0
  36. package/src/components/custom/Gauge/Gauge.test.tsx +71 -0
  37. package/src/components/custom/Gauge/Gauge.tsx +167 -0
  38. package/src/components/custom/Gauge/index.ts +2 -0
  39. package/src/components/custom/Scatter/Scatter.stories.tsx +85 -0
  40. package/src/components/custom/Scatter/Scatter.test.tsx +96 -0
  41. package/src/components/custom/Scatter/Scatter.tsx +260 -0
  42. package/src/components/custom/Scatter/index.ts +2 -0
  43. package/src/components/custom/Sidebar/Sidebar.tsx +1 -1
  44. package/src/components/custom/Table/Table.test.tsx +27 -0
  45. package/src/components/custom/Table/Table.tsx +33 -17
  46. package/src/components/custom/Treemap/Treemap.stories.tsx +60 -0
  47. package/src/components/custom/Treemap/Treemap.test.tsx +67 -0
  48. package/src/components/custom/Treemap/Treemap.tsx +192 -0
  49. package/src/components/custom/Treemap/index.ts +2 -0
  50. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +118 -0
  51. package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +171 -0
  52. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +447 -0
  53. package/src/components/custom/Workout/BaseBadge.stories.tsx +75 -0
  54. package/src/components/custom/Workout/BaseBadge.test.tsx +102 -0
  55. package/src/components/custom/Workout/BaseBadge.tsx +113 -0
  56. package/src/components/custom/Workout/BodyMap.stories.tsx +121 -0
  57. package/src/components/custom/Workout/BodyMap.test.tsx +124 -0
  58. package/src/components/custom/Workout/BodyMap.tsx +347 -0
  59. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +171 -0
  60. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +225 -0
  61. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +477 -0
  62. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +125 -0
  63. package/src/components/custom/Workout/CapacityBandChart.test.tsx +193 -0
  64. package/src/components/custom/Workout/CapacityBandChart.tsx +493 -0
  65. package/src/components/custom/Workout/DeviationBar.stories.tsx +58 -0
  66. package/src/components/custom/Workout/DeviationBar.test.tsx +86 -0
  67. package/src/components/custom/Workout/DeviationBar.tsx +78 -0
  68. package/src/components/custom/Workout/ExerciseCard.stories.tsx +186 -0
  69. package/src/components/custom/Workout/ExerciseCard.test.tsx +343 -0
  70. package/src/components/custom/Workout/ExerciseCard.tsx +442 -0
  71. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +225 -0
  72. package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +128 -0
  73. package/src/components/custom/Workout/ExerciseDetailPage.tsx +630 -0
  74. package/src/components/custom/Workout/InputBar.stories.tsx +75 -0
  75. package/src/components/custom/Workout/InputBar.test.tsx +116 -0
  76. package/src/components/custom/Workout/InputBar.tsx +162 -0
  77. package/src/components/custom/Workout/IntensityBar.stories.tsx +60 -0
  78. package/src/components/custom/Workout/IntensityBar.test.tsx +113 -0
  79. package/src/components/custom/Workout/IntensityBar.tsx +166 -0
  80. package/src/components/custom/Workout/MesoCard.stories.tsx +152 -0
  81. package/src/components/custom/Workout/MesoCard.test.tsx +170 -0
  82. package/src/components/custom/Workout/MesoCard.tsx +237 -0
  83. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +85 -0
  84. package/src/components/custom/Workout/MesoProgressBar.test.tsx +153 -0
  85. package/src/components/custom/Workout/MesoProgressBar.tsx +165 -0
  86. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +126 -0
  87. package/src/components/custom/Workout/MesoStatusCard.test.tsx +209 -0
  88. package/src/components/custom/Workout/MesoStatusCard.tsx +456 -0
  89. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +118 -0
  90. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +91 -0
  91. package/src/components/custom/Workout/MuscleGroupChip.tsx +92 -0
  92. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +94 -0
  93. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +83 -0
  94. package/src/components/custom/Workout/PlaceholderStrip.tsx +90 -0
  95. package/src/components/custom/Workout/PrBadge.stories.tsx +105 -0
  96. package/src/components/custom/Workout/PrBadge.test.tsx +111 -0
  97. package/src/components/custom/Workout/PrBadge.tsx +103 -0
  98. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +116 -0
  99. package/src/components/custom/Workout/PrHistoryModal.test.tsx +161 -0
  100. package/src/components/custom/Workout/PrHistoryModal.tsx +244 -0
  101. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +257 -0
  102. package/src/components/custom/Workout/ProgramPlanningPage.test.tsx +142 -0
  103. package/src/components/custom/Workout/ProgramPlanningPage.tsx +422 -0
  104. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +126 -0
  105. package/src/components/custom/Workout/ReadinessCheck.test.tsx +181 -0
  106. package/src/components/custom/Workout/ReadinessCheck.tsx +265 -0
  107. package/src/components/custom/Workout/RestTimer.test.tsx +10 -0
  108. package/src/components/custom/Workout/RestTimer.tsx +15 -11
  109. package/src/components/custom/Workout/SetRow.stories.tsx +165 -0
  110. package/src/components/custom/Workout/SetRow.test.tsx +222 -0
  111. package/src/components/custom/Workout/SetRow.tsx +247 -0
  112. package/src/components/custom/Workout/Sparkline.stories.tsx +125 -0
  113. package/src/components/custom/Workout/Sparkline.test.tsx +113 -0
  114. package/src/components/custom/Workout/Sparkline.tsx +188 -0
  115. package/src/components/custom/Workout/StatusDot.stories.tsx +150 -0
  116. package/src/components/custom/Workout/StatusDot.test.tsx +165 -0
  117. package/src/components/custom/Workout/StatusDot.tsx +160 -0
  118. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +130 -0
  119. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +217 -0
  120. package/src/components/custom/Workout/StrengthTrendChart.tsx +628 -0
  121. package/src/components/custom/Workout/SupersetWrapper.tsx +1 -2
  122. package/src/components/custom/Workout/TempoDisplay.stories.tsx +66 -0
  123. package/src/components/custom/Workout/TempoDisplay.test.tsx +90 -0
  124. package/src/components/custom/Workout/TempoDisplay.tsx +209 -0
  125. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +212 -0
  126. package/src/components/custom/Workout/TrainingStatusPage.test.tsx +131 -0
  127. package/src/components/custom/Workout/TrainingStatusPage.tsx +321 -0
  128. package/src/components/custom/Workout/VelocityStrip.stories.tsx +125 -0
  129. package/src/components/custom/Workout/VelocityStrip.test.tsx +244 -0
  130. package/src/components/custom/Workout/VelocityStrip.tsx +288 -0
  131. package/src/components/custom/Workout/WeekRow.stories.tsx +121 -0
  132. package/src/components/custom/Workout/WeekRow.test.tsx +117 -0
  133. package/src/components/custom/Workout/WeekRow.tsx +140 -0
  134. package/src/components/custom/Workout/WeightBadge.stories.tsx +87 -0
  135. package/src/components/custom/Workout/WeightBadge.test.tsx +164 -0
  136. package/src/components/custom/Workout/WeightBadge.tsx +113 -0
  137. package/src/components/custom/Workout/WorkoutCard.stories.tsx +135 -0
  138. package/src/components/custom/Workout/WorkoutCard.test.tsx +172 -0
  139. package/src/components/custom/Workout/WorkoutCard.tsx +228 -0
  140. package/src/components/custom/Workout/WorkoutPill.stories.tsx +63 -0
  141. package/src/components/custom/Workout/WorkoutPill.test.tsx +153 -0
  142. package/src/components/custom/Workout/WorkoutPill.tsx +177 -0
  143. package/src/components/custom/Workout/index.ts +152 -0
  144. package/src/components/custom/Workout/muscleTaxonomy.ts +252 -0
  145. package/src/components/custom/index.ts +3 -0
  146. package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
  147. package/src/components/custom/stepper/Stepper.tsx +2 -2
  148. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
  149. package/src/components/ui/autocomplete/Autocomplete.tsx +1 -1
  150. package/src/components/ui/card/Card.tsx +1 -1
  151. package/src/components/ui/checkbox/Checkbox.tsx +1 -1
  152. package/src/components/ui/collapse/Collapse.tsx +1 -1
  153. package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
  154. package/src/components/ui/drawer/Drawer.tsx +3 -3
  155. package/src/components/ui/form-field/FormField.tsx +1 -1
  156. package/src/components/ui/help-tip/HelpTip.tsx +1 -1
  157. package/src/components/ui/menu/Menu.tsx +2 -2
  158. package/src/components/ui/pill/Pill.tsx +1 -1
  159. package/src/components/ui/popover/Popover.stories.tsx +2 -2
  160. package/src/components/ui/popover/Popover.tsx +1 -1
  161. package/src/components/ui/radio/Radio.stories.tsx +1 -1
  162. package/src/components/ui/section/Section.stories.tsx +4 -4
  163. package/src/components/ui/select/Select.tsx +1 -1
  164. package/src/components/ui/stack/Stack.stories.tsx +4 -4
  165. package/src/components/ui/tabs/Tabs.tsx +2 -2
  166. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +1 -1
  167. package/src/components/ui/toolbar-button/ToolbarButton.tsx +1 -1
  168. package/src/examples/react-hook-form/ControlledFields.tsx +171 -0
  169. package/src/examples/react-hook-form/ReactHookForm.stories.tsx +51 -0
  170. package/src/examples/react-hook-form/ReactHookForm.test.tsx +61 -0
  171. package/src/examples/react-hook-form/RhfContactForm.tsx +99 -0
  172. package/src/stories/PresetShowcase.stories.tsx +15 -15
  173. package/src/theme/config.completeness.test.ts +77 -0
  174. package/src/theme/config.ts +151 -0
  175. package/src/theme/index.ts +2 -1
  176. package/src/theme/manifest/css-property-manifest.example.json +79 -0
  177. package/src/theme/manifest/css-property-manifest.schema.json +93 -0
  178. package/src/theme/manifest/css-property-manifest.test.ts +81 -0
  179. package/src/theme/manifest/css-property-manifest.types.ts +49 -0
  180. package/src/theme/manifest/css-property-manifest.validate.ts +84 -0
  181. package/src/theme/manifest/design-freeze.test.ts +155 -0
  182. package/src/theme/manifest/extract-css-properties.fixture.html +29 -0
  183. package/src/theme/manifest/extract-css-properties.test.ts +112 -0
  184. package/src/theme/manifest/index.ts +11 -0
  185. package/src/theme/tokens-css.test.ts +28 -0
  186. package/src/theme/tokens-css.ts +36 -0
  187. package/src/theme/workout-tokens.ts +59 -0
  188. package/src/utils/index.ts +10 -0
  189. package/src/utils/workout-format.test.ts +81 -0
  190. package/src/utils/workout-format.ts +83 -0
  191. package/dist/chunk-UXVRPOME.mjs.map +0 -1
@@ -0,0 +1,1101 @@
1
+ import { WORKOUT_TOKENS, jsxs, jsx, cn, Badge, Sparkline, MesoStatusCard } from './chunk-TOD2WQBG.mjs';
2
+ import './chunk-P7TSQUN6.mjs';
3
+ import './chunk-7XPB4NAO.mjs';
4
+ import { useMemo, useState, useEffect } from 'react';
5
+ import { Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
6
+ import BodyHighlighter from 'react-native-body-highlighter';
7
+
8
+ // src/components/custom/Workout/muscleTaxonomy.ts
9
+ var MuscleGroup = /* @__PURE__ */ ((MuscleGroup5) => {
10
+ MuscleGroup5["CHEST"] = "chest";
11
+ MuscleGroup5["FRONT_DELTS"] = "front_delts";
12
+ MuscleGroup5["SIDE_DELTS"] = "side_delts";
13
+ MuscleGroup5["TRICEPS"] = "triceps";
14
+ MuscleGroup5["LATS"] = "lats";
15
+ MuscleGroup5["UPPER_BACK"] = "upper_back";
16
+ MuscleGroup5["REAR_DELTS"] = "rear_delts";
17
+ MuscleGroup5["BICEPS"] = "biceps";
18
+ MuscleGroup5["FOREARMS"] = "forearms";
19
+ MuscleGroup5["QUADS"] = "quads";
20
+ MuscleGroup5["HAMSTRINGS"] = "hamstrings";
21
+ MuscleGroup5["GLUTES"] = "glutes";
22
+ MuscleGroup5["CALVES"] = "calves";
23
+ MuscleGroup5["ABS"] = "abs";
24
+ MuscleGroup5["OBLIQUES"] = "obliques";
25
+ return MuscleGroup5;
26
+ })(MuscleGroup || {});
27
+ var SimpleMuscleGroup = /* @__PURE__ */ ((SimpleMuscleGroup3) => {
28
+ SimpleMuscleGroup3["CHEST"] = "chest";
29
+ SimpleMuscleGroup3["BACK"] = "back";
30
+ SimpleMuscleGroup3["SHOULDERS"] = "shoulders";
31
+ SimpleMuscleGroup3["BICEPS"] = "biceps";
32
+ SimpleMuscleGroup3["TRICEPS"] = "triceps";
33
+ SimpleMuscleGroup3["LEGS"] = "legs";
34
+ SimpleMuscleGroup3["CORE"] = "core";
35
+ SimpleMuscleGroup3["FOREARMS"] = "forearms";
36
+ return SimpleMuscleGroup3;
37
+ })(SimpleMuscleGroup || {});
38
+ var SIMPLE_TO_DETAILED = {
39
+ ["chest" /* CHEST */]: ["chest" /* CHEST */],
40
+ ["back" /* BACK */]: ["lats" /* LATS */, "upper_back" /* UPPER_BACK */],
41
+ ["shoulders" /* SHOULDERS */]: [
42
+ "front_delts" /* FRONT_DELTS */,
43
+ "side_delts" /* SIDE_DELTS */,
44
+ "rear_delts" /* REAR_DELTS */
45
+ ],
46
+ ["biceps" /* BICEPS */]: ["biceps" /* BICEPS */],
47
+ ["triceps" /* TRICEPS */]: ["triceps" /* TRICEPS */],
48
+ ["legs" /* LEGS */]: [
49
+ "quads" /* QUADS */,
50
+ "hamstrings" /* HAMSTRINGS */,
51
+ "glutes" /* GLUTES */,
52
+ "calves" /* CALVES */
53
+ ],
54
+ ["core" /* CORE */]: ["abs" /* ABS */, "obliques" /* OBLIQUES */],
55
+ ["forearms" /* FOREARMS */]: ["forearms" /* FOREARMS */]
56
+ };
57
+ var DETAILED_TO_SIMPLE = Object.entries(
58
+ SIMPLE_TO_DETAILED
59
+ ).reduce(
60
+ (acc, [simple, groups]) => {
61
+ for (const group of groups) {
62
+ acc[group] = simple;
63
+ }
64
+ return acc;
65
+ },
66
+ {}
67
+ );
68
+ var MUSCLE_TO_CATEGORY = {
69
+ ["chest" /* CHEST */]: "push",
70
+ ["front_delts" /* FRONT_DELTS */]: "push",
71
+ ["side_delts" /* SIDE_DELTS */]: "push",
72
+ ["triceps" /* TRICEPS */]: "push",
73
+ ["lats" /* LATS */]: "pull",
74
+ ["upper_back" /* UPPER_BACK */]: "pull",
75
+ ["rear_delts" /* REAR_DELTS */]: "pull",
76
+ ["biceps" /* BICEPS */]: "pull",
77
+ ["forearms" /* FOREARMS */]: "pull",
78
+ ["quads" /* QUADS */]: "legs",
79
+ ["hamstrings" /* HAMSTRINGS */]: "legs",
80
+ ["glutes" /* GLUTES */]: "legs",
81
+ ["calves" /* CALVES */]: "legs",
82
+ ["abs" /* ABS */]: "core",
83
+ ["obliques" /* OBLIQUES */]: "core"
84
+ };
85
+ var MUSCLE_TO_SVG_SLUGS = {
86
+ ["chest" /* CHEST */]: ["chest"],
87
+ ["front_delts" /* FRONT_DELTS */]: ["deltoids"],
88
+ ["side_delts" /* SIDE_DELTS */]: ["deltoids"],
89
+ ["rear_delts" /* REAR_DELTS */]: ["deltoids"],
90
+ ["triceps" /* TRICEPS */]: ["triceps"],
91
+ ["lats" /* LATS */]: ["upper-back"],
92
+ ["upper_back" /* UPPER_BACK */]: ["upper-back", "trapezius"],
93
+ ["biceps" /* BICEPS */]: ["biceps"],
94
+ ["forearms" /* FOREARMS */]: ["forearm"],
95
+ ["quads" /* QUADS */]: ["quadriceps"],
96
+ ["hamstrings" /* HAMSTRINGS */]: ["hamstring"],
97
+ ["glutes" /* GLUTES */]: ["gluteal"],
98
+ ["calves" /* CALVES */]: ["calves"],
99
+ ["abs" /* ABS */]: ["abs"],
100
+ ["obliques" /* OBLIQUES */]: ["obliques"]
101
+ };
102
+ var MUSCLE_DISPLAY_NAMES = {
103
+ ["chest" /* CHEST */]: "Chest",
104
+ ["front_delts" /* FRONT_DELTS */]: "Front Delts",
105
+ ["side_delts" /* SIDE_DELTS */]: "Side Delts",
106
+ ["rear_delts" /* REAR_DELTS */]: "Rear Delts",
107
+ ["triceps" /* TRICEPS */]: "Triceps",
108
+ ["lats" /* LATS */]: "Lats",
109
+ ["upper_back" /* UPPER_BACK */]: "Upper Back",
110
+ ["biceps" /* BICEPS */]: "Biceps",
111
+ ["forearms" /* FOREARMS */]: "Forearms",
112
+ ["quads" /* QUADS */]: "Quads",
113
+ ["hamstrings" /* HAMSTRINGS */]: "Hamstrings",
114
+ ["glutes" /* GLUTES */]: "Glutes",
115
+ ["calves" /* CALVES */]: "Calves",
116
+ ["abs" /* ABS */]: "Abs",
117
+ ["obliques" /* OBLIQUES */]: "Obliques"
118
+ };
119
+ var SIMPLE_DISPLAY_NAMES = {
120
+ ["chest" /* CHEST */]: "Chest",
121
+ ["back" /* BACK */]: "Back",
122
+ ["shoulders" /* SHOULDERS */]: "Shoulders",
123
+ ["biceps" /* BICEPS */]: "Biceps",
124
+ ["triceps" /* TRICEPS */]: "Triceps",
125
+ ["legs" /* LEGS */]: "Legs",
126
+ ["core" /* CORE */]: "Core",
127
+ ["forearms" /* FOREARMS */]: "Forearms"
128
+ };
129
+ var DEFAULT_VOLUME_LANDMARKS = {
130
+ ["chest" /* CHEST */]: { mev: 8, mav: 14, mrv: 20 },
131
+ ["lats" /* LATS */]: { mev: 8, mav: 14, mrv: 20 },
132
+ ["upper_back" /* UPPER_BACK */]: { mev: 6, mav: 12, mrv: 18 },
133
+ ["front_delts" /* FRONT_DELTS */]: { mev: 2, mav: 6, mrv: 10 },
134
+ ["side_delts" /* SIDE_DELTS */]: { mev: 6, mav: 14, mrv: 22 },
135
+ ["rear_delts" /* REAR_DELTS */]: { mev: 6, mav: 12, mrv: 18 },
136
+ ["biceps" /* BICEPS */]: { mev: 4, mav: 10, mrv: 18 },
137
+ ["triceps" /* TRICEPS */]: { mev: 4, mav: 8, mrv: 14 },
138
+ ["forearms" /* FOREARMS */]: { mev: 2, mav: 6, mrv: 12 },
139
+ ["quads" /* QUADS */]: { mev: 6, mav: 12, mrv: 18 },
140
+ ["hamstrings" /* HAMSTRINGS */]: { mev: 4, mav: 10, mrv: 16 },
141
+ ["glutes" /* GLUTES */]: { mev: 4, mav: 10, mrv: 16 },
142
+ ["calves" /* CALVES */]: { mev: 6, mav: 10, mrv: 16 },
143
+ ["abs" /* ABS */]: { mev: 0, mav: 8, mrv: 16 },
144
+ ["obliques" /* OBLIQUES */]: { mev: 0, mav: 6, mrv: 12 }
145
+ };
146
+ var VOLUME_STATUS_LABELS = {
147
+ under: "under-trained",
148
+ maintenance: "maintenance",
149
+ productive: "productive",
150
+ over: "over-reaching"
151
+ };
152
+ var STATUS_SEVERITY = {
153
+ under: 1,
154
+ maintenance: 2,
155
+ productive: 3,
156
+ over: 4
157
+ };
158
+ function getHeatmapColor(status, intensity = 0) {
159
+ const heatmap = WORKOUT_TOKENS.heatmap;
160
+ switch (status) {
161
+ case "under":
162
+ return heatmap.under;
163
+ case "maintenance":
164
+ return heatmap.maintenance;
165
+ case "productive":
166
+ return intensity >= 0.85 ? heatmap.approaching : heatmap.productive;
167
+ case "over":
168
+ return heatmap.over;
169
+ default:
170
+ return heatmap.none;
171
+ }
172
+ }
173
+ function isMoreSevere(a, b) {
174
+ return STATUS_SEVERITY[a] >= STATUS_SEVERITY[b];
175
+ }
176
+ var SLUG_TO_PRIMARY_MUSCLE = {
177
+ chest: "chest" /* CHEST */,
178
+ deltoids: "side_delts" /* SIDE_DELTS */,
179
+ triceps: "triceps" /* TRICEPS */,
180
+ "upper-back": "lats" /* LATS */,
181
+ trapezius: "upper_back" /* UPPER_BACK */,
182
+ biceps: "biceps" /* BICEPS */,
183
+ forearm: "forearms" /* FOREARMS */,
184
+ quadriceps: "quads" /* QUADS */,
185
+ hamstring: "hamstrings" /* HAMSTRINGS */,
186
+ gluteal: "glutes" /* GLUTES */,
187
+ calves: "calves" /* CALVES */,
188
+ abs: "abs" /* ABS */,
189
+ obliques: "obliques" /* OBLIQUES */
190
+ };
191
+
192
+ // src/components/custom/Workout/BodyMap.tsx
193
+ var Body = BodyHighlighter.default ?? BodyHighlighter;
194
+ var OUTLINE_FILL = "rgba(255,255,255,0.08)";
195
+ var OUTLINE_BORDER = "rgba(255,255,255,0.12)";
196
+ var BODY_SCALE = 0.8;
197
+ var TEXT_PRIMARY = "var(--color-text-primary)";
198
+ var TEXT_SECONDARY = "var(--color-text-secondary)";
199
+ function buildSlugParts(data) {
200
+ const bySlug = /* @__PURE__ */ new Map();
201
+ for (const d of data) {
202
+ for (const slug of MUSCLE_TO_SVG_SLUGS[d.muscleGroup] ?? []) {
203
+ const existing = bySlug.get(slug);
204
+ if (!existing || isMoreSevere(d.volumeStatus, existing.status)) {
205
+ bySlug.set(slug, { status: d.volumeStatus, intensity: d.intensity });
206
+ }
207
+ }
208
+ }
209
+ return Array.from(bySlug.entries()).map(([slug, v]) => ({
210
+ slug,
211
+ color: getHeatmapColor(v.status, v.intensity)
212
+ }));
213
+ }
214
+ function buildSimpleLegend(data) {
215
+ const bySimple = /* @__PURE__ */ new Map();
216
+ for (const d of data) {
217
+ const simple = DETAILED_TO_SIMPLE[d.muscleGroup];
218
+ const existing = bySimple.get(simple);
219
+ if (!existing) {
220
+ bySimple.set(simple, {
221
+ key: simple,
222
+ name: SIMPLE_DISPLAY_NAMES[simple],
223
+ status: d.volumeStatus,
224
+ intensity: d.intensity,
225
+ sets: d.weeklySets,
226
+ muscle: d.muscleGroup
227
+ });
228
+ continue;
229
+ }
230
+ existing.sets += d.weeklySets;
231
+ existing.intensity = Math.max(existing.intensity, d.intensity);
232
+ if (isMoreSevere(d.volumeStatus, existing.status)) {
233
+ existing.status = d.volumeStatus;
234
+ existing.muscle = d.muscleGroup;
235
+ }
236
+ }
237
+ return Array.from(bySimple.values());
238
+ }
239
+ function buildDetailedLegend(data) {
240
+ return data.map((d) => ({
241
+ key: d.muscleGroup,
242
+ name: MUSCLE_DISPLAY_NAMES[d.muscleGroup],
243
+ status: d.volumeStatus,
244
+ intensity: d.intensity,
245
+ sets: d.weeklySets,
246
+ muscle: d.muscleGroup
247
+ }));
248
+ }
249
+ function BodyMap({
250
+ data,
251
+ view,
252
+ onViewChange,
253
+ onMusclePress,
254
+ highlightedMuscle,
255
+ mode = "detailed",
256
+ className,
257
+ ...props
258
+ }) {
259
+ const slugParts = useMemo(() => buildSlugParts(data), [data]);
260
+ const legend = useMemo(
261
+ () => mode === "simple" ? buildSimpleLegend(data) : buildDetailedLegend(data),
262
+ [data, mode]
263
+ );
264
+ const [highlight] = useState(() => new Animated.Value(highlightedMuscle ? 1 : 0));
265
+ useEffect(() => {
266
+ const animation = Animated.timing(highlight, {
267
+ toValue: highlightedMuscle ? 1 : 0,
268
+ duration: 250,
269
+ easing: Easing.out(Easing.ease),
270
+ useNativeDriver: false
271
+ });
272
+ animation.start();
273
+ return () => animation.stop();
274
+ }, [highlightedMuscle, highlight]);
275
+ const scale = highlight.interpolate({ inputRange: [0, 1], outputRange: [1, 1.02] });
276
+ const glowColor = highlightedMuscle ? getHeatmapColor(
277
+ data.find((d) => d.muscleGroup === highlightedMuscle)?.volumeStatus,
278
+ data.find((d) => d.muscleGroup === highlightedMuscle)?.intensity ?? 0
279
+ ) : null;
280
+ const handleBodyPress = (part) => {
281
+ if (!onMusclePress || !part.slug) return;
282
+ const fromData = data.find(
283
+ (d) => (MUSCLE_TO_SVG_SLUGS[d.muscleGroup] ?? []).includes(part.slug)
284
+ );
285
+ const muscle = fromData?.muscleGroup ?? SLUG_TO_PRIMARY_MUSCLE[part.slug];
286
+ if (muscle) onMusclePress(muscle);
287
+ };
288
+ return /* @__PURE__ */ jsxs(View, { className: cn(className), testID: "body-map", ...props, children: [
289
+ /* @__PURE__ */ jsx(ViewToggle, { view, onViewChange }),
290
+ /* @__PURE__ */ jsx(
291
+ Animated.View,
292
+ {
293
+ style: [
294
+ {
295
+ width: 200 * BODY_SCALE,
296
+ alignSelf: "center",
297
+ transform: [{ scale }]
298
+ },
299
+ glowColor ? { boxShadow: `0 0 14px 2px ${glowColor}` } : void 0
300
+ ],
301
+ "aria-hidden": true,
302
+ accessibilityElementsHidden: true,
303
+ importantForAccessibility: "no-hide-descendants",
304
+ testID: "body-map-svg",
305
+ children: /* @__PURE__ */ jsx(
306
+ Body,
307
+ {
308
+ side: view,
309
+ data: slugParts,
310
+ scale: BODY_SCALE,
311
+ gender: "male",
312
+ defaultFill: OUTLINE_FILL,
313
+ border: OUTLINE_BORDER,
314
+ onBodyPartPress: handleBodyPress
315
+ }
316
+ )
317
+ }
318
+ ),
319
+ legend.length === 0 ? /* @__PURE__ */ jsx(
320
+ Text,
321
+ {
322
+ style: {
323
+ marginTop: 8,
324
+ fontSize: 12,
325
+ color: TEXT_SECONDARY,
326
+ textAlign: "center",
327
+ fontFamily: "Inter, sans-serif"
328
+ },
329
+ testID: "body-map-empty",
330
+ children: "No training data"
331
+ }
332
+ ) : /* @__PURE__ */ jsx(
333
+ View,
334
+ {
335
+ className: "flex-row flex-wrap",
336
+ style: { marginTop: 10, gap: 6, justifyContent: "center" },
337
+ testID: "body-map-legend",
338
+ children: legend.map((entry) => /* @__PURE__ */ jsx(
339
+ MuscleButton,
340
+ {
341
+ entry,
342
+ highlighted: highlightedMuscle === entry.muscle,
343
+ onMusclePress
344
+ },
345
+ entry.key
346
+ ))
347
+ }
348
+ )
349
+ ] });
350
+ }
351
+ function ViewToggle({ view, onViewChange }) {
352
+ return /* @__PURE__ */ jsx(
353
+ View,
354
+ {
355
+ className: "flex-row self-center",
356
+ style: { gap: 4, marginBottom: 8 },
357
+ testID: "body-map-view-toggle",
358
+ children: ["front", "back"].map((side) => {
359
+ const active = view === side;
360
+ return /* @__PURE__ */ jsx(
361
+ Pressable,
362
+ {
363
+ onPress: () => onViewChange?.(side),
364
+ accessibilityRole: "button",
365
+ accessibilityLabel: `Show ${side} view`,
366
+ "aria-pressed": active,
367
+ disabled: !onViewChange,
368
+ style: {
369
+ paddingHorizontal: 12,
370
+ paddingVertical: 4,
371
+ borderRadius: 9999,
372
+ backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
373
+ borderWidth: 1,
374
+ borderColor: active ? "#FF7900" : "var(--color-border-strong)"
375
+ },
376
+ testID: `body-map-toggle-${side}`,
377
+ children: /* @__PURE__ */ jsx(
378
+ Text,
379
+ {
380
+ style: {
381
+ fontSize: 12,
382
+ fontFamily: "Inter, sans-serif",
383
+ fontWeight: active ? "700" : "500",
384
+ color: active ? "#FF7900" : TEXT_SECONDARY,
385
+ textTransform: "capitalize"
386
+ },
387
+ children: side
388
+ }
389
+ )
390
+ },
391
+ side
392
+ );
393
+ })
394
+ }
395
+ );
396
+ }
397
+ function MuscleButton({ entry, highlighted, onMusclePress }) {
398
+ const dotColor = getHeatmapColor(entry.status, entry.intensity);
399
+ const label = `${entry.name}, ${VOLUME_STATUS_LABELS[entry.status]}, ${entry.sets} sets this week`;
400
+ return /* @__PURE__ */ jsxs(
401
+ Pressable,
402
+ {
403
+ onPress: () => onMusclePress?.(entry.muscle),
404
+ accessibilityRole: "button",
405
+ accessibilityLabel: label,
406
+ "aria-pressed": highlighted,
407
+ style: {
408
+ flexDirection: "row",
409
+ alignItems: "center",
410
+ gap: 5,
411
+ paddingHorizontal: 8,
412
+ paddingVertical: 3,
413
+ borderRadius: 9999,
414
+ borderWidth: 1,
415
+ borderColor: highlighted ? "#FF7900" : "var(--color-border-default)",
416
+ backgroundColor: "var(--color-surface-raised)"
417
+ },
418
+ testID: `body-map-muscle-${entry.key}`,
419
+ children: [
420
+ /* @__PURE__ */ jsx(
421
+ View,
422
+ {
423
+ style: { width: 7, height: 7, borderRadius: 9999, backgroundColor: dotColor },
424
+ accessibilityElementsHidden: true,
425
+ testID: `body-map-muscle-dot-${entry.key}`
426
+ }
427
+ ),
428
+ /* @__PURE__ */ jsx(
429
+ Text,
430
+ {
431
+ style: {
432
+ fontSize: 11,
433
+ fontFamily: "Inter, sans-serif",
434
+ fontWeight: "500",
435
+ color: TEXT_PRIMARY
436
+ },
437
+ accessibilityElementsHidden: true,
438
+ children: entry.name
439
+ }
440
+ )
441
+ ]
442
+ }
443
+ );
444
+ }
445
+ var SURFACE_ELEVATED = "var(--color-surface-elevated)";
446
+ var SURFACE_RAISED = "var(--color-surface-raised)";
447
+ var BORDER_STRONG = "var(--color-border-strong)";
448
+ var BORDER_DEFAULT = "var(--color-border-default)";
449
+ var BRAND_PRIMARY = "#FF7900";
450
+ var TEXT_PRIMARY2 = "var(--color-text-primary)";
451
+ var TEXT_SECONDARY2 = "var(--color-text-secondary)";
452
+ var TEXT_TERTIARY = "var(--color-text-tertiary)";
453
+ var VOLUME_GRADIENT = "linear-gradient(90deg, #2196F3 0%, #14B8A6 50%, #D14343 100%)";
454
+ var SLIDE_OFFSET = 400;
455
+ var BACKDROP_OPACITY = 0.4;
456
+ var STATUS_BADGE_COLOR = {
457
+ under: "info",
458
+ maintenance: "warning",
459
+ productive: "success",
460
+ over: "error"
461
+ };
462
+ function clamp01(value) {
463
+ if (value < 0) return 0;
464
+ if (value > 1) return 1;
465
+ return value;
466
+ }
467
+ function markerFraction(weeklySets, { mev, mrv }) {
468
+ const span = mrv - mev;
469
+ if (span <= 0) return weeklySets >= mrv ? 1 : 0;
470
+ return clamp01((weeklySets - mev) / span);
471
+ }
472
+ function BodyMapDetailPanel({
473
+ muscleGroup,
474
+ displayName,
475
+ weeklySets,
476
+ landmarks,
477
+ volumeStatus,
478
+ lastTrained,
479
+ weeklyHistory,
480
+ contributingExercises,
481
+ upcomingExercises,
482
+ isOpen,
483
+ visible,
484
+ onClose,
485
+ onViewExercises,
486
+ ...props
487
+ }) {
488
+ const open = isOpen ?? visible ?? false;
489
+ const [translateY] = useState(() => new Animated.Value(SLIDE_OFFSET));
490
+ const [backdrop] = useState(() => new Animated.Value(0));
491
+ useEffect(() => {
492
+ if (!open) return;
493
+ const animation = Animated.parallel([
494
+ Animated.timing(translateY, {
495
+ toValue: 0,
496
+ duration: 400,
497
+ easing: Easing.out(Easing.ease),
498
+ useNativeDriver: false
499
+ }),
500
+ Animated.timing(backdrop, {
501
+ toValue: BACKDROP_OPACITY,
502
+ duration: 300,
503
+ easing: Easing.out(Easing.ease),
504
+ useNativeDriver: false
505
+ })
506
+ ]);
507
+ animation.start();
508
+ return () => animation.stop();
509
+ }, [open, translateY, backdrop]);
510
+ if (!open) return null;
511
+ const dialogLabel = `${displayName} volume details`;
512
+ const markerLeft = markerFraction(weeklySets, landmarks) * 100;
513
+ const hasContributing = (contributingExercises?.length ?? 0) > 0;
514
+ const hasUpcoming = (upcomingExercises?.length ?? 0) > 0;
515
+ return /* @__PURE__ */ jsxs(
516
+ View,
517
+ {
518
+ style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, justifyContent: "flex-end" },
519
+ testID: "body-map-detail-panel-root",
520
+ children: [
521
+ /* @__PURE__ */ jsx(
522
+ Animated.View,
523
+ {
524
+ style: {
525
+ position: "absolute",
526
+ top: 0,
527
+ left: 0,
528
+ right: 0,
529
+ bottom: 0,
530
+ backgroundColor: "#000000",
531
+ opacity: backdrop
532
+ },
533
+ testID: "body-map-detail-panel-backdrop-anim",
534
+ children: /* @__PURE__ */ jsx(
535
+ Pressable,
536
+ {
537
+ onPress: onClose,
538
+ accessibilityRole: "button",
539
+ accessibilityLabel: `Close ${displayName} details`,
540
+ style: { flex: 1 },
541
+ testID: "body-map-detail-panel-backdrop"
542
+ }
543
+ )
544
+ }
545
+ ),
546
+ /* @__PURE__ */ jsxs(
547
+ Animated.View,
548
+ {
549
+ accessibilityRole: "dialog",
550
+ accessibilityLabel: dialogLabel,
551
+ "aria-label": dialogLabel,
552
+ style: {
553
+ backgroundColor: SURFACE_ELEVATED,
554
+ borderTopLeftRadius: 16,
555
+ borderTopRightRadius: 16,
556
+ maxHeight: "88%",
557
+ transform: [{ translateY }]
558
+ },
559
+ testID: "body-map-detail-panel",
560
+ ...props,
561
+ children: [
562
+ /* @__PURE__ */ jsx(
563
+ Pressable,
564
+ {
565
+ onPress: onClose,
566
+ accessibilityRole: "button",
567
+ accessibilityLabel: `Close ${displayName} details`,
568
+ hitSlop: 12,
569
+ style: { alignSelf: "center", paddingVertical: 8 },
570
+ testID: "body-map-detail-panel-handle",
571
+ children: /* @__PURE__ */ jsx(
572
+ View,
573
+ {
574
+ style: { width: 40, height: 4, borderRadius: 2, backgroundColor: BORDER_STRONG },
575
+ accessibilityElementsHidden: true
576
+ }
577
+ )
578
+ }
579
+ ),
580
+ /* @__PURE__ */ jsxs(
581
+ ScrollView,
582
+ {
583
+ style: { paddingHorizontal: 16 },
584
+ contentContainerStyle: { paddingBottom: 20 },
585
+ testID: "body-map-detail-panel-scroll",
586
+ children: [
587
+ /* @__PURE__ */ jsxs(
588
+ View,
589
+ {
590
+ className: "flex-row items-center justify-between",
591
+ style: { gap: 8, paddingTop: 4, paddingBottom: 4 },
592
+ testID: "body-map-detail-panel-header",
593
+ children: [
594
+ /* @__PURE__ */ jsxs(View, { className: "flex-row items-center", style: { gap: 8, flexShrink: 1 }, children: [
595
+ /* @__PURE__ */ jsx(
596
+ Text,
597
+ {
598
+ accessibilityRole: "header",
599
+ style: {
600
+ fontSize: 16,
601
+ fontFamily: '"Space Grotesk", sans-serif',
602
+ fontWeight: "700",
603
+ color: TEXT_PRIMARY2
604
+ },
605
+ testID: "body-map-detail-panel-title",
606
+ children: displayName
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsx(
610
+ Badge,
611
+ {
612
+ variant: "subtle",
613
+ color: STATUS_BADGE_COLOR[volumeStatus],
614
+ size: "sm",
615
+ testID: "body-map-detail-panel-status-badge",
616
+ children: VOLUME_STATUS_LABELS[volumeStatus]
617
+ }
618
+ )
619
+ ] }),
620
+ /* @__PURE__ */ jsx(
621
+ Pressable,
622
+ {
623
+ onPress: onClose,
624
+ accessibilityRole: "button",
625
+ accessibilityLabel: `Close ${displayName} details`,
626
+ hitSlop: 8,
627
+ style: { padding: 4, margin: -4 },
628
+ testID: "body-map-detail-panel-close",
629
+ children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 22, lineHeight: 22, color: TEXT_SECONDARY2 }, children: "\xD7" })
630
+ }
631
+ )
632
+ ]
633
+ }
634
+ ),
635
+ lastTrained != null && /* @__PURE__ */ jsx(
636
+ Text,
637
+ {
638
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY2 },
639
+ testID: "body-map-detail-panel-last-trained",
640
+ children: `Last trained ${lastTrained}`
641
+ }
642
+ ),
643
+ /* @__PURE__ */ jsxs(View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-volume", children: [
644
+ /* @__PURE__ */ jsxs(
645
+ View,
646
+ {
647
+ className: "flex-row items-center justify-between",
648
+ style: { marginBottom: 6 },
649
+ accessibilityElementsHidden: true,
650
+ children: [
651
+ /* @__PURE__ */ jsx(Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_TERTIARY }, children: `MEV ${landmarks.mev}` }),
652
+ /* @__PURE__ */ jsx(Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_TERTIARY }, children: `MRV ${landmarks.mrv}` })
653
+ ]
654
+ }
655
+ ),
656
+ /* @__PURE__ */ jsxs(
657
+ View,
658
+ {
659
+ style: { height: 14, justifyContent: "center" },
660
+ accessibilityRole: "progressbar",
661
+ accessibilityValue: { min: landmarks.mev, max: landmarks.mrv, now: weeklySets },
662
+ accessibilityLabel: `${weeklySets} weekly sets, between MEV ${landmarks.mev} and MRV ${landmarks.mrv}`,
663
+ "aria-valuenow": weeklySets,
664
+ "aria-valuemin": landmarks.mev,
665
+ "aria-valuemax": landmarks.mrv,
666
+ testID: "body-map-detail-panel-volume-bar",
667
+ children: [
668
+ /* @__PURE__ */ jsx(
669
+ View,
670
+ {
671
+ style: { height: 8, borderRadius: 4, backgroundImage: VOLUME_GRADIENT },
672
+ accessibilityElementsHidden: true
673
+ }
674
+ ),
675
+ /* @__PURE__ */ jsx(
676
+ View,
677
+ {
678
+ style: {
679
+ position: "absolute",
680
+ left: `${markerLeft}%`,
681
+ marginLeft: -7,
682
+ width: 14,
683
+ height: 14,
684
+ borderRadius: 7,
685
+ borderWidth: 2,
686
+ borderColor: TEXT_PRIMARY2,
687
+ backgroundColor: SURFACE_ELEVATED,
688
+ boxShadow: "0 0 4px rgba(0,0,0,0.5)"
689
+ },
690
+ accessibilityElementsHidden: true,
691
+ testID: "body-map-detail-panel-volume-marker"
692
+ }
693
+ )
694
+ ]
695
+ }
696
+ )
697
+ ] }),
698
+ /* @__PURE__ */ jsxs(View, { className: "flex-row items-baseline", style: { marginTop: 14, gap: 4 }, children: [
699
+ /* @__PURE__ */ jsx(
700
+ Text,
701
+ {
702
+ style: {
703
+ fontSize: 24,
704
+ fontFamily: '"Space Grotesk", sans-serif',
705
+ fontWeight: "700",
706
+ color: TEXT_PRIMARY2
707
+ },
708
+ testID: "body-map-detail-panel-set-count",
709
+ children: weeklySets
710
+ }
711
+ ),
712
+ /* @__PURE__ */ jsx(
713
+ Text,
714
+ {
715
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY2 },
716
+ testID: "body-map-detail-panel-mrv-suffix",
717
+ children: `/ ${landmarks.mrv} MRV`
718
+ }
719
+ )
720
+ ] }),
721
+ weeklyHistory != null && weeklyHistory.length > 0 && /* @__PURE__ */ jsxs(View, { style: { marginTop: 14 }, testID: "body-map-detail-panel-sparkline", children: [
722
+ /* @__PURE__ */ jsx(
723
+ Text,
724
+ {
725
+ style: {
726
+ fontSize: 10,
727
+ fontFamily: "Inter, sans-serif",
728
+ fontWeight: "600",
729
+ color: TEXT_TERTIARY,
730
+ marginBottom: 6
731
+ },
732
+ accessibilityElementsHidden: true,
733
+ children: "VOLUME TREND"
734
+ }
735
+ ),
736
+ /* @__PURE__ */ jsx(Sparkline, { data: weeklyHistory, width: 80, height: 30, highlightLast: true })
737
+ ] }),
738
+ hasContributing && /* @__PURE__ */ jsxs(View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-contributing", children: [
739
+ /* @__PURE__ */ jsx(
740
+ Text,
741
+ {
742
+ style: {
743
+ fontSize: 10,
744
+ fontFamily: "Inter, sans-serif",
745
+ fontWeight: "600",
746
+ color: TEXT_TERTIARY,
747
+ marginBottom: 8
748
+ },
749
+ children: "CONTRIBUTING EXERCISES"
750
+ }
751
+ ),
752
+ contributingExercises.map((exercise, index) => /* @__PURE__ */ jsxs(
753
+ View,
754
+ {
755
+ className: "flex-row items-center justify-between",
756
+ style: {
757
+ gap: 10,
758
+ paddingVertical: 8,
759
+ paddingHorizontal: 12,
760
+ marginBottom: 6,
761
+ borderRadius: 8,
762
+ backgroundColor: SURFACE_RAISED,
763
+ borderWidth: 1,
764
+ borderColor: BORDER_DEFAULT
765
+ },
766
+ testID: `body-map-detail-panel-contributing-${index}`,
767
+ children: [
768
+ /* @__PURE__ */ jsx(
769
+ Text,
770
+ {
771
+ style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_PRIMARY2 },
772
+ testID: `body-map-detail-panel-contributing-${index}-name`,
773
+ children: exercise.name
774
+ }
775
+ ),
776
+ /* @__PURE__ */ jsx(
777
+ Text,
778
+ {
779
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY2 },
780
+ testID: `body-map-detail-panel-contributing-${index}-detail`,
781
+ children: `${exercise.sets} sets \xB7 ${Math.round(exercise.contributionWeight * 100)}%`
782
+ }
783
+ )
784
+ ]
785
+ },
786
+ `${exercise.name}-${index}`
787
+ ))
788
+ ] }),
789
+ hasUpcoming && /* @__PURE__ */ jsxs(View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-upcoming", children: [
790
+ /* @__PURE__ */ jsx(
791
+ Text,
792
+ {
793
+ style: {
794
+ fontSize: 10,
795
+ fontFamily: "Inter, sans-serif",
796
+ fontWeight: "600",
797
+ color: TEXT_TERTIARY,
798
+ marginBottom: 8
799
+ },
800
+ children: "UPCOMING"
801
+ }
802
+ ),
803
+ upcomingExercises.map((exercise, index) => /* @__PURE__ */ jsxs(
804
+ View,
805
+ {
806
+ className: "flex-row items-center justify-between",
807
+ style: { gap: 10, paddingVertical: 6 },
808
+ testID: `body-map-detail-panel-upcoming-${index}`,
809
+ children: [
810
+ /* @__PURE__ */ jsx(
811
+ Text,
812
+ {
813
+ style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_PRIMARY2 },
814
+ testID: `body-map-detail-panel-upcoming-${index}-name`,
815
+ children: exercise.name
816
+ }
817
+ ),
818
+ /* @__PURE__ */ jsx(
819
+ Text,
820
+ {
821
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_TERTIARY },
822
+ testID: `body-map-detail-panel-upcoming-${index}-detail`,
823
+ children: `${exercise.workoutName} \xB7 ${exercise.sets} sets`
824
+ }
825
+ )
826
+ ]
827
+ },
828
+ `${exercise.name}-${index}`
829
+ ))
830
+ ] }),
831
+ onViewExercises != null && /* @__PURE__ */ jsx(
832
+ Pressable,
833
+ {
834
+ onPress: onViewExercises,
835
+ accessibilityRole: "button",
836
+ accessibilityLabel: `View ${displayName} exercises`,
837
+ style: {
838
+ marginTop: 16,
839
+ paddingVertical: 10,
840
+ borderRadius: 8,
841
+ alignItems: "center",
842
+ backgroundColor: "rgba(255,121,0,0.12)",
843
+ borderWidth: 1,
844
+ borderColor: "rgba(255,121,0,0.3)"
845
+ },
846
+ testID: "body-map-detail-panel-view-exercises",
847
+ children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY }, children: "View exercises" })
848
+ }
849
+ )
850
+ ]
851
+ }
852
+ )
853
+ ]
854
+ }
855
+ )
856
+ ]
857
+ }
858
+ );
859
+ }
860
+ var SURFACE_ELEVATED2 = "var(--color-surface-elevated)";
861
+ var BORDER_DEFAULT2 = "var(--color-border-default)";
862
+ var TEXT_PRIMARY3 = "var(--color-text-primary)";
863
+ var TEXT_SECONDARY3 = "var(--color-text-secondary)";
864
+ var TEXT_TERTIARY2 = "var(--color-text-tertiary)";
865
+ var PAGE_BG = "var(--color-background-base)";
866
+ var STATUS_ORDER = ["under", "maintenance", "productive", "over"];
867
+ function deriveTrainingSummary(muscles) {
868
+ const statusCounts = {
869
+ under: 0,
870
+ maintenance: 0,
871
+ productive: 0,
872
+ over: 0
873
+ };
874
+ let totalWeeklySets = 0;
875
+ for (const muscle of muscles) {
876
+ totalWeeklySets += muscle.weeklySets;
877
+ statusCounts[muscle.volumeStatus] += 1;
878
+ }
879
+ return { totalWeeklySets, trackedMuscles: muscles.length, statusCounts };
880
+ }
881
+ function toBodyMapData(muscles, side) {
882
+ return muscles.filter((muscle) => muscle.side === side).map(({ muscleGroup, intensity, volumeStatus, weeklySets }) => ({
883
+ muscleGroup,
884
+ intensity,
885
+ volumeStatus,
886
+ weeklySets
887
+ }));
888
+ }
889
+ var SUMMARY_CARDS = [
890
+ { key: "total", label: "Weekly Sets" },
891
+ { key: "productive", label: "Productive" },
892
+ { key: "under", label: "Under" },
893
+ { key: "over", label: "Over" }
894
+ ];
895
+ function SummaryCards({ summary }) {
896
+ return /* @__PURE__ */ jsx(View, { className: "flex-row flex-wrap", style: { gap: 8 }, testID: "training-status-page-summary", children: SUMMARY_CARDS.map(({ key, label }) => {
897
+ const value = key === "total" ? summary.totalWeeklySets : summary.statusCounts[key];
898
+ return /* @__PURE__ */ jsxs(
899
+ View,
900
+ {
901
+ style: {
902
+ flexGrow: 1,
903
+ flexBasis: "46%",
904
+ padding: 12,
905
+ borderRadius: 10,
906
+ backgroundColor: SURFACE_ELEVATED2,
907
+ borderWidth: 1,
908
+ borderColor: BORDER_DEFAULT2
909
+ },
910
+ testID: `training-status-page-summary-${key}`,
911
+ children: [
912
+ /* @__PURE__ */ jsx(
913
+ Text,
914
+ {
915
+ style: {
916
+ fontSize: 22,
917
+ fontFamily: '"Space Grotesk", sans-serif',
918
+ fontWeight: "700",
919
+ color: TEXT_PRIMARY3
920
+ },
921
+ children: value
922
+ }
923
+ ),
924
+ /* @__PURE__ */ jsx(
925
+ Text,
926
+ {
927
+ style: {
928
+ marginTop: 2,
929
+ fontSize: 11,
930
+ fontFamily: "Inter, sans-serif",
931
+ fontWeight: "600",
932
+ letterSpacing: 0.4,
933
+ textTransform: "uppercase",
934
+ color: TEXT_TERTIARY2
935
+ },
936
+ children: label
937
+ }
938
+ )
939
+ ]
940
+ },
941
+ key
942
+ );
943
+ }) });
944
+ }
945
+ function StatusLegend() {
946
+ return /* @__PURE__ */ jsx(
947
+ View,
948
+ {
949
+ className: "flex-row flex-wrap",
950
+ style: { gap: 10, justifyContent: "center" },
951
+ testID: "training-status-page-legend",
952
+ children: STATUS_ORDER.map((status) => /* @__PURE__ */ jsxs(
953
+ View,
954
+ {
955
+ className: "flex-row items-center",
956
+ style: { gap: 5 },
957
+ testID: `training-status-page-legend-${status}`,
958
+ children: [
959
+ /* @__PURE__ */ jsx(
960
+ View,
961
+ {
962
+ style: {
963
+ width: 8,
964
+ height: 8,
965
+ borderRadius: 9999,
966
+ backgroundColor: getHeatmapColor(status, 0.6)
967
+ },
968
+ accessibilityElementsHidden: true
969
+ }
970
+ ),
971
+ /* @__PURE__ */ jsx(
972
+ Text,
973
+ {
974
+ style: {
975
+ fontSize: 11,
976
+ fontFamily: "Inter, sans-serif",
977
+ color: TEXT_SECONDARY3,
978
+ textTransform: "capitalize"
979
+ },
980
+ children: VOLUME_STATUS_LABELS[status]
981
+ }
982
+ )
983
+ ]
984
+ },
985
+ status
986
+ ))
987
+ }
988
+ );
989
+ }
990
+ function BodyMapColumn({ side, muscles, selected, onSelect }) {
991
+ const data = useMemo(() => toBodyMapData(muscles, side), [muscles, side]);
992
+ return /* @__PURE__ */ jsx(View, { style: { flexGrow: 1, flexBasis: "46%" }, testID: `training-status-page-bodymap-${side}`, children: /* @__PURE__ */ jsx(
993
+ BodyMap,
994
+ {
995
+ data,
996
+ view: side,
997
+ onMusclePress: onSelect,
998
+ highlightedMuscle: selected,
999
+ mode: "detailed"
1000
+ }
1001
+ ) });
1002
+ }
1003
+ function TrainingStatusPage({
1004
+ title = "Training Status",
1005
+ meso,
1006
+ muscles,
1007
+ className,
1008
+ ...props
1009
+ }) {
1010
+ const [selected, setSelected] = useState(null);
1011
+ const summary = useMemo(() => deriveTrainingSummary(muscles), [muscles]);
1012
+ const active = selected != null ? muscles.find((m) => m.muscleGroup === selected) ?? null : null;
1013
+ return /* @__PURE__ */ jsxs(
1014
+ View,
1015
+ {
1016
+ className,
1017
+ style: { position: "relative", width: 390, backgroundColor: PAGE_BG },
1018
+ accessibilityRole: "main",
1019
+ "aria-label": title,
1020
+ testID: "training-status-page",
1021
+ ...props,
1022
+ children: [
1023
+ /* @__PURE__ */ jsxs(View, { style: { padding: 16, gap: 16 }, testID: "training-status-page-content", children: [
1024
+ /* @__PURE__ */ jsx(
1025
+ Text,
1026
+ {
1027
+ accessibilityRole: "header",
1028
+ style: {
1029
+ fontSize: 20,
1030
+ fontFamily: '"Space Grotesk", sans-serif',
1031
+ fontWeight: "700",
1032
+ color: TEXT_PRIMARY3
1033
+ },
1034
+ testID: "training-status-page-title",
1035
+ children: title
1036
+ }
1037
+ ),
1038
+ /* @__PURE__ */ jsx(MesoStatusCard, { ...meso }),
1039
+ /* @__PURE__ */ jsx(SummaryCards, { summary }),
1040
+ /* @__PURE__ */ jsxs(
1041
+ View,
1042
+ {
1043
+ style: {
1044
+ backgroundColor: SURFACE_ELEVATED2,
1045
+ borderWidth: 1,
1046
+ borderColor: BORDER_DEFAULT2,
1047
+ borderRadius: 12,
1048
+ padding: 12,
1049
+ gap: 12
1050
+ },
1051
+ testID: "training-status-page-bodymaps",
1052
+ children: [
1053
+ /* @__PURE__ */ jsxs(View, { className: "flex-row", style: { gap: 8 }, children: [
1054
+ /* @__PURE__ */ jsx(
1055
+ BodyMapColumn,
1056
+ {
1057
+ side: "front",
1058
+ muscles,
1059
+ selected,
1060
+ onSelect: setSelected
1061
+ }
1062
+ ),
1063
+ /* @__PURE__ */ jsx(
1064
+ BodyMapColumn,
1065
+ {
1066
+ side: "back",
1067
+ muscles,
1068
+ selected,
1069
+ onSelect: setSelected
1070
+ }
1071
+ )
1072
+ ] }),
1073
+ /* @__PURE__ */ jsx(StatusLegend, {})
1074
+ ]
1075
+ }
1076
+ )
1077
+ ] }),
1078
+ active != null && /* @__PURE__ */ jsx(
1079
+ BodyMapDetailPanel,
1080
+ {
1081
+ muscleGroup: active.muscleGroup,
1082
+ displayName: active.displayName,
1083
+ weeklySets: active.weeklySets,
1084
+ landmarks: active.landmarks,
1085
+ volumeStatus: active.volumeStatus,
1086
+ lastTrained: active.lastTrained,
1087
+ weeklyHistory: active.weeklyHistory,
1088
+ contributingExercises: active.contributingExercises,
1089
+ upcomingExercises: active.upcomingExercises,
1090
+ isOpen: true,
1091
+ onClose: () => setSelected(null)
1092
+ }
1093
+ )
1094
+ ]
1095
+ }
1096
+ );
1097
+ }
1098
+
1099
+ export { BodyMap, BodyMapDetailPanel, DEFAULT_VOLUME_LANDMARKS, DETAILED_TO_SIMPLE, MUSCLE_DISPLAY_NAMES, MUSCLE_TO_CATEGORY, MUSCLE_TO_SVG_SLUGS, MuscleGroup, SIMPLE_DISPLAY_NAMES, SIMPLE_TO_DETAILED, SimpleMuscleGroup, TrainingStatusPage, VOLUME_STATUS_LABELS, deriveTrainingSummary, getHeatmapColor, toBodyMapData };
1100
+ //# sourceMappingURL=bodymap.mjs.map
1101
+ //# sourceMappingURL=bodymap.mjs.map