@titan-design/react-ui 0.12.1 → 0.13.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 (509) hide show
  1. package/README.md +46 -47
  2. package/dist/bodymap.js +768 -701
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +770 -703
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1319 -216
  7. package/dist/index.d.ts +1319 -216
  8. package/dist/index.js +5996 -4498
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +5773 -4357
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
  13. package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1435 -1428
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1443 -1436
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +195 -134
  21. package/dist/theme/index.d.ts +195 -134
  22. package/dist/theme/index.js +215 -300
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +202 -296
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +62 -5
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +62 -5
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +73 -5
  31. package/dist/theme/tokens.d.ts +73 -5
  32. package/dist/theme/tokens.js +55 -7
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +55 -8
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/package.json +1 -1
  40. package/src/arch/arch-graph.freshness.test.ts +52 -0
  41. package/src/arch/arch-graph.json +5021 -1617
  42. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  43. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  44. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  45. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  46. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  48. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  49. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  51. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  52. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  54. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  55. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  57. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  58. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  60. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  61. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
  63. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  64. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  66. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  67. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  69. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  70. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  71. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  73. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  74. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  76. package/src/components/custom/ActiveWork/README.md +305 -0
  77. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  78. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  80. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  81. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  82. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  83. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  84. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  86. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  87. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  88. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  90. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  91. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  92. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  93. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  94. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  95. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  96. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  97. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  98. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  99. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  100. package/src/components/custom/ActiveWork/index.ts +19 -0
  101. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  102. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  103. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  104. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  105. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
  106. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  107. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  108. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  109. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  110. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  111. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  112. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  113. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  116. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  117. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  119. package/src/components/custom/Fatigue/README.md +40 -3
  120. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  121. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  122. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  123. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  124. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  125. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  126. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  127. package/src/components/custom/Fatigue/index.ts +17 -5
  128. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  129. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  130. package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
  131. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  132. package/src/components/custom/Gauge/Gauge.tsx +4 -1
  133. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  134. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  135. package/src/components/custom/Metric/Metric.tsx +5 -20
  136. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  137. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  138. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  139. package/src/components/custom/Prose/README.md +58 -0
  140. package/src/components/custom/Prose/index.ts +1 -0
  141. package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
  142. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  143. package/src/components/custom/Scatter/Scatter.tsx +116 -14
  144. package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
  145. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  146. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  147. package/src/components/custom/Table/Table.stories.tsx +98 -15
  148. package/src/components/custom/Table/Table.test.tsx +273 -86
  149. package/src/components/custom/Table/Table.tsx +159 -67
  150. package/src/components/custom/Table/column-fit.test.ts +75 -0
  151. package/src/components/custom/Table/column-fit.ts +116 -0
  152. package/src/components/custom/Table/index.ts +9 -0
  153. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  154. package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
  155. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  156. package/src/components/custom/Treemap/Treemap.tsx +7 -2
  157. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  158. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  159. package/src/components/custom/Typography/Typography.tsx +6 -0
  160. package/src/components/custom/Typography/index.ts +1 -8
  161. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
  162. package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
  163. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  164. package/src/components/custom/Workout/BaseBadge.tsx +3 -0
  165. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  166. package/src/components/custom/Workout/BodyMap.tsx +3 -1
  167. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
  168. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  169. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
  170. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
  171. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  172. package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
  173. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  174. package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
  175. package/src/components/custom/Workout/DeviationBar.tsx +21 -16
  176. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
  177. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
  178. package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
  179. package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
  180. package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
  181. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
  182. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  183. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  184. package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
  185. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
  186. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  187. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  188. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  189. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  190. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  191. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  192. package/src/components/custom/Workout/IntensityBar.tsx +4 -2
  193. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  194. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  195. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  196. package/src/components/custom/Workout/MesoCard.tsx +12 -9
  197. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  198. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  199. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  200. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  201. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  202. package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
  203. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  204. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  205. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  206. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  207. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  208. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  209. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  210. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  211. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  212. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  213. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
  214. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  215. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  216. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  217. package/src/components/custom/Workout/README.md +11 -6
  218. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  219. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  220. package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
  221. package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
  222. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  223. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  224. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  225. package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
  226. package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
  227. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  228. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  229. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  230. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  231. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  232. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  233. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  234. package/src/components/custom/Workout/SetBar.tsx +38 -12
  235. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  236. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  237. package/src/components/custom/Workout/SetRow.tsx +61 -23
  238. package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
  239. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  240. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  241. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  242. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  243. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  244. package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
  245. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  246. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  247. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  248. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  249. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  250. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  251. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  252. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  253. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  254. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
  255. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  256. package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
  257. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  258. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  259. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  260. package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
  261. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  262. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  263. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  264. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
  265. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
  266. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
  267. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  268. package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
  269. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  270. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  271. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  272. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  273. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  274. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  275. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  276. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  277. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  278. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  279. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  280. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  281. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  282. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  283. package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
  284. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  285. package/src/components/custom/Workout/index.ts +5 -0
  286. package/src/components/custom/Workout/metricText.stories.tsx +6 -5
  287. package/src/components/custom/Workout/metricText.tsx +4 -0
  288. package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
  289. package/src/components/custom/charts/README.md +61 -0
  290. package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
  291. package/src/components/custom/charts/SetBarChart.tsx +42 -4
  292. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  293. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  294. package/src/components/custom/charts/SparkBars.tsx +85 -0
  295. package/src/components/custom/charts/index.ts +3 -0
  296. package/src/components/custom/index.ts +3 -0
  297. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  298. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  299. package/src/components/custom/stepper/Stepper.tsx +13 -28
  300. package/src/components/icons/icons.stories.tsx +1 -1
  301. package/src/components/icons/icons.tsx +51 -0
  302. package/src/components/shell/AppShell.stories.tsx +150 -0
  303. package/src/components/shell/AppShell.test.tsx +70 -0
  304. package/src/components/shell/AppShell.tsx +90 -0
  305. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  306. package/src/components/shell/BrandLockup.test.tsx +34 -1
  307. package/src/components/shell/BrandLockup.tsx +27 -11
  308. package/src/components/shell/NavItem.stories.tsx +4 -4
  309. package/src/components/shell/NavItem.test.tsx +17 -0
  310. package/src/components/shell/NavItem.tsx +17 -5
  311. package/src/components/shell/README.md +89 -26
  312. package/src/components/shell/SideNav.stories.tsx +38 -7
  313. package/src/components/shell/SideNav.test.tsx +16 -8
  314. package/src/components/shell/SideNav.tsx +17 -17
  315. package/src/components/shell/TopBar.stories.tsx +44 -19
  316. package/src/components/shell/TopBar.test.tsx +34 -12
  317. package/src/components/shell/TopBar.tsx +61 -40
  318. package/src/components/shell/brands.tsx +66 -0
  319. package/src/components/shell/index.ts +9 -8
  320. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  321. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  322. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  323. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  324. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  325. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  326. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  327. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  328. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  329. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  330. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  331. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  332. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  333. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  334. package/src/components/shell/workout/index.ts +9 -0
  335. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  336. package/src/components/ui/README.md +110 -0
  337. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  338. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  339. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  340. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  341. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  342. package/src/components/ui/avatar/Avatar.tsx +2 -10
  343. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  344. package/src/components/ui/badge/Badge.test.tsx +19 -3
  345. package/src/components/ui/badge/Badge.tsx +48 -55
  346. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  347. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  348. package/src/components/ui/button/Button.stories.tsx +46 -12
  349. package/src/components/ui/button/Button.tsx +32 -25
  350. package/src/components/ui/card/Card.stories.tsx +90 -94
  351. package/src/components/ui/card/Card.test.tsx +80 -6
  352. package/src/components/ui/card/Card.tsx +150 -203
  353. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  354. package/src/components/ui/checkbox/Checkbox.tsx +6 -26
  355. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  356. package/src/components/ui/chip/Chip.test.tsx +10 -6
  357. package/src/components/ui/chip/Chip.tsx +76 -91
  358. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  359. package/src/components/ui/collapse/Collapse.tsx +6 -11
  360. package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
  361. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  362. package/src/components/ui/data-row/DataRow.tsx +18 -7
  363. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  364. package/src/components/ui/divider/Divider.tsx +1 -5
  365. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  366. package/src/components/ui/drawer/Drawer.tsx +13 -30
  367. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  368. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  369. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  370. package/src/components/ui/form-field/FormField.tsx +10 -46
  371. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  372. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  373. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  374. package/src/components/ui/help-tip/index.ts +7 -1
  375. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  376. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  377. package/src/components/ui/icon-box/IconBox.tsx +2 -12
  378. package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
  379. package/src/components/ui/indicator/Indicator.tsx +20 -14
  380. package/src/components/ui/input/Input.stories.tsx +3 -11
  381. package/src/components/ui/input/Input.test.tsx +2 -10
  382. package/src/components/ui/input/Input.tsx +10 -25
  383. package/src/components/ui/input/index.ts +7 -1
  384. package/src/components/ui/link/Link.stories.tsx +19 -7
  385. package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
  386. package/src/components/ui/list-item/ListItem.tsx +2 -9
  387. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  388. package/src/components/ui/menu/Menu.test.tsx +2 -11
  389. package/src/components/ui/menu/Menu.tsx +12 -14
  390. package/src/components/ui/menu/index.ts +8 -1
  391. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  392. package/src/components/ui/modal/Modal.tsx +29 -19
  393. package/src/components/ui/pill/Pill.stories.tsx +58 -23
  394. package/src/components/ui/pill/Pill.test.tsx +101 -3
  395. package/src/components/ui/pill/Pill.tsx +164 -49
  396. package/src/components/ui/pill/index.ts +1 -1
  397. package/src/components/ui/popover/Popover.stories.tsx +5 -7
  398. package/src/components/ui/popover/Popover.test.tsx +1 -6
  399. package/src/components/ui/popover/Popover.tsx +20 -15
  400. package/src/components/ui/popover/index.ts +7 -1
  401. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  402. package/src/components/ui/progress/Progress.test.tsx +1 -5
  403. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  404. package/src/components/ui/radio/Radio.test.tsx +6 -2
  405. package/src/components/ui/radio/Radio.tsx +23 -22
  406. package/src/components/ui/section/Section.stories.tsx +5 -14
  407. package/src/components/ui/section/Section.test.tsx +1 -6
  408. package/src/components/ui/section/Section.tsx +1 -3
  409. package/src/components/ui/section/index.ts +1 -5
  410. package/src/components/ui/select/Select.stories.tsx +3 -13
  411. package/src/components/ui/select/Select.test.tsx +2 -11
  412. package/src/components/ui/select/Select.tsx +14 -14
  413. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  414. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  415. package/src/components/ui/skeleton/index.ts +1 -7
  416. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  417. package/src/components/ui/spinner/Spinner.tsx +1 -4
  418. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  419. package/src/components/ui/stack/Stack.tsx +1 -1
  420. package/src/components/ui/surface/Surface.stories.tsx +17 -5
  421. package/src/components/ui/surface/Surface.test.tsx +88 -28
  422. package/src/components/ui/surface/Surface.tsx +37 -87
  423. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  424. package/src/components/ui/surface/index.ts +8 -0
  425. package/src/components/ui/surface/resolveSurface.ts +98 -0
  426. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  427. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  428. package/src/components/ui/switch/Switch.tsx +7 -6
  429. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  430. package/src/components/ui/tabs/Tabs.tsx +7 -22
  431. package/src/components/ui/tabs/index.ts +1 -7
  432. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  433. package/src/components/ui/tile/Tile.tsx +3 -0
  434. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  435. package/src/components/ui/toast/Toast.test.tsx +2 -8
  436. package/src/components/ui/toast/Toast.tsx +43 -53
  437. package/src/components/ui/toast/index.ts +0 -1
  438. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  439. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  440. package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
  441. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  442. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  443. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  444. package/src/components/ui/tooltip/index.ts +1 -1
  445. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  446. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  447. package/src/components/ui/trigger/index.ts +2 -0
  448. package/src/stories/PresetShowcase.stories.tsx +100 -47
  449. package/src/test/no-device-internals.test.ts +3 -3
  450. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  451. package/src/theme/ColorPalettes.stories.tsx +62 -45
  452. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  453. package/src/theme/Depth.stories.tsx +132 -65
  454. package/src/theme/DepthCalibration.stories.tsx +23 -21
  455. package/src/theme/ThemeProvider.test.tsx +4 -4
  456. package/src/theme/barrel.ts +7 -6
  457. package/src/theme/color-stories.coverage.test.ts +1 -1
  458. package/src/theme/color-utils.ts +41 -29
  459. package/src/theme/config.completeness.test.ts +1 -1
  460. package/src/theme/config.ts +28 -0
  461. package/src/theme/elevation.test.ts +82 -56
  462. package/src/theme/elevation.ts +77 -561
  463. package/src/theme/global.css +30 -2
  464. package/src/theme/grey-ramp.test.ts +24 -8
  465. package/src/theme/lift.test.ts +39 -0
  466. package/src/theme/lift.ts +102 -0
  467. package/src/theme/materials.test.ts +5 -2
  468. package/src/theme/materials.ts +38 -4
  469. package/src/theme/native-theming-guard.test.ts +5 -5
  470. package/src/theme/presets/apply.ts +4 -0
  471. package/src/theme/presets/audiobook.ts +5 -2
  472. package/src/theme/presets/default.ts +4 -0
  473. package/src/theme/presets/index.ts +14 -1
  474. package/src/theme/presets/types.ts +1 -1
  475. package/src/theme/semantic-contrast.test.ts +13 -4
  476. package/src/theme/status-distinctness.test.ts +66 -0
  477. package/src/theme/surface-planes.test.ts +37 -0
  478. package/src/theme/surface-planes.ts +68 -0
  479. package/src/theme/token-export-guard.test.ts +1 -3
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +65 -33
  482. package/src/theme/tokens/semantic.ts +71 -37
  483. package/src/theme/wash-ladder.test.ts +58 -0
  484. package/src/theme/workout-tokens.ts +1 -7
  485. package/src/types/jest-axe.d.ts +2 -6
  486. package/src/types/raw-md.d.ts +5 -0
  487. package/src/utils/colors.ts +4 -4
  488. package/src/utils/form.ts +1 -3
  489. package/src/utils/index.ts +2 -7
  490. package/src/utils/number-format.ts +17 -0
  491. package/src/utils/workout-format.ts +15 -6
  492. package/src/web-jsx/jsx-runtime.ts +1 -5
  493. package/tailwind.config.js +5 -0
  494. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  495. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  496. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  497. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  498. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  499. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  500. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  501. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  502. package/src/components/shell/DashboardShell.tsx +0 -75
  503. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  504. package/src/theme/elevation.stories.tsx +0 -346
  505. package/src/utils/useTheme.ts +0 -72
  506. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  507. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  508. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  509. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -1,4 +1,5 @@
