@titan-design/react-ui 0.12.0 → 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 +1320 -215
  7. package/dist/index.d.ts +1320 -215
  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 +202 -1042
  21. package/dist/theme/index.d.ts +202 -1042
  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 +972 -0
  31. package/dist/theme/tokens.d.ts +972 -0
  32. package/dist/theme/tokens.js +904 -0
  33. package/dist/theme/tokens.js.map +1 -0
  34. package/dist/theme/tokens.mjs +880 -0
  35. package/dist/theme/tokens.mjs.map +1 -0
  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 +7 -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 +12 -7
  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 +90 -27
  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 +24 -22
  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 +102 -0
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +67 -35
  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,11 +1,10 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import { useEffect, useState } from 'react'
3
- import { View, Text, Animated, Easing, type ViewProps } from 'react-native'
3
+ import { View, Animated, Easing, type ViewProps } from 'react-native'
4
4
  import { StarIcon } from './icons'
5
5
  import { BaseBadge } from './BaseBadge'
6
- import { getSemanticColors } from '../../../theme/tokens/semantic'
7
-
8
- const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
6
+ import { Typography } from '../Typography'
7
+ import { resolveColor } from '../../../theme/resolve-color'
9
8
 
10
9
  export type PRType = 'e1rm' | 'weight' | 'reps' | 'volume' | 'velocity'
11
10
 
