@titan-design/react-ui 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/README.md +46 -47
  2. package/dist/bodymap.js +768 -701
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +770 -703
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1320 -215
  7. package/dist/index.d.ts +1320 -215
  8. package/dist/index.js +5996 -4498
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +5773 -4357
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
  13. package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1435 -1428
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1443 -1436
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +202 -1042
  21. package/dist/theme/index.d.ts +202 -1042
  22. package/dist/theme/index.js +215 -300
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +202 -296
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +62 -5
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +62 -5
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +972 -0
  31. package/dist/theme/tokens.d.ts +972 -0
  32. package/dist/theme/tokens.js +904 -0
  33. package/dist/theme/tokens.js.map +1 -0
  34. package/dist/theme/tokens.mjs +880 -0
  35. package/dist/theme/tokens.mjs.map +1 -0
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/package.json +7 -1
  40. package/src/arch/arch-graph.freshness.test.ts +52 -0
  41. package/src/arch/arch-graph.json +5021 -1617
  42. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  43. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  44. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  45. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  46. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  48. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  49. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  51. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  52. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  54. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  55. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  57. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  58. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  60. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  61. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
  63. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  64. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  66. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  67. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  69. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  70. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  71. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  73. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  74. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  76. package/src/components/custom/ActiveWork/README.md +305 -0
  77. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  78. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  80. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  81. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  82. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  83. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  84. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  86. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  87. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  88. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  90. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  91. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  92. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  93. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  94. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  95. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  96. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  97. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  98. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  99. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  100. package/src/components/custom/ActiveWork/index.ts +19 -0
  101. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  102. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  103. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  104. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  105. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
  106. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  107. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  108. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  109. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  110. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  111. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  112. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  113. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  116. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  117. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  119. package/src/components/custom/Fatigue/README.md +40 -3
  120. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  121. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  122. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  123. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  124. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  125. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  126. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  127. package/src/components/custom/Fatigue/index.ts +17 -5
  128. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  129. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  130. package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
  131. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  132. package/src/components/custom/Gauge/Gauge.tsx +4 -1
  133. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  134. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  135. package/src/components/custom/Metric/Metric.tsx +5 -20
  136. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  137. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  138. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  139. package/src/components/custom/Prose/README.md +58 -0
  140. package/src/components/custom/Prose/index.ts +1 -0
  141. package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
  142. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  143. package/src/components/custom/Scatter/Scatter.tsx +116 -14
  144. package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
  145. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  146. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  147. package/src/components/custom/Table/Table.stories.tsx +98 -15
  148. package/src/components/custom/Table/Table.test.tsx +273 -86
  149. package/src/components/custom/Table/Table.tsx +159 -67
  150. package/src/components/custom/Table/column-fit.test.ts +75 -0
  151. package/src/components/custom/Table/column-fit.ts +116 -0
  152. package/src/components/custom/Table/index.ts +9 -0
  153. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  154. package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
  155. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  156. package/src/components/custom/Treemap/Treemap.tsx +7 -2
  157. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  158. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  159. package/src/components/custom/Typography/Typography.tsx +6 -0
  160. package/src/components/custom/Typography/index.ts +1 -8
  161. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
  162. package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
  163. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  164. package/src/components/custom/Workout/BaseBadge.tsx +3 -0
  165. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  166. package/src/components/custom/Workout/BodyMap.tsx +3 -1
  167. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
  168. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  169. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
  170. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
  171. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  172. package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
  173. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  174. package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
  175. package/src/components/custom/Workout/DeviationBar.tsx +21 -16
  176. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
  177. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
  178. package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
  179. package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
  180. package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
  181. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
  182. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  183. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  184. package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
  185. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
  186. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  187. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  188. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  189. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  190. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  191. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  192. package/src/components/custom/Workout/IntensityBar.tsx +4 -2
  193. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  194. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  195. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  196. package/src/components/custom/Workout/MesoCard.tsx +12 -9
  197. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  198. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  199. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  200. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  201. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  202. package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
  203. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  204. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  205. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  206. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  207. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  208. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  209. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  210. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  211. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  212. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  213. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
  214. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  215. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  216. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  217. package/src/components/custom/Workout/README.md +12 -7
  218. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  219. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  220. package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
  221. package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
  222. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  223. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  224. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  225. package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
  226. package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
  227. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  228. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  229. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  230. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  231. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  232. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  233. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  234. package/src/components/custom/Workout/SetBar.tsx +38 -12
  235. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  236. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  237. package/src/components/custom/Workout/SetRow.tsx +61 -23
  238. package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
  239. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  240. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  241. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  242. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  243. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  244. package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
  245. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  246. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  247. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  248. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  249. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  250. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  251. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  252. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  253. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  254. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
  255. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  256. package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
  257. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  258. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  259. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  260. package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
  261. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  262. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  263. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  264. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
  265. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
  266. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
  267. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  268. package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
  269. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  270. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  271. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  272. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  273. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  274. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  275. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  276. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  277. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  278. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  279. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  280. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  281. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  282. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  283. package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
  284. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  285. package/src/components/custom/Workout/index.ts +5 -0
  286. package/src/components/custom/Workout/metricText.stories.tsx +6 -5
  287. package/src/components/custom/Workout/metricText.tsx +4 -0
  288. package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
  289. package/src/components/custom/charts/README.md +61 -0
  290. package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
  291. package/src/components/custom/charts/SetBarChart.tsx +42 -4
  292. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  293. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  294. package/src/components/custom/charts/SparkBars.tsx +85 -0
  295. package/src/components/custom/charts/index.ts +3 -0
  296. package/src/components/custom/index.ts +3 -0
  297. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  298. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  299. package/src/components/custom/stepper/Stepper.tsx +13 -28
  300. package/src/components/icons/icons.stories.tsx +1 -1
  301. package/src/components/icons/icons.tsx +51 -0
  302. package/src/components/shell/AppShell.stories.tsx +150 -0
  303. package/src/components/shell/AppShell.test.tsx +70 -0
  304. package/src/components/shell/AppShell.tsx +90 -0
  305. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  306. package/src/components/shell/BrandLockup.test.tsx +34 -1
  307. package/src/components/shell/BrandLockup.tsx +27 -11
  308. package/src/components/shell/NavItem.stories.tsx +4 -4
  309. package/src/components/shell/NavItem.test.tsx +17 -0
  310. package/src/components/shell/NavItem.tsx +17 -5
  311. package/src/components/shell/README.md +90 -27
  312. package/src/components/shell/SideNav.stories.tsx +38 -7
  313. package/src/components/shell/SideNav.test.tsx +16 -8
  314. package/src/components/shell/SideNav.tsx +17 -17
  315. package/src/components/shell/TopBar.stories.tsx +44 -19
  316. package/src/components/shell/TopBar.test.tsx +34 -12
  317. package/src/components/shell/TopBar.tsx +61 -40
  318. package/src/components/shell/brands.tsx +66 -0
  319. package/src/components/shell/index.ts +9 -8
  320. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  321. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  322. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  323. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  324. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  325. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  326. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  327. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  328. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  329. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  330. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  331. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  332. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  333. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  334. package/src/components/shell/workout/index.ts +9 -0
  335. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  336. package/src/components/ui/README.md +110 -0
  337. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  338. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  339. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  340. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  341. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  342. package/src/components/ui/avatar/Avatar.tsx +2 -10
  343. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  344. package/src/components/ui/badge/Badge.test.tsx +19 -3
  345. package/src/components/ui/badge/Badge.tsx +48 -55
  346. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  347. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  348. package/src/components/ui/button/Button.stories.tsx +46 -12
  349. package/src/components/ui/button/Button.tsx +32 -25
  350. package/src/components/ui/card/Card.stories.tsx +90 -94
  351. package/src/components/ui/card/Card.test.tsx +80 -6
  352. package/src/components/ui/card/Card.tsx +150 -203
  353. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  354. package/src/components/ui/checkbox/Checkbox.tsx +6 -26
  355. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  356. package/src/components/ui/chip/Chip.test.tsx +10 -6
  357. package/src/components/ui/chip/Chip.tsx +76 -91
  358. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  359. package/src/components/ui/collapse/Collapse.tsx +6 -11
  360. package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
  361. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  362. package/src/components/ui/data-row/DataRow.tsx +18 -7
  363. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  364. package/src/components/ui/divider/Divider.tsx +1 -5
  365. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  366. package/src/components/ui/drawer/Drawer.tsx +13 -30
  367. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  368. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  369. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  370. package/src/components/ui/form-field/FormField.tsx +10 -46
  371. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  372. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  373. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  374. package/src/components/ui/help-tip/index.ts +7 -1
  375. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  376. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  377. package/src/components/ui/icon-box/IconBox.tsx +2 -12
  378. package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
  379. package/src/components/ui/indicator/Indicator.tsx +20 -14
  380. package/src/components/ui/input/Input.stories.tsx +3 -11
  381. package/src/components/ui/input/Input.test.tsx +2 -10
  382. package/src/components/ui/input/Input.tsx +10 -25
  383. package/src/components/ui/input/index.ts +7 -1
  384. package/src/components/ui/link/Link.stories.tsx +19 -7
  385. package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
  386. package/src/components/ui/list-item/ListItem.tsx +2 -9
  387. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  388. package/src/components/ui/menu/Menu.test.tsx +2 -11
  389. package/src/components/ui/menu/Menu.tsx +12 -14
  390. package/src/components/ui/menu/index.ts +8 -1
  391. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  392. package/src/components/ui/modal/Modal.tsx +29 -19
  393. package/src/components/ui/pill/Pill.stories.tsx +58 -23
  394. package/src/components/ui/pill/Pill.test.tsx +101 -3
  395. package/src/components/ui/pill/Pill.tsx +164 -49
  396. package/src/components/ui/pill/index.ts +1 -1
  397. package/src/components/ui/popover/Popover.stories.tsx +5 -7
  398. package/src/components/ui/popover/Popover.test.tsx +1 -6
  399. package/src/components/ui/popover/Popover.tsx +20 -15
  400. package/src/components/ui/popover/index.ts +7 -1
  401. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  402. package/src/components/ui/progress/Progress.test.tsx +1 -5
  403. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  404. package/src/components/ui/radio/Radio.test.tsx +6 -2
  405. package/src/components/ui/radio/Radio.tsx +23 -22
  406. package/src/components/ui/section/Section.stories.tsx +5 -14
  407. package/src/components/ui/section/Section.test.tsx +1 -6
  408. package/src/components/ui/section/Section.tsx +1 -3
  409. package/src/components/ui/section/index.ts +1 -5
  410. package/src/components/ui/select/Select.stories.tsx +3 -13
  411. package/src/components/ui/select/Select.test.tsx +2 -11
  412. package/src/components/ui/select/Select.tsx +14 -14
  413. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  414. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  415. package/src/components/ui/skeleton/index.ts +1 -7
  416. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  417. package/src/components/ui/spinner/Spinner.tsx +1 -4
  418. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  419. package/src/components/ui/stack/Stack.tsx +1 -1
  420. package/src/components/ui/surface/Surface.stories.tsx +17 -5
  421. package/src/components/ui/surface/Surface.test.tsx +88 -28
  422. package/src/components/ui/surface/Surface.tsx +37 -87
  423. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  424. package/src/components/ui/surface/index.ts +8 -0
  425. package/src/components/ui/surface/resolveSurface.ts +98 -0
  426. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  427. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  428. package/src/components/ui/switch/Switch.tsx +7 -6
  429. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  430. package/src/components/ui/tabs/Tabs.tsx +7 -22
  431. package/src/components/ui/tabs/index.ts +1 -7
  432. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  433. package/src/components/ui/tile/Tile.tsx +3 -0
  434. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  435. package/src/components/ui/toast/Toast.test.tsx +2 -8
  436. package/src/components/ui/toast/Toast.tsx +43 -53
  437. package/src/components/ui/toast/index.ts +0 -1
  438. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  439. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  440. package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
  441. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  442. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  443. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  444. package/src/components/ui/tooltip/index.ts +1 -1
  445. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  446. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  447. package/src/components/ui/trigger/index.ts +2 -0
  448. package/src/stories/PresetShowcase.stories.tsx +100 -47
  449. package/src/test/no-device-internals.test.ts +3 -3
  450. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  451. package/src/theme/ColorPalettes.stories.tsx +62 -45
  452. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  453. package/src/theme/Depth.stories.tsx +132 -65
  454. package/src/theme/DepthCalibration.stories.tsx +24 -22
  455. package/src/theme/ThemeProvider.test.tsx +4 -4
  456. package/src/theme/barrel.ts +7 -6
  457. package/src/theme/color-stories.coverage.test.ts +1 -1
  458. package/src/theme/color-utils.ts +41 -29
  459. package/src/theme/config.completeness.test.ts +1 -1
  460. package/src/theme/config.ts +28 -0
  461. package/src/theme/elevation.test.ts +82 -56
  462. package/src/theme/elevation.ts +77 -561
  463. package/src/theme/global.css +30 -2
  464. package/src/theme/grey-ramp.test.ts +24 -8
  465. package/src/theme/lift.test.ts +39 -0
  466. package/src/theme/lift.ts +102 -0
  467. package/src/theme/materials.test.ts +5 -2
  468. package/src/theme/materials.ts +38 -4
  469. package/src/theme/native-theming-guard.test.ts +5 -5
  470. package/src/theme/presets/apply.ts +4 -0
  471. package/src/theme/presets/audiobook.ts +5 -2
  472. package/src/theme/presets/default.ts +4 -0
  473. package/src/theme/presets/index.ts +14 -1
  474. package/src/theme/presets/types.ts +1 -1
  475. package/src/theme/semantic-contrast.test.ts +13 -4
  476. package/src/theme/status-distinctness.test.ts +66 -0
  477. package/src/theme/surface-planes.test.ts +37 -0
  478. package/src/theme/surface-planes.ts +68 -0
  479. package/src/theme/token-export-guard.test.ts +102 -0
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +67 -35
  482. package/src/theme/tokens/semantic.ts +71 -37
  483. package/src/theme/wash-ladder.test.ts +58 -0
  484. package/src/theme/workout-tokens.ts +1 -7
  485. package/src/types/jest-axe.d.ts +2 -6
  486. package/src/types/raw-md.d.ts +5 -0
  487. package/src/utils/colors.ts +4 -4
  488. package/src/utils/form.ts +1 -3
  489. package/src/utils/index.ts +2 -7
  490. package/src/utils/number-format.ts +17 -0
  491. package/src/utils/workout-format.ts +15 -6
  492. package/src/web-jsx/jsx-runtime.ts +1 -5
  493. package/tailwind.config.js +5 -0
  494. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  495. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  496. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  497. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  498. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  499. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  500. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  501. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  502. package/src/components/shell/DashboardShell.tsx +0 -75
  503. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  504. package/src/theme/elevation.stories.tsx +0 -346
  505. package/src/utils/useTheme.ts +0 -72
  506. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  507. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  508. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  509. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -0,0 +1,81 @@
