@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
@@ -1,6 +1,8 @@
1
1
  import React, { useState, useRef, useCallback, createContext, useContext } from 'react'
2
2
  import { View, Pressable, Modal, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
+ import { Surface } from '../surface'
5
+ import { TriggerSurface } from '../trigger'
4
6
 
5
7
  export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right'
6
8
 
@@ -68,12 +70,15 @@ export function Popover({
68
70
  const isOpen = controlledIsOpen ?? internalIsOpen
69
71
  const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
70
72
 
71
- const setIsOpen = useCallback((open: boolean) => {
72
- if (controlledIsOpen === undefined) {
73
- setInternalIsOpen(open)
74
- }
75
- onOpenChange?.(open)
76
- }, [controlledIsOpen, onOpenChange])
73
+ const setIsOpen = useCallback(
74
+ (open: boolean) => {
75
+ if (controlledIsOpen === undefined) {
76
+ setInternalIsOpen(open)
77
+ }
78
+ onOpenChange?.(open)
79
+ },
80
+ [controlledIsOpen, onOpenChange]
81
+ )
77
82
 
78
83
  const handleHoverIn = useCallback(() => {
79
84
  if (triggerMode !== 'hover') return
@@ -126,15 +131,14 @@ export function PopoverTrigger({ children, className }: PopoverTriggerProps) {
126
131
  : {}
127
132
 
128
133
  return (
129
- <Pressable
130
- onPress={() => setIsOpen(!isOpen)}
134
+ <TriggerSurface
135
+ handlers={{ onPress: () => setIsOpen(!isOpen), ...hoverProps }}
131
136
  accessibilityRole="button"
132
137
  accessibilityState={{ expanded: isOpen }}
133
138
  className={className}
134
- {...hoverProps}
135
139
  >
136
140
  {children}
137
- </Pressable>
141
+ </TriggerSurface>
138
142
  )
139
143
  }
140
144
 
@@ -184,12 +188,13 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
184
188
  className="fixed inset-0 z-40"
185
189
  style={{ position: 'absolute' }}
186
190
  />
187
- {/* Content */}
188
- <View
191
+ {/* Content — floating: overlay plane + lift, no ring. */}
192
+ <Surface
193
+ elevation={4}
194
+ rounded={false}
189
195
  className={cn(
190
196
  'absolute z-50 min-w-[200px]',
191
- 'bg-surface-elevated rounded-lg shadow-lg border border-hairline',
192
- 'p-4',
197
+ 'rounded-lg p-4',
193
198
  placementStyles[placement],
194
199
  className
195
200
  )}
@@ -208,7 +213,7 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
208
213
  />
209
214
  )}
210
215
  {children}
211
- </View>
216
+ </Surface>
212
217
  </>
213
218
  )
214
219
  }
@@ -1,2 +1,8 @@
1
1
  export { Popover, PopoverTrigger, PopoverContent, PopoverCloseButton } from './Popover'
2
- export type { PopoverProps, PopoverTriggerProps, PopoverContentProps, PopoverCloseButtonProps, PopoverPlacement } from './Popover'
2
+ export type {
3
+ PopoverProps,
4
+ PopoverTriggerProps,
5
+ PopoverContentProps,
6
+ PopoverCloseButtonProps,
7
+ PopoverPlacement,
8
+ } from './Popover'
@@ -5,7 +5,7 @@ import { Progress, CircularProgress, ProgressSteps } from './Progress'
5
5
  const meta: Meta<typeof Progress> = {
6
6
  title: 'Components/Molecules/Progress',
7
7
  component: Progress,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  value: {
11
11
  control: { type: 'range', min: 0, max: 100, step: 1 },
@@ -131,11 +131,7 @@ export const Steps: Story = {
131
131
  color="success"
132
132
  labels={['Step 1', 'Step 2', 'Step 3', 'Step 4']}
133
133
  />
134
- <ProgressSteps
135
- currentStep={0}
136
- totalSteps={5}
137
- size="lg"
138
- />
134
+ <ProgressSteps currentStep={0} totalSteps={5} size="lg" />
139
135
  </View>
140
136
  ),
141
137
  }
@@ -152,12 +148,7 @@ export const UsageExamples: Story = {
152
148
  {/* Storage quota */}
153
149
  <View className="p-4 bg-surface-elevated rounded-lg">
154
150
  <Text className="text-text-primary font-medium mb-3">Storage</Text>
155
- <Progress
156
- value={8.5}
157
- max={10}
158
- color="warning"
159
- label="8.5 GB of 10 GB used"
160
- />
151
+ <Progress value={8.5} max={10} color="warning" label="8.5 GB of 10 GB used" />
161
152
  </View>
162
153
 
163
154
  {/* Checkout steps */}
@@ -154,11 +154,7 @@ describe('Progress', () => {
154
154
 
155
155
  it('renders labels', () => {
156
156
  render(
157
- <ProgressSteps
158
- currentStep={1}
159
- totalSteps={3}
160
- labels={['Step 1', 'Step 2', 'Step 3']}
161
- />
157
+ <ProgressSteps currentStep={1} totalSteps={3} labels={['Step 1', 'Step 2', 'Step 3']} />
162
158
  )
163
159
  expect(screen.getByText('Step 1')).toBeInTheDocument()
164
160
  expect(screen.getByText('Step 2')).toBeInTheDocument()
@@ -56,13 +56,16 @@ const colorStyles: Record<ProgressColor, string> = {
56
56
  info: 'bg-status-info',
57
57
  }
58
58
 
59
+ // `-muted` rather than `-subtle`: the track is structural — it has to show the
60
+ // bar's full extent behind the fill — and the lightest rung disappears on the
61
+ // dark base. Replaces a `/20` modifier that emitted no rule (VW-308).
59
62
  const trackColorStyles: Record<ProgressColor, string> = {
60
- primary: 'bg-brand-primary/20',
61
- secondary: 'bg-brand-secondary/20',
62
- success: 'bg-status-success/20',
63
- error: 'bg-status-error/20',
64
- warning: 'bg-status-warning/20',
65
- info: 'bg-status-info/20',
63
+ primary: 'bg-brand-primary-muted',
64
+ secondary: 'bg-brand-secondary-muted',
65
+ success: 'bg-status-success-muted',
66
+ error: 'bg-status-error-muted',
67
+ warning: 'bg-status-warning-muted',
68
+ info: 'bg-status-info-muted',
66
69
  }
67
70
 
68
71
  /**
@@ -6,7 +6,7 @@ import { Radio, RadioGroup } from './Radio'
6
6
  const meta: Meta<typeof RadioGroup> = {
7
7
  title: 'Components/Molecules/Radio',
8
8
  component: RadioGroup,
9
- tags: ['autodocs'],
9
+ tags: ['autodocs', 'status:stable', '!status:review'],
10
10
  argTypes: {
11
11
  size: {
12
12
  control: 'select',
@@ -60,12 +60,7 @@ export const Horizontal: Story = {
60
60
  render: function Render() {
61
61
  const [value, setValue] = useState<string | null>('monthly')
62
62
  return (
63
- <RadioGroup
64
- value={value}
65
- onChange={setValue}
66
- orientation="horizontal"
67
- label="Billing Cycle"
68
- >
63
+ <RadioGroup value={value} onChange={setValue} orientation="horizontal" label="Billing Cycle">
69
64
  <Radio value="monthly">Monthly</Radio>
70
65
  <Radio value="quarterly">Quarterly</Radio>
71
66
  <Radio value="yearly">Yearly</Radio>
@@ -79,7 +74,7 @@ export const AllSizes: Story = {
79
74
  const [small, setSmall] = useState<string | null>('a')
80
75
  const [medium, setMedium] = useState<string | null>('a')
81
76
  const [large, setLarge] = useState<string | null>('a')
82
-
77
+
83
78
  return (
84
79
  <View className="gap-6">
85
80
  <View>
@@ -114,22 +109,46 @@ export const AllColors: Story = {
114
109
  const [secondary, setSecondary] = useState<string | null>('a')
115
110
  const [success, setSuccess] = useState<string | null>('a')
116
111
  const [error, setError] = useState<string | null>('a')
117
-
112
+
118
113
  return (
119
114
  <View className="gap-6">
120
- <RadioGroup value={primary} onChange={setPrimary} color="primary" orientation="horizontal" label="Primary">
115
+ <RadioGroup
116
+ value={primary}
117
+ onChange={setPrimary}
118
+ color="primary"
119
+ orientation="horizontal"
120
+ label="Primary"
121
+ >
121
122
  <Radio value="a">Option A</Radio>
122
123
  <Radio value="b">Option B</Radio>
123
124
  </RadioGroup>
124
- <RadioGroup value={secondary} onChange={setSecondary} color="secondary" orientation="horizontal" label="Secondary">
125
+ <RadioGroup
126
+ value={secondary}
127
+ onChange={setSecondary}
128
+ color="secondary"
129
+ orientation="horizontal"
130
+ label="Secondary"
131
+ >
125
132
  <Radio value="a">Option A</Radio>
126
133
  <Radio value="b">Option B</Radio>
127
134
  </RadioGroup>
128
- <RadioGroup value={success} onChange={setSuccess} color="success" orientation="horizontal" label="Success">
135
+ <RadioGroup
136
+ value={success}
137
+ onChange={setSuccess}
138
+ color="success"
139
+ orientation="horizontal"
140
+ label="Success"
141
+ >
129
142
  <Radio value="a">Option A</Radio>
130
143
  <Radio value="b">Option B</Radio>
131
144
  </RadioGroup>
132
- <RadioGroup value={error} onChange={setError} color="error" orientation="horizontal" label="Error">
145
+ <RadioGroup
146
+ value={error}
147
+ onChange={setError}
148
+ color="error"
149
+ orientation="horizontal"
150
+ label="Error"
151
+ >
133
152
  <Radio value="a">Option A</Radio>
134
153
  <Radio value="b">Option B</Radio>
135
154
  </RadioGroup>
@@ -154,7 +173,9 @@ export const Disabled: Story = {
154
173
  <Text className="text-text-secondary text-sm mb-2">Individual option disabled</Text>
155
174
  <RadioGroup value={value} onChange={setValue}>
156
175
  <Radio value="option1">Option 1 (enabled)</Radio>
157
- <Radio value="option2" isDisabled>Option 2 (disabled)</Radio>
176
+ <Radio value="option2" isDisabled>
177
+ Option 2 (disabled)
178
+ </Radio>
158
179
  <Radio value="option3">Option 3 (enabled)</Radio>
159
180
  </RadioGroup>
160
181
  </View>
@@ -167,27 +188,27 @@ export const FormExample: Story = {
167
188
  render: function Render() {
168
189
  const [plan, setPlan] = useState<string | null>('pro')
169
190
  const [billing, setBilling] = useState<string | null>('monthly')
170
-
191
+
171
192
  return (
172
193
  <View className="gap-6 p-4 bg-surface-base rounded-lg max-w-md">
173
194
  <Text className="text-lg font-semibold text-text-primary">Subscription Settings</Text>
174
-
195
+
175
196
  <RadioGroup value={plan} onChange={setPlan} label="Select Plan">
176
197
  <Radio value="free">Free - Basic features</Radio>
177
198
  <Radio value="pro">Pro - Advanced features</Radio>
178
199
  <Radio value="enterprise">Enterprise - Custom solutions</Radio>
179
200
  </RadioGroup>
180
-
181
- <RadioGroup
182
- value={billing}
183
- onChange={setBilling}
201
+
202
+ <RadioGroup
203
+ value={billing}
204
+ onChange={setBilling}
184
205
  orientation="horizontal"
185
206
  label="Billing Frequency"
186
207
  >
187
208
  <Radio value="monthly">Monthly</Radio>
188
209
  <Radio value="yearly">Yearly (save 20%)</Radio>
189
210
  </RadioGroup>
190
-
211
+
191
212
  <View className="pt-4 border-t border-hairline">
192
213
  <Text className="text-sm text-text-secondary">
193
214
  Selected: {plan} plan, billed {billing}
@@ -68,7 +68,9 @@ describe('Radio', () => {
68
68
  render(
69
69
  <RadioGroup value="a" onChange={onChange}>
70
70
  <Radio value="a">A</Radio>
71
- <Radio value="b" isDisabled>B</Radio>
71
+ <Radio value="b" isDisabled>
72
+ B
73
+ </Radio>
72
74
  </RadioGroup>
73
75
  )
74
76
  const radios = screen.getAllByRole('radio')
@@ -134,7 +136,9 @@ describe('Radio', () => {
134
136
  it('allows Radio to override group size and color', () => {
135
137
  render(
136
138
  <RadioGroup value="a" onChange={() => {}} size="sm" color="primary">
137
- <Radio value="a" size="lg" color="error">A</Radio>
139
+ <Radio value="a" size="lg" color="error">
140
+ A
141
+ </Radio>
138
142
  </RadioGroup>
139
143
  )
140
144
  expect(screen.getByRole('radio')).toBeInTheDocument()
@@ -78,11 +78,7 @@ export function RadioGroup({
78
78
  accessibilityLabel={label}
79
79
  {...props}
80
80
  >
81
- {label && (
82
- <Text className="text-sm font-medium text-text-primary mb-2">
83
- {label}
84
- </Text>
85
- )}
81
+ {label && <Text className="text-sm font-medium text-text-primary mb-2">{label}</Text>}
86
82
  <View
87
83
  className={cn(
88
84
  orientation === 'horizontal' ? 'flex-row flex-wrap' : 'flex-col',
@@ -117,9 +113,18 @@ const sizeConfig: Record<RadioSize, { outer: string; inner: string; text: string
117
113
  }
118
114
 
119
115
  const colorStyles: Record<RadioColor, { checked: string; unchecked: string }> = {
120
- primary: { checked: 'border-brand-primary bg-brand-primary', unchecked: 'border-hairline-strong' },
121
- secondary: { checked: 'border-brand-secondary bg-brand-secondary', unchecked: 'border-hairline-strong' },
122
- success: { checked: 'border-status-success bg-status-success', unchecked: 'border-hairline-strong' },
116
+ primary: {
117
+ checked: 'border-brand-primary bg-brand-primary',
118
+ unchecked: 'border-hairline-strong',
119
+ },
120
+ secondary: {
121
+ checked: 'border-brand-secondary bg-brand-secondary',
122
+ unchecked: 'border-hairline-strong',
123
+ },
124
+ success: {
125
+ checked: 'border-status-success bg-status-success',
126
+ unchecked: 'border-hairline-strong',
127
+ },
123
128
  error: { checked: 'border-status-error bg-status-error', unchecked: 'border-hairline-strong' },
124
129
  }
125
130
 
@@ -144,7 +149,13 @@ export function Radio({
144
149
  throw new Error('Radio must be used within a RadioGroup')
145
150
  }
146
151
 
147
- const { value: selectedValue, onChange, isDisabled: groupDisabled, size: groupSize, color: groupColor } = context
152
+ const {
153
+ value: selectedValue,
154
+ onChange,
155
+ isDisabled: groupDisabled,
156
+ size: groupSize,
157
+ color: groupColor,
158
+ } = context
148
159
 
149
160
  const isDisabled = radioDisabled ?? groupDisabled ?? false
150
161
  const size = radioSize ?? groupSize ?? 'md'
@@ -166,11 +177,7 @@ export function Radio({
166
177
  disabled={isDisabled}
167
178
  accessibilityRole="radio"
168
179
  accessibilityState={{ checked: isChecked, disabled: isDisabled }}
169
- className={cn(
170
- 'flex-row items-center',
171
- isDisabled && 'opacity-50',
172
- className
173
- )}
180
+ className={cn('flex-row items-center', isDisabled && 'opacity-50', className)}
174
181
  {...props}
175
182
  >
176
183
  {/* Radio circle */}
@@ -184,17 +191,11 @@ export function Radio({
184
191
  )}
185
192
  >
186
193
  {/* Inner dot */}
187
- {isChecked && (
188
- <View className={cn('rounded-full bg-white', inner)} />
189
- )}
194
+ {isChecked && <View className={cn('rounded-full bg-on-brand-primary', inner)} />}
190
195
  </View>
191
196
 
192
197
  {/* Label */}
193
- {children && (
194
- <Text className={cn('ml-2 text-text-primary', text)}>
195
- {children}
196
- </Text>
197
- )}
198
+ {children && <Text className={cn('ml-2 text-text-primary', text)}>{children}</Text>}
198
199
  </Pressable>
199
200
  )
200
201
  }
@@ -5,7 +5,7 @@ import { Section, SectionHeader, SectionContent } from './Section'
5
5
  const meta: Meta<typeof Section> = {
6
6
  title: 'Components/Atoms/Section',
7
7
  component: Section,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  }
10
10
 
11
11
  export default meta
@@ -16,7 +16,7 @@ export const Default: Story = {
16
16
  <Section>
17
17
  <SectionHeader title="Recent Workouts" />
18
18
  <SectionContent>
19
- <Text style={{ color: '#a0a0a0' }}>Workout items would go here</Text>
19
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Workout items would go here</Text>
20
20
  </SectionContent>
21
21
  </Section>
22
22
  ),
@@ -25,12 +25,9 @@ export const Default: Story = {
25
25
  export const WithSubtitle: Story = {
26
26
  render: () => (
27
27
  <Section>
28
- <SectionHeader
29
- title="Workout Stats"
30
- subtitle="Last 7 days"
31
- />
28
+ <SectionHeader title="Workout Stats" subtitle="Last 7 days" />
32
29
  <SectionContent>
33
- <Text style={{ color: '#a0a0a0' }}>Stats content</Text>
30
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Stats content</Text>
34
31
  </SectionContent>
35
32
  </Section>
36
33
  ),
@@ -41,12 +38,10 @@ export const WithTrailingAction: Story = {
41
38
  <Section>
42
39
  <SectionHeader
43
40
  title="Exercises"
44
- trailing={
45
- <Text style={{ color: '#6366f1', fontSize: 13 }}>View All</Text>
46
- }
41
+ trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>View All</Text>}
47
42
  />
48
43
  <SectionContent>
49
- <Text style={{ color: '#a0a0a0' }}>Exercise list</Text>
44
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Exercise list</Text>
50
45
  </SectionContent>
51
46
  </Section>
52
47
  ),
@@ -58,12 +53,10 @@ export const FullExample: Story = {
58
53
  <SectionHeader
59
54
  title="Performance"
60
55
  subtitle="Average velocity by set"
61
- trailing={
62
- <Text style={{ color: '#6366f1', fontSize: 13 }}>Details</Text>
63
- }
56
+ trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>Details</Text>}
64
57
  />
65
58
  <SectionContent className="rounded-lg bg-surface-elevated p-4">
66
- <Text style={{ color: '#a0a0a0' }}>Chart or data visualization</Text>
59
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Chart or data visualization</Text>
67
60
  </SectionContent>
68
61
  </Section>
69
62
  ),
@@ -75,7 +68,7 @@ export const MultipleSections: Story = {
75
68
  <Section>
76
69
  <SectionHeader title="Today" subtitle="3 exercises" />
77
70
  <SectionContent className="rounded-lg bg-surface-elevated p-4">
78
- <Text style={{ color: '#a0a0a0' }}>Today&apos;s workout data</Text>
71
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Today&apos;s workout data</Text>
79
72
  </SectionContent>
80
73
  </Section>
81
74
 
@@ -83,19 +76,17 @@ export const MultipleSections: Story = {
83
76
  <SectionHeader
84
77
  title="This Week"
85
78
  subtitle="12 sets completed"
86
- trailing={
87
- <Text style={{ color: '#6366f1', fontSize: 13 }}>See All</Text>
88
- }
79
+ trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>See All</Text>}
89
80
  />
90
81
  <SectionContent className="rounded-lg bg-surface-elevated p-4">
91
- <Text style={{ color: '#a0a0a0' }}>Weekly summary</Text>
82
+ <Text style={{ color: 'var(--color-text-secondary)' }}>Weekly summary</Text>
92
83
  </SectionContent>
93
84
  </Section>
94
85
 
95
86
  <Section>
96
87
  <SectionHeader title="Personal Records" />
97
88
  <SectionContent className="rounded-lg bg-surface-elevated p-4">
98
- <Text style={{ color: '#a0a0a0' }}>PR list</Text>
89
+ <Text style={{ color: 'var(--color-text-secondary)' }}>PR list</Text>
99
90
  </SectionContent>
100
91
  </Section>
101
92
  </View>
@@ -42,12 +42,7 @@ describe('SectionHeader', () => {
42
42
  })
43
43
 
44
44
  it('renders trailing action when provided', () => {
45
- render(
46
- <SectionHeader
47
- title="Title"
48
- trailing={<Text>View All</Text>}
49
- />
50
- )
45
+ render(<SectionHeader title="Title" trailing={<Text>View All</Text>} />)
51
46
  expect(screen.getByText('View All')).toBeInTheDocument()
52
47
  })
53
48
 
@@ -29,9 +29,7 @@ export function SectionHeader({ title, subtitle, trailing, className }: SectionH
29
29
  <Text className="text-sm font-semibold text-text-secondary uppercase tracking-wider">
30
30
  {title}
31
31
  </Text>
32
- {subtitle && (
33
- <Text className="text-xs text-text-tertiary mt-0.5">{subtitle}</Text>
34
- )}
32
+ {subtitle && <Text className="text-xs text-text-tertiary mt-0.5">{subtitle}</Text>}
35
33
  </View>
36
34
  {trailing && <View>{trailing}</View>}
37
35
  </View>
@@ -1,6 +1,2 @@
1
1
  export { Section, SectionHeader, SectionContent } from './Section'
2
- export type {
3
- SectionProps,
4
- SectionHeaderProps,
5
- SectionContentProps,
6
- } from './Section'
2
+ export type { SectionProps, SectionHeaderProps, SectionContentProps } from './Section'
@@ -101,12 +101,7 @@ export const Disabled: Story = {
101
101
  </View>
102
102
  <View style={{ gap: 4 }}>
103
103
  <Text className="text-sm text-text-secondary">Disabled with value</Text>
104
- <Select
105
- value="banana"
106
- onChange={() => {}}
107
- options={basicOptions}
108
- isDisabled
109
- />
104
+ <Select value="banana" onChange={() => {}} options={basicOptions} isDisabled />
110
105
  </View>
111
106
  </View>
112
107
  ),
@@ -235,16 +230,11 @@ export const Controlled: Story = {
235
230
  </Text>
236
231
  </View>
237
232
  ))}
238
- <Text
239
- className="text-sm text-status-error underline"
240
- onPress={() => setValue(null)}
241
- >
233
+ <Text className="text-sm text-status-error underline" onPress={() => setValue(null)}>
242
234
  Clear
243
235
  </Text>
244
236
  </View>
245
- <Text className="text-sm text-text-secondary">
246
- Current value: {value ?? 'null'}
247
- </Text>
237
+ <Text className="text-sm text-text-secondary">Current value: {value ?? 'null'}</Text>
248
238
  </View>
249
239
  )
250
240
  },
@@ -94,14 +94,7 @@ describe('Select', () => {
94
94
 
95
95
  it('calls onChangeMulti when toggling options', () => {
96
96
  const onChangeMulti = vi.fn()
97
- render(
98
- <Select
99
- options={defaultOptions}
100
- isMulti
101
- values={[]}
102
- onChangeMulti={onChangeMulti}
103
- />
104
- )
97
+ render(<Select options={defaultOptions} isMulti values={[]} onChangeMulti={onChangeMulti} />)
105
98
 
106
99
  fireEvent.click(screen.getByRole('combobox'))
107
100
  fireEvent.click(screen.getByText('Option 1'))
@@ -163,9 +156,7 @@ describe('Select', () => {
163
156
 
164
157
  describe('accessibility', () => {
165
158
  it('has no accessibility violations', async () => {
166
- const { container } = render(
167
- <Select options={defaultOptions} value="1" />
168
- )
159
+ const { container } = render(<Select options={defaultOptions} value="1" />)
169
160
  const results = await axe(container, {
170
161
  rules: {
171
162
  'aria-input-field-name': { enabled: false },
@@ -1,6 +1,7 @@
1
1
  import React, { useState, createContext, useContext } from 'react'
2
2
  import { View, Text, Pressable, ScrollView, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
+ import { Surface } from '../surface'
4
5
 
5
6
  export interface SelectOption<T = string> {
6
7
  value: T
@@ -91,9 +92,7 @@ export function Select<T extends string = string>({
91
92
 
92
93
  const selectValue = (val: T) => {
93
94
  if (isMulti) {
94
- const newValues = values.includes(val)
95
- ? values.filter((v) => v !== val)
96
- : [...values, val]
95
+ const newValues = values.includes(val) ? values.filter((v) => v !== val) : [...values, val]
97
96
  onChangeMulti?.(newValues)
98
97
  } else {
99
98
  onChange?.(val)
@@ -141,6 +140,7 @@ export function Select<T extends string = string>({
141
140
  accessibilityState={{ expanded: isOpen, disabled: isDisabled }}
142
141
  className={cn(
143
142
  'flex-row items-center justify-between px-4 py-2.5 rounded-md border',
143
+ // VW-82: scrim-style fill, left raw (see Modal.tsx).
144
144
  variant === 'filled' ? 'bg-black/30' : 'bg-surface-base',
145
145
  isInvalid
146
146
  ? 'border-border-input-error'
@@ -152,12 +152,7 @@ export function Select<T extends string = string>({
152
152
  isDisabled && 'opacity-50 cursor-not-allowed'
153
153
  )}
154
154
  >
155
- <Text
156
- className={cn(
157
- 'flex-1',
158
- hasValue ? 'text-text-primary' : 'text-text-tertiary'
159
- )}
160
- >
155
+ <Text className={cn('flex-1', hasValue ? 'text-text-primary' : 'text-text-tertiary')}>
161
156
  {getDisplayValue()}
162
157
  </Text>
163
158
  <View className="flex-row items-center gap-2">
@@ -184,11 +179,12 @@ export function Select<T extends string = string>({
184
179
  className="fixed inset-0 z-40"
185
180
  style={{ position: 'absolute' }}
186
181
  />
187
- <View
182
+ <Surface
183
+ elevation={4}
184
+ rounded={false}
188
185
  className={cn(
189
186
  'absolute z-50 top-full left-0 right-0 mt-1',
190
- 'bg-surface-elevated rounded-md shadow-lg border border-hairline',
191
- 'max-h-60 overflow-hidden'
187
+ 'rounded-md max-h-60 overflow-hidden'
192
188
  )}
193
189
  >
194
190
  <ScrollView className="py-1">
@@ -196,7 +192,7 @@ export function Select<T extends string = string>({
196
192
  <SelectOption key={option.value} option={option} />
197
193
  ))}
198
194
  </ScrollView>
199
- </View>
195
+ </Surface>
200
196
  </>
201
197
  )}
202
198
  </View>
@@ -232,10 +228,15 @@ function SelectOption<T>({ option }: SelectOptionComponentProps<T>) {
232
228
  selected ? 'bg-brand-primary border-brand-primary' : 'border-hairline-strong'
233
229
  )}
234
230
  >
235
- {selected && <Text className="text-white text-xs text-center">✓</Text>}
231
+ {selected && <Text className="text-on-brand-primary text-xs text-center">✓</Text>}
236
232
  </View>
237
233
  )}
238
- <Text className={cn('text-sm', selected && !isMulti ? 'text-brand-primary font-medium' : 'text-text-primary')}>
234
+ <Text
235
+ className={cn(
236
+ 'text-sm',
237
+ selected && !isMulti ? 'text-brand-primary font-medium' : 'text-text-primary'
238
+ )}
239
+ >
239
240
  {option.label}
240
241
  </Text>
241
242
  </Pressable>