@@ -38,6 +37,7 @@ export function PrBadge({
38
37
  ...props
39
38
  }: PrBadgeProps) {
40
39
  const resolvedLabel = labelProp ?? typeLabels[type]
40
+ const brandPrimary = resolveColor('brand-primary')
41
41
  const [scale] = useState(() => new Animated.Value(animate ? 0.8 : 1))
42
42
  const [opacity] = useState(() => new Animated.Value(animate ? 0 : 1))
43
43
 
@@ -69,7 +69,7 @@ export function PrBadge({
69
69
  testID="pr-badge-star"
70
70
  {...props}
71
71
  >
72
- <StarIcon size={14} color={BRAND_PRIMARY} fill={BRAND_PRIMARY} strokeWidth={2} />
72
+ <StarIcon size={14} color={brandPrimary} fill={brandPrimary} strokeWidth={2} />
73
73
  </View>
74
74
  ) : (
75
75
  <BaseBadge
@@ -78,25 +78,21 @@ export function PrBadge({
78
78
  accessibilityLabel={`Personal record: ${resolvedLabel}`}
79
79
  {...props}
80
80
  >
81
- <Text
82
- style={{
83
- fontSize: 12,
84
- color: BRAND_PRIMARY,
85
- fontWeight: '700',
86
- fontFamily: 'Inter, sans-serif',
87
- }}
81
+ {/* `boldLabel` is the badge label exactly: 12px/700 Inter. The line box is pinned
82
+ because the raw <Text> it replaced carried no lineHeight. */}
83
+ <Typography
84
+ variant="boldLabel"
85
+ color="inherit"
86
+ className="leading-[normal] text-brand-primary"
88
87
  >
89
88
  {'\u2605'} {resolvedLabel}
90
- </Text>
89
+ </Typography>
91
90
  </BaseBadge>
92
91
  )
93
92
 
94
93
  if (animate) {
95
94
  return (
96
- <Animated.View
97
- style={{ transform: [{ scale }], opacity }}
98
- testID="pr-badge-animated"
99
- >
95
+ <Animated.View style={{ transform: [{ scale }], opacity }} testID="pr-badge-animated">
100
96
  {badge}
101
97
  </Animated.View>
102
98
  )
@@ -12,8 +12,11 @@ const records: PrRecord[] = [
12
12
  ]
13
13
 
14
14
  const meta: Meta<typeof PrHistoryModal> = {
15
- title: 'Workout/PrHistoryModal',
15
+ title: 'Custom/Workout/PrHistoryModal',
16
16
  component: PrHistoryModal,
17
+ parameters: {
18
+ docs: { description: { component: 'Composes **Icons** · **Drawer** · **DrawerBody**.' } },
19
+ },
17
20
  tags: ['autodocs'],
18
21
  argTypes: {
19
22
  exerciseId: {
@@ -23,7 +23,7 @@ describe('PrHistoryModal', () => {
23
23
  render(<PrHistoryModal {...baseProps} />)
24
24
  expect(screen.getByTestId('pr-history-modal')).toBeInTheDocument()
25
25
  expect(screen.getByTestId('pr-history-modal-title')).toHaveTextContent(
26
- 'Bench Press PR history',
26
+ 'Bench Press PR history'
27
27
  )
28
28
  })
29
29
 
@@ -40,23 +40,14 @@ describe('PrHistoryModal', () => {
40
40
  visible
41
41
  records={records}
42
42
  onClose={vi.fn()}
43
- />,
43
+ />
44
44
  )
45
45
  expect(screen.getByTestId('pr-history-modal')).toBeInTheDocument()
46
46
  })
47
47
 
48
48
  it('falls back to exerciseId when no name is given', () => {
49
- render(
50
- <PrHistoryModal
51
- exerciseId="deadlift"
52
- isOpen
53
- records={records}
54
- onClose={vi.fn()}
55
- />,
56
- )
57
- expect(screen.getByTestId('pr-history-modal-title')).toHaveTextContent(
58
- 'deadlift PR history',
59
- )
49
+ render(<PrHistoryModal exerciseId="deadlift" isOpen records={records} onClose={vi.fn()} />)
50
+ expect(screen.getByTestId('pr-history-modal-title')).toHaveTextContent('deadlift PR history')
60
51
  })
61
52
 
62
53
  it('renders a drag handle', () => {
@@ -68,22 +59,14 @@ describe('PrHistoryModal', () => {
68
59
  describe('records', () => {
69
60
  it('renders a row per record with type, value, and date', () => {
70
61
  render(<PrHistoryModal {...baseProps} />)
71
- expect(screen.getByTestId('pr-history-modal-record-0-type')).toHaveTextContent(
72
- 'e1RM',
73
- )
74
- expect(screen.getByTestId('pr-history-modal-record-0-value')).toHaveTextContent(
75
- '245 lbs',
76
- )
77
- expect(screen.getByTestId('pr-history-modal-record-0-date')).toHaveTextContent(
78
- 'Mar 14',
79
- )
62
+ expect(screen.getByTestId('pr-history-modal-record-0-type')).toHaveTextContent('e1RM')
63
+ expect(screen.getByTestId('pr-history-modal-record-0-value')).toHaveTextContent('245 lbs')
64
+ expect(screen.getByTestId('pr-history-modal-record-0-date')).toHaveTextContent('Mar 14')
80
65
  })
81
66
 
82
67
  it('renders pre-formatted string values verbatim', () => {
83
68
  render(<PrHistoryModal {...baseProps} />)
84
- expect(screen.getByTestId('pr-history-modal-record-1-value')).toHaveTextContent(
85
- '8 @ 185 lbs',
86
- )
69
+ expect(screen.getByTestId('pr-history-modal-record-1-value')).toHaveTextContent('8 @ 185 lbs')
87
70
  })
88
71
 
89
72
  it('renders one row per supplied record', () => {
@@ -91,27 +74,21 @@ describe('PrHistoryModal', () => {
91
74
  expect(screen.getByTestId('pr-history-modal-record-0')).toBeInTheDocument()
92
75
  expect(screen.getByTestId('pr-history-modal-record-1')).toBeInTheDocument()
93
76
  expect(screen.getByTestId('pr-history-modal-record-2')).toBeInTheDocument()
94
- expect(
95
- screen.queryByTestId('pr-history-modal-record-3'),
96
- ).not.toBeInTheDocument()
77
+ expect(screen.queryByTestId('pr-history-modal-record-3')).not.toBeInTheDocument()
97
78
  })
98
79
 
99
80
  it('marks recent records in their accessible label', () => {
100
81
  render(<PrHistoryModal {...baseProps} />)
101
82
  expect(
102
- screen.getByLabelText('e1RM personal record: 245 lbs, Mar 14, recent'),
103
- ).toBeInTheDocument()
104
- expect(
105
- screen.getByLabelText('Reps personal record: 8 @ 185 lbs, Feb 28'),
83
+ screen.getByLabelText('e1RM personal record: 245 lbs, Mar 14, recent')
106
84
  ).toBeInTheDocument()
85
+ expect(screen.getByLabelText('Reps personal record: 8 @ 185 lbs, Feb 28')).toBeInTheDocument()
107
86
  })
108
87
 
109
88
  it('shows an empty state when there are no records', () => {
110
89
  render(<PrHistoryModal {...baseProps} records={[]} />)
111
90
  expect(screen.getByTestId('pr-history-modal-empty')).toBeInTheDocument()
112
- expect(
113
- screen.queryByTestId('pr-history-modal-record-0'),
114
- ).not.toBeInTheDocument()
91
+ expect(screen.queryByTestId('pr-history-modal-record-0')).not.toBeInTheDocument()
115
92
  })
116
93
  })
117
94
 
@@ -153,7 +130,7 @@ describe('PrHistoryModal', () => {
153
130
  { type: 'weight', value: 365, unit: 'lbs', date: 'Last week' },
154
131
  { type: 'volume', value: '18,200 lbs', date: 'Mar 1' },
155
132
  ]}
156
- />,
133
+ />
157
134
  )
158
135
  expect(await axe(container)).toHaveNoViolations()
159
136
  })
@@ -4,10 +4,14 @@ import { StarIcon } from './icons'
4
4
  import { Drawer, DrawerBody } from '../../ui/drawer'
5
5
  import { resolveColor } from '../../../theme/resolve-color'
6
6
  import { getSemanticColors } from '../../../theme/tokens/semantic'
7
+ import { getGlowShadow } from '../../../theme/elevation'
8
+ import { alpha } from '../../../utils/colors'
7
9
 
8
- const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
9
- const RECENT_BORDER = 'rgba(249,180,21,0.3)'
10
- const RECENT_GLOW = '0 0 12px rgba(249,180,21,0.06)'
10
+ const SEMANTIC = getSemanticColors('dark')
11
+ const BRAND_PRIMARY = SEMANTIC['brand-primary']
12
+ const RECENT_BORDER = alpha(SEMANTIC['status-warning'], 0.3)
13
+ /** A recent PR is EMPHASIS, not depth: a warning-toned glow, shared builder. */
14
+ const RECENT_GLOW = getGlowShadow(SEMANTIC['status-warning'], 'subtle')
11
15
  // Native-safe fallback for the conditional row border (recent uses a computed
12
16
  // rgba, so className can't express both branches).
13
17
  const BORDER_DEFAULT = resolveColor('hairline-default')
@@ -81,7 +85,7 @@ function PrRecordRow({ record, index }: { record: PrRecord; index: number }) {
81
85
  borderRadius: 8,
82
86
  borderWidth: 1,
83
87
  borderColor: record.isRecent ? RECENT_BORDER : BORDER_DEFAULT,
84
- ...(record.isRecent ? { boxShadow: RECENT_GLOW } : {}),
88
+ ...(record.isRecent ? RECENT_GLOW : {}),
85
89
  }}
86
90
  testID={`pr-history-modal-record-${index}`}
87
91
  >
@@ -230,7 +230,12 @@ const mesos: PlanMeso[] = [accumulationDone, accumulation, intensification, peak
230
230
  const meta: Meta<typeof ProgramPlanningPage> = {
231
231
  title: 'Pages/Program Planning',
232
232
  component: ProgramPlanningPage,
233
- parameters: { layout: 'fullscreen' },
233
+ parameters: {
234
+ layout: 'fullscreen',
235
+ docs: {
236
+ description: { component: 'Composes **MesoProgressBar** · **MesoCard** · **WorkoutCard**.' },
237
+ },
238
+ },
234
239
  tags: ['autodocs'],
235
240
  args: { title: 'Program Plan', mesos },
236
241
  }
@@ -102,10 +102,14 @@ type props without pulling the dependency.
102
102
  (`SET_STRIP_VARIABLE_COLOR`) is the shared "variable / unknown / opportunity" pin.
103
103
  `SegmentedBar` carries these via additive `leadingGap` (per-segment left margin) and
104
104
  static `opacity` props — the flat sets stay byte-identical.
105
+ `active`/`todo` sets optionally carry the plan's prescribed rep RANGE (`repsLow`/
106
+ `repsHigh`, VMCP-03.04), rendered as a small label above the bar (`8–12`, or `8` when
107
+ equal/only one is given) via the shared `formatRepsRange` helper — independent of
108
+ `range`'s `floor`/`max` value range.
105
109
  `SetStrip`/`SetBar` colors are the real titan ramp pins (`primitiveRamps` red-600 /
106
- orange-400 / amber-300 / green-300); the rail surfaces bind to the charcoal ramp +
107
- a subtle neumorphic inset (`neumorphicShadows.charcoal.pressed.subtle`). The heading
108
- design is locked in `coordination/.../S3-sessionrail/DECISIONS-ExerciseRow.md`; the
110
+ orange-400 / amber-300 / green-300); the rail surfaces bind to the grey ramp and the
111
+ list is a well cut with the shared `insetWell` material. The heading
112
+ design is locked in `sources/design/shell/S3-sessionrail/DECISIONS-ExerciseRow.md`; the
109
113
  exploration specimens live under `Custom/Workout/Explorations/*` (do not repoint yet).
110
114
  In Storybook the family nests by composition under **`Shell/SessionRail/…`**
111
115
  (organism → `ExerciseCardHeading` → `ExerciseHeading` → its atoms/molecules →
@@ -179,13 +183,13 @@ Modalities`** (each card carries a `Collapse` accordion; promoted from the
179
183
  vertical (rotated) orientation so it never overlaps the bars. Two scales: `hero` (tall
180
184
  wings, per-rep m/s velocity labels, a dashed running-best reference line per side) and
181
185
  `rail` (compact — no velocity labels / reference lines, slot names in a narrow gutter).
182
- **Rep-index alignment is the invariant:** column *i* is rep *i* on
183
- both sides, so the set-type slot *kinds* carry through (rep / todo / variable / continue,
186
+ **Rep-index alignment is the invariant:** column _i_ is rep _i_ on
187
+ both sides, so the set-type slot _kinds_ carry through (rep / todo / variable / continue,
184
188
  coloured as in the single strip) but the wide-notch chunk **gaps** (drop / myo / cluster
185
189
  boundaries) are intentionally NOT rendered — per-side horizontal gaps would break the
186
190
  mirrored L↔R column alignment. Single-voltra sets keep using `VelocityStrip`
187
191
  `variant="hero"`. Documented by the `Playground` / `Hero*` / `Rail` stories on the wall
188
- background (`Workout/DataViz/DualVelocityStrip`).
192
+ background (`Custom/Workout/DataViz/DualVelocityStrip`).
189
193
 
190
194
  **Reuse audit — `DashedReferenceLine` (in-file today, top-level follow-up).** The dashed
191
195
  running-best line was hand-rolled three times inside `VelocityStrip.tsx` (the single
@@ -199,6 +203,7 @@ Modalities`** (each card carries a `Collapse` accordion; promoted from the
199
203
  a follow-up so the hero PR stays focused (the cross-file migration touches `Sparkline`'s
200
204
  test surface and the Lab specimens, which are out of this branch's scope). Proposed API:
201
205
  `<ReferenceLine anchor offset color dashed opacity? label? testID />`.
206
+
202
207
  - **RestTimer `ring` variant** — the across-the-room **wall** rest treatment (the
203
208
  north-star rest page). Built as a **three-tier decomposition** (not a one-off):
204
209
  `CircularProgress` (atom, gained a **`children`** center slot + a **`fill`**
@@ -215,7 +220,7 @@ Modalities`** (each card carries a `Collapse` accordion; promoted from the
215
220
  hides the shared `RestActions` (+30s/Skip, extracted, used by both variants);
216
221
  `size` (default 180) sets the diameter; the eyebrow/section title is organism
217
222
  chrome. Web/RNW-only (like `CircularProgress`) — the wall variant; mobile keeps
218
- `bar`. `Ring*` (RestTimer) + `Custom/CircularTimer` stories on the wall background.
223
+ `bar`. `Ring*` (RestTimer) + `Components/Molecules/CircularTimer` stories on the wall background.
219
224
  - **`size="wall"` density (FatigueMeter · ZoneTrack)** — the across-the-room
220
225
  dashboard scale, added as the idiomatic titan `size` union (a JS number-map per
221
226
  component; **`default` values are byte-identical** to before, so existing consumers are
@@ -16,8 +16,9 @@ const staticFactors: ReadinessFactor[] = FACTOR_SEED.map((f) => ({
16
16
  }))
17
17
 
18
18
  const meta: Meta<typeof ReadinessCheck> = {
19
- title: 'Workout/ReadinessCheck',
19
+ title: 'Custom/Workout/ReadinessCheck',
20
20
  component: ReadinessCheck,
21
+ parameters: { docs: { description: { component: 'Composes **Card** · **Badge**.' } } },
21
22
  tags: ['autodocs'],
22
23
  argTypes: {
23
24
  score: {
@@ -89,7 +90,7 @@ export const WithWarmUpCaution: Story = {
89
90
 
90
91
  function InteractiveReadinessCheck() {
91
92
  const [values, setValues] = useState<Record<string, number>>(
92
- Object.fromEntries(FACTOR_SEED.map((f) => [f.id, f.value])),
93
+ Object.fromEntries(FACTOR_SEED.map((f) => [f.id, f.value]))
93
94
  )
94
95
 
95
96
  const factors: ReadinessFactor[] = FACTOR_SEED.map((f) => ({
@@ -22,9 +22,7 @@ describe('ReadinessCheck', () => {
22
22
  describe('rendering', () => {
23
23
  it('renders the title and one row per factor', () => {
24
24
  render(<ReadinessCheck {...baseProps} factors={makeFactors()} />)
25
- expect(screen.getByTestId('readiness-check-title')).toHaveTextContent(
26
- 'How are you feeling?',
27
- )
25
+ expect(screen.getByTestId('readiness-check-title')).toHaveTextContent('How are you feeling?')
28
26
  expect(screen.getByTestId('readiness-check-factor-sleep')).toBeInTheDocument()
29
27
  expect(screen.getByTestId('readiness-check-factor-stress')).toBeInTheDocument()
30
28
  })
@@ -78,7 +76,7 @@ describe('ReadinessCheck', () => {
78
76
  {...baseProps}
79
77
  factors={makeFactors()}
80
78
  warmUpValidation={{ velocityDeficit: 5, recommendation: 'OK', status: 'good' }}
81
- />,
79
+ />
82
80
  )
83
81
  expect(screen.queryByTestId('readiness-check-warmup')).not.toBeInTheDocument()
84
82
  })
@@ -94,13 +92,13 @@ describe('ReadinessCheck', () => {
94
92
  recommendation: 'Reduce load today.',
95
93
  status: 'caution',
96
94
  }}
97
- />,
95
+ />
98
96
  )
99
97
  expect(screen.getByTestId('readiness-check-warmup-deficit')).toHaveTextContent(
100
- '18% below 14-day average',
98
+ '18% below 14-day average'
101
99
  )
102
100
  expect(screen.getByTestId('readiness-check-warmup-recommendation')).toHaveTextContent(
103
- 'Reduce load today.',
101
+ 'Reduce load today.'
104
102
  )
105
103
  expect(screen.getByTestId('readiness-check-warmup-badge')).toHaveTextContent('Caution')
106
104
  })
@@ -112,10 +110,10 @@ describe('ReadinessCheck', () => {
112
110
  factors={makeFactors()}
113
111
  warmUpCompleted
114
112
  warmUpValidation={{ velocityDeficit: 0, recommendation: 'Proceed.', status: 'good' }}
115
- />,
113
+ />
116
114
  )
117
115
  expect(screen.getByTestId('readiness-check-warmup-deficit')).toHaveTextContent(
118
- 'Velocity on 14-day average',
116
+ 'Velocity on 14-day average'
119
117
  )
120
118
  })
121
119
 
@@ -126,10 +124,10 @@ describe('ReadinessCheck', () => {
126
124
  factors={makeFactors()}
127
125
  warmUpCompleted
128
126
  warmUpValidation={{ velocityDeficit: -6, recommendation: 'Proceed.', status: 'good' }}
129
- />,
127
+ />
130
128
  )
131
129
  expect(screen.getByTestId('readiness-check-warmup-deficit')).toHaveTextContent(
132
- 'Velocity 6% above 14-day average',
130
+ 'Velocity 6% above 14-day average'
133
131
  )
134
132
  })
135
133
  })
@@ -149,15 +147,11 @@ describe('ReadinessCheck', () => {
149
147
 
150
148
  it('exposes the readiness score on the gauge', () => {
151
149
  render(<ReadinessCheck {...baseProps} factors={makeFactors()} score={78} />)
152
- expect(
153
- screen.getByLabelText('Readiness score: 78 out of 100'),
154
- ).toBeInTheDocument()
150
+ expect(screen.getByLabelText('Readiness score: 78 out of 100')).toBeInTheDocument()
155
151
  })
156
152
 
157
153
  it('has no accessibility violations', async () => {
158
- const { container } = render(
159
- <ReadinessCheck {...baseProps} factors={makeFactors()} />,
160
- )
154
+ const { container } = render(<ReadinessCheck {...baseProps} factors={makeFactors()} />)
161
155
  expect(await axe(container)).toHaveNoViolations()
162
156
  })
163
157
 
@@ -173,7 +167,7 @@ describe('ReadinessCheck', () => {
173
167
  status: 'moderate',
174
168
  }}
175
169
  onConfirm={vi.fn()}
176
- />,
170
+ />
177
171
  )
178
172
  expect(await axe(container)).toHaveNoViolations()
179
173
  })
@@ -71,7 +71,11 @@ const WARMUP_BADGE: Record<WarmUpStatus, { color: BadgeColor; label: string }> =
71
71
  }
72
72
 
73
73
  function emojiSet(factor: ReadinessFactor): readonly string[] {
74
- return EMOJI_SETS[factor.id.toLowerCase()] ?? EMOJI_SETS[factor.label.toLowerCase()] ?? DEFAULT_EMOJI_SET
74
+ return (
75
+ EMOJI_SETS[factor.id.toLowerCase()] ??
76
+ EMOJI_SETS[factor.label.toLowerCase()] ??
77
+ DEFAULT_EMOJI_SET
78
+ )
75
79
  }
76
80
 
77
81
  /** Warm-up velocity phrasing. Deficit is % below the 14-day average, so a
@@ -158,7 +162,12 @@ function ScoreGauge({ score }: { score: number }) {
158
162
  }}
159
163
  >
160
164
  <Text
161
- style={{ fontSize: 20, fontWeight: '700', fontFamily: '"Space Grotesk", sans-serif', color }}
165
+ style={{
166
+ fontSize: 20,
167
+ fontWeight: '700',
168
+ fontFamily: '"Space Grotesk", sans-serif',
169
+ color,
170
+ }}
162
171
  testID="readiness-check-score-value"
163
172
  >
164
173
  {score}
@@ -260,7 +269,14 @@ export function ReadinessCheck({
260
269
  opacity: pressed ? 0.8 : 1,
261
270
  })}
262
271
  >
263
- <Text style={{ fontSize: 13, fontWeight: '700', fontFamily: 'Inter, sans-serif', color: '#FFFFFF' }}>
272
+ <Text
273
+ style={{
274
+ fontSize: 13,
275
+ fontWeight: '700',
276
+ fontFamily: 'Inter, sans-serif',
277
+ color: '#FFFFFF',
278
+ }}
279
+ >
264
280
  Start Workout
265
281
  </Text>
266
282
  </Pressable>
@@ -3,7 +3,7 @@ import { View, Text } from 'react-native'
3
3
  import { RestTimer } from './RestTimer'
4
4
 
5
5
  const meta: Meta<typeof RestTimer> = {
6
- title: 'Workout/RestTimer',
6
+ title: 'Custom/Workout/RestTimer',
7
7
  component: RestTimer,
8
8
  tags: ['autodocs'],
9
9
  parameters: {
@@ -16,7 +16,8 @@ const meta: Meta<typeof RestTimer> = {
16
16
  'across-the-room wall treatment: a draining countdown ring (composes `CircularProgress`) ' +
17
17
  'with the mm:ss countdown in its center, flipping to a full `success` ring reading "GO" ' +
18
18
  'when rest is up. `displayOnly` hides the +30s/Skip controls in either variant; `size` ' +
19
- 'sets the ring diameter.',
19
+ 'sets the ring diameter.' +
20
+ ' Composes **CircularTimer**.',
20
21
  },
21
22
  },
22
23
  },
@@ -9,14 +9,15 @@ const DAY = 24 * HOUR
9
9
  const NOW = Date.now()
10
10
 
11
11
  const meta: Meta<typeof ScheduleTiles> = {
12
- title: 'Workout/ScheduleTiles',
12
+ title: 'Custom/Workout/ScheduleTiles',
13
13
  component: ScheduleTiles,
14
14
  tags: ['autodocs'],
15
15
  parameters: {
16
16
  docs: {
17
17
  description: {
18
18
  component:
19
- '**Molecule.** An HStack of [Tile](?path=/docs/components-atoms-tile--docs); Until reuses [DateTime](?path=/docs/custom-datetime--docs) relative. Used-by ↑ SessionHeader.',
19
+ '**Molecule.** An HStack of [Tile](?path=/docs/components-atoms-tile--docs); Until reuses [DateTime](?path=/docs/custom-datetime--docs) relative. Used-by ↑ SessionHeader.' +
20
+ ' Composes **HStack** · **Tile**.',
20
21
  },
21
22
  },
22
23
  },
@@ -1,11 +1,10 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import { render, screen } from '@testing-library/react'
3
3
  import { ScheduleTiles, compactUntil } from './ScheduleTiles'
4
- import { primitiveRamps } from '../../../theme/tokens/primitives'
4
+ import { resolveColor } from '../../../theme/resolve-color'
5
5
 
6
6
  const HOUR = 60 * 60 * 1000
7
7
  const DAY = 24 * HOUR
8
- const ORANGE = primitiveRamps.orange[400]
9
8
 
10
9
  // A fixed reference; the compact Until label is deterministic from (when - now).
11
10
  const NOW = Date.now()
@@ -25,10 +24,10 @@ describe('ScheduleTiles', () => {
25
24
  expect(value.style.color).toBe('')
26
25
  })
27
26
 
28
- it('accents the Until value orange when less than a day away', () => {
27
+ it('accents the Until value with the brand token when less than a day away', () => {
29
28
  const when = NOW + 5 * HOUR
30
29
  render(<ScheduleTiles now={NOW} when={when} />)
31
30
  const value = screen.getByText(compactUntil(when - NOW))
32
- expect(value).toHaveStyle({ color: ORANGE })
31
+ expect(value).toHaveStyle({ color: resolveColor('brand-primary') })
33
32
  })
34
33
  })
@@ -1,15 +1,12 @@
1
1
  import { useState } from 'react'
2
2
  import { type ViewProps } from 'react-native'
3
- import { primitiveRamps } from '../../../theme/tokens/primitives'
3
+ import { resolveColor } from '../../../theme/resolve-color'
4
4
  import { HStack } from '../../ui/stack'
5
5
  import { Tile } from '../../ui/tile/Tile'
6
6
  import { formatDateTime } from '../DateTime/DateTime'
7
7
 
8
8
  const DAY_MS = 24 * 60 * 60 * 1000
9
9
 
10
- /** Accent applied to the Until value when the session is < 1 day away. */
11
- const SOON_ACCENT = primitiveRamps.orange[400]
12
-
13
10
  /** Compact time-until label: `30m` / `5h` / `2d` / `3w`. Deterministic from the delta. */
14
11
  export function compactUntil(ms: number): string {
15
12
  if (ms <= 0) return 'now'
@@ -37,8 +34,8 @@ export interface ScheduleTilesProps extends ViewProps {
37
34
  * ScheduleTiles — Date / Time / Until row for an upcoming session.
38
35
  *
39
36
  * An HStack of three {@link Tile}s derived from a single scheduled moment. The
40
- * Until value reuses {@link formatDateTime} relative formatting and turns
41
- * accent-orange only when the session is less than a day away.
37
+ * Until value reuses {@link formatDateTime} relative formatting and takes the
38
+ * `brand-primary` accent only when the session is less than a day away.
42
39
  *
43
40
  * @example
44
41
  * <ScheduleTiles when={Date.now() + 5 * 60 * 60 * 1000} />
@@ -63,7 +60,7 @@ export function ScheduleTiles({ when, now, gap = 1, ...props }: ScheduleTilesPro
63
60
  <Tile
64
61
  label="Until"
65
62
  value={compactUntil(whenMs - reference)}
66
- valueColor={soon ? SOON_ACCENT : undefined}
63
+ valueColor={soon ? resolveColor('brand-primary') : undefined}
67
64
  />
68
65
  </HStack>
69
66
  )
@@ -1,6 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { View } from 'react-native'
3
2
  import { SegmentedBar } from './SegmentedBar'
3
+ import { Surface } from '../../ui/surface'
4
4
 
5
5
  /**
6
6
  * `SegmentedBar` — a horizontal track split into weighted, individually-fillable
@@ -9,7 +9,7 @@ import { SegmentedBar } from './SegmentedBar'
9
9
  * vertical line at a fraction of the width. Colours are passed-in literal hex.
10
10
  */
11
11
  const meta: Meta<typeof SegmentedBar> = {
12
- title: 'Workout/SegmentedBar',
12
+ title: 'Custom/Workout/SegmentedBar',
13
13
  component: SegmentedBar,
14
14
  tags: ['autodocs'],
15
15
  parameters: {
@@ -19,7 +19,7 @@ const meta: Meta<typeof SegmentedBar> = {
19
19
  '**Atom.** A horizontal track split into weighted, individually-fillable ' +
20
20
  'segments (weight · fill · colour · pulse) with an optional marker line — the ' +
21
21
  'presentational primitive the per-set strips build on. ' +
22
- 'Used-by ↑ [SetStrip](?path=/docs/workout-setstrip--docs).',
22
+ 'Used-by ↑ [SetStrip](?path=/docs/custom-workout-setstrip--docs).',
23
23
  },
24
24
  },
25
25
  },
@@ -30,9 +30,9 @@ const meta: Meta<typeof SegmentedBar> = {
30
30
  },
31
31
  decorators: [
32
32
  (Story) => (
33
- <View style={{ width: 240, padding: 16, backgroundColor: '#131313' }}>
33
+ <Surface level="base" style={{ width: 240, padding: 16 }}>
34
34
  <Story />
35
- </View>
35
+ </Surface>
36
36
  ),
37
37
  ],
38
38
  }
@@ -16,13 +16,16 @@ export interface SegmentedBarSegment {
16
16
  weight?: number
17
17
  /** Fraction 0..1 of the slot the coloured fill covers, left-aligned. Default 1 (full). */
18
18
  fill?: number
19
- /** Fill colour — a literal hex (RNW-safe), never a `var()` token ref. */
19
+ /** Fill colour. Pass `resolveColor(token)` — a plain fill takes a `var()` ref fine. */
20
20
  color: string
21
21
  /** When true the fill animates on the shared active-pulse loop. */
22
22
  pulse?: boolean
23
23
  /**
24
24
  * When pulsing, interpolate the fill's `backgroundColor` from→to over the loop
25
25
  * (full opacity). Omit to fall back to the default opacity breathe.
26
+ *
27
+ * Literal hex only: `Animated.interpolate` parses these two endpoints itself
28
+ * and cannot read a `var()` ref, so `resolveColor(token)` does not work here.
26
29
  */
27
30
  pulseColor?: [from: string, to: string]
28
31
  /**
@@ -90,7 +93,8 @@ function usePulse(active: boolean): Animated.Value {
90
93
  * presentational atom the per-set strips are built from. Each segment is a flex
91
94
  * slot (flex = `weight`) holding a left-aligned fill (`fill` fraction, `color`);
92
95
  * `pulse` segments breathe on a shared active-pulse loop, and `marker` drops a
93
- * vertical line at a fraction of the total width. Colours are passed-in literal hex.
96
+ * vertical line at a fraction of the total width. Every colour is injected by the
97
+ * composer, so this atom holds no palette of its own.
94
98
  */
95
99
  export function SegmentedBar({
96
100
  segments,
@@ -1,27 +1,27 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import type { Meta, StoryObj } from '@storybook/react-vite'
3
- import { View } from 'react-native'
4
3
  import { SegmentedProgressBar } from './SegmentedProgressBar'
4
+ import { Surface } from '../../ui/surface'
5
5
 
6
6
  const PLAN = [{ weight: 3 }, { weight: 3 }, { weight: 2 }, { weight: 2 }, { weight: 2 }]
7
7
 
8
8
  const meta: Meta<typeof SegmentedProgressBar> = {
9
- title: 'Workout/SegmentedProgressBar',
9
+ title: 'Custom/Workout/SegmentedProgressBar',
10
10
  component: SegmentedProgressBar,
11
11
  tags: ['autodocs'],
12
12
  parameters: {
13
13
  docs: {
14
14
  description: {
15
15
  component:
16
- '**Atom.** Composes [SegmentedBar](?path=/docs/workout-segmentedbar--docs) + paceTone. Used-by ↑ SessionHeader.',
16
+ '**Atom.** Composes [SegmentedBar](?path=/docs/custom-workout-segmentedbar--docs) + paceTone. Used-by ↑ SessionHeader.',
17
17
  },
18
18
  },
19
19
  },
20
20
  decorators: [
21
21
  (Story) => (
22
- <View style={{ width: 246, padding: 16, backgroundColor: '#242424' }}>
22
+ <Surface level="base" style={{ width: 246, padding: 16 }}>
23
23
  <Story />
24
- </View>
24
+ </Surface>
25
25
  ),
26
26
  ],
27
27
  }