1
+ import React, { isValidElement, cloneElement } from 'react'
2
+ import { Pressable, type AccessibilityState } from 'react-native'
3
+
4
+ type Handler = (...args: never[]) => void
5
+ type Handlers = Record<string, Handler | undefined>
6
+
7
+ export interface TriggerSurfaceProps {
8
+ /** Pressable handlers (onPress, onHoverIn, …) for whichever element owns the interaction. */
9
+ handlers: Handlers
10
+ /** Role for the wrapper when it is the one handling the interaction. */
11
+ accessibilityRole?: 'button'
12
+ /** Merged onto whichever element ends up owning the interaction. */
13
+ accessibilityState?: AccessibilityState
14
+ className?: string
15
+ children: React.ReactNode
16
+ }
17
+
18
+ type ComposableChildProps = Handlers & { accessibilityState?: AccessibilityState }
19
+
20
+ function chain(childHandler: Handler | undefined, ownHandler: Handler | undefined): Handler {
21
+ return (...args: never[]) => {
22
+ childHandler?.(...args)
23
+ ownHandler?.(...args)
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Give interaction handling to a composed child instead of wrapping it in a second Pressable.
29
+ *
30
+ * React Native Web lets only the innermost pressable in a chain handle a gesture:
31
+ * PressResponder calls `stopPropagation()` on the click that drives `onPress`,
32
+ * and `useHover` contains hover the same way. A trigger that wraps a `Pressable`
33
+ * child (a `Button`, say) in its own `Pressable` therefore never sees the
34
+ * interaction — in a browser the trigger looks completely dead.
35
+ *
36
+ * A component child may be a Pressable, so the handlers are cloned onto it and
37
+ * the wrapper drops the button role — that also leaves one `[role=button]`
38
+ * rather than an invalid button-inside-button pair. The wrapper stays a
39
+ * Pressable, out of the tab order, to still catch children that turn out not to
40
+ * be pressable. Host elements (`<button>`, `<span>`) cannot take these handlers
41
+ * and do not swallow the gesture, so for those the wrapper handles it.
42
+ */
43
+ export function TriggerSurface({
44
+ handlers,
45
+ accessibilityRole,
46
+ accessibilityState,
47
+ className,
48
+ children,
49
+ }: TriggerSurfaceProps) {
50
+ const child = isValidElement(children) ? children : null
51
+ const childCanCompose = child !== null && typeof child.type !== 'string'
52
+
53
+ if (!childCanCompose) {
54
+ return (
55
+ <Pressable
56
+ accessibilityRole={accessibilityRole}
57
+ accessibilityState={accessibilityState}
58
+ className={className}
59
+ {...handlers}
60
+ >
61
+ {children}
62
+ </Pressable>
63
+ )
64
+ }
65
+
66
+ const childElement = child as React.ReactElement<ComposableChildProps>
67
+ const composed: ComposableChildProps = {}
68
+ for (const [name, handler] of Object.entries(handlers)) {
69
+ composed[name] = chain(childElement.props[name], handler)
70
+ }
71
+ composed.accessibilityState = {
72
+ ...childElement.props.accessibilityState,
73
+ ...accessibilityState,
74
+ }
75
+
76
+ return (
77
+ <Pressable focusable={false} tabIndex={-1} className={className} {...handlers}>
78
+ {cloneElement(childElement, composed)}
79
+ </Pressable>
80
+ )
81
+ }
@@ -0,0 +1,2 @@
1
+ export { TriggerSurface } from './TriggerSurface'
2
+ export type { TriggerSurfaceProps } from './TriggerSurface'
@@ -70,9 +70,7 @@ function SideBySideShowcase() {
70
70
  return (
71
71
  <View className="gap-6 p-6 bg-background-default min-h-screen">
72
72
  <View className="gap-2">
73
- <Text className="text-3xl font-bold text-text-primary font-heading">
74
- Preset Showcase
75
- </Text>
73
+ <Text className="text-3xl font-bold text-text-primary font-heading">Preset Showcase</Text>
76
74
  <Text className="text-text-secondary text-base">
77
75
  Toggle between presets to see how the entire design system adapts.
78
76
  </Text>
@@ -89,14 +87,14 @@ function SideBySideShowcase() {
89
87
  Subheading (font-heading)
90
88
  </Text>
91
89
  <Text className="text-base text-text-primary font-body">
92
- Body text using font-body. The quick brown fox jumps over the lazy dog. This
93
- demonstrates how paragraph text renders under the current preset.
90
+ Body text using font-body. The quick brown fox jumps over the lazy dog. This demonstrates
91
+ how paragraph text renders under the current preset.
94
92
  </Text>
95
93
  <Text className="text-sm text-text-secondary font-body">
96
94
  Secondary body text for captions and supporting content.
97
95
  </Text>
98
96
  <Text className="text-sm text-text-primary font-mono">
99
- {'const monospace = \'font-mono rendering\''}
97
+ {"const monospace = 'font-mono rendering'"}
100
98
  </Text>
101
99
  </Section>
102
100
 
@@ -195,20 +193,40 @@ function SideBySideShowcase() {
195
193
  {/* Toasts */}
196
194
  <Section title="Toasts">
197
195
  <View className="gap-3">
198
- <Toast title="Operation successful" description="Your changes have been saved." status="success" />
199
- <Toast title="Something went wrong" description="Please try again later." status="error" />
196
+ <Toast
197
+ title="Operation successful"
198
+ description="Your changes have been saved."
199
+ status="success"
200
+ />
201
+ <Toast
202
+ title="Something went wrong"
203
+ description="Please try again later."
204
+ status="error"
205
+ />
200
206
  <Toast title="Heads up" description="This action cannot be undone." status="warning" />
201
- <Toast title="New update available" description="Version 2.0 is ready to install." status="info" />
207
+ <Toast
208
+ title="New update available"
209
+ description="Version 2.0 is ready to install."
210
+ status="info"
211
+ />
202
212
  </View>
203
213
  </Section>
204
214
 
205
215
  {/* Status Colors */}
206
216
  <Section title="Status Colors">
207
217
  <View className="flex-row gap-3 flex-wrap">
208
- <Badge color="success" size="lg">Success</Badge>
209
- <Badge color="error" size="lg">Error</Badge>
210
- <Badge color="warning" size="lg">Warning</Badge>
211
- <Badge color="info" size="lg">Info</Badge>
218
+ <Badge color="success" size="lg">
219
+ Success
220
+ </Badge>
221
+ <Badge color="error" size="lg">
222
+ Error
223
+ </Badge>
224
+ <Badge color="warning" size="lg">
225
+ Warning
226
+ </Badge>
227
+ <Badge color="info" size="lg">
228
+ Info
229
+ </Badge>
212
230
  </View>
213
231
  </Section>
214
232
  </View>
@@ -225,9 +243,7 @@ function TypographyShowcase() {
225
243
  return (
226
244
  <View className="gap-6 p-6 bg-background-default min-h-screen">
227
245
  <View className="gap-2">
228
- <Text className="text-3xl font-bold text-text-primary font-heading">
229
- Typography
230
- </Text>
246
+ <Text className="text-3xl font-bold text-text-primary font-heading">Typography</Text>
231
247
  <Text className="text-text-secondary text-base">
232
248
  How fonts and text styles change across presets.
233
249
  </Text>
@@ -252,9 +268,9 @@ function TypographyShowcase() {
252
268
 
253
269
  <Section title="Body Font (font-body)">
254
270
  <Text className="text-base text-text-primary font-body">
255
- Regular body text. Design systems provide a shared language for product teams.
256
- By codifying decisions into reusable components and tokens, teams move faster
257
- while maintaining visual consistency across every surface.
271
+ Regular body text. Design systems provide a shared language for product teams. By
272
+ codifying decisions into reusable components and tokens, teams move faster while
273
+ maintaining visual consistency across every surface.
258
274
  </Text>
259
275
  <Text className="text-base font-semibold text-text-primary font-body">
260
276
  Bold body text. Emphasis and hierarchy within paragraph content.
@@ -263,8 +279,8 @@ function TypographyShowcase() {
263
279
  Italic body text. Used for quotations, citations, and emphasis.
264
280
  </Text>
265
281
  <Text className="text-sm text-text-secondary font-body">
266
- Small / secondary text. Captions, labels, and supporting information
267
- that supplements the main content without competing for attention.
282
+ Small / secondary text. Captions, labels, and supporting information that supplements the
283
+ main content without competing for attention.
268
284
  </Text>
269
285
  <Text className="text-xs text-text-tertiary font-body">
270
286
  Extra-small / tertiary text. Timestamps, metadata, fine print.
@@ -287,19 +303,14 @@ function TypographyShowcase() {
287
303
 
288
304
  <Section title="Mixed Typography">
289
305
  <Card className="p-5 gap-3">
290
- <Text className="text-2xl font-bold text-text-primary font-heading">
291
- Chapter One
292
- </Text>
306
+ <Text className="text-2xl font-bold text-text-primary font-heading">Chapter One</Text>
293
307
  <Text className="text-base text-text-secondary font-body">
294
- It was a bright cold day in April, and the clocks were striking thirteen.
295
- Winston Smith, his chin nuzzled into his breast in an effort to escape the
296
- vile wind, slipped quickly through the glass doors of Victory Mansions,
297
- though not quickly enough to prevent a swirl of gritty dust from entering
298
- along with him.
299
- </Text>
300
- <Text className="text-xs text-text-tertiary font-mono">
301
- George Orwell, 1984
308
+ It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith,
309
+ his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly
310
+ through the glass doors of Victory Mansions, though not quickly enough to prevent a
311
+ swirl of gritty dust from entering along with him.
302
312
  </Text>
313
+ <Text className="text-xs text-text-tertiary font-mono">George Orwell, 1984</Text>
303
314
  </Card>
304
315
  </Section>
305
316
  </View>
@@ -332,9 +343,7 @@ function ColorPaletteShowcase() {
332
343
  return (
333
344
  <View className="gap-6 p-6 bg-background-default min-h-screen">
334
345
  <View className="gap-2">
335
- <Text className="text-3xl font-bold text-text-primary font-heading">
336
- Color Palette
337
- </Text>
346
+ <Text className="text-3xl font-bold text-text-primary font-heading">Color Palette</Text>
338
347
  <Text className="text-text-secondary text-base">
339
348
  Semantic color tokens rendered as swatches. Toggle presets to compare palettes.
340
349
  </Text>
@@ -347,13 +356,21 @@ function ColorPaletteShowcase() {
347
356
  <ColorSwatch label="brand-primary" className="bg-brand-primary" />
348
357
  <ColorSwatch label="brand-primary-light" className="bg-brand-primary-light" />
349
358
  <ColorSwatch label="brand-primary-dark" className="bg-brand-primary-dark" />
350
- <ColorSwatch label="brand-primary-subtle" className="bg-brand-primary-subtle" textClass="text-text-primary" />
359
+ <ColorSwatch
360
+ label="brand-primary-subtle"
361
+ className="bg-brand-primary-subtle"
362
+ textClass="text-text-primary"
363
+ />
351
364
  </View>
352
365
  <View className="flex-row gap-3 flex-wrap mt-2">
353
366
  <ColorSwatch label="brand-secondary" className="bg-brand-secondary" />
354
367
  <ColorSwatch label="brand-secondary-light" className="bg-brand-secondary-light" />
355
368
  <ColorSwatch label="brand-secondary-dark" className="bg-brand-secondary-dark" />
356
- <ColorSwatch label="brand-secondary-subtle" className="bg-brand-secondary-subtle" textClass="text-text-primary" />
369
+ <ColorSwatch
370
+ label="brand-secondary-subtle"
371
+ className="bg-brand-secondary-subtle"
372
+ textClass="text-text-primary"
373
+ />
357
374
  </View>
358
375
  </Section>
359
376
 
@@ -372,7 +389,9 @@ function ColorPaletteShowcase() {
372
389
  <Text className="text-xs font-mono font-medium text-text-primary">text-primary</Text>
373
390
  </View>
374
391
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-elevated border border-hairline">
375
- <Text className="text-xs font-mono font-medium text-text-secondary">text-secondary</Text>
392
+ <Text className="text-xs font-mono font-medium text-text-secondary">
393
+ text-secondary
394
+ </Text>
376
395
  </View>
377
396
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-elevated border border-hairline">
378
397
  <Text className="text-xs font-mono font-medium text-text-tertiary">text-tertiary</Text>
@@ -382,26 +401,60 @@ function ColorPaletteShowcase() {
382
401
 
383
402
  <Section title="Surface Colors">
384
403
  <View className="flex-row gap-3 flex-wrap">
385
- <ColorSwatch label="surface-base" className="bg-surface-base border border-hairline" textClass="text-text-primary" />
386
- <ColorSwatch label="surface-elevated" className="bg-surface-elevated border border-hairline" textClass="text-text-primary" />
387
- <ColorSwatch label="surface-raised" className="bg-surface-raised border border-hairline" textClass="text-text-primary" />
388
- <ColorSwatch label="surface-overlay" className="bg-surface-overlay border border-hairline" textClass="text-text-primary" />
389
- <ColorSwatch label="surface-input" className="bg-surface-input border border-hairline" textClass="text-text-primary" />
404
+ <ColorSwatch
405
+ label="surface-base"
406
+ className="bg-surface-base border border-hairline"
407
+ textClass="text-text-primary"
408
+ />
409
+ <ColorSwatch
410
+ label="surface-elevated"
411
+ className="bg-surface-elevated border border-hairline"
412
+ textClass="text-text-primary"
413
+ />
414
+ <ColorSwatch
415
+ label="surface-raised"
416
+ className="bg-surface-raised border border-hairline"
417
+ textClass="text-text-primary"
418
+ />
419
+ <ColorSwatch
420
+ label="surface-overlay"
421
+ className="bg-surface-overlay border border-hairline"
422
+ textClass="text-text-primary"
423
+ />
424
+ <ColorSwatch
425
+ label="surface-input"
426
+ className="bg-surface-input border border-hairline"
427
+ textClass="text-text-primary"
428
+ />
390
429
  </View>
391
430
  </Section>
392
431
 
393
432
  <Section title="Background Colors">
394
433
  <View className="flex-row gap-3 flex-wrap">
395
- <ColorSwatch label="background-base" className="bg-background-base border border-hairline" textClass="text-text-primary" />
396
- <ColorSwatch label="background-default" className="bg-background-default border border-hairline" textClass="text-text-primary" />
397
- <ColorSwatch label="background-subtle" className="bg-background-subtle border border-hairline" textClass="text-text-primary" />
434
+ <ColorSwatch
435
+ label="background-base"
436
+ className="bg-background-base border border-hairline"
437
+ textClass="text-text-primary"
438
+ />
439
+ <ColorSwatch
440
+ label="background-default"
441
+ className="bg-background-default border border-hairline"
442
+ textClass="text-text-primary"
443
+ />
444
+ <ColorSwatch
445
+ label="background-subtle"
446
+ className="bg-background-subtle border border-hairline"
447
+ textClass="text-text-primary"
448
+ />
398
449
  </View>
399
450
  </Section>
400
451
 
401
452
  <Section title="Border Colors">
402
453
  <View className="flex-row gap-3 flex-wrap">
403
454
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-base border-2 border-hairline-default">
404
- <Text className="text-xs font-mono font-medium text-text-primary">hairline-default</Text>
455
+ <Text className="text-xs font-mono font-medium text-text-primary">
456
+ hairline-default
457
+ </Text>
405
458
  </View>
406
459
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-base border-2 border-hairline-subtle">
407
460
  <Text className="text-xs font-mono font-medium text-text-primary">hairline-subtle</Text>
@@ -21,13 +21,13 @@ describe('no-device-internals', () => {
21
21
  // Dimension and ratio strings: the `\b` guard before `0x` means a digit
22
22
  // followed by `x` never reads as a hex literal. These exact strings
23
23
  // tripped an earlier, looser sweep.
24
- { code: "// icons render at 20x20" },
25
- { code: "// 200x400 intrinsic -> ~160x320 px" },
24
+ { code: '// icons render at 20x20' },
25
+ { code: '// 200x400 intrinsic -> ~160x320 px' },
26
26
  // SVG path coordinates — digit-only runs are not byte frames.
27
27
  { code: 'const d = "M12 2 22 12 12 22 2 12Z"' },
28
28
  { code: 'const d = "M7 7 17 17 12 22 12 2 17 7 7 17"' },
29
29
  // Timestamps — `-` and `:` are not byte separators.
30
- { code: "// datetime // 2024-01-15 14:30" },
30
+ { code: '// datetime // 2024-01-15 14:30' },
31
31
  // "cascade" in its CSS sense is ordinary styling vocabulary.
32
32
  { code: "// RN doesn't cascade text color, so hand-color the text" },
33
33
  // Plain numbers and durations.
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View, Text } from 'react-native'
3
+ import tokensDoc from '../../TOKENS.md?raw'
4
+ import { Typography } from '../components/custom/Typography'
5
+
6
+ /**
7
+ * Rendered straight from `packages/ui/TOKENS.md` via Vite's `?raw`, deliberately
8
+ * as its markdown source rather than a hand-built React page. A prettier page
9
+ * would be a second copy of the rules that can drift from the file — and a token
10
+ * guide that disagrees with itself is worse than a plain one. The content is
11
+ * mostly aligned tables, which read fine in mono.
12
+ */
13
+ function ChoosingTokens() {
14
+ return (
15
+ <View className="gap-4 p-6">
16
+ <Typography variant="h3" className="text-text-primary">
17
+ Choosing tokens
18
+ </Typography>
19
+ <Typography variant="body2" className="text-text-secondary">
20
+ The decision table to read before writing a component. Source of truth:{' '}
21
+ <Text className="font-mono text-text-primary">packages/ui/TOKENS.md</Text> — this page
22
+ renders that file, so the two cannot disagree.
23
+ </Typography>
24
+ <View className="rounded-lg bg-surface-raised p-4">
25
+ <Text className="font-mono text-xs leading-5 text-text-secondary">{tokensDoc}</Text>
26
+ </View>
27
+ </View>
28
+ )
29
+ }
30
+
31
+ const meta: Meta<typeof ChoosingTokens> = {
32
+ title: 'Foundations/Choosing Tokens',
33
+ component: ChoosingTokens,
34
+ parameters: {
35
+ layout: 'fullscreen',
36
+ docs: {
37
+ description: {
38
+ component:
39
+ 'Which palette for which meaning, how to resolve a colour in code, and the type/spacing ' +
40
+ 'scales. Rendered from `packages/ui/TOKENS.md`.',
41
+ },
42
+ },
43
+ },
44
+ }
45
+ export default meta
46
+ type Story = StoryObj<typeof ChoosingTokens>
47
+
48
+ export const Default: Story = {}
@@ -1,6 +1,15 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { View, Text } from 'react-native'
3
- import { categoricalPalette, getCategoricalColor, CATEGORICAL_CVD_SAFE_MAX, divergingScale, sequentialEffort, discreteRainbow, bestTextColor, greyRamp } from './tokens/primitives'
3
+ import {
4
+ categoricalPalette,
5
+ getCategoricalColor,
6
+ CATEGORICAL_CVD_SAFE_MAX,
7
+ divergingScale,
8
+ sequentialEffort,
9
+ discreteRainbow,
10
+ bestTextColor,
11
+ greyRamp,
12
+ } from './tokens/primitives'
4
13
  import { semanticColorsLight, semanticColorsDark } from './tokens/semantic'
5
14
  import { WORKOUT_TOKENS } from './workout-tokens'
6
15
  import { WORKOUT_PILL_DELOAD } from './extracted-colors-dataviz'
@@ -52,7 +61,12 @@ export default meta
52
61
  * `Foundations/Color/Primitives`.
53
62
  */
54
63
  const SURFACE_PLANES = [
55
- { step: 975, hex: greyRamp[975], lStar: 3.8, role: 'Frame / bezel — chrome the ramp sits inside' },
64
+ {
65
+ step: 975,
66
+ hex: greyRamp[975],
67
+ lStar: 3.8,
68
+ role: 'Frame / bezel — chrome the ramp sits inside',
69
+ },
56
70
  { step: 950, hex: greyRamp[950], lStar: 9, role: 'Shell' },
57
71
  { step: 925, hex: greyRamp[925], lStar: 13.9, role: 'Main content plane' },
58
72
  { step: 900, hex: greyRamp[900], lStar: 17.2, role: 'Nav / rail' },
@@ -113,12 +127,12 @@ export const SurfaceRamp: StoryObj = {
113
127
  <View style={{ padding: 24 }}>
114
128
  <Text className="text-2xl font-bold text-text-primary mb-2">Surface Ramp (Dark Mode)</Text>
115
129
  <SectionIntro>
116
- The v0.10.0 surface foundation, and the assignment the most surfaces depend on. Depth is
117
- an <Text className="font-semibold">ordered ramp</Text>, not a set of unrelated fills —
118
- planes are spaced by perceptual lightness (L*) on a diminishing taper, so &quot;one step
119
- up&quot; is the same visual distance anywhere in the stack. Listed darkest first. Several
120
- semantic tokens deliberately share a plane (shown per row); that aliasing is what lets a
121
- component say what it <Text className="italic">is</Text> rather than how deep it sits.
130
+ The v0.10.0 surface foundation, and the assignment the most surfaces depend on. Depth is an{' '}
131
+ <Text className="font-semibold">ordered ramp</Text>, not a set of unrelated fills — planes
132
+ are spaced by perceptual lightness (L*) on a diminishing taper, so &quot;one step up&quot;
133
+ is the same visual distance anywhere in the stack. Listed darkest first. Several semantic
134
+ tokens deliberately share a plane (shown per row); that aliasing is what lets a component
135
+ say what it <Text className="italic">is</Text> rather than how deep it sits.
122
136
  </SectionIntro>
123
137
 
124
138
  <View style={{ gap: 14 }}>
@@ -132,9 +146,9 @@ export const SurfaceRamp: StoryObj = {
132
146
  scales — the greys it is built from are in Foundations/Color/Primitives. To apply it at
133
147
  runtime use <Text className="font-semibold text-text-primary">&lt;Surface level&gt;</Text>{' '}
134
148
  and <Text className="font-semibold text-text-primary">useOnSurfaceColor</Text> rather than
135
- reading tokens directly — see Components/Atoms/Surface. Shadow and glow treatments layered
136
- on top of these planes are in Foundations/Shadows; the legacy numeric elevation scale is
137
- in Foundations/Elevation.
149
+ reading tokens directly — see Components/Atoms/Surface. How a plane says it is ABOVE its
150
+ neighbour (tone, lift, hairline, material) and how the elevation levels map onto these steps
151
+ are in Foundations/Depth.
138
152
  </Text>
139
153
  </View>
140
154
  ),
@@ -188,16 +202,14 @@ export const CategoricalPalette: StoryObj = {
188
202
  <SectionIntro>
189
203
  Seven hues in one canonical order —{' '}
190
204
  <Text className="font-semibold">blue → magenta → red → orange → green → cyan → amber</Text>{' '}
191
- — expressed as references into the tonal ramps. The sequence is nested-stable: a chart
192
- with N series takes the first N colors and a series&apos; index does not shift as N
193
- changes. The worst-case deuteranopia/protanopia ΔE floor of 8 holds through the first{' '}
194
- {CATEGORICAL_CVD_SAFE_MAX} (
195
- <Text className="font-semibold">CATEGORICAL_CVD_SAFE_MAX</Text>); the 7th is extended and
196
- wants a legend or a second encoding. Two variants ship:{' '}
205
+ — expressed as references into the tonal ramps. The sequence is nested-stable: a chart with
206
+ N series takes the first N colors and a series&apos; index does not shift as N changes. The
207
+ worst-case deuteranopia/protanopia ΔE floor of 8 holds through the first{' '}
208
+ {CATEGORICAL_CVD_SAFE_MAX} (<Text className="font-semibold">CATEGORICAL_CVD_SAFE_MAX</Text>
209
+ ); the 7th is extended and wants a legend or a second encoding. Two variants ship:{' '}
197
210
  <Text className="font-semibold">default</Text> (vivid, for neutral/light surfaces, legible
198
- under black text) and <Text className="font-semibold">dark</Text> (deeper, for white text
199
- on a filled swatch). A third &quot;light&quot; variant was dropped — `default` doubles as
200
- it.
211
+ under black text) and <Text className="font-semibold">dark</Text> (deeper, for white text on
212
+ a filled swatch). A third &quot;light&quot; variant was dropped — `default` doubles as it.
201
213
  </SectionIntro>
202
214
 
203
215
  <CategoricalRow name="Default (black text)" colors={categoricalPalette.default} />
@@ -394,8 +406,8 @@ export const FatigueRomPalette: StoryObj = {
394
406
  </Text>{' '}
395
407
  One scheme shared by the two live-quality readouts — the ROM progression bars and the
396
408
  ghost-spark current line. Deliberately no greens and no ambers: those languages belong to
397
- the verdict tones and the velocity-loss bands (stories 3 and 4), and reusing them here
398
- would make &quot;fine&quot; and &quot;fast&quot; look like the same claim. Every stop is a
409
+ the verdict tones and the velocity-loss bands (stories 3 and 4), and reusing them here would
410
+ make &quot;fine&quot; and &quot;fast&quot; look like the same claim. Every stop is a
399
411
  reference into the tonal ramps.
400
412
  </SectionIntro>
401
413
 
@@ -426,8 +438,8 @@ export const FatigueRomPalette: StoryObj = {
426
438
  <Text className="text-text-secondary text-xs mb-3">
427
439
  A controlled rep (grind signature below GRIND_THRESHOLD = {GRIND_THRESHOLD}) stays in the
428
440
  silver family, dimming toward DRIFT_GREY with tempo deviation — a &quot;drifting but not
429
- failing&quot; cue that never becomes a color. At or above the threshold the line runs
430
- light → mid → deep by severity.
441
+ failing&quot; cue that never becomes a color. At or above the threshold the line runs light
442
+ → mid → deep by severity.
431
443
  </Text>
432
444
  <View style={{ flexDirection: 'row', gap: 32 }}>
433
445
  <FatigueRampStrip
@@ -442,8 +454,8 @@ export const FatigueRomPalette: StoryObj = {
442
454
  DRIFT_GREY is `neutral[600]` #4B5563, and the unified warm grey ramp assigns it no
443
455
  destination — the 15-row fold maps the other greys but skips this one. It needs an
444
456
  assignment before that migration lands. Note that the recovered spec records DRIFT_GREY as
445
- `grey[500]` #1C1C1C; that is stale, `fatigue-tokens.ts` on main reads `neutral[600]`,
446
- which puts it in the expensive half of the fold rather than the cheap one.
457
+ `grey[500]` #1C1C1C; that is stale, `fatigue-tokens.ts` on main reads `neutral[600]`, which
458
+ puts it in the expensive half of the fold rather than the cheap one.
447
459
  </Text>
448
460
  </View>
449
461
  ),
@@ -461,7 +473,9 @@ export const FatigueRomPalette: StoryObj = {
461
473
  * buries. Columns are derived from the shipped tokens, so a new modifier shows
462
474
  * up here without editing the story.
463
475
  */
464
- const VARIANT_SUFFIXES = ['light', 'dark', 'subtle', 'hover', 'active', 'muted'] as const
476
+ // Wash rungs run subtle -> muted -> strong (0.12 / 0.30 / 0.50) so the matrix
477
+ // reads as the ramp it is.
478
+ const VARIANT_SUFFIXES = ['light', 'dark', 'subtle', 'muted', 'strong', 'hover', 'active'] as const
465
479
 
466
480
  function variantsOf(base: string, palette: Record<string, string>) {
467
481
  return [
@@ -513,12 +527,12 @@ export const StatusColors: StoryObj = {
513
527
  <Text className="text-2xl font-bold text-text-primary mb-2">Status Colors</Text>
514
528
  <SectionIntro>
515
529
  Status roles and their modifiers. <Text className="font-semibold">status-error-vivid</Text>{' '}
516
- is a separate role (not a modifier of status-error) reserved for destructive
517
- emphasis. It used to be the one status family sourced from the `redVivid` support scale
518
- rather than the OKLCH ramps; TD-07.14 deleted that scale, so the family now resolves to
519
- the same red[600]/[500]/[700] steps as status-error. The two are therefore identical in
520
- value today — the role is kept distinct because emphasis is meant to come from a glow
521
- derived from red[500], not from a second, higher-chroma red.
530
+ is a separate role (not a modifier of status-error) reserved for destructive emphasis. It
531
+ used to be the one status family sourced from the `redVivid` support scale rather than the
532
+ OKLCH ramps; TD-07.14 deleted that scale, so the family now resolves to the same
533
+ red[600]/[500]/[700] steps as status-error. The two are therefore identical in value today —
534
+ the role is kept distinct because emphasis is meant to come from a glow derived from
535
+ red[500], not from a second, higher-chroma red.
522
536
  </SectionIntro>
523
537
  <VariantMatrix
524
538
  bases={[
@@ -557,8 +571,8 @@ export const ResultColors: StoryObj = {
557
571
  <Text className="text-2xl font-bold text-text-primary mb-2">Result / Outcome Colors</Text>
558
572
  <SectionIntro>
559
573
  Colors for indicating positive, negative, or neutral outcomes. Distinct from status: these
560
- encode the <Text className="italic">direction of a change</Text> (did this get better?),
561
- not a system state.
574
+ encode the <Text className="italic">direction of a change</Text> (did this get better?), not
575
+ a system state.
562
576
  </SectionIntro>
563
577
  <VariantMatrix
564
578
  bases={['result-improve', 'result-degrade', 'result-inconclusive', 'result-neutral']}
@@ -574,11 +588,11 @@ export const TextAndBorderColors: StoryObj = {
574
588
  <View style={{ padding: 24 }}>
575
589
  <Text className="text-2xl font-bold text-text-primary mb-2">Text & Border Colors</Text>
576
590
  <SectionIntro>
577
- The dark-mode text and border roles. Today the border family is the grey grey ramp
578
- assigned to line-work, and text-tertiary and the link colors come from the neutral and
579
- blue support scales — all three of which are pending migration (TD-07.14): the greys fold
580
- into one warm grey ramp and the links move to the OKLCH blue. These are the roles that
581
- will move most, because the mid-grey text steps shift furthest. Prefer{' '}
591
+ The dark-mode text and border roles. Today the border family is the grey grey ramp assigned
592
+ to line-work, and text-tertiary and the link colors come from the neutral and blue support
593
+ scales — all three of which are pending migration (TD-07.14): the greys fold into one warm
594
+ grey ramp and the links move to the OKLCH blue. These are the roles that will move most,
595
+ because the mid-grey text steps shift furthest. Prefer{' '}
582
596
  <Text className="font-semibold">useOnSurfaceColor</Text> for text sitting on a{' '}
583
597
  <Text className="font-semibold">&lt;Surface&gt;</Text> — it picks the right text role for
584
598
  the plane instead of hardcoding one, which is also what makes the migration survivable.
@@ -782,7 +796,10 @@ export const RolesInUse: StoryObj = {
782
796
  <Demo label="IntensityBar · effort">
783
797
  <View style={{ flexDirection: 'row', gap: 2, width: 132 }}>
784
798
  {sequentialEffort.map((hex, i) => (
785
- <View key={i} style={{ flex: 1, height: 20, backgroundColor: hex, borderRadius: 2 }} />
799
+ <View
800
+ key={i}
801
+ style={{ flex: 1, height: 20, backgroundColor: hex, borderRadius: 2 }}
802
+ />
786
803
  ))}
787
804
  </View>
788
805
  </Demo>
@@ -832,10 +849,10 @@ export const LegacyDataVisualizationColors: StoryObj = {
832
849
  </Text>
833
850
  <SectionIntro>
834
851
  <Text className="font-semibold">Do not use for new work.</Text> Paul Tol&apos;s
835
- discrete-rainbow scale behind the `data-1..10` tokens — no longer consumed by any
836
- component. Use the Categorical Palette (story 2) for charts and qualitative series. This
837
- story exists because the tokens are still shipped, and a shipped token without a swatch is
838
- the drift the coverage test guards against; it goes away when the tokens do.
852
+ discrete-rainbow scale behind the `data-1..10` tokens — no longer consumed by any component.
853
+ Use the Categorical Palette (story 2) for charts and qualitative series. This story exists
854
+ because the tokens are still shipped, and a shipped token without a swatch is the drift the
855
+ coverage test guards against; it goes away when the tokens do.
839
856
  </SectionIntro>
840
857
 
841
858
  <View style={{ gap: 16 }}>