@titan-design/react-ui 0.12.1 → 0.14.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 (531) hide show
  1. package/README.md +60 -47
  2. package/dist/bodymap.js +856 -736
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +858 -738
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1431 -237
  7. package/dist/index.d.ts +1431 -237
  8. package/dist/index.js +6506 -4781
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +6280 -4642
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
  13. package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1919 -1937
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1927 -1945
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +225 -140
  21. package/dist/theme/index.d.ts +225 -140
  22. package/dist/theme/index.js +298 -319
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +283 -315
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +145 -24
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +145 -24
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +128 -11
  31. package/dist/theme/tokens.d.ts +128 -11
  32. package/dist/theme/tokens.js +126 -26
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +124 -27
  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/docs/render-testing-pattern.md +130 -0
  40. package/package.json +1 -1
  41. package/src/arch/Architecture.stories.tsx +3 -1
  42. package/src/arch/arch-graph.freshness.test.ts +52 -0
  43. package/src/arch/arch-graph.json +4989 -1583
  44. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  45. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  46. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  48. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  49. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  51. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  52. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  54. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  55. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  57. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  58. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  60. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  61. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  63. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  64. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  66. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  67. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  69. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  70. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  71. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  73. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  74. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  76. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  77. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  78. package/src/components/custom/ActiveWork/README.md +305 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  80. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  81. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  82. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  83. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  84. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  86. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  87. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  88. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  90. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  91. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  92. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  93. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  94. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  95. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  96. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  97. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  98. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  99. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  100. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  101. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  102. package/src/components/custom/ActiveWork/index.ts +19 -0
  103. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  104. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  105. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  106. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  107. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
  108. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  109. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  110. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  111. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  112. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  113. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  116. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  117. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  119. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  120. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  121. package/src/components/custom/Fatigue/README.md +40 -3
  122. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  123. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  124. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  125. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  126. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  127. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  128. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  129. package/src/components/custom/Fatigue/index.ts +17 -5
  130. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  131. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  132. package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
  133. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  134. package/src/components/custom/Gauge/Gauge.tsx +7 -2
  135. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  136. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  137. package/src/components/custom/Metric/Metric.tsx +5 -20
  138. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  139. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  140. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  141. package/src/components/custom/Prose/README.md +58 -0
  142. package/src/components/custom/Prose/index.ts +1 -0
  143. package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
  144. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  145. package/src/components/custom/Scatter/Scatter.tsx +122 -18
  146. package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
  147. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  148. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  149. package/src/components/custom/Table/Table.stories.tsx +99 -16
  150. package/src/components/custom/Table/Table.test.tsx +273 -86
  151. package/src/components/custom/Table/Table.tsx +159 -67
  152. package/src/components/custom/Table/column-fit.test.ts +75 -0
  153. package/src/components/custom/Table/column-fit.ts +116 -0
  154. package/src/components/custom/Table/index.ts +9 -0
  155. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  156. package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
  157. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  158. package/src/components/custom/Treemap/Treemap.tsx +11 -3
  159. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  160. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  161. package/src/components/custom/Typography/Typography.tsx +6 -0
  162. package/src/components/custom/Typography/index.ts +1 -8
  163. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
  164. package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
  165. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  166. package/src/components/custom/Workout/BaseBadge.tsx +6 -2
  167. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  168. package/src/components/custom/Workout/BodyMap.tsx +8 -4
  169. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
  170. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  171. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
  172. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
  173. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  174. package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
  175. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  176. package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
  177. package/src/components/custom/Workout/DeviationBar.tsx +24 -16
  178. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
  179. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
  180. package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
  181. package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
  182. package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
  183. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
  184. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
  185. package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
  186. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  187. package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
  188. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  189. package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
  190. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
  191. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  192. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  193. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  194. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  195. package/src/components/custom/Workout/InputBar.tsx +4 -2
  196. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  197. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  198. package/src/components/custom/Workout/IntensityBar.tsx +8 -3
  199. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  200. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  201. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  202. package/src/components/custom/Workout/MesoCard.tsx +14 -10
  203. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  204. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  205. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  206. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  207. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  208. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
  209. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  210. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  211. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  212. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  213. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
  214. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  215. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  216. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  217. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  218. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  219. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
  220. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  221. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  222. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  223. package/src/components/custom/Workout/README.md +68 -17
  224. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  225. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  226. package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
  227. package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
  228. package/src/components/custom/Workout/RestTimer.tsx +4 -2
  229. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  230. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  231. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  232. package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
  233. package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
  234. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  235. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  236. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  237. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  238. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  239. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  240. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  241. package/src/components/custom/Workout/SetBar.tsx +38 -12
  242. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  243. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  244. package/src/components/custom/Workout/SetRow.tsx +61 -23
  245. package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
  246. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  247. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  248. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  249. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  250. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  251. package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
  252. package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
  253. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  254. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  255. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  256. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  257. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  258. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  259. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  260. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  261. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
  262. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  263. package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
  264. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  265. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  266. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  267. package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
  268. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  269. package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
  270. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  271. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  272. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
  273. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
  274. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
  275. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  276. package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
  277. package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
  278. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  279. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  280. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  281. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  282. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  283. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  284. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  285. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  286. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  287. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  288. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  289. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  290. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  291. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  292. package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
  293. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  294. package/src/components/custom/Workout/exerciseRowState.ts +29 -0
  295. package/src/components/custom/Workout/index.ts +17 -2
  296. package/src/components/custom/Workout/metricText.stories.tsx +15 -13
  297. package/src/components/custom/Workout/metricText.tsx +8 -2
  298. package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
  299. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  300. package/src/components/custom/charts/README.md +66 -0
  301. package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
  302. package/src/components/custom/charts/SetBarChart.tsx +56 -9
  303. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  304. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  305. package/src/components/custom/charts/SparkBars.tsx +85 -0
  306. package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
  307. package/src/components/custom/charts/flatBarGeometry.ts +32 -0
  308. package/src/components/custom/charts/index.ts +3 -0
  309. package/src/components/custom/index.ts +3 -0
  310. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  311. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  312. package/src/components/custom/stepper/Stepper.tsx +21 -34
  313. package/src/components/icons/icons.stories.tsx +1 -1
  314. package/src/components/icons/icons.tsx +51 -0
  315. package/src/components/shell/AppShell.stories.tsx +150 -0
  316. package/src/components/shell/AppShell.test.tsx +70 -0
  317. package/src/components/shell/AppShell.tsx +90 -0
  318. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  319. package/src/components/shell/BrandLockup.test.tsx +34 -1
  320. package/src/components/shell/BrandLockup.tsx +27 -11
  321. package/src/components/shell/NavItem.stories.tsx +4 -4
  322. package/src/components/shell/NavItem.test.tsx +17 -0
  323. package/src/components/shell/NavItem.tsx +17 -5
  324. package/src/components/shell/README.md +89 -26
  325. package/src/components/shell/SideNav.stories.tsx +38 -7
  326. package/src/components/shell/SideNav.test.tsx +16 -8
  327. package/src/components/shell/SideNav.tsx +17 -17
  328. package/src/components/shell/TopBar.stories.tsx +44 -19
  329. package/src/components/shell/TopBar.test.tsx +34 -12
  330. package/src/components/shell/TopBar.tsx +61 -40
  331. package/src/components/shell/brands.tsx +66 -0
  332. package/src/components/shell/index.ts +9 -8
  333. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  334. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  335. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  336. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  337. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  338. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  339. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  340. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  341. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  342. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  343. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  344. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  345. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  346. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  347. package/src/components/shell/workout/index.ts +9 -0
  348. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  349. package/src/components/ui/README.md +110 -0
  350. package/src/components/ui/alert/Alert.stories.tsx +15 -5
  351. package/src/components/ui/alert/Alert.tsx +24 -3
  352. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  353. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  354. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  355. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  356. package/src/components/ui/avatar/Avatar.tsx +2 -10
  357. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  358. package/src/components/ui/badge/Badge.test.tsx +19 -3
  359. package/src/components/ui/badge/Badge.tsx +48 -55
  360. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  361. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  362. package/src/components/ui/button/Button.stories.tsx +46 -12
  363. package/src/components/ui/button/Button.tsx +44 -37
  364. package/src/components/ui/card/Card.stories.tsx +90 -94
  365. package/src/components/ui/card/Card.test.tsx +80 -6
  366. package/src/components/ui/card/Card.tsx +150 -203
  367. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  368. package/src/components/ui/checkbox/Checkbox.tsx +7 -27
  369. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  370. package/src/components/ui/chip/Chip.test.tsx +10 -6
  371. package/src/components/ui/chip/Chip.tsx +76 -91
  372. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  373. package/src/components/ui/collapse/Collapse.tsx +6 -11
  374. package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
  375. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  376. package/src/components/ui/data-row/DataRow.tsx +18 -7
  377. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  378. package/src/components/ui/divider/Divider.tsx +1 -5
  379. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  380. package/src/components/ui/drawer/Drawer.tsx +13 -27
  381. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  382. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  383. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  384. package/src/components/ui/form-field/FormField.tsx +10 -46
  385. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  386. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  387. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  388. package/src/components/ui/help-tip/index.ts +7 -1
  389. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  390. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  391. package/src/components/ui/icon-box/IconBox.tsx +10 -18
  392. package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
  393. package/src/components/ui/indicator/Indicator.tsx +20 -14
  394. package/src/components/ui/input/Input.stories.tsx +3 -11
  395. package/src/components/ui/input/Input.test.tsx +2 -10
  396. package/src/components/ui/input/Input.tsx +10 -25
  397. package/src/components/ui/input/index.ts +7 -1
  398. package/src/components/ui/link/Link.stories.tsx +19 -7
  399. package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
  400. package/src/components/ui/list-item/ListItem.tsx +2 -9
  401. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  402. package/src/components/ui/menu/Menu.test.tsx +2 -11
  403. package/src/components/ui/menu/Menu.tsx +12 -14
  404. package/src/components/ui/menu/index.ts +8 -1
  405. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  406. package/src/components/ui/modal/Modal.tsx +31 -19
  407. package/src/components/ui/pill/Pill.stories.tsx +111 -23
  408. package/src/components/ui/pill/Pill.test.tsx +101 -3
  409. package/src/components/ui/pill/Pill.tsx +168 -49
  410. package/src/components/ui/pill/index.ts +1 -1
  411. package/src/components/ui/popover/Popover.stories.tsx +6 -8
  412. package/src/components/ui/popover/Popover.test.tsx +1 -6
  413. package/src/components/ui/popover/Popover.tsx +20 -15
  414. package/src/components/ui/popover/index.ts +7 -1
  415. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  416. package/src/components/ui/progress/Progress.test.tsx +1 -5
  417. package/src/components/ui/progress/Progress.tsx +9 -6
  418. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  419. package/src/components/ui/radio/Radio.test.tsx +6 -2
  420. package/src/components/ui/radio/Radio.tsx +23 -22
  421. package/src/components/ui/section/Section.stories.tsx +12 -21
  422. package/src/components/ui/section/Section.test.tsx +1 -6
  423. package/src/components/ui/section/Section.tsx +1 -3
  424. package/src/components/ui/section/index.ts +1 -5
  425. package/src/components/ui/select/Select.stories.tsx +3 -13
  426. package/src/components/ui/select/Select.test.tsx +2 -11
  427. package/src/components/ui/select/Select.tsx +16 -15
  428. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  429. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  430. package/src/components/ui/skeleton/index.ts +1 -7
  431. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  432. package/src/components/ui/spinner/Spinner.tsx +4 -5
  433. package/src/components/ui/stack/Stack.stories.tsx +8 -8
  434. package/src/components/ui/stack/Stack.tsx +1 -1
  435. package/src/components/ui/surface/Surface.stories.tsx +92 -33
  436. package/src/components/ui/surface/Surface.test.tsx +88 -28
  437. package/src/components/ui/surface/Surface.tsx +37 -87
  438. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  439. package/src/components/ui/surface/index.ts +8 -0
  440. package/src/components/ui/surface/resolveSurface.ts +98 -0
  441. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  442. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  443. package/src/components/ui/switch/Switch.tsx +7 -6
  444. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  445. package/src/components/ui/tabs/Tabs.tsx +8 -21
  446. package/src/components/ui/tabs/index.ts +1 -7
  447. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  448. package/src/components/ui/tile/Tile.tsx +3 -0
  449. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  450. package/src/components/ui/toast/Toast.test.tsx +2 -8
  451. package/src/components/ui/toast/Toast.tsx +49 -57
  452. package/src/components/ui/toast/index.ts +0 -1
  453. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  454. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  455. package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
  456. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  457. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  458. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  459. package/src/components/ui/tooltip/index.ts +1 -1
  460. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  461. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  462. package/src/components/ui/trigger/index.ts +2 -0
  463. package/src/stories/PresetShowcase.stories.tsx +101 -48
  464. package/src/test/no-device-internals.test.ts +3 -3
  465. package/src/test/no-raw-color.test.ts +39 -0
  466. package/src/theme/Alpha.stories.tsx +103 -0
  467. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  468. package/src/theme/ColorPalettes.stories.tsx +62 -45
  469. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  470. package/src/theme/Depth.stories.tsx +132 -65
  471. package/src/theme/DepthCalibration.stories.tsx +23 -21
  472. package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
  473. package/src/theme/ThemeProvider.test.tsx +4 -4
  474. package/src/theme/barrel.ts +7 -6
  475. package/src/theme/color-stories.coverage.test.ts +1 -1
  476. package/src/theme/color-utils.ts +41 -29
  477. package/src/theme/config.completeness.test.ts +1 -1
  478. package/src/theme/config.ts +40 -0
  479. package/src/theme/elevation.test.ts +82 -56
  480. package/src/theme/elevation.ts +77 -561
  481. package/src/theme/global.css +45 -5
  482. package/src/theme/grey-ramp.test.ts +24 -8
  483. package/src/theme/lift.test.ts +39 -0
  484. package/src/theme/lift.ts +102 -0
  485. package/src/theme/materials.test.ts +5 -2
  486. package/src/theme/materials.ts +38 -4
  487. package/src/theme/native-theming-guard.test.ts +5 -5
  488. package/src/theme/presets/apply.ts +4 -0
  489. package/src/theme/presets/audiobook.ts +5 -2
  490. package/src/theme/presets/default.ts +4 -0
  491. package/src/theme/presets/index.ts +14 -1
  492. package/src/theme/presets/types.ts +1 -1
  493. package/src/theme/semantic-contrast.test.ts +13 -4
  494. package/src/theme/status-distinctness.test.ts +66 -0
  495. package/src/theme/subtle-tone-weight.test.ts +163 -0
  496. package/src/theme/surface-planes.test.ts +37 -0
  497. package/src/theme/surface-planes.ts +68 -0
  498. package/src/theme/tailwind-var-opacity.test.ts +163 -0
  499. package/src/theme/token-export-guard.test.ts +1 -3
  500. package/src/theme/tokens/primitives.test.ts +15 -7
  501. package/src/theme/tokens/primitives.ts +98 -33
  502. package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
  503. package/src/theme/tokens/semantic.ts +124 -54
  504. package/src/theme/wash-ladder.test.ts +58 -0
  505. package/src/theme/workout-tokens.ts +1 -7
  506. package/src/types/jest-axe.d.ts +2 -6
  507. package/src/types/raw-md.d.ts +5 -0
  508. package/src/utils/colors.alpha-adoption.test.ts +408 -0
  509. package/src/utils/colors.ts +4 -4
  510. package/src/utils/form.ts +1 -3
  511. package/src/utils/index.ts +2 -7
  512. package/src/utils/number-format.ts +17 -0
  513. package/src/utils/workout-format.ts +15 -6
  514. package/src/web-jsx/jsx-runtime.ts +1 -5
  515. package/tailwind.config.js +55 -9
  516. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  517. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  518. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  519. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  520. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  521. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  522. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  523. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  524. package/src/components/shell/DashboardShell.tsx +0 -75
  525. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  526. package/src/theme/elevation.stories.tsx +0 -346
  527. package/src/utils/useTheme.ts +0 -72
  528. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  529. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  530. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  531. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -4,6 +4,8 @@ import { View, Text, Pressable, Animated, Easing, type ViewProps } from 'react-n
