@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
@@ -0,0 +1,55 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { SparkBars } from './SparkBars'
3
+
4
+ const meta: Meta<typeof SparkBars> = {
5
+ title: 'Custom/Charts/SparkBars',
6
+ component: SparkBars,
7
+ tags: ['autodocs', 'status:candidate', '!status:review'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component:
12
+ '**Atom.** A tiny bar-mark sparkline for a signed series — the counterpart to ' +
13
+ '[Sparkline](?path=/docs/custom-workout-dataviz-sparkline--docs). Where a line reads a *trajectory*, ' +
14
+ 'bars read *discrete per-period magnitude*. Bars scale on absolute value so a negative ' +
15
+ 'period is as tall as an equally large positive one, with the sign carried by fill colour.',
16
+ },
17
+ },
18
+ },
19
+ args: {
20
+ values: [120, 340, -80, 910, 420, 0, 1580, 260, -310, 740, 1120, 90],
21
+ height: 22,
22
+ barWidth: 3,
23
+ gap: 2,
24
+ maxBars: 24,
25
+ },
26
+ }
27
+ export default meta
28
+ type Story = StoryObj<typeof SparkBars>
29
+
30
+ export const Default: Story = {}
31
+
32
+ /** All-positive — the plain growth case. */
33
+ export const AllPositive: Story = {
34
+ args: { values: [40, 120, 260, 310, 480, 520, 900] },
35
+ }
36
+
37
+ /** All-negative — every bar takes the error token. */
38
+ export const AllNegative: Story = {
39
+ args: { values: [-40, -120, -260, -310, -480] },
40
+ }
41
+
42
+ /** Taller field, as used in the file-history growth block. */
43
+ export const Tall: Story = {
44
+ args: { height: 34, barWidth: 5, gap: 3 },
45
+ }
46
+
47
+ /** `maxBars` keeps only the most recent values — a sparkline is a glance, not an archive. */
48
+ export const Truncated: Story = {
49
+ args: { values: Array.from({ length: 60 }, (_, i) => (i % 7) * 30 - 40), maxBars: 12 },
50
+ }
51
+
52
+ /** An empty series renders an empty field rather than collapsing the layout. */
53
+ export const Empty: Story = {
54
+ args: { values: [] },
55
+ }
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { axe } from 'jest-axe'
4
+ import { SparkBars } from './SparkBars'
5
+
6
+ describe('SparkBars', () => {
7
+ it('renders one bar per value', () => {
8
+ render(<SparkBars values={[1, 2, 3, 4]} />)
9
+ expect(screen.getAllByTestId(/^spark-bars-bar-/)).toHaveLength(4)
10
+ })
11
+
12
+ it('keeps only the last maxBars values', () => {
13
+ render(<SparkBars values={[1, 2, 3, 4, 5, 6]} maxBars={2} />)
14
+ expect(screen.getAllByTestId(/^spark-bars-bar-/)).toHaveLength(2)
15
+ })
16
+
17
+ it('renders no bars for an empty series but keeps the field', () => {
18
+ render(<SparkBars values={[]} />)
19
+ expect(screen.queryByTestId(/^spark-bars-bar-/)).not.toBeInTheDocument()
20
+ expect(screen.getByTestId('spark-bars')).toBeInTheDocument()
21
+ })
22
+
23
+ it('tints bars by sign with the result-* tokens', () => {
24
+ // Asserts the token, not its current value: resolveColor emits the CSS var on
25
+ // web, which is what keeps the chart theme-correct.
26
+ render(<SparkBars values={[10, -10]} />)
27
+ expect(screen.getByTestId('spark-bars-bar-0')).toHaveStyle({
28
+ backgroundColor: 'var(--color-result-improve)',
29
+ })
30
+ expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({
31
+ backgroundColor: 'var(--color-result-degrade)',
32
+ })
33
+ })
34
+
35
+ it('honours explicit color overrides', () => {
36
+ render(<SparkBars values={[10, -10]} color="#00ff00" negativeColor="#ff00ff" />)
37
+ expect(screen.getByTestId('spark-bars-bar-0')).toHaveStyle({
38
+ backgroundColor: 'rgb(0, 255, 0)',
39
+ })
40
+ expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({
41
+ backgroundColor: 'rgb(255, 0, 255)',
42
+ })
43
+ })
44
+
45
+ it('scales bars on magnitude, so equal-magnitude values are equally tall', () => {
46
+ render(<SparkBars values={[100, -100, 50]} height={40} />)
47
+ const [a, b, c] = ['0', '1', '2'].map((i) => screen.getByTestId(`spark-bars-bar-${i}`))
48
+ expect(a).toHaveStyle({ height: '40px' })
49
+ expect(b).toHaveStyle({ height: '40px' })
50
+ expect(c).toHaveStyle({ height: '20px' })
51
+ })
52
+
53
+ it('gives a zero value the minimum bar height rather than collapsing it', () => {
54
+ render(<SparkBars values={[100, 0]} height={40} />)
55
+ expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({ height: '2px' })
56
+ })
57
+
58
+ it('exposes a default accessible label and accepts an override', () => {
59
+ const { rerender } = render(<SparkBars values={[1, 2]} />)
60
+ expect(screen.getByLabelText('Bar sparkline with 2 values')).toBeInTheDocument()
61
+ rerender(<SparkBars values={[1, 2]} label="Growth for open.ts" />)
62
+ expect(screen.getByLabelText('Growth for open.ts')).toBeInTheDocument()
63
+ })
64
+
65
+ it('has no a11y violations', async () => {
66
+ const { container } = render(<SparkBars values={[3, -1, 4]} />)
67
+ expect(await axe(container)).toHaveNoViolations()
68
+ })
69
+ })
@@ -0,0 +1,85 @@
1
+ // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
+ import { View, type ViewProps } from 'react-native'
3
+ import { cn } from '../../../utils/cn'
4
+ import { resolveColor } from '../../../theme/resolve-color'
5
+
6
+ /** Shortest bar drawn, so an all-but-empty series still reads as a series. */
7
+ const MIN_BAR_HEIGHT = 2
8
+
9
+ export interface SparkBarsProps extends Omit<ViewProps, 'accessibilityLabel'> {
10
+ /** The series, oldest first. Negative values draw in `negativeColor`. */
11
+ values: number[]
12
+ /** Overall bar-field height in px. */
13
+ height?: number
14
+ /** Width of a single bar in px. */
15
+ barWidth?: number
16
+ /** Gap between bars in px. */
17
+ gap?: number
18
+ /** Keep only the last N values — a sparkline is a recent-history glance, not an archive. */
19
+ maxBars?: number
20
+ /** Fill for non-negative bars. Defaults to `result-improve`. */
21
+ color?: string
22
+ /** Fill for negative bars. Defaults to `result-degrade`. */
23
+ negativeColor?: string
24
+ /** Screen-reader description. Defaults to a bar count. */
25
+ label?: string
26
+ className?: string
27
+ }
28
+
29
+ /**
30
+ * SparkBars — a tiny bar-mark sparkline for a signed series.
31
+ *
32
+ * The bar-mark counterpart to {@link Sparkline}: where a line reads a
33
+ * *trajectory*, bars read *discrete per-period magnitude*, which is what
34
+ * per-session activity and per-session net growth actually are. Bars are scaled
35
+ * by absolute value so a negative period is as tall as an equally large
36
+ * positive one, and tinted with `negativeColor` to carry the sign.
37
+ *
38
+ * @example
39
+ * <SparkBars values={[3, 8, -2, 14]} height={22} />
40
+ */
41
+ export function SparkBars({
42
+ values,
43
+ height = 22,
44
+ barWidth = 3,
45
+ gap = 2,
46
+ maxBars = 24,
47
+ color,
48
+ negativeColor,
49
+ label,
50
+ className,
51
+ ...props
52
+ }: SparkBarsProps) {
53
+ const shown = values.slice(-maxBars)
54
+ // A per-period delta going up or down is `result-*` (a change in a measurement),
55
+ // not `status-*` (a thing being broken). See TOKENS.md §1.
56
+ const positiveFill = color ?? resolveColor('result-improve')
57
+ const negativeFill = negativeColor ?? resolveColor('result-degrade')
58
+ // Scaling on magnitude keeps a -100 as tall as a +100; sign is carried by fill.
59
+ const peak = Math.max(1, ...shown.map((v) => Math.abs(v)))
60
+
61
+ return (
62
+ <View
63
+ style={{ height, gap }}
64
+ className={cn('flex-row items-end', className)}
65
+ accessibilityRole="image"
66
+ accessibilityLabel={label ?? `Bar sparkline with ${shown.length} values`}
67
+ testID="spark-bars"
68
+ {...props}
69
+ >
70
+ {shown.map((v, i) => (
71
+ <View
72
+ key={i}
73
+ style={{
74
+ height: Math.max(MIN_BAR_HEIGHT, Math.round((Math.abs(v) / peak) * height)),
75
+ width: barWidth,
76
+ backgroundColor: v < 0 ? negativeFill : positiveFill,
77
+ }}
78
+ className="rounded-t-[1px]"
79
+ accessibilityElementsHidden
80
+ testID={`spark-bars-bar-${i}`}
81
+ />
82
+ ))}
83
+ </View>
84
+ )
85
+ }
@@ -0,0 +1,41 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { describe, expect, it } from 'vitest'
5
+ import { SET_LEVEL_FLAT_BAR, REP_LEVEL_FLAT_BAR } from './flatBarGeometry'
6
+
7
+ const DIR = path.dirname(fileURLToPath(import.meta.url))
8
+ const segmentedBarSource = readFileSync(path.join(DIR, '../Workout/SegmentedBar.tsx'), 'utf8')
9
+ const setBarChartSource = readFileSync(path.join(DIR, 'SetBarChart.tsx'), 'utf8')
10
+
11
+ describe('flat-bar geometry (VW-86)', () => {
12
+ it('documents intentionally different set-level and rep-level sizes', () => {
13
+ expect(SET_LEVEL_FLAT_BAR).toEqual({ height: 8, gap: 5, radius: 2 })
14
+ expect(REP_LEVEL_FLAT_BAR).toEqual({ height: null, gapFloor: 2, radius: 5 })
15
+ })
16
+
17
+ it('SegmentedBar imports its geometry from the shared module rather than its own literals', () => {
18
+ expect(segmentedBarSource).toMatch(
19
+ /import\s*\{\s*SET_LEVEL_FLAT_BAR\s*\}\s*from\s*'\.\.\/charts\/flatBarGeometry'/
20
+ )
21
+ // The old hardcoded defaults must be gone from the component's own prop destructuring.
22
+ expect(segmentedBarSource).not.toMatch(/height\s*=\s*8\b/)
23
+ expect(segmentedBarSource).not.toMatch(/radius\s*=\s*2\b/)
24
+ expect(segmentedBarSource).toMatch(/height\s*=\s*SET_LEVEL_FLAT_BAR\.height/)
25
+ expect(segmentedBarSource).toMatch(/radius\s*=\s*SET_LEVEL_FLAT_BAR\.radius/)
26
+ })
27
+
28
+ it('SetBarChart imports its geometry from the shared module rather than its own literals', () => {
29
+ expect(setBarChartSource).toMatch(
30
+ /import\s*\{\s*REP_LEVEL_FLAT_BAR\s*\}\s*from\s*'\.\/flatBarGeometry'/
31
+ )
32
+ expect(setBarChartSource).not.toMatch(/const MIN_BAR_GAP = 2\b/)
33
+ expect(setBarChartSource).not.toMatch(/const DEFAULT_BAR_RADIUS = 5\b/)
34
+ expect(setBarChartSource).toMatch(/const MIN_BAR_GAP = REP_LEVEL_FLAT_BAR\.gapFloor/)
35
+ expect(setBarChartSource).toMatch(/const DEFAULT_BAR_RADIUS = REP_LEVEL_FLAT_BAR\.radius/)
36
+ })
37
+
38
+ it('SegmentedBar keeps SEGMENTED_BAR_GAP derived from the shared set-level gap', () => {
39
+ expect(segmentedBarSource).toMatch(/const SEGMENTED_BAR_GAP = SET_LEVEL_FLAT_BAR\.gap/)
40
+ })
41
+ })
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The flat-bar geometry `SegmentedBar` (set-level: one row per SET, e.g. SetStrip/SessionRail)
3
+ * and `SetBarChart` (rep-level: one bar per REP within a set) each declare as their own component
4
+ * defaults. VW-86 named the fact that these lived in two files with no shared source as the drift
5
+ * risk: a future edit to one could silently diverge from the other without anyone noticing they
6
+ * were ever meant to be compared.
7
+ *
8
+ * They are NOT unified into one set of numbers — a strip of SETS across a session and a chart of
9
+ * REPS within one set are genuinely different sizes by design. This module exists so that
10
+ * difference is a documented, single-sourced choice instead of two numbers that happen to match
11
+ * or drift by accident.
12
+ */
13
+
14
+ /** `SegmentedBar`'s own default geometry (set-level: one row per SET). */
15
+ export const SET_LEVEL_FLAT_BAR = {
16
+ /** Track height (px). */
17
+ height: 8,
18
+ /** Gap between segment slots (px) — also SetStrip's between-set gap, see `SEGMENTED_BAR_GAP`. */
19
+ gap: 5,
20
+ /** Corner radius (px). */
21
+ radius: 2,
22
+ } as const
23
+
24
+ /** `SetBarChart`'s own default geometry (rep-level: one bar per REP within a set). */
25
+ export const REP_LEVEL_FLAT_BAR = {
26
+ /** No fixed height default — SetBarChart's `height` is a required prop set by the caller. */
27
+ height: null,
28
+ /** Inter-bar gap is proportional (`gapRatio · barWidth`), floored at this many px. */
29
+ gapFloor: 2,
30
+ /** Corner radius (px) default. */
31
+ radius: 5,
32
+ } as const
@@ -0,0 +1,3 @@
1
+ // Public chart primitives. `SetBarChart` and `live-rep-growth` are deliberately
2
+ // not re-exported here — they are workout-internal and imported by path.
3
+ export * from './SparkBars'
@@ -13,3 +13,6 @@ export * from './Fatigue'
13
13
  export * from './Treemap'