1
1
  export { cn } from './cn'
2
+ export { formatCompact, formatSignedCompact } from './number-format'
2
3
  export {
3
4
  getStatusColor,
4
5
  getResultColor,
@@ -20,13 +21,7 @@ export {
20
21
  validationRules,
21
22
  composeValidators,
22
23
  } from './form'
23
- export type {
24
- FieldState,
25
- FieldWrapperProps,
26
- FormValues,
27
- FormErrors,
28
- FormTouched,
29
- } from './form'
24
+ export type { FieldState, FieldWrapperProps, FormValues, FormErrors, FormTouched } from './form'
30
25
  export {
31
26
  roundRpe,
32
27
  rpeColor,
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Compact integer formatting for dense readouts (stat tiles, sparkline
3
+ * captions) where a full-precision number would blow the column width.
4
+ */
5
+
6
+ /** 1234 → "1.2k", 1048576 → "1.0M", 42 → "42". Sign is preserved. */
7
+ export function formatCompact(n: number): string {
8
+ const abs = Math.abs(n)
9
+ if (abs >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M'
10
+ if (abs >= 1_000) return (n / 1_000).toFixed(1) + 'k'
11
+ return String(n)
12
+ }
13
+
14
+ /** Like {@link formatCompact} but always signed: 514689 → "+514.7k", -20 → "-20". */
15
+ export function formatSignedCompact(n: number): string {
16
+ return (n >= 0 ? '+' : '') + formatCompact(n)
17
+ }
@@ -52,6 +52,20 @@ export function formatSignedPct(ratio: number): string {
52
52
  return `${pct > 0 ? '+' : ''}${pct}%`
53
53
  }
54
54
 
55
+ /**
56
+ * Rep-range label, e.g. `"8–10"`. `"8"` when the bounds are equal or only one is
57
+ * given; `null` when neither is set. Shared by {@link formatPrescription} and the
58
+ * set strip's per-set prescribed-range label so the two never drift apart.
59
+ */
60
+ export function formatRepsRange(repsLow?: number, repsHigh?: number): string | null {
61
+ if (repsLow != null && repsHigh != null) {
62
+ return repsLow === repsHigh ? `${repsLow}` : `${repsLow}–${repsHigh}`
63
+ }
64
+ if (repsLow != null) return `${repsLow}`
65
+ if (repsHigh != null) return `${repsHigh}`
66
+ return null
67
+ }
68
+
55
69
  /** Structured prescription for the active exercise (from the plan). */
56
70
  export interface PrescriptionInput {
57
71
  repsLow?: number
@@ -67,12 +81,7 @@ export interface PrescriptionInput {
67
81
  */
68
82
  export function formatPrescription(p: PrescriptionInput | null | undefined): string | null {
69
83
  if (p == null) return null
70
- let reps: string | null = null
71
- if (p.repsLow != null && p.repsHigh != null) {
72
- reps = p.repsLow === p.repsHigh ? `${p.repsLow}` : `${p.repsLow}–${p.repsHigh}`
73
- } else if (p.repsLow != null) {
74
- reps = `${p.repsLow}`
75
- }
84
+ const reps = formatRepsRange(p.repsLow, p.repsHigh)
76
85
  const weight = p.weightLbs != null ? `${p.weightLbs} lb` : null
77
86
  const head = [reps, weight].filter((s): s is string => s != null).join(' @ ')
78
87
  const rpe = p.rpe != null ? `RPE ${p.rpe}` : null
@@ -10,11 +10,7 @@
10
10
  * native Metro). It is only inlined into the dist by tsup via
11
11
  * an esbuild onResolve plugin.
12
12
  */
13
- import {
14
- jsx as reactJsx,
15
- jsxs as reactJsxs,
16
- Fragment,
17
- } from 'react/jsx-runtime'
13
+ import { jsx as reactJsx, jsxs as reactJsxs, Fragment } from 'react/jsx-runtime'
18
14
  import type { StyleProp } from 'react-native'
19
15
 
20
16
  type JsxFn = typeof reactJsx
@@ -183,6 +183,11 @@ module.exports = {
183
183
  mono: ['var(--font-family-mono)', 'monospace'],
184
184
  },
185
185
  fontSize: {
186
+ // Micro steps. `2xs` carries a paired line-height like the rest of the
187
+ // scale (Typography's microLabel needs it); `3xs` is bare because a pill
188
+ // capsule takes its height from padding, not from the label's leading.
189
+ '3xs': '0.5625rem',
190
+ '2xs': ['0.625rem', { lineHeight: '0.875rem' }],
186
191
  xs: ['0.75rem', { lineHeight: '1rem' }],
187
192
  sm: ['0.875rem', { lineHeight: '1.25rem' }],
188
193
  base: ['1rem', { lineHeight: '1.5rem' }],
@@ -1,151 +0,0 @@
1
- /**
2
- * SHEET · Unified exercise card (page 2) — the LOCKED rail-expansion, hardened onto the
3
- * REAL {@link ExerciseCard}. The collapsed rail item and the expanded card are ONE object: the
4
- * persistent header is the real {@link ExerciseCardHeading}, and expanding reveals the body on the
5
- * SAME surface — PREV dropped, done + upcoming sets share ONE muted treatment, the ACTIVE set
6
- * stands out by brightness. Every per-row strip is the REAL {@link VelocityStrip} via its `set`
7
- * descriptor: `mini` (flat 3px) for done/upcoming, and the `compact` velocity-height variant as
8
- * the active-set SPOTLIGHT (option B, locked). No hand-built prototype strip remains.
9
- */
10
- import type { Meta, StoryObj } from '@storybook/react-vite'
11
- import { View, Text } from 'react-native'
12
- import { ExerciseCard } from './ExerciseCard'
13
- import { ExerciseCardHeading } from './ExerciseCardHeading'
14
- import { VelocityStrip } from './VelocityStrip'
15
- import { type SetRowProps } from './SetRow'
16
- import { type SetStripSet } from './SetStrip'
17
- import { INSET, BORDER_SUBTLE, T_PRIMARY, T_SECONDARY, Page, monoTag } from './setHeadingKit'
18
-
19
- const INTER = 'Inter, sans-serif'
20
-
21
- /** Per-rep mean velocity that DECAYS across a set (fast → slow). */
22
- const decay = (n: number, start: number, span = 0.5) =>
23
- Array.from({ length: n }, (_, r) => +(start - (span * r) / Math.max(1, n - 1)).toFixed(3))
24
-
25
- // The exercise: a flat straight set (Cable Chest Press, 3 × 10 @ 90 lb).
26
- const DONE = decay(10, 1.05)
27
- const ACTIVE = decay(5, 0.95, 0.3)
28
-
29
- // One data source drives both representations. Set 1 done · set 2 LIVE · set 3 upcoming.
30
- const SETS: SetRowProps[] = [
31
- { state: 'done', setNumber: 1, unit: 'lbs', reps: 10, weight: 90, rpe: 7.5, velocities: DONE },
32
- {
33
- state: 'live',
34
- setNumber: 2,
35
- unit: 'lbs',
36
- target: { reps: 10, weight: 90 },
37
- reps: 5,
38
- weight: 90,
39
- velocities: ACTIVE,
40
- },
41
- { state: 'todo', setNumber: 3, unit: 'lbs', target: { reps: 10, weight: 90 } },
42
- ]
43
-
44
- // The header's per-set strip: the same lifecycle the card derives internally, built here
45
- // so the collapsed rail item (ExerciseCardHeading) reads from the same source as the body.
46
- const HEADER_STATES: SetStripSet[] = [
47
- { status: 'done', velocities: DONE },
48
- { status: 'active', velocities: ACTIVE, planned: 10 },
49
- { status: 'todo', planned: 10 },
50
- ]
51
-
52
- const CARD_PROPS = {
53
- name: 'Cable Chest Press',
54
- summary: { sets: 3, reps: 10, weight: 90, unit: 'lbs' as const },
55
- tempo: [2, 1, 2, 0] as [number, number, number, number],
56
- indicator: 'info' as const,
57
- sets: SETS,
58
- }
59
-
60
- function Surface({ children, width = 260 }: { children: React.ReactNode; width?: number }) {
61
- return (
62
- <View style={{ width, backgroundColor: INSET, borderRadius: 8, overflow: 'hidden' }}>
63
- {children}
64
- </View>
65
- )
66
- }
67
-
68
- const meta: Meta = {
69
- title: 'Lab/Explorations/Unified Exercise Card',
70
- parameters: { layout: 'fullscreen' },
71
- }
72
- export default meta
73
- type Story = StoryObj
74
-
75
- export const Unified: Story = {
76
- name: 'One object · rail header → expanded body (real ExerciseCard)',
77
- render: () => (
78
- <Page
79
- title="Unified exercise card — the rail heading IS the header"
80
- note="The LOCKED rail-expansion, hardened onto the real ExerciseCard. Collapsed, it's the rail item (the real ExerciseCardHeading); expanded, the SAME surface reveals the table body — PREV dropped, done + upcoming sets share ONE muted treatment, the ACTIVE set stands out by brightness. Every per-row strip is the real VelocityStrip: `mini` for done/upcoming, the `compact` velocity-height variant as the active-set spotlight (B, locked). No hand-built prototype strip remains."
81
- >
82
- <View style={{ flexDirection: 'row', gap: 40, alignItems: 'flex-start', flexWrap: 'wrap' }}>
83
- <View style={{ gap: 8 }}>
84
- <Text style={{ ...monoTag, color: T_SECONDARY }}>
85
- collapsed · rail item (ExerciseCardHeading)
86
- </Text>
87
- <Surface>
88
- <ExerciseCardHeading
89
- name={CARD_PROPS.name}
90
- sets={3}
91
- reps={10}
92
- load={90}
93
- unit="lbs"
94
- tempo={CARD_PROPS.tempo}
95
- indicator={CARD_PROPS.indicator}
96
- setStates={HEADER_STATES}
97
- />
98
- </Surface>
99
- </View>
100
-
101
- <View style={{ gap: 8 }}>
102
- <Text style={{ ...monoTag, color: T_SECONDARY }}>
103
- expanded · same header + revealed body
104
- </Text>
105
- <Surface>
106
- <ExerciseCard {...CARD_PROPS} defaultExpanded />
107
- </Surface>
108
- </View>
109
- </View>
110
-
111
- <View style={{ height: 1, backgroundColor: BORDER_SUBTLE, marginVertical: 8 }} />
112
-
113
- <View style={{ gap: 10, maxWidth: 320 }}>
114
- <Text style={{ ...monoTag, color: T_SECONDARY }}>
115
- the locked active-set spotlight · VelocityStrip variant=&quot;expanded&quot; (bare)
116
- </Text>
117
- <View style={{ backgroundColor: INSET, borderRadius: 8, padding: 12 }}>
118
- <VelocityStrip
119
- variant="expanded"
120
- showNumbers={false}
121
- showInfo={false}
122
- height={24}
123
- scale="fixed"
124
- set={{ type: 'straight', velocities: ACTIVE, planned: 10 }}
125
- />
126
- </View>
127
- <Text style={{ fontFamily: INTER, fontSize: 12.5, color: T_SECONDARY, lineHeight: 19 }}>
128
- A small fixed-height (~24px) velocity-HEIGHT strip: bar height ∝ velocity against a fixed
129
- 1.15 m/s ceiling, planned reps as grey stubs, set-type aware — none of the full
130
- variant&apos;s labels, info row, or mount animation. It reads as the same object as the
131
- flat `mini` strips above it, just taller and brighter to mark the live set.
132
- </Text>
133
- </View>
134
-
135
- <Text
136
- style={{
137
- fontFamily: INTER,
138
- fontSize: 12.5,
139
- color: T_PRIMARY,
140
- lineHeight: 19,
141
- maxWidth: 780,
142
- marginTop: 6,
143
- }}
144
- >
145
- The header is the same molecule collapsed and expanded — the card reads as one object, the
146
- body flowing out of the rail row rather than a separate panel. The expanded card is the real
147
- ExerciseCard; its header per-set strip is derived from the same rows the body renders.
148
- </Text>
149
- </Page>
150
- ),
151
- }
@@ -1,408 +0,0 @@
1
- /**
2
- * Row Inventory — a READ-ONLY survey of every existing way the Workout library renders
3
- * "an exercise / set / workout / week / mesocycle" as a row / list-entry / card.
4
- *
5
- * Built from the 2026-07-08 duplication audit (S3 SessionRail reuse question). This pane only
6
- * NAMES and DISPLAYS what exists — no extraction, no changes to the components. It's here so we
7
- * can eyeball the overlapping row representations together before deciding a reuse strategy.
8
- */
9
- import type { Meta, StoryObj } from '@storybook/react-vite'
10
- import { Component, type ReactNode } from 'react'
11
- import { View, Text } from 'react-native'
12
- import { ExerciseCard } from './ExerciseCard'
13
- import { SetRow } from './SetRow'
14
- import { WorkoutCard } from './WorkoutCard'
15
- import { WorkoutPill } from './WorkoutPill'
16
- import { WeekRow } from './WeekRow'
17
- import { MesoCard } from './MesoCard'
18
- import { MesoProgressBar } from './MesoProgressBar'
19
- import { MuscleGroupChip } from './MuscleGroupChip'
20
- import { StatusDot } from './StatusDot'
21
- import { WeightBadge } from './WeightBadge'
22
- import { PrBadge } from './PrBadge'
23
- import { PlaceholderStrip } from './PlaceholderStrip'
24
- import { SupersetWrapper } from './SupersetWrapper'
25
- import { getSemanticColors } from '../../../theme/tokens/semantic'
26
-
27
- const t = getSemanticColors('dark')
28
-
29
- // ----------------------------------------------------------------------------- gallery scaffold
30
- class Boundary extends Component<{ children: ReactNode }, { err: string | null }> {
31
- state = { err: null as string | null }
32
- static getDerivedStateFromError(e: Error) {
33
- return { err: e.message }
34
- }
35
- render() {
36
- if (this.state.err)
37
- return (
38
- <div style={{ color: '#ff6b6b', fontFamily: 'monospace', fontSize: 11, padding: 8 }}>
39
- render error: {this.state.err}
40
- </div>
41
- )
42
- return this.props.children
43
- }
44
- }
45
-
46
- function Cell({
47
- name,
48
- entity,
49
- expand,
50
- width = 340,
51
- children,
52
- }: {
53
- name: string
54
- entity: string
55
- expand: string
56
- width?: number
57
- children: ReactNode
58
- }) {
59
- return (
60
- <div
61
- style={{
62
- width,
63
- display: 'flex',
64
- flexDirection: 'column',
65
- gap: 8,
66
- padding: 14,
67
- borderRadius: 12,
68
- border: '1px solid #24262d',
69
- background: '#131418',
70
- }}
71
- >
72
- <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
73
- <span style={{ fontSize: 13, fontWeight: 800, color: '#E8EAED' }}>{name}</span>
74
- <span
75
- style={{ fontFamily: 'monospace', fontSize: 10, color: '#5b616d', letterSpacing: 0.3 }}
76
- >
77
- {entity} · {expand}
78
- </span>
79
- </div>
80
- <div style={{ marginTop: 2 }}>
81
- <Boundary>{children}</Boundary>
82
- </div>
83
- </div>
84
- )
85
- }
86
-
87
- function Section({ title, note, children }: { title: string; note?: string; children: ReactNode }) {
88
- return (
89
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
90
- <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
91
- <span
92
- style={{
93
- fontSize: 11,
94
- fontWeight: 800,
95
- letterSpacing: 1.2,
96
- textTransform: 'uppercase',
97
- color: '#FF7900',
98
- }}
99
- >
100
- {title}
101
- </span>
102
- {note && <span style={{ fontSize: 11, color: '#8D95A3' }}>{note}</span>}
103
- </div>
104
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: 14, alignItems: 'flex-start' }}>
105
- {children}
106
- </div>
107
- </div>
108
- )
109
- }
110
-
111
- // ----------------------------------------------------------------------------- sample data
112
- const setVel = [
113
- [0.6, 0.58, 0.55, 0.52],
114
- [0.58, 0.55, 0.53, 0.5],
115
- [0.55, 0.52, 0.5, 0.47],
116
- ]
117
- const exSets = [1, 2, 3, 4].map((n) => ({
118
- state: 'done' as const,
119
- setNumber: n,
120
- reps: 8,
121
- weight: 145,
122
- rpe: 6.5 + n * 0.5,
123
- unit: 'lbs' as const,
124
- velocities: setVel[(n - 1) % 3],
125
- }))
126
- const weeks = [
127
- {
128
- weekNumber: 1,
129
- workouts: [
130
- { name: 'Upper', status: 'completed' as const },
131
- { name: 'Lower', status: 'completed' as const },
132
- ],
133
- },
134
- {
135
- weekNumber: 2,
136
- workouts: [
137
- { name: 'Upper', status: 'current' as const },
138
- { name: 'Lower', status: 'upcoming' as const },
139
- ],
140
- },
141
- {
142
- weekNumber: 3,
143
- workouts: [
144
- { name: 'Upper', status: 'upcoming' as const },
145
- { name: 'Lower', status: 'upcoming' as const },
146
- ],
147
- },
148
- ]
149
- const mesos = [
150
- { id: 'm1', name: 'Accumulation', weekCount: 4, status: 'completed' as const },
151
- { id: 'm2', name: 'Intensification', weekCount: 3, status: 'current' as const, currentWeek: 2 },
152
- { id: 'm3', name: 'Peak', weekCount: 2, status: 'upcoming' as const },
153
- ]
154
-
155
- // ----------------------------------------------------------------------------- the pane
156
- const meta: Meta = {
157
- title: 'Lab/Audits/Row Inventory',
158
- parameters: { layout: 'fullscreen' },
159
- }
160
- export default meta
161
- type Story = StoryObj
162
-
163
- export const AllRows: Story = {
164
- name: 'All row representations',
165
- render: () => (
166
- <div
167
- style={{
168
- minHeight: '100vh',
169
- background: '#0c0d0f',
170
- padding: 28,
171
- display: 'flex',
172
- flexDirection: 'column',
173
- gap: 34,
174
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
175
- }}
176
- >
177
- <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
178
- <span style={{ fontSize: 20, fontWeight: 800, color: '#E8EAED' }}>
179
- Workout library · row representations
180
- </span>
181
- <span style={{ fontSize: 12, color: '#8D95A3', maxWidth: 720 }}>
182
- Every existing component that draws an exercise / set / workout / week / meso as a list
183
- entry. Read-only survey for the S3 reuse decision — names + entity + expand behavior, no
184
- code changes.
185
- </span>
186
- </div>
187
-
188
- <Section
189
- title="Exercise"
190
- note="3 representations of the one ExerciseCard: collapsed glance, expanded body, upcoming"
191
- >
192
- <Cell name="ExerciseCard" entity="exercise" expand="collapsed · expandable">
193
- <ExerciseCard
194
- name="Seated Cable Row"
195
- summary={{ sets: 4, reps: 8, weight: 145, unit: 'lbs' }}
196
- isPR
197
- totalPlannedSets={5}
198
- setVelocities={setVel}
199
- />
200
- </Cell>
201
- <Cell name="ExerciseCard" entity="exercise" expand="expanded → reveals SetRows">
202
- <ExerciseCard
203
- name="Seated Cable Row"
204
- defaultExpanded
205
- summary={{ sets: 4, reps: 8, weight: 145, unit: 'lbs' }}
206
- tempo={[3, 1, 2, 0]}
207
- sets={exSets}
208
- />
209
- </Cell>
210
- <Cell name="ExerciseCard" entity="exercise" expand="upcoming (static)">
211
- <ExerciseCard
212
- name="Face Pull"
213
- upcoming
214
- prescription="3 × 12-15 @ RPE 7"
215
- previousBest="15 × 35 lb"
216
- />
217
- </Cell>
218
- </Section>
219
-
220
- <Section
221
- title="Set"
222
- note="SetRow is the primitive — one row per set lifecycle state (done / live / todo)"
223
- >
224
- <Cell name="SetRow" entity="set · done" expand="no · flat mini strip" width={360}>
225
- <SetRow
226
- state="done"
227
- setNumber={1}
228
- reps={8}
229
- weight={145}
230
- rpe={8}
231
- unit="lbs"
232
- velocities={[0.6, 0.58, 0.55, 0.52]}
233
- />
234
- </Cell>
235
- <Cell name="SetRow" entity="set · live" expand="no · compact spotlight" width={360}>
236
- <SetRow
237
- state="live"
238
- setNumber={2}
239
- unit="lbs"
240
- target={{ reps: 8, weight: 145 }}
241
- reps={8}
242
- weight={145}
243
- velocities={[0.58, 0.55, 0.53, 0.5]}
244
- />
245
- </Cell>
246
- <Cell name="SetRow" entity="set · todo" expand="no · grey stub strip" width={360}>
247
- <SetRow state="todo" setNumber={4} unit="lbs" target={{ reps: 8, weight: 145 }} />
248
- </Cell>
249
- </Section>
250
-
251
- <Section
252
- title="Workout"
253
- note="WorkoutCard (full) and WorkoutPill (chip) = two legit densities; ExerciseDetailPage overloads ExerciseCard as a 3rd"
254
- >
255
- <Cell
256
- name="WorkoutCard"
257
- entity="workout"
258
- expand="expandable · expanded+onToggle → ExerciseCards"
259
- width={380}
260
- >
261
- <WorkoutCard
262
- name="Push Day A"
263
- date="Mon · Jul 6"
264
- duration="52 min"
265
- status="today"
266
- muscleGroups={[
267
- { group: 'chest', label: 'Chest', volumeStatus: 'productive' },
268
- { group: 'delts', label: 'Delts', volumeStatus: 'maintenance' },
269
- { group: 'triceps', label: 'Triceps', volumeStatus: 'under' },
270
- ]}
271
- totalSets={18}
272
- totalVolume={7340}
273
- unit="lbs"
274
- onToggle={() => {}}
275
- />
276
- </Cell>
277
- <Cell name="WorkoutPill" entity="workout · chip" expand="no">
278
- <View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
279
- <WorkoutPill name="Push" status="completed" />
280
- <WorkoutPill name="Pull" status="current" />
281
- <WorkoutPill name="Legs" status="upcoming" />
282
- <WorkoutPill name="Deload" status="deload" />
283
- </View>
284
- </Cell>
285
- </Section>
286
-
287
- <Section
288
- title="Week"
289
- note="WeekRow is the primitive; ExerciseDetailPage overloads ExerciseCard as a competing week row"
290
- >
291
- <Cell
292
- name="WeekRow"
293
- entity="week"
294
- expand="no · row of WorkoutPills + intensity bar"
295
- width={380}
296
- >
297
- <WeekRow
298
- weekNumber={3}
299
- totalWeeks={4}
300
- isCurrent
301
- intensityLevel={0.55}
302
- intensityThreshold={0.8}
303
- workouts={weeks[1].workouts}
304
- />
305
- </Cell>
306
- </Section>
307
-
308
- <Section
309
- title="Mesocycle"
310
- note="3 views for different jobs (list card / timeline / detail) — each with its own status enum"
311
- >
312
- <Cell
313
- name="MesoCard"
314
- entity="meso"
315
- expand="expandable · expanded+onToggle → WeekRows"
316
- width={380}
317
- >
318
- <MesoCard
319
- name="Accumulation"
320
- goal="Hypertrophy"
321
- split="Upper/Lower"
322
- weekRange="Weeks 1-4"
323
- currentWeek={2}
324
- totalWeeks={4}
325
- weeks={weeks}
326
- volumeHeatmap={[
327
- { group: 'chest', percentage: 80 },
328
- { group: 'back', percentage: 70 },
329
- { group: 'legs', percentage: 90 },
330
- ]}
331
- />
332
- </Cell>
333
- <Cell name="MesoProgressBar" entity="meso · timeline" expand="no · segments" width={380}>
334
- <MesoProgressBar mesos={mesos} />
335
- </Cell>
336
- </Section>
337
-
338
- <Section
339
- title="Shared sub-parts"
340
- note="appear inside the rows above — not entity rows themselves"
341
- >
342
- <Cell name="MuscleGroupChip" entity="muscle-group" expand="no">
343
- <View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
344
- <MuscleGroupChip name="Chest" volumeStatus="ontrack" />
345
- <MuscleGroupChip name="Quads" volumeStatus="behind" />
346
- <MuscleGroupChip name="Lats" volumeStatus="over" />
347
- </View>
348
- </Cell>
349
- <Cell name="StatusDot" entity="status glyph" expand="no">
350
- <StatusDot variant="success" label="On track" />
351
- </Cell>
352
- <Cell name="WeightBadge" entity="badge" expand="no">
353
- <View style={{ flexDirection: 'row', gap: 8 }}>
354
- <WeightBadge value={205} unit="lbs" />
355
- <WeightBadge value={217} unit="lbs" isPr />
356
- </View>
357
- </Cell>
358
- <Cell name="PrBadge" entity="badge" expand="no">
359
- <PrBadge type="e1rm" animate={false} />
360
- </Cell>
361
- <Cell name="PlaceholderStrip" entity="pending-set strip" expand="no">
362
- <View style={{ flexDirection: 'row', gap: 4 }}>
363
- <PlaceholderStrip />
364
- <PlaceholderStrip />
365
- <PlaceholderStrip />
366
- </View>
367
- </Cell>
368
- <Cell name="SupersetWrapper" entity="grouping bracket" expand="no">
369
- <SupersetWrapper label="SS1" color="#FF7900">
370
- <View style={{ padding: 10, backgroundColor: t['surface-raised'], borderRadius: 8 }}>
371
- <Text style={{ color: '#F3F4F6' }}>Exercise A</Text>
372
- </View>
373
- <View style={{ padding: 10, backgroundColor: t['surface-raised'], borderRadius: 8 }}>
374
- <Text style={{ color: '#F3F4F6' }}>Exercise B</Text>
375
- </View>
376
- </SupersetWrapper>
377
- </Cell>
378
- </Section>
379
-
380
- <Section
381
- title="Page-level organisms"
382
- note="composition roots (390px+), not rows — listed for reference, see their own stories"
383
- >
384
- {[
385
- ['ActiveWorkoutPage', 'renders ExerciseCards + SupersetWrapper + InputBar/RestTimer'],
386
- ['ProgramPlanningPage', 'MesoProgressBar + MesoCard → WeekRow → WorkoutCard drill-down'],
387
- ['ExerciseDetailPage', 'EntryList overloads ExerciseCard as week AND session rows'],
388
- ['MesoStatusCard', 'per-exercise meso detail card (StatusDot + metric grid + gauges)'],
389
- ['ReadinessCheck', 'pre-workout factor rows + score gauge'],
390
- ].map(([n, d]) => (
391
- <div
392
- key={n}
393
- style={{
394
- width: 340,
395
- padding: 14,
396
- borderRadius: 12,
397
- border: '1px dashed #31343d',
398
- background: '#0f1012',
399
- }}
400
- >
401
- <div style={{ fontSize: 13, fontWeight: 800, color: '#E8EAED' }}>{n}</div>
402
- <div style={{ fontSize: 11, color: '#8D95A3', marginTop: 4 }}>{d}</div>
403
- </div>
404
- ))}
405
- </Section>
406
- </div>
407
- ),
408
- }