4
4
  import { cn } from '../../../utils/cn'
5
5
  import { resolveColor } from '../../../theme/resolve-color'
6
6
  import { getSemanticColors } from '../../../theme/tokens/semantic'
7
+ import { primitiveColors } from '../../../theme/tokens/primitives'
8
+ import { alpha } from '../../../utils/colors'
7
9
 
8
10
  const sem = getSemanticColors('dark')
9
11
 
@@ -14,11 +16,11 @@ const PROJECTION_LINE_COLOR = resolveColor('text-tertiary')
14
16
  const STATUS_SUCCESS = sem['status-success']
15
17
  const STATUS_ERROR = sem['status-error']
16
18
  const STATUS_WARNING = sem['status-warning']
17
- const GRID_LINE = 'rgba(255,255,255,0.06)'
18
- const SUCCESS_PILL_BG = 'rgba(46,213,115,0.10)'
19
- const SUCCESS_PILL_BORDER = 'rgba(46,213,115,0.20)'
20
- const ERROR_PILL_BG = 'rgba(209,67,67,0.10)'
21
- const ERROR_PILL_BORDER = 'rgba(209,67,67,0.20)'
19
+ const GRID_LINE = alpha(primitiveColors.white, 0.06)
20
+ const SUCCESS_PILL_BG = alpha(STATUS_SUCCESS, 0.1)
21
+ const SUCCESS_PILL_BORDER = alpha(STATUS_SUCCESS, 0.2)
22
+ const ERROR_PILL_BG = alpha(STATUS_ERROR, 0.1)
23
+ const ERROR_PILL_BORDER = alpha(STATUS_ERROR, 0.2)
22
24
 