14
14
  export * from './Scatter'
15
15
  export * from './Gauge'
16
+ export * from './charts'
17
+ export * from './ActiveWork'
18
+ export * from './Prose'
@@ -5,7 +5,16 @@ import { Stepper, Step, StepIndicator, StepLabel, StepContent } from './Stepper'
5
5
  const meta: Meta<typeof Stepper> = {
6
6
  title: 'Components/Molecules/Stepper',
7
7
  component: Stepper,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:candidate', '!status:review'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'Composes RN primitives only. The five parts share step index and orientation through ' +
14
+ 'a context, the same shape as **Tabs**.',
15
+ },
16
+ },
17
+ },
9
18
  argTypes: {
10
19
  activeStep: {
11
20
  control: { type: 'number', min: 0, max: 4 },
@@ -124,9 +133,7 @@ export const VerticalWithContent: Story = {
124
133
  <StepIndicator />
125
134
  <StepLabel>Create Account</StepLabel>
126
135
  <StepContent>
127
- <Text className="text-text-secondary text-sm">
128
- Account creation is complete.
129
- </Text>
136
+ <Text className="text-text-secondary text-sm">Account creation is complete.</Text>
130
137
  </StepContent>
131
138
  </Step>
132
139
  <Step>
@@ -147,9 +154,7 @@ export const VerticalWithContent: Story = {
147
154
  <StepIndicator />
148
155
  <StepLabel>Configure Settings</StepLabel>
149
156
  <StepContent>
150
- <Text className="text-text-secondary text-sm">
151
- Adjust your preferences.
152
- </Text>
157
+ <Text className="text-text-secondary text-sm">Adjust your preferences.</Text>
153
158
  </StepContent>
154
159
  </Step>
155
160
  </Stepper>
@@ -221,9 +226,7 @@ export const ActiveStepProgression: Story = {
221
226
  <View style={{ gap: 24 }}>
222
227
  {[0, 1, 2, 3].map((activeStep) => (
223
228
  <View key={activeStep}>
224
- <Text className="text-text-secondary text-xs mb-2">
225
- Active step: {activeStep}
226
- </Text>
229
+ <Text className="text-text-secondary text-xs mb-2">Active step: {activeStep}</Text>
227
230
  <Stepper activeStep={activeStep} orientation="horizontal">
228
231
  <Step>
229
232
  <StepIndicator />
@@ -1,13 +1,7 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import { render, screen } from '@testing-library/react'
3
3
  import { axe } from 'jest-axe'
4
- import {
5
- Stepper,
6
- Step,
7
- StepIndicator,
8
- StepLabel,
9
- StepContent,
10
- } from './Stepper'
4
+ import { Stepper, Step, StepIndicator, StepLabel, StepContent } from './Stepper'
11
5
 
12
6
  function renderStepper(activeStep = 1) {
13
7
  return render(
@@ -65,9 +65,7 @@ export function Stepper({
65
65
  return (
66
66
  <>
67
67
  {React.cloneElement(child as React.ReactElement<any>, { index })}
68
- {index < React.Children.count(children) - 1 && (
69
- <StepConnector index={index} />
70
- )}
68
+ {index < React.Children.count(children) - 1 && <StepConnector index={index} />}
71
69
  </>
72
70
  )
73
71
  }
@@ -88,22 +86,12 @@ function StepConnector({ index }: StepConnectorProps) {
88
86
 
89
87
  if (orientation === 'horizontal') {
90
88
  return (
91
- <View
92
- className={cn(
93
- 'flex-1 h-0.5 mx-2',
94
- isCompleted ? 'bg-brand-primary' : 'bg-hairline'
95
- )}
96
- />
89
+ <View className={cn('flex-1 h-0.5 mx-2', isCompleted ? 'bg-brand-primary' : 'bg-hairline')} />
97
90
  )
98
91
  }
99
92
 
100
93
  return (
101
- <View
102
- className={cn(
103
- 'w-0.5 h-8 ml-4 my-1',
104
- isCompleted ? 'bg-brand-primary' : 'bg-hairline'
105
- )}
106
- />
94
+ <View className={cn('w-0.5 h-8 ml-4 my-1', isCompleted ? 'bg-brand-primary' : 'bg-hairline')} />
107
95
  )
108
96
  }
109
97
 
@@ -123,10 +111,8 @@ export interface StepProps {
123
111
  export function Step({ index = 0, status, className, children }: StepProps) {
124
112
  const { activeStep, orientation } = useContext(StepperContext)
125
113
 
126
- const derivedStatus: StepStatus = status || (
127
- index < activeStep ? 'completed' :
128
- index === activeStep ? 'active' : 'upcoming'
129
- )
114
+ const derivedStatus: StepStatus =
115
+ status || (index < activeStep ? 'completed' : index === activeStep ? 'active' : 'upcoming')
130
116
 
131
117
  return (
132
118
  <View
@@ -175,6 +161,13 @@ export function StepIndicator({
175
161
  error: 'bg-status-error border-status-error',
176
162
  }
177
163
 
164
+ const glyphStyles: Record<StepStatus, string> = {
165
+ completed: 'text-on-brand-primary',
166
+ active: 'text-on-brand-primary',
167
+ upcoming: 'text-text-secondary',
168
+ error: 'text-on-status-error',
169
+ }
170
+
178
171
  return (
179
172
  <View
180
173
  className={cn(
@@ -184,12 +177,7 @@ export function StepIndicator({
184
177
  )}
185
178
  >
186
179
  {icon || (
187
- <Text
188
- className={cn(
189
- 'text-sm font-semibold',
190
- status === 'upcoming' ? 'text-text-secondary' : 'text-white'
191
- )}
192
- >
180
+ <Text className={cn('text-sm font-semibold', glyphStyles[status])}>
193
181
  {status === 'completed' ? '✓' : index + 1}
194
182
  </Text>
195
183
  )}
@@ -216,10 +204,13 @@ export function StepLabel({ status = 'upcoming', className, children }: StepLabe
216
204
  className={cn(
217
205
  'text-sm font-medium',
218
206
  orientation === 'horizontal' ? 'mt-2' : 'ml-3',
219
- status === 'active' ? 'text-text-primary' :
220
- status === 'completed' ? 'text-brand-primary' :
221
- status === 'error' ? 'text-status-error' :
222
- 'text-text-secondary',
207
+ status === 'active'
208
+ ? 'text-text-primary'
209
+ : status === 'completed'
210
+ ? 'text-brand-primary'
211
+ : status === 'error'
212
+ ? 'text-status-error'
213
+ : 'text-text-secondary',
223
214
  className
224
215
  )}
225
216
  >
@@ -242,9 +233,5 @@ export interface StepContentProps {
242
233
  export function StepContent({ status = 'upcoming', className, children }: StepContentProps) {
243
234
  if (status !== 'active') return null
244
235
 
245
- return (
246
- <View className={cn('ml-11 mt-2 pb-4', className)}>
247
- {children}
248
- </View>
249
- )
236
+ return <View className={cn('ml-11 mt-2 pb-4', className)}>{children}</View>
250
237
  }
@@ -20,7 +20,7 @@ import {
20
20
 
21
21
  const meta: Meta = {
22
22
  title: 'Foundations/Icons',
23
- tags: ['autodocs'],
23
+ tags: ['autodocs', 'status:candidate', '!status:review'],
24
24
  parameters: {
25
25
  docs: {
26
26
  description: {
@@ -151,3 +151,54 @@ export function InfoIcon(props: IconProps) {
151
151
  </SvgIcon>
152
152
  )
153
153
  }
154
+
155
+ // ---------------------------------------------------------------------------
156
+ // AW-132 · App brand marks — the mark half of a `BrandLockup` for each app that
157
+ // is likely to mount the shell. Sized 14 by default, like `VoltrasMark`.
158
+ // ---------------------------------------------------------------------------
159
+
160
+ /** Headphones glyph (mirrors lucide-react `Headphones`). Audiobook brand mark. */
161
+ export function HeadphonesIcon({ size = 14, ...props }: IconProps) {
162
+ return (
163
+ <SvgIcon size={size} {...props}>
164
+ <path d="M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5a9 9 0 0 1 18 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3" />
165
+ </SvgIcon>
166
+ )
167
+ }
168
+
169
+ /** Kanban board glyph (mirrors lucide-react `SquareKanban`). Active-work brand mark. */
170
+ export function KanbanIcon({ size = 14, ...props }: IconProps) {
171
+ return (
172
+ <SvgIcon size={size} {...props}>
173
+ <rect width="18" height="18" x="3" y="3" rx="2" />
174
+ <path d="M8 7v7" />
175
+ <path d="M12 7v4" />
176
+ <path d="M16 7v9" />
177
+ </SvgIcon>
178
+ )
179
+ }
180
+
181
+ /** Robot glyph (mirrors lucide-react `Bot`). Agent-dashboard brand mark. */
182
+ export function BotIcon({ size = 14, ...props }: IconProps) {
183
+ return (
184
+ <SvgIcon size={size} {...props}>
185
+ <path d="M12 8V4H8" />
186
+ <rect width="16" height="12" x="4" y="8" rx="2" />
187
+ <path d="M2 14h2" />
188
+ <path d="M20 14h2" />
189
+ <path d="M15 13v2" />
190
+ <path d="M9 13v2" />
191
+ </SvgIcon>
192
+ )
193
+ }
194
+
195
+ /** Brain glyph (mirrors lucide-react `Brain`). Brain-app brand mark. */
196
+ export function BrainIcon({ size = 14, ...props }: IconProps) {
197
+ return (
198
+ <SvgIcon size={size} {...props}>
199
+ <path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" />
200
+ <path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" />
201
+ <path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" />
202
+ </SvgIcon>
203
+ )
204
+ }