@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,52 @@
1
+ import { TopBar } from '../TopBar'
2
+ import { SessionStatePill, type SessionState } from './SessionStatePill'
3
+ import { DeviceMenu } from './DeviceMenu'
4
+ import { type Device } from './DeviceRow'
5
+
6
+ export interface WorkoutTopBarProps {
7
+ /** Global session state → the status pill. */
8
+ state: SessionState
9
+ /** Devices for the connection glyph + dropdown. */
10
+ devices: Device[]
11
+ /** The moment to display in the clock (Date/timestamp). Omit for a live ticking clock. */
12
+ time?: number | Date
13
+ /** Brand subtitle. Default "wall dashboard". */
14
+ subtitle?: string
15
+ /** Force the subtitle on/off; defaults to container-responsive. */
16
+ showSubtitle?: boolean
17
+ /** Force the clock on/off; defaults to container-responsive. */
18
+ showClock?: boolean
19
+ onSelectDevice?: (device: Device) => void
20
+ className?: string
21
+ }
22
+
23
+ /**
24
+ * The workout app's top bar — the generic {@link TopBar} with the workout's own
25
+ * chrome in its `trailing` slot: session state, then the device menu. The bar
26
+ * adds its dividers and the clock; this component only supplies the items.
27
+ */
28
+ export function WorkoutTopBar({
29
+ state,
30
+ devices,
31
+ time,
32
+ subtitle,
33
+ showSubtitle,
34
+ showClock,
35
+ onSelectDevice,
36
+ className,
37
+ }: WorkoutTopBarProps) {
38
+ return (
39
+ <TopBar
40
+ brand="voltras"
41
+ subtitle={subtitle}
42
+ showSubtitle={showSubtitle}
43
+ showClock={showClock}
44
+ time={time}
45
+ className={className}
46
+ trailing={[
47
+ <SessionStatePill key="state" state={state} />,
48
+ <DeviceMenu key="devices" devices={devices} onSelectDevice={onSelectDevice} />,
49
+ ]}
50
+ />
51
+ )
52
+ }
@@ -0,0 +1,9 @@
1
+ // Workout-app shell chrome — composes the generic shell family one directory up.
2
+ // Nothing here is reusable by another app; nothing generic may import from here.
3
+ export * from './SessionStatePill'
4
+ export * from './DeviceIndicator'
5
+ export * from './DeviceRow'
6
+ export * from './DeviceMenu'
7
+ export * from './workoutNavItems'
8
+ export * from './WorkoutTopBar'
9
+ export * from './WorkoutShell'
@@ -0,0 +1,16 @@
1
+ import { ActivityIcon, HistoryIcon, LayersIcon, PersonStandingIcon } from '../../icons'
2
+ import { type SideNavItem } from '../SideNav'
3
+
4
+ /** The four workout-dashboard categories with their locked S2 glyphs (activity · history · layers · figure). */
5
+ export const workoutNavItems: SideNavItem[] = [
6
+ { key: 'live', label: 'Live', icon: <ActivityIcon size={20} color="currentColor" /> },
7
+ { key: 'review', label: 'Review', icon: <HistoryIcon size={20} color="currentColor" /> },
8
+ { key: 'program', label: 'Plan', icon: <LayersIcon size={20} color="currentColor" /> },
9
+ { key: 'body', label: 'Body', icon: <PersonStandingIcon size={20} color="currentColor" /> },
10
+ ]
11
+
12
+ /**
13
+ * @deprecated Use `workoutNavItems` — these are the workout app's categories,
14
+ * not a generic shell default. `SideNav.items` is required now (AW-132).
15
+ */
16
+ export const defaultNavItems = workoutNavItems
@@ -0,0 +1,110 @@
1
+ # `ui/*` — the generic primitive family
2
+
3
+ The domain-free foundation tier: 38 primitives that know nothing about workouts,
4
+ sessions or initiatives. Everything in `custom/*` and `shell/*` is built on this
5
+ layer, and `ui/*` may not import from either of them — the tier order is
6
+ `theme → icons → ui → custom → shell → pages`.
7
+
8
+ This README is the **index**. It maps each primitive's dependencies
9
+ (**composes ↓**) and its consumers (**used-by ↑**) so the tree navigates in both
10
+ directions and a hand-rolled element that should have reached for an existing
11
+ primitive is visible. Storybook mirrors it under
12
+ `Components/Atoms|Molecules|Organisms/…`; each primitive's autodocs page repeats
13
+ its Composes links.
14
+
15
+ Counts below are generated, not hand-kept: they come from
16
+ [`src/arch/arch-graph.json`](../../arch/arch-graph.json) (regenerate with
17
+ `pnpm arch:graph`, which `arch-graph.freshness.test.ts` keeps honest). **In-repo**
18
+ is in-library consumers; **external** is import sites in the three checkouts the
19
+ graph scans (voltras mobile, voltras-mcp, codewatch dashboard). It is a floor,
20
+ not a census: `docs/audits/2026-09-08-critique-addenda.md` §D1 found seven
21
+ downstream checkouts, and audiobook/frontend — the one that tracks HEAD — is not
22
+ among the three.
23
+
24
+ ## The one rule this family exists to enforce
25
+
26
+ A primitive here is the _only_ implementation of its shape. When a family needs
27
+ a rule, a pill, a dot or a plane, it composes `ui/*` — it does not draw one. The
28
+ audit that produced this file found four container primitives competing and
29
+ twelve pill-shaped components; roadmap decisions 1, 3, 4, 5, 10 and 11 collapsed
30
+ them, and the survivors are marked as presets below.
31
+
32
+ ## Dependency map
33
+
34
+ | Component | Tier | Composes ↓ | Used-by ↑ (in-repo) | In-repo | External |
35
+ | ---------------- | -------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- |
36
+ | `alert` | atom | — | — (app-facing leaf) | 0 | 6 |
37
+ | `autocomplete` | molecule | Surface | — | 0 | 0 |
38
+ | `avatar` | atom | — | — | 0 | 0 |
39
+ | `badge` | molecule | Pill, Indicator | BodyMapDetailPanel, MesoCard, ReadinessCheck | 3 | 3 |
40
+ | `breadcrumbs` | atom | — | — | 0 | 0 |
41
+ | `button` | atom | — | examples | 1 | 17 |
42
+ | `card` | molecule | Surface | CoChangeChip, FileActivityDetail, FileHistoryExplorer, InitiativeCard, MesoCard, MesoStatusCard, PortfolioOverview, ReadinessCheck, SessionDetail, WorkoutCard | 10 | 74 |
43
+ | `checkbox` | atom | — | examples | 1 | 0 |
44
+ | `chip` | molecule | Pill | — (external-only preset) | 0 | 0 |
45
+ | `collapse` | atom | — | SessionDetail | 1 | 0 |
46
+ | `data-row` | atom | — | FileActivityDetail, VolumeLandmarkBar | 2 | 2 |
47
+ | `divider` | atom | — | FileHistoryExplorer, OpenLoops, SessionDetail, SessionList, TopBar | 5 | 2 |
48
+ | `drawer` | molecule | Surface | PrHistoryModal | 1 | 6 |
49
+ | `form-field` | atom | — | examples | 1 | 0 |
50
+ | `help-tip` | molecule | Surface | — **deprecated**, use Tooltip | 0 | 0 |
51
+ | `icon-box` | atom | — | — | 0 | 0 |
52
+ | `indicator` | atom | — | Badge, DeviceRow, SessionStatePill, SeverityLabel | 6 | 0 |
53
+ | `input` | atom | — | examples | 1 | 1 |
54
+ | `link` | atom | — | — | 0 | 0 |
55
+ | `list-item` | atom | — | — (app-facing leaf) | 0 | 9 |
56
+ | `menu` | molecule | Surface | — | 0 | 0 |
57
+ | `modal` | molecule | Surface | — | 0 | 0 |
58
+ | `pill` | atom | — | Badge, Chip, CoChangeChip, FileActivityDetail, InitiativeCard, InitiativeHeader, MuscleGroupChip, OpenLoops, SessionDetail, StatusPill, TaskRow | 11 | 1 |
59
+ | `popover` | molecule | Surface | DeviceMenu | 1 | 0 |
60
+ | `progress` | atom | — | CircularTimer | 1 | 2 |
61
+ | `radio` | atom | — | examples | 1 | 2 |
62
+ | `section` | atom | — | — (app-facing leaf) | 0 | 10 |
63
+ | `select` | molecule | Surface | examples | 2 | 1 |
64
+ | `skeleton` | atom | — | — | 0 | 0 |
65
+ | `spinner` | atom | — | — (app-facing leaf) | 0 | 2 |
66
+ | `stack` | atom | — | MetricTiles, ScheduleTiles | 2 | 27 |
67
+ | `surface` | atom | — | Autocomplete, Card, DashboardShell, Drawer, HelpTip, LiveFatigueCard, Menu, Modal, Popover, Select, SessionHeader, SessionRail, Toast, ToolbarButton, Tooltip | 15 | 29 |
68
+ | `switch` | atom | — | — | 0 | 0 |
69
+ | `tabs` | atom | — | — | 0 | 0 |
70
+ | `tile` | atom | — | FileActivityDetail, FileHistoryExplorer, MetricTiles, ScheduleTiles — **deprecated**, use a Card stat preset | 4 | 0 |
71
+ | `toast` | molecule | Surface | — | 0 | 0 |
72
+ | `toolbar-button` | molecule | Surface | — | 0 | 0 |
73
+ | `tooltip` | molecule | Surface | FatigueLights, SessionDetail, SessionListItem, Table, TaskRow, ZoneTrack | 8 | 1 |
74
+
75
+ Two roots carry the family: **`surface`** (15 in-repo consumers — every floating
76
+ and raised plane) and **`pill`** (11 — every pill-shaped label since decision 3).
77
+ Nothing else in `ui/*` is composed by more than six.
78
+
79
+ ## Reuse audit — where `ui/*` still hand-rolls
80
+
81
+ | Leaf | Should compose | Status |
82
+ | -------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83
+ | Text runs (79 raw `<Text>` in 27 files) | `Typography` | **Open.** `Typography` is in `custom/`, which `ui/*` may not import. Roadmap decision 9 moves it into `ui/`; until then every heading and label here is hand-styled. |
84
+ | Pill-shaped labels | `Pill` | **Closed** (#172). `Badge` and `Chip` now render `<Pill>`; the six folded-in variants are in `DEPRECATIONS.md`. |
85
+ | Status dots | `Indicator` | **Closed** for `ui/*`. `StatusDot` (Workout) is deprecated toward `Indicator` (decision 10). |
86
+ | Raised / floating planes | `Surface` (`raise` / `elevation`) | **Closed** (#166, #173). Eleven molecules compose `Surface` rather than setting `bg-surface-*` themselves. |
87
+ | Rules and separators (20 `border-hairline*` in 12 files) | `Divider` | **Partly open.** Decision 4 allows `border-hairline` only on Card `outline`/`subtle`, Table rules and input borders — `Select`, `Radio`, `Drawer` and `Tabs` still draw their own. |
88
+ | Tooltip-with-a-label lockup | `Tooltip` + your own label | **Closed** by deprecation. `HelpTip` and `LabelWithHelp` are retired (decision 5). |
89
+
90
+ ## Watch list
91
+
92
+ - **`Typography` cannot be composed here.** The tier order forbids the import, so
93
+ the 79 raw `<Text>` runs above cannot be fixed inside this family. Blocked on
94
+ roadmap E3 moving `Typography` and `Eyebrow` into `ui/`.
95
+ - **Fourteen primitives read as dead** — `autocomplete`, `avatar`, `breadcrumbs`,
96
+ `chip`, `help-tip`, `icon-box`, `link`, `menu`, `modal`, `skeleton`, `switch`,
97
+ `tabs`, `toast`, `toolbar-button`. That is not automatically a delete: the graph
98
+ sees three of seven downstream checkouts, and `Chip` in particular has a known
99
+ consumer (audiobook/frontend, §D1) the graph cannot see. Settle per component
100
+ under roadmap E6.4, not by reading this table.
101
+ - **`modal` and `menu` read dead while `drawer` and `popover` do not.** The
102
+ overlay set is mid-migration onto the floating lift (E1); recheck after the
103
+ trigger work lands rather than treating the split as a decision.
104
+
105
+ ## Maturity
106
+
107
+ Status tags on these stories are derived, not chosen — the rule is in
108
+ [`MATURITY.md`](../../../MATURITY.md). Membership in the dependency map above is
109
+ one of its three inputs, so **adding a primitive here without adding its row
110
+ leaves it `status:candidate`**.
@@ -1,11 +1,12 @@
1
1
  import type { Decorator, Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { View, Text } from 'react-native'
3
3
  import { Alert, AlertTitle, AlertDescription } from './Alert'
4
+ import { greyRamp } from '../../../theme/tokens/primitives'
4
5
 
5
6
  const meta: Meta<typeof Alert> = {
6
7
  title: 'Components/Molecules/Alert',
7
8
  component: Alert,
8
- tags: ['autodocs'],
9
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
10
  parameters: {
10
11
  docs: {
11
12
  description: {
@@ -178,7 +179,7 @@ export const DescriptionOnly: Story = {
178
179
 
179
180
  /** Wall-background frame for the compact cue stories. */
180
181
  const wall: Decorator = (Story) => (
181
- <View style={{ width: 460, padding: 28, backgroundColor: '#0E0E0E' }}>
182
+ <View style={{ width: 460, padding: 28, backgroundColor: 'var(--color-background-frame)' }}>
182
183
  <Story />
183
184
  </View>
184
185
  )
@@ -219,13 +220,22 @@ export const CompactLiveCue: Story = {
219
220
  /** Default vs compact, side by side, for the density comparison. */
220
221
  export const DefaultVsCompact: Story = {
221
222
  render: () => (
222
- <View style={{ gap: 16, width: 460, padding: 28, backgroundColor: '#0E0E0E' }}>
223
- <Text style={{ color: '#5A5A5A', fontSize: 10, fontWeight: '700' }}>DEFAULT</Text>
223
+ <View
224
+ style={{
225
+ gap: 16,
226
+ width: 460,
227
+ padding: 28,
228
+ backgroundColor: 'var(--color-background-frame)',
229
+ }}
230
+ >
231
+ <Text style={{ color: greyRamp[700], fontSize: 10, fontWeight: '700' }}>DEFAULT</Text>
224
232
  <Alert status="warning" variant="subtle">
225
233
  <AlertTitle>Approaching threshold</AlertTitle>
226
234
  <AlertDescription>18% velocity loss — one or two reps left in the band.</AlertDescription>
227
235
  </Alert>
228
- <Text style={{ color: '#5A5A5A', fontSize: 10, fontWeight: '700' }}>COMPACT (cue pill)</Text>
236
+ <Text style={{ color: greyRamp[700], fontSize: 10, fontWeight: '700' }}>
237
+ COMPACT (cue pill)
238
+ </Text>
229
239
  <Alert
230
240
  status="warning"
231
241
  variant="subtle"
@@ -44,42 +44,54 @@ const statusColors: Record<
44
44
  subtle: string
45
45
  outline: string
46
46
  solid: string
47
+ /** Text/glyph colour on the `solid` fill — the status's on-colour. */
48
+ onSolid: string
47
49
  border: string
48
50
  icon: string
49
51
  text: string
52
+ /** Label ON the `subtle` fill — see AW-133; the base token is too deep to read there. */
53
+ subtleText: string
50
54
  }
51
55
  > = {
52
56
  success: {
53
57
  subtle: 'bg-status-success-subtle',
54
58
  outline: 'border-2 border-status-success bg-transparent',
55
59
  solid: 'bg-status-success',
60
+ onSolid: 'text-on-status-success',
56
61
  border: 'border-status-success',
57
62
  icon: 'text-status-success',
58
63
  text: 'text-status-success',
64
+ subtleText: 'text-on-status-success-subtle',
59
65
  },
60
66
  info: {
61
67
  subtle: 'bg-status-info-subtle',
62
68
  outline: 'border-2 border-status-info bg-transparent',
63
69
  solid: 'bg-status-info',
70
+ onSolid: 'text-on-status-info',
64
71
  border: 'border-status-info',
65
72
  icon: 'text-status-info',
66
73
  text: 'text-status-info',
74
+ subtleText: 'text-on-status-info-subtle',
67
75
  },
68
76
  warning: {
69
77
  subtle: 'bg-status-warning-subtle',
70
78
  outline: 'border-2 border-status-warning bg-transparent',
71
79
  solid: 'bg-status-warning',
80
+ onSolid: 'text-on-status-warning',
72
81
  border: 'border-status-warning',
73
82
  icon: 'text-status-warning',
74
83
  text: 'text-status-warning',
84
+ subtleText: 'text-on-status-warning-subtle',
75
85
  },
76
86
  error: {
77
87
  subtle: 'bg-status-error-subtle',
78
88
  outline: 'border-2 border-status-error bg-transparent',
79
89
  solid: 'bg-status-error',
90
+ onSolid: 'text-on-status-error',
80
91
  border: 'border-status-error',
81
92
  icon: 'text-status-error',
82
93
  text: 'text-status-error',
94
+ subtleText: 'text-on-status-error-subtle',
83
95
  },
84
96
  }
85
97
 
@@ -142,7 +154,7 @@ export function Alert({
142
154
  className={cn(
143
155
  'font-bold',
144
156
  isCompact ? 'text-base' : 'text-lg',
145
- isSolid ? 'text-white' : colors.icon
157
+ isSolid ? colors.onSolid : variant === 'subtle' ? colors.subtleText : colors.icon
146
158
  )}
147
159
  >
148
160
  {defaultIcons[status]}
@@ -154,7 +166,10 @@ export function Alert({
154
166
  <View className="flex-1">
155
167
  {message != null && (
156
168
  <Text
157
- className={cn('text-sm font-semibold', isSolid ? 'text-white' : colors.text)}
169
+ className={cn(
170
+ 'text-sm font-semibold',
171
+ isSolid ? colors.onSolid : variant === 'subtle' ? colors.subtleText : colors.text
172
+ )}
158
173
  testID="alert-message"
159
174
  >
160
175
  {message}
@@ -168,9 +183,15 @@ export function Alert({
168
183
  onPress={onClose}
169
184
  accessibilityRole="button"
170
185
  accessibilityLabel="Close alert"
186
+ /* VW-82: press-state scrims stay raw (see Modal.tsx). */
171
187
  className="ml-2 p-1 rounded web:hover:bg-black/10 active:bg-black/20"
172
188
  >
173
- <Text className={cn('text-lg', isSolid ? 'text-white/70' : 'text-text-secondary')}>
189
+ <Text
190
+ className={cn(
191
+ 'text-lg',
192
+ isSolid ? cn(colors.onSolid, 'opacity-70') : 'text-text-secondary'
193
+ )}
194
+ >
174
195
  ×
175
196
  </Text>
176
197
  </Pressable>
@@ -6,7 +6,7 @@ import { Autocomplete, AutocompleteOption } from './Autocomplete'
6
6
  const meta: Meta<typeof Autocomplete> = {
7
7
  title: 'Components/Molecules/Autocomplete',
8
8
  component: Autocomplete,
9
- tags: ['autodocs'],
9
+ tags: ['autodocs', 'status:stable', '!status:review'],
10
10
  argTypes: {
11
11
  isDisabled: {
12
12
  control: 'boolean',
@@ -48,9 +48,7 @@ export const Default: Story = {
48
48
  onChange={setValue}
49
49
  placeholder="Search fruits..."
50
50
  />
51
- <Text className="text-sm text-text-secondary mt-2">
52
- Selected: {value || 'None'}
53
- </Text>
51
+ <Text className="text-sm text-text-secondary mt-2">Selected: {value || 'None'}</Text>
54
52
  </View>
55
53
  )
56
54
  },
@@ -140,12 +138,7 @@ export const Disabled: Story = {
140
138
  render: function Render() {
141
139
  return (
142
140
  <View className="w-64">
143
- <Autocomplete
144
- options={fruitOptions}
145
- value="apple"
146
- label="Disabled field"
147
- isDisabled
148
- />
141
+ <Autocomplete options={fruitOptions} value="apple" label="Disabled field" isDisabled />
149
142
  </View>
150
143
  )
151
144
  },
@@ -175,7 +168,12 @@ export const DisabledOptions: Story = {
175
168
  const optionsWithDisabled: AutocompleteOption[] = [
176
169
  { value: 'free', label: 'Free Plan' },
177
170
  { value: 'pro', label: 'Pro Plan' },
178
- { value: 'enterprise', label: 'Enterprise Plan', isDisabled: true, description: 'Contact sales' },
171
+ {
172
+ value: 'enterprise',
173
+ label: 'Enterprise Plan',
174
+ isDisabled: true,
175
+ description: 'Contact sales',
176
+ },
179
177
  ]
180
178
  return (
181
179
  <View className="w-64">
@@ -289,8 +287,8 @@ export const FormExample: Story = {
289
287
 
290
288
  <View className="pt-2 border-t border-hairline">
291
289
  <Text className="text-sm text-text-secondary">
292
- Selected: {country ? `${countryOptions.find(c => c.value === country)?.label}` : '-'}
293
- {city ? `, ${cityOptions[country!]?.find(c => c.value === city)?.label}` : ''}
290
+ Selected: {country ? `${countryOptions.find((c) => c.value === country)?.label}` : '-'}
291
+ {city ? `, ${cityOptions[country!]?.find((c) => c.value === city)?.label}` : ''}
294
292
  </Text>
295
293
  </View>
296
294
  </View>
@@ -102,26 +102,20 @@ describe('Autocomplete', () => {
102
102
  })
103
103
 
104
104
  it('shows clear button when value is selected', () => {
105
- render(
106
- <Autocomplete options={defaultOptions} value="1" isClearable />
107
- )
105
+ render(<Autocomplete options={defaultOptions} value="1" isClearable />)
108
106
  expect(screen.getByLabelText('Clear selection')).toBeInTheDocument()
109
107
  })
110
108
 
111
109
  it('calls onChange with null when clear is pressed', () => {
112
110
  const onChange = vi.fn()
113
- render(
114
- <Autocomplete options={defaultOptions} value="1" onChange={onChange} isClearable />
115
- )
111
+ render(<Autocomplete options={defaultOptions} value="1" onChange={onChange} isClearable />)
116
112
 
117
113
  fireEvent.click(screen.getByLabelText('Clear selection'))
118
114
  expect(onChange).toHaveBeenCalledWith(null)
119
115
  })
120
116
 
121
117
  it('does not show clear button when isClearable is false', () => {
122
- render(
123
- <Autocomplete options={defaultOptions} value="1" isClearable={false} />
124
- )
118
+ render(<Autocomplete options={defaultOptions} value="1" isClearable={false} />)
125
119
  expect(screen.queryByLabelText('Clear selection')).not.toBeInTheDocument()
126
120
  })
127
121
 
@@ -144,13 +138,7 @@ describe('Autocomplete', () => {
144
138
  })
145
139
 
146
140
  it('shows custom minCharsText', () => {
147
- render(
148
- <Autocomplete
149
- options={defaultOptions}
150
- minChars={3}
151
- minCharsText="Keep typing..."
152
- />
153
- )
141
+ render(<Autocomplete options={defaultOptions} minChars={3} minCharsText="Keep typing..." />)
154
142
  const input = screen.getByPlaceholderText('Search...')
155
143
 
156
144
  typeInInput(input, 'A')
@@ -185,9 +173,7 @@ describe('Autocomplete', () => {
185
173
  })
186
174
 
187
175
  it('does not show clear button when disabled', () => {
188
- render(
189
- <Autocomplete options={defaultOptions} value="1" isDisabled isClearable />
190
- )
176
+ render(<Autocomplete options={defaultOptions} value="1" isDisabled isClearable />)
191
177
  expect(screen.queryByLabelText('Clear selection')).not.toBeInTheDocument()
192
178
  })
193
179
  })
@@ -225,9 +211,7 @@ describe('Autocomplete', () => {
225
211
 
226
212
  describe('accessibility', () => {
227
213
  it('has no accessibility violations', async () => {
228
- const { container } = render(
229
- <Autocomplete options={defaultOptions} label="Search" />
230
- )
214
+ const { container } = render(<Autocomplete options={defaultOptions} label="Search" />)
231
215
  const results = await axe(container)
232
216
  expect(results).toHaveNoViolations()
233
217
  })
@@ -238,9 +222,7 @@ describe('Autocomplete', () => {
238
222
  })
239
223
 
240
224
  it('clear button has accessible label', () => {
241
- render(
242
- <Autocomplete options={defaultOptions} value="1" isClearable />
243
- )
225
+ render(<Autocomplete options={defaultOptions} value="1" isClearable />)
244
226
  expect(screen.getByLabelText('Clear selection')).toBeInTheDocument()
245
227
  })
246
228
  })
@@ -1,6 +1,15 @@
1
1
  import React, { useState, useCallback, useMemo } from 'react'
2
- import { View, Text, TextInput, Pressable, ScrollView, type ViewProps, type TextInputProps } from 'react-native'
2
+ import {
3
+ View,
4
+ Text,
5
+ TextInput,
6
+ Pressable,
7
+ ScrollView,
8
+ type ViewProps,
9
+ type TextInputProps,
10
+ } from 'react-native'
3
11
  import { cn } from '../../../utils/cn'
12
+ import { Surface } from '../surface'
4
13
 
5
14
  export interface AutocompleteOption<T = string> {
6
15
  value: T
@@ -115,10 +124,7 @@ export function Autocomplete<T extends string = string>({
115
124
  const [highlightedIndex, setHighlightedIndex] = useState(-1)
116
125
 
117
126
  // Get the label for the selected value
118
- const selectedOption = useMemo(
119
- () => options.find((o) => o.value === value),
120
- [options, value]
121
- )
127
+ const selectedOption = useMemo(() => options.find((o) => o.value === value), [options, value])
122
128
 
123
129
  // Filter options based on input
124
130
  const filteredOptions = useMemo(() => {
@@ -206,21 +212,14 @@ export function Autocomplete<T extends string = string>({
206
212
  onBlur={handleBlur}
207
213
  placeholder={placeholder}
208
214
  editable={!isDisabled}
209
- className={cn(
210
- 'flex-1 px-3 py-2 text-text-primary',
211
- 'placeholder:text-text-tertiary'
212
- )}
215
+ className={cn('flex-1 px-3 py-2 text-text-primary', 'placeholder:text-text-tertiary')}
213
216
  accessibilityLabel={label}
214
217
  {...inputProps}
215
218
  />
216
219
 
217
220
  {/* Clear button */}
218
221
  {isClearable && value && !isDisabled && (
219
- <Pressable
220
- onPress={handleClear}
221
- className="p-2"
222
- accessibilityLabel="Clear selection"
223
- >
222
+ <Pressable onPress={handleClear} className="p-2" accessibilityLabel="Clear selection">
224
223
  <Text className="text-text-tertiary">×</Text>
225
224
  </Pressable>
226
225
  )}
@@ -235,11 +234,12 @@ export function Autocomplete<T extends string = string>({
235
234
 
236
235
  {/* Dropdown */}
237
236
  {isOpen && (
238
- <View
237
+ <Surface
238
+ elevation={4}
239
+ rounded={false}
239
240
  className={cn(
240
241
  'absolute z-50 top-full left-0 right-0 mt-1',
241
- 'bg-surface-elevated rounded-md shadow-lg border border-hairline',
242
- 'max-h-60 overflow-hidden'
242
+ 'rounded-md max-h-60 overflow-hidden'
243
243
  )}
244
244
  >
245
245
  <ScrollView className="py-1">
@@ -252,16 +252,12 @@ export function Autocomplete<T extends string = string>({
252
252
 
253
253
  {/* Loading message */}
254
254
  {isLoading && (
255
- <Text className="px-3 py-2 text-sm text-text-tertiary">
256
- {loadingText}
257
- </Text>
255
+ <Text className="px-3 py-2 text-sm text-text-tertiary">{loadingText}</Text>
258
256
  )}
259
257
 
260
258
  {/* No results */}
261
259
  {showNoResults && (
262
- <Text className="px-3 py-2 text-sm text-text-tertiary">
263
- {noOptionsText}
264
- </Text>
260
+ <Text className="px-3 py-2 text-sm text-text-tertiary">{noOptionsText}</Text>
265
261
  )}
266
262
 
267
263
  {/* Options */}
@@ -312,17 +308,14 @@ export function Autocomplete<T extends string = string>({
312
308
  )
313
309
  })}
314
310
  </ScrollView>
315
- </View>
311
+ </Surface>
316
312
  )}
317
313
  </View>
318
314
 
319
315
  {/* Helper/Error text */}
320
316
  {(helperText || errorMessage) && (
321
317
  <Text
322
- className={cn(
323
- 'text-xs mt-1',
324
- isInvalid ? 'text-status-error' : 'text-text-tertiary'
325
- )}
318
+ className={cn('text-xs mt-1', isInvalid ? 'text-status-error' : 'text-text-tertiary')}
326
319
  >
327
320
  {errorMessage || helperText}
328
321
  </Text>
@@ -5,7 +5,7 @@ import { Avatar, AvatarBadge, AvatarGroup } from './Avatar'
5
5
  const meta: Meta<typeof Avatar> = {
6
6
  title: 'Components/Atoms/Avatar',
7
7
  component: Avatar,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  size: {
11
11
  control: 'select',
@@ -133,12 +133,7 @@ export interface AvatarGroupProps {
133
133
  /**
134
134
  * Group of avatars with stacking effect.
135
135
  */
136
- export function AvatarGroup({
137
- children,
138
- max,
139
- size = 'md',
140
- className,
141
- }: AvatarGroupProps) {
136
+ export function AvatarGroup({ children, max, size = 'md', className }: AvatarGroupProps) {
142
137
  const childArray = React.Children.toArray(children)
143
138
  const visibleChildren = max ? childArray.slice(0, max) : childArray
144
139
  const remainingCount = max ? Math.max(0, childArray.length - max) : 0
@@ -148,10 +143,7 @@ export function AvatarGroup({
148
143
  {visibleChildren.map((child, index) => (
149
144
  <View
150
145
  key={index}
151
- className={cn(
152
- 'border-2 border-surface-base rounded-full',
153
- index > 0 && '-ml-2'
154
- )}
146
+ className={cn('border-2 border-surface-base rounded-full', index > 0 && '-ml-2')}
155
147
  >
156
148
  {React.isValidElement(child)
157
149
  ? React.cloneElement(child as React.ReactElement<any>, { size })