23
25
  /** Left gutter reserved for y-axis value labels. */
24
26
  const PLOT_LEFT = 26
@@ -94,7 +96,7 @@ function buildGeometry(
94
96
  projection: StrengthTrendDataPoint[],
95
97
  boundaries: StrengthTrendChartMesoBoundary[],
96
98
  width: number,
97
- height: number,
99
+ height: number
98
100
  ): Geometry {
99
101
  const values = [...data, ...projection].map((p) => p.e1rm)
100
102
  // Empty state keys off actual data only: a projection with no measured
@@ -128,10 +130,8 @@ function buildGeometry(
128
130
  const domainMax = yMax + padV
129
131
 
130
132
  const innerW = Math.max(1, width - PLOT_LEFT)
131
- const toX = (time: number) =>
132
- PLOT_LEFT + ((time - tMin) / (tMax - tMin)) * innerW
133
- const toY = (value: number) =>
134
- height - ((value - domainMin) / (domainMax - domainMin)) * height
133
+ const toX = (time: number) => PLOT_LEFT + ((time - tMin) / (tMax - tMin)) * innerW
134
+ const toY = (value: number) => height - ((value - domainMin) / (domainMax - domainMin)) * height
135
135
 
136
136
  const project = (points: StrengthTrendDataPoint[]): Coord[] =>
137
137
  points.map((point, index) => ({
@@ -141,9 +141,7 @@ function buildGeometry(
141
141
  index,
142
142
  }))
143
143
 
144
- const tickValues = Array.from(
145
- new Set([yMax, (yMin + yMax) / 2, yMin].map((v) => Math.round(v))),
146
- )
144
+ const tickValues = Array.from(new Set([yMax, (yMin + yMax) / 2, yMin].map((v) => Math.round(v))))
147
145
  const gridLines = tickValues.map((v) => ({ y: toY(v), label: formatValue(v) }))
148
146
 
149
147
  return {
@@ -162,7 +160,7 @@ function buildGeometry(
162
160
 
163
161
  function computeTrend(
164
162
  data: StrengthTrendDataPoint[],
165
- boundaries: StrengthTrendChartMesoBoundary[],
163
+ boundaries: StrengthTrendChartMesoBoundary[]
166
164
  ): { percent: number; positive: boolean } {
167
165
  if (data.length < 2) return { percent: 0, positive: true }
168
166
  let series = data
@@ -267,12 +265,9 @@ export function StrengthTrendChart({
267
265
  }: StrengthTrendChartProps) {
268
266
  const geometry = useMemo(
269
267
  () => buildGeometry(data, projection, mesoBoundaries, width, height),
270
- [data, projection, mesoBoundaries, width, height],
271
- )
272
- const trend = useMemo(
273
- () => computeTrend(data, mesoBoundaries),
274
- [data, mesoBoundaries],
268
+ [data, projection, mesoBoundaries, width, height]
275
269
  )
270
+ const trend = useMemo(() => computeTrend(data, mesoBoundaries), [data, mesoBoundaries])
276
271
 
277
272
  const [reveal] = useState(() => new Animated.Value(animateOnMount ? 0 : 1))
278
273
  const [selected, setSelected] = useState<number | null>(null)
@@ -314,7 +309,10 @@ export function StrengthTrendChart({
314
309
  justifyContent: 'center',
315
310
  }}
316
311
  >
317
- <Text className="text-text-tertiary" style={{ fontSize: 12, fontFamily: 'Inter, sans-serif' }}>
312
+ <Text
313
+ className="text-text-tertiary"
314
+ style={{ fontSize: 12, fontFamily: 'Inter, sans-serif' }}
315
+ >
318
316
  No strength data yet
319
317
  </Text>
320
318
  </View>
@@ -327,16 +325,10 @@ export function StrengthTrendChart({
327
325
  outputRange: [0, width],
328
326
  })
329
327
 
330
- const selectedCoord =
331
- selected != null ? geometry.actual[selected] : undefined
328
+ const selectedCoord = selected != null ? geometry.actual[selected] : undefined
332
329
 
333
330
  return (
334
- <View
335
- style={{ width }}
336
- className={cn(className)}
337
- testID="strength-trend-chart"
338
- {...props}
339
- >
331
+ <View style={{ width }} className={cn(className)} testID="strength-trend-chart" {...props}>
340
332
  <View style={{ width, height, position: 'relative' }}>
341
333
  {/* Labelled, non-interactive chart canvas (grid + lines + markers). */}
342
334
  <View
@@ -389,7 +381,7 @@ export function StrengthTrendChart({
389
381
  height,
390
382
  borderLeftWidth: 1,
391
383
  borderStyle: 'dashed',
392
- borderLeftColor: 'rgba(255,255,255,0.10)',
384
+ borderLeftColor: alpha(primitiveColors.white, 0.1),
393
385
  }}
394
386
  />
395
387
  ))}
@@ -438,7 +430,7 @@ export function StrengthTrendChart({
438
430
  >
439
431
 
440
432
  </Text>
441
- ) : null,
433
+ ) : null
442
434
  )}
443
435
  </View>
444
436
 
@@ -482,7 +474,7 @@ export function StrengthTrendChart({
482
474
  position: 'absolute',
483
475
  left: Math.max(
484
476
  0,
485
- Math.min(width - TOOLTIP_WIDTH, selectedCoord.x - TOOLTIP_WIDTH / 2),
477
+ Math.min(width - TOOLTIP_WIDTH, selectedCoord.x - TOOLTIP_WIDTH / 2)
486
478
  ),
487
479
  top: Math.max(0, selectedCoord.y - 52),
488
480
  maxWidth: TOOLTIP_WIDTH,
@@ -529,7 +521,7 @@ export function StrengthTrendChart({
529
521
  ? '+'
530
522
  : '-'
531
523
  }${Math.abs(
532
- selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm,
524
+ selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
533
525
  ).toFixed(1)} ${unit}`}
534
526
  </Text>
535
527
  )}
@@ -598,8 +590,13 @@ export function StrengthTrendChart({
598
590
  testID="strength-trend-chart-legend"
599
591
  >
600
592
  <View className="flex-row items-center" style={{ gap: 5 }}>
601
- <View style={{ width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY }} />
602
- <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
593
+ <View
594
+ style={{ width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY }}
595
+ />
596
+ <Text
597
+ className="text-text-secondary"
598
+ style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}
599
+ >
603
600
  Actual
604
601
  </Text>
605
602
  </View>
@@ -613,13 +610,19 @@ export function StrengthTrendChart({
613
610
  borderTopColor: PROJECTION_LINE_COLOR,
614
611
  }}
615
612
  />
616
- <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
613
+ <Text
614
+ className="text-text-secondary"
615
+ style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}
616
+ >
617
617
  Projected
618
618
  </Text>
619
619
  </View>
620
620
  <View className="flex-row items-center" style={{ gap: 5 }}>
621
621
  <Text style={{ fontSize: 12, color: STATUS_WARNING }}>★</Text>
622
- <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
622
+ <Text
623
+ className="text-text-secondary"
624
+ style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}
625
+ >
623
626
  PR
624
627
  </Text>
625
628
  </View>
@@ -1,20 +1,20 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { View, Text } from 'react-native'
3
2
  import { SupersetWrapper } from './SupersetWrapper'
4
3
  import { ExerciseCard } from './ExerciseCard'
5
- import { getSemanticColors } from '../../../theme/tokens/semantic'
6
-
7
- const t = getSemanticColors('dark')
4
+ import { Card } from '../../ui/card'
5
+ import { Typography } from '../Typography'
6
+ import { Surface } from '../../ui/surface'
7
+ import { resolveColor } from '../../../theme/resolve-color'
8
8
 
9
9
  const meta: Meta<typeof SupersetWrapper> = {
10
- title: 'Workout/SupersetWrapper',
10
+ title: 'Custom/Workout/SupersetWrapper',
11
11
  component: SupersetWrapper,
12
12
  tags: ['autodocs'],
13
13
  decorators: [
14
14
  (Story) => (
15
- <View style={{ maxWidth: 400, padding: 16, backgroundColor: t['background-base'] }}>
15
+ <Surface level="background" style={{ maxWidth: 400, padding: 16 }}>
16
16
  <Story />
17
- </View>
17
+ </Surface>
18
18
  ),
19
19
  ],
20
20
  }
@@ -22,28 +22,21 @@ const meta: Meta<typeof SupersetWrapper> = {
22
22
  export default meta
23
23
  type Story = StoryObj<typeof SupersetWrapper>
24
24
 
25
+ /** Stand-in for a real exercise row: a filled Card on the wrapper's own plane. */
26
+ function DemoExercise({ name }: { name: string }) {
27
+ return (
28
+ <Card variant="filled" elevation={1} className="p-3">
29
+ <Typography variant="body2">{name}</Typography>
30
+ </Card>
31
+ )
32
+ }
33
+
25
34
  export const Default: Story = {
26
35
  args: {
27
36
  children: (
28
37
  <>
29
- <View
30
- style={{
31
- padding: 12,
32
- backgroundColor: t['surface-raised'],
33
- borderRadius: 8,
34
- }}
35
- >
36
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise A</Text>
37
- </View>
38
- <View
39
- style={{
40
- padding: 12,
41
- backgroundColor: t['surface-raised'],
42
- borderRadius: 8,
43
- }}
44
- >
45
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise B</Text>
46
- </View>
38
+ <DemoExercise name="Exercise A" />
39
+ <DemoExercise name="Exercise B" />
47
40
  </>
48
41
  ),
49
42
  },
@@ -54,24 +47,8 @@ export const CustomLabel: Story = {
54
47
  label: 'A1/A2',
55
48
  children: (
56
49
  <>
57
- <View
58
- style={{
59
- padding: 12,
60
- backgroundColor: t['surface-raised'],
61
- borderRadius: 8,
62
- }}
63
- >
64
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise A1</Text>
65
- </View>
66
- <View
67
- style={{
68
- padding: 12,
69
- backgroundColor: t['surface-raised'],
70
- borderRadius: 8,
71
- }}
72
- >
73
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise A2</Text>
74
- </View>
50
+ <DemoExercise name="Exercise A1" />
51
+ <DemoExercise name="Exercise A2" />
75
52
  </>
76
53
  ),
77
54
  },
@@ -79,39 +56,25 @@ export const CustomLabel: Story = {
79
56
 
80
57
  export const CustomColor: Story = {
81
58
  args: {
82
- color: '#22C55E',
59
+ color: resolveColor('status-success'),
83
60
  children: (
84
61
  <>
85
- <View
86
- style={{
87
- padding: 12,
88
- backgroundColor: t['surface-raised'],
89
- borderRadius: 8,
90
- }}
91
- >
92
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise A</Text>
93
- </View>
94
- <View
95
- style={{
96
- padding: 12,
97
- backgroundColor: t['surface-raised'],
98
- borderRadius: 8,
99
- }}
100
- >
101
- <Text style={{ color: '#F3F4F6', fontFamily: 'Inter, sans-serif' }}>Exercise B</Text>
102
- </View>
62
+ <DemoExercise name="Exercise A" />
63
+ <DemoExercise name="Exercise B" />
103
64
  </>
104
65
  ),
105
66
  },
106
67
  }
107
68
 
69
+ const supersetColor = resolveColor('brand-primary')
70
+
108
71
  const exerciseA = {
109
72
  name: 'Bench Press',
110
73
  state: 'collapsed' as const,
111
74
  onToggle: () => {},
112
75
  summary: { sets: 3, reps: 8, weight: 185, unit: 'lbs' as const },
113
76
  supersetPosition: 'first' as const,
114
- supersetColor: '#FF7900',
77
+ supersetColor,
115
78
  }
116
79
 
117
80
  const exerciseB = {
@@ -120,7 +83,7 @@ const exerciseB = {
120
83
  onToggle: () => {},
121
84
  summary: { sets: 3, reps: 8, weight: 155, unit: 'lbs' as const },
122
85
  supersetPosition: 'last' as const,
123
- supersetColor: '#FF7900',
86
+ supersetColor,
124
87
  }
125
88
 
126
89
  export const WithExerciseCards: Story = {
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react'
3
3
  import { axe } from 'jest-axe'
4
4
  import { View, Text } from 'react-native'
5
5
  import { SupersetWrapper } from './SupersetWrapper'
6
+ import { resolveColor } from '../../../theme/resolve-color'
6
7
 
7
8
  describe('SupersetWrapper', () => {
8
9
  describe('label', () => {
@@ -10,7 +11,7 @@ describe('SupersetWrapper', () => {
10
11
  render(
11
12
  <SupersetWrapper>
12
13
  <View />
13
- </SupersetWrapper>,
14
+ </SupersetWrapper>
14
15
  )
15
16
  expect(screen.getByTestId('superset-label')).toHaveTextContent('SS')
16
17
  })
@@ -19,31 +20,32 @@ describe('SupersetWrapper', () => {
19
20
  render(
20
21
  <SupersetWrapper label="A1/A2">
21
22
  <View />
22
- </SupersetWrapper>,
23
+ </SupersetWrapper>
23
24
  )
24
25
  expect(screen.getByTestId('superset-label')).toHaveTextContent('A1/A2')
25
26
  })
26
27
  })
27
28
 
28
29
  describe('color', () => {
29
- it('applies default color #FF7900 to border and label background', () => {
30
+ it('defaults border and label background to the brand-primary token', () => {
30
31
  render(
31
32
  <SupersetWrapper>
32
33
  <View />
33
- </SupersetWrapper>,
34
+ </SupersetWrapper>
34
35
  )
36
+ const brand = resolveColor('brand-primary')
35
37
  const wrapper = screen.getByTestId('superset-wrapper')
36
- expect(wrapper).toHaveStyle({ borderLeftColor: '#FF7900' })
38
+ expect(wrapper).toHaveStyle({ borderLeftColor: brand })
37
39
 
38
40
  const label = screen.getByTestId('superset-label')
39
- expect(label).toHaveStyle({ backgroundColor: '#FF7900' })
41
+ expect(label).toHaveStyle({ backgroundColor: brand })
40
42
  })
41
43
 
42
44
  it('applies custom color to border and label background', () => {
43
45
  render(
44
46
  <SupersetWrapper color="#22C55E">
45
47
  <View />
46
- </SupersetWrapper>,
48
+ </SupersetWrapper>
47
49
  )
48
50
  const wrapper = screen.getByTestId('superset-wrapper')
49
51
  expect(wrapper).toHaveStyle({ borderLeftColor: '#22C55E' })
@@ -59,7 +61,7 @@ describe('SupersetWrapper', () => {
59
61
  <SupersetWrapper>
60
62
  <Text testID="child-1">Exercise A</Text>
61
63
  <Text testID="child-2">Exercise B</Text>
62
- </SupersetWrapper>,
64
+ </SupersetWrapper>
63
65
  )
64
66
  expect(screen.getByTestId('child-1')).toHaveTextContent('Exercise A')
65
67
  expect(screen.getByTestId('child-2')).toHaveTextContent('Exercise B')
@@ -71,7 +73,7 @@ describe('SupersetWrapper', () => {
71
73
  render(
72
74
  <SupersetWrapper>
73
75
  <View />
74
- </SupersetWrapper>,
76
+ </SupersetWrapper>
75
77
  )
76
78
  expect(screen.getByRole('group')).toBeInTheDocument()
77
79
  })
@@ -80,7 +82,7 @@ describe('SupersetWrapper', () => {
80
82
  render(
81
83
  <SupersetWrapper>
82
84
  <View />
83
- </SupersetWrapper>,
85
+ </SupersetWrapper>
84
86
  )
85
87
  expect(screen.getByLabelText('Superset: SS')).toBeInTheDocument()
86
88
  })
@@ -89,7 +91,7 @@ describe('SupersetWrapper', () => {
89
91
  render(
90
92
  <SupersetWrapper label="A1/A2">
91
93
  <View />
92
- </SupersetWrapper>,
94
+ </SupersetWrapper>
93
95
  )
94
96
  expect(screen.getByLabelText('Superset: A1/A2')).toBeInTheDocument()
95
97
  })
@@ -99,7 +101,7 @@ describe('SupersetWrapper', () => {
99
101
  <SupersetWrapper>
100
102
  <Text>Exercise A</Text>
101
103
  <Text>Exercise B</Text>
102
- </SupersetWrapper>,
104
+ </SupersetWrapper>
103
105
  )
104
106
  const results = await axe(container)
105
107
  expect(results).toHaveNoViolations()
@@ -111,7 +113,7 @@ describe('SupersetWrapper', () => {
111
113
  render(
112
114
  <SupersetWrapper>
113
115
  <View />
114
- </SupersetWrapper>,
116
+ </SupersetWrapper>
115
117
  )
116
118
  const label = screen.getByTestId('superset-label')
117
119
  expect(label).toHaveStyle({ position: 'absolute' })
@@ -121,7 +123,7 @@ describe('SupersetWrapper', () => {
121
123
  render(
122
124
  <SupersetWrapper>
123
125
  <View />
124
- </SupersetWrapper>,
126
+ </SupersetWrapper>
125
127
  )
126
128
  const label = screen.getByTestId('superset-label')
127
129
  expect(label).toHaveStyle({ top: '-1px', left: '-3px' })
@@ -1,31 +1,27 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import React from 'react'
3
- import { View, Text } from 'react-native'
4
- import { getSemanticColors } from '../../../theme/tokens/semantic'
3
+ import { View } from 'react-native'
4
+ import { Typography } from '../Typography'
5
+ import { resolveColor } from '../../../theme/resolve-color'
5
6
 
6
7
  export interface SupersetWrapperProps {
7
8
  label?: string
9
+ /** Rail and label-chip colour. Defaults to the `brand-primary` token. */
8
10
  color?: string
9
11
  children: React.ReactNode
10
12
  }
11
13
 
12
- const DEFAULTS = {
13
- label: 'SS',
14
- color: getSemanticColors('dark')['brand-primary'],
15
- bgBase: getSemanticColors('dark')['background-base'],
16
- } as const
14
+ const DEFAULT_LABEL = 'SS'
15
+
16
+ export function SupersetWrapper({ label = DEFAULT_LABEL, color, children }: SupersetWrapperProps) {
17
+ const rail = color ?? resolveColor('brand-primary')
17
18
 
18
- export function SupersetWrapper({
19
- label = DEFAULTS.label,
20
- color = DEFAULTS.color,
21
- children,
22
- }: SupersetWrapperProps) {
23
19
  return (
24
20
  <View
25
21
  style={{
26
22
  position: 'relative',
27
23
  borderLeftWidth: 3,
28
- borderLeftColor: color,
24
+ borderLeftColor: rail,
29
25
  paddingLeft: 8,
30
26
  marginHorizontal: 12,
31
27
  marginBottom: 8,
@@ -35,26 +31,26 @@ export function SupersetWrapper({
35
31
  accessibilityLabel={`Superset: ${label}`}
36
32
  testID="superset-wrapper"
37
33
  >
38
- <Text
34
+ {/* `microLabel` is the 10px uppercase micro-label form and carries its own
35
+ face, weight and tracking. The chip was 9px/700 with a hand-set 0.5px
36
+ tracking; 9px is off the type scale (TOKENS.md §4), so it rounds up. */}
37
+ <Typography
38
+ variant="microLabel"
39
+ color="inverse"
39
40
  style={{
40
41
  position: 'absolute',
41
42
  top: -1,
42
43
  left: -3,
43
- fontSize: 9,
44
- fontFamily: 'Inter, sans-serif',
45
- fontWeight: '700',
46
- backgroundColor: color,
47
- color: DEFAULTS.bgBase,
44
+ backgroundColor: rail,
48
45
  paddingVertical: 2,
49
46
  paddingHorizontal: 6,
50
47
  borderBottomRightRadius: 4,
51
- letterSpacing: 0.5,
52
48
  zIndex: 2,
53
49
  }}
54
50
  testID="superset-label"
55
51
  >
56
52
  {label}
57
- </Text>
53
+ </Typography>
58
54
  <View style={{ gap: 2 }} testID="superset-children">
59
55
  {children}
60
56
  </View>
@@ -3,10 +3,11 @@ import type { ComponentProps } from 'react'
3
3
  import { useEffect, useState } from 'react'
4
4
  import { View, Text } from 'react-native'
5
5
  import { TempoDisplay, type TempoLivePhase, type TempoLiveState } from './TempoDisplay'
6
+ import { greyRamp } from '../../../theme/tokens/primitives'
6
7
 
7
8
  // tempo = [eccentric, pauseBottom, concentric, pauseTop]
8
9
  const meta: Meta<typeof TempoDisplay> = {
9
- title: 'Workout/TempoDisplay',
10
+ title: 'Custom/Workout/TempoDisplay',
10
11
  component: TempoDisplay,
11
12
  tags: ['autodocs'],
12
13
  parameters: {
@@ -14,9 +15,9 @@ const meta: Meta<typeof TempoDisplay> = {
14
15
  description: {
15
16
  component:
16
17
  '**Molecule.** The eccentric/pause/concentric/pause tempo display. Composes ' +
17
- '[MetricCell](?path=/docs/workout-metriccell--docs) ' +
18
+ '[MetricCell](?path=/docs/custom-workout-metriccell--docs) ' +
18
19
  '(shared value/separator cell). Used-by ↑ ' +
19
- '[ExerciseHeading](?path=/docs/workout-exerciseheading--docs) (`showLabel={false}`).',
20
+ '[ExerciseHeading](?path=/docs/custom-workout-exerciseheading--docs) (`showLabel={false}`).',
20
21
  },
21
22
  },
22
23
  },
@@ -26,7 +27,10 @@ const meta: Meta<typeof TempoDisplay> = {
26
27
  description: 'Tempo values [eccentric, pauseBottom, concentric, pauseTop] in seconds',
27
28
  },
28
29
  size: { control: 'select', options: ['sm', 'md'], description: 'Size variant' },
29
- fontSize: { control: { type: 'range', min: 9, max: 48, step: 1 }, description: 'Digit size (overrides `size`)' },
30
+ fontSize: {
31
+ control: { type: 'range', min: 9, max: 48, step: 1 },
32
+ description: 'Digit size (overrides `size`)',
33
+ },
30
34
  showLabel: { control: 'boolean', description: 'Show the TEMPO caption' },
31
35
  showInfo: { control: 'boolean', description: 'Show info tooltip on press' },
32
36
  live: {
@@ -163,7 +167,7 @@ function Condition({
163
167
  }: { caption: string } & ComponentProps<typeof TempoDisplay>) {
164
168
  return (
165
169
  <View style={{ gap: 5 }}>
166
- <Text style={{ color: '#9CA3AF', fontFamily: 'Inter, sans-serif', fontSize: 11 }}>
170
+ <Text style={{ color: greyRamp[400], fontFamily: 'Inter, sans-serif', fontSize: 11 }}>
167
171
  {caption}
168
172
  </Text>
169
173
  <TempoDisplay showLabel={false} showInfo={false} fontSize={26} {...props} />
@@ -176,7 +180,7 @@ function Section({ title, children }: { title: string; children: React.ReactNode
176
180
  <View style={{ gap: 12 }}>
177
181
  <Text
178
182
  style={{
179
- color: '#E5E7EB',
183
+ color: greyRamp[100],
180
184
  fontFamily: 'Inter, sans-serif',
181
185
  fontSize: 12,
182
186
  fontWeight: '700',
@@ -273,21 +277,33 @@ export const ActiveTempoConditions: Story = {
273
277
  caption="Compact (14) · label off"
274
278
  tempo={TEMPO}
275
279
  fontSize={14}
276
- live={{ activePhase: 'concentric', phaseElapsedMs: 900, completed: { eccentric: 3000, pauseBottom: 1000 } }}
280
+ live={{
281
+ activePhase: 'concentric',
282
+ phaseElapsedMs: 900,
283
+ completed: { eccentric: 3000, pauseBottom: 1000 },
284
+ }}
277
285
  />
278
286
  <Condition
279
287
  caption="Default (22) · label on"
280
288
  tempo={TEMPO}
281
289
  fontSize={22}
282
290
  showLabel
283
- live={{ activePhase: 'concentric', phaseElapsedMs: 900, completed: { eccentric: 3000, pauseBottom: 1000 } }}
291
+ live={{
292
+ activePhase: 'concentric',
293
+ phaseElapsedMs: 900,
294
+ completed: { eccentric: 3000, pauseBottom: 1000 },
295
+ }}
284
296
  />
285
297
  <Condition
286
298
  caption="Wall (34) · label on"
287
299
  tempo={TEMPO}
288
300
  fontSize={34}
289
301
  showLabel
290
- live={{ activePhase: 'concentric', phaseElapsedMs: 900, completed: { eccentric: 3000, pauseBottom: 1000 } }}
302
+ live={{
303
+ activePhase: 'concentric',
304
+ phaseElapsedMs: 900,
305
+ completed: { eccentric: 3000, pauseBottom: 1000 },
306
+ }}
291
307
  />
292
308
  </Section>
293
309
 
@@ -298,7 +314,7 @@ export const ActiveTempoConditions: Story = {
298
314
  live={{ activePhase: null, phaseElapsedMs: 0 }}
299
315
  />
300
316
  <View style={{ gap: 5 }}>
301
- <Text style={{ color: '#9CA3AF', fontFamily: 'Inter, sans-serif', fontSize: 11 }}>
317
+ <Text style={{ color: greyRamp[400], fontFamily: 'Inter, sans-serif', fontSize: 11 }}>
302
318
  Animated · Ecc → Pause → Con → 2s rest, banking each phase
303
319
  </Text>
304
320
  <LiveTempoDemo />
@@ -120,12 +120,18 @@ describe('TempoDisplay', () => {
120
120
  it('locks the phases completed earlier in the rep, and resets on the first phase', () => {
121
121
  // Concentric active (3rd phase) → eccentric + pauseBottom are locked done.
122
122
  const mid = render(
123
- <TempoDisplay tempo={[3, 1, 2, 1]} live={{ activePhase: 'concentric', phaseElapsedMs: 800 }} />
123
+ <TempoDisplay
124
+ tempo={[3, 1, 2, 1]}
125
+ live={{ activePhase: 'concentric', phaseElapsedMs: 800 }}
126
+ />
124
127
  )
125
128
  expect(mid.getAllByTestId('tempo-live-done')).toHaveLength(2)
126
129
  // Back to the first phase (next rep) → nothing is locked yet.
127
130
  mid.rerender(
128
- <TempoDisplay tempo={[3, 1, 2, 1]} live={{ activePhase: 'eccentric', phaseElapsedMs: 200 }} />
131
+ <TempoDisplay
132
+ tempo={[3, 1, 2, 1]}
133
+ live={{ activePhase: 'eccentric', phaseElapsedMs: 200 }}
134
+ />
129
135
  )
130
136
  expect(mid.queryByTestId('tempo-live-done')).not.toBeInTheDocument()
131
137
  })
@@ -133,13 +139,21 @@ describe('TempoDisplay', () => {
133
139
  it('colours the TEMPO label live-muted while live', () => {
134
140
  const { getByText, rerender } = render(<TempoDisplay tempo={[3, 1, 1, 0]} />)
135
141
  const restColor = getByText('TEMPO').style.color
136
- rerender(<TempoDisplay tempo={[3, 1, 1, 0]} live={{ activePhase: 'eccentric', phaseElapsedMs: 500 }} />)
142
+ rerender(
143
+ <TempoDisplay
144
+ tempo={[3, 1, 1, 0]}
145
+ live={{ activePhase: 'eccentric', phaseElapsedMs: 500 }}
146
+ />
147
+ )
137
148
  expect(getByText('TEMPO').style.color).not.toBe(restColor)
138
149
  })
139
150
 
140
151
  it('shows upcoming phases as their prescribed time and the active as the live readout', () => {
141
152
  render(
142
- <TempoDisplay tempo={[5, 3, 2, 1]} live={{ activePhase: 'eccentric', phaseElapsedMs: 1000 }} />
153
+ <TempoDisplay
154
+ tempo={[5, 3, 2, 1]}
155
+ live={{ activePhase: 'eccentric', phaseElapsedMs: 1000 }}
156
+ />
143
157
  )
144
158
  // active eccentric: 5s target, 1s in → 4.0 remaining
145
159
  expect(screen.getByText('4.0')).toBeInTheDocument()