@titan-design/react-ui 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. package/README.md +60 -47
  2. package/dist/bodymap.js +856 -736
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +858 -738
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1431 -237
  7. package/dist/index.d.ts +1431 -237
  8. package/dist/index.js +6506 -4781
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +6280 -4642
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
  13. package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1919 -1937
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1927 -1945
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +225 -140
  21. package/dist/theme/index.d.ts +225 -140
  22. package/dist/theme/index.js +298 -319
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +283 -315
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +145 -24
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +145 -24
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +128 -11
  31. package/dist/theme/tokens.d.ts +128 -11
  32. package/dist/theme/tokens.js +126 -26
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +124 -27
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/docs/render-testing-pattern.md +130 -0
  40. package/package.json +1 -1
  41. package/src/arch/Architecture.stories.tsx +3 -1
  42. package/src/arch/arch-graph.freshness.test.ts +52 -0
  43. package/src/arch/arch-graph.json +4989 -1583
  44. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  45. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  46. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  48. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  49. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  51. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  52. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  54. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  55. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  57. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  58. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  60. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  61. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  63. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  64. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  66. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  67. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  69. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  70. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  71. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  73. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  74. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  76. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  77. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  78. package/src/components/custom/ActiveWork/README.md +305 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  80. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  81. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  82. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  83. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  84. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  86. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  87. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  88. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  90. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  91. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  92. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  93. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  94. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  95. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  96. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  97. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  98. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  99. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  100. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  101. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  102. package/src/components/custom/ActiveWork/index.ts +19 -0
  103. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  104. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  105. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  106. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  107. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
  108. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  109. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  110. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  111. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  112. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  113. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  116. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  117. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  119. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  120. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  121. package/src/components/custom/Fatigue/README.md +40 -3
  122. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  123. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  124. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  125. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  126. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  127. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  128. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  129. package/src/components/custom/Fatigue/index.ts +17 -5
  130. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  131. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  132. package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
  133. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  134. package/src/components/custom/Gauge/Gauge.tsx +7 -2
  135. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  136. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  137. package/src/components/custom/Metric/Metric.tsx +5 -20
  138. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  139. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  140. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  141. package/src/components/custom/Prose/README.md +58 -0
  142. package/src/components/custom/Prose/index.ts +1 -0
  143. package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
  144. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  145. package/src/components/custom/Scatter/Scatter.tsx +122 -18
  146. package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
  147. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  148. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  149. package/src/components/custom/Table/Table.stories.tsx +99 -16
  150. package/src/components/custom/Table/Table.test.tsx +273 -86
  151. package/src/components/custom/Table/Table.tsx +159 -67
  152. package/src/components/custom/Table/column-fit.test.ts +75 -0
  153. package/src/components/custom/Table/column-fit.ts +116 -0
  154. package/src/components/custom/Table/index.ts +9 -0
  155. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  156. package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
  157. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  158. package/src/components/custom/Treemap/Treemap.tsx +11 -3
  159. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  160. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  161. package/src/components/custom/Typography/Typography.tsx +6 -0
  162. package/src/components/custom/Typography/index.ts +1 -8
  163. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
  164. package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
  165. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  166. package/src/components/custom/Workout/BaseBadge.tsx +6 -2
  167. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  168. package/src/components/custom/Workout/BodyMap.tsx +8 -4
  169. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
  170. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  171. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
  172. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
  173. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  174. package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
  175. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  176. package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
  177. package/src/components/custom/Workout/DeviationBar.tsx +24 -16
  178. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
  179. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
  180. package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
  181. package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
  182. package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
  183. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
  184. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
  185. package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
  186. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  187. package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
  188. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  189. package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
  190. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
  191. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  192. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  193. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  194. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  195. package/src/components/custom/Workout/InputBar.tsx +4 -2
  196. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  197. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  198. package/src/components/custom/Workout/IntensityBar.tsx +8 -3
  199. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  200. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  201. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  202. package/src/components/custom/Workout/MesoCard.tsx +14 -10
  203. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  204. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  205. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  206. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  207. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  208. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
  209. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  210. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  211. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  212. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  213. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
  214. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  215. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  216. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  217. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  218. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  219. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
  220. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  221. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  222. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  223. package/src/components/custom/Workout/README.md +68 -17
  224. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  225. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  226. package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
  227. package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
  228. package/src/components/custom/Workout/RestTimer.tsx +4 -2
  229. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  230. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  231. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  232. package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
  233. package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
  234. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  235. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  236. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  237. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  238. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  239. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  240. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  241. package/src/components/custom/Workout/SetBar.tsx +38 -12
  242. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  243. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  244. package/src/components/custom/Workout/SetRow.tsx +61 -23
  245. package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
  246. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  247. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  248. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  249. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  250. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  251. package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
  252. package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
  253. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  254. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  255. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  256. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  257. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  258. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  259. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  260. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  261. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
  262. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  263. package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
  264. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  265. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  266. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  267. package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
  268. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  269. package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
  270. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  271. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  272. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
  273. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
  274. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
  275. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  276. package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
  277. package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
  278. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  279. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  280. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  281. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  282. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  283. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  284. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  285. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  286. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  287. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  288. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  289. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  290. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  291. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  292. package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
  293. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  294. package/src/components/custom/Workout/exerciseRowState.ts +29 -0
  295. package/src/components/custom/Workout/index.ts +17 -2
  296. package/src/components/custom/Workout/metricText.stories.tsx +15 -13
  297. package/src/components/custom/Workout/metricText.tsx +8 -2
  298. package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
  299. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  300. package/src/components/custom/charts/README.md +66 -0
  301. package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
  302. package/src/components/custom/charts/SetBarChart.tsx +56 -9
  303. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  304. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  305. package/src/components/custom/charts/SparkBars.tsx +85 -0
  306. package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
  307. package/src/components/custom/charts/flatBarGeometry.ts +32 -0
  308. package/src/components/custom/charts/index.ts +3 -0
  309. package/src/components/custom/index.ts +3 -0
  310. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  311. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  312. package/src/components/custom/stepper/Stepper.tsx +21 -34
  313. package/src/components/icons/icons.stories.tsx +1 -1
  314. package/src/components/icons/icons.tsx +51 -0
  315. package/src/components/shell/AppShell.stories.tsx +150 -0
  316. package/src/components/shell/AppShell.test.tsx +70 -0
  317. package/src/components/shell/AppShell.tsx +90 -0
  318. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  319. package/src/components/shell/BrandLockup.test.tsx +34 -1
  320. package/src/components/shell/BrandLockup.tsx +27 -11
  321. package/src/components/shell/NavItem.stories.tsx +4 -4
  322. package/src/components/shell/NavItem.test.tsx +17 -0
  323. package/src/components/shell/NavItem.tsx +17 -5
  324. package/src/components/shell/README.md +89 -26
  325. package/src/components/shell/SideNav.stories.tsx +38 -7
  326. package/src/components/shell/SideNav.test.tsx +16 -8
  327. package/src/components/shell/SideNav.tsx +17 -17
  328. package/src/components/shell/TopBar.stories.tsx +44 -19
  329. package/src/components/shell/TopBar.test.tsx +34 -12
  330. package/src/components/shell/TopBar.tsx +61 -40
  331. package/src/components/shell/brands.tsx +66 -0
  332. package/src/components/shell/index.ts +9 -8
  333. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  334. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  335. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  336. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  337. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  338. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  339. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  340. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  341. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  342. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  343. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  344. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  345. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  346. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  347. package/src/components/shell/workout/index.ts +9 -0
  348. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  349. package/src/components/ui/README.md +110 -0
  350. package/src/components/ui/alert/Alert.stories.tsx +15 -5
  351. package/src/components/ui/alert/Alert.tsx +24 -3
  352. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  353. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  354. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  355. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  356. package/src/components/ui/avatar/Avatar.tsx +2 -10
  357. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  358. package/src/components/ui/badge/Badge.test.tsx +19 -3
  359. package/src/components/ui/badge/Badge.tsx +48 -55
  360. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  361. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  362. package/src/components/ui/button/Button.stories.tsx +46 -12
  363. package/src/components/ui/button/Button.tsx +44 -37
  364. package/src/components/ui/card/Card.stories.tsx +90 -94
  365. package/src/components/ui/card/Card.test.tsx +80 -6
  366. package/src/components/ui/card/Card.tsx +150 -203
  367. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  368. package/src/components/ui/checkbox/Checkbox.tsx +7 -27
  369. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  370. package/src/components/ui/chip/Chip.test.tsx +10 -6
  371. package/src/components/ui/chip/Chip.tsx +76 -91
  372. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  373. package/src/components/ui/collapse/Collapse.tsx +6 -11
  374. package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
  375. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  376. package/src/components/ui/data-row/DataRow.tsx +18 -7
  377. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  378. package/src/components/ui/divider/Divider.tsx +1 -5
  379. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  380. package/src/components/ui/drawer/Drawer.tsx +13 -27
  381. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  382. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  383. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  384. package/src/components/ui/form-field/FormField.tsx +10 -46
  385. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  386. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  387. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  388. package/src/components/ui/help-tip/index.ts +7 -1
  389. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  390. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  391. package/src/components/ui/icon-box/IconBox.tsx +10 -18
  392. package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
  393. package/src/components/ui/indicator/Indicator.tsx +20 -14
  394. package/src/components/ui/input/Input.stories.tsx +3 -11
  395. package/src/components/ui/input/Input.test.tsx +2 -10
  396. package/src/components/ui/input/Input.tsx +10 -25
  397. package/src/components/ui/input/index.ts +7 -1
  398. package/src/components/ui/link/Link.stories.tsx +19 -7
  399. package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
  400. package/src/components/ui/list-item/ListItem.tsx +2 -9
  401. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  402. package/src/components/ui/menu/Menu.test.tsx +2 -11
  403. package/src/components/ui/menu/Menu.tsx +12 -14
  404. package/src/components/ui/menu/index.ts +8 -1
  405. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  406. package/src/components/ui/modal/Modal.tsx +31 -19
  407. package/src/components/ui/pill/Pill.stories.tsx +111 -23
  408. package/src/components/ui/pill/Pill.test.tsx +101 -3
  409. package/src/components/ui/pill/Pill.tsx +168 -49
  410. package/src/components/ui/pill/index.ts +1 -1
  411. package/src/components/ui/popover/Popover.stories.tsx +6 -8
  412. package/src/components/ui/popover/Popover.test.tsx +1 -6
  413. package/src/components/ui/popover/Popover.tsx +20 -15
  414. package/src/components/ui/popover/index.ts +7 -1
  415. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  416. package/src/components/ui/progress/Progress.test.tsx +1 -5
  417. package/src/components/ui/progress/Progress.tsx +9 -6
  418. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  419. package/src/components/ui/radio/Radio.test.tsx +6 -2
  420. package/src/components/ui/radio/Radio.tsx +23 -22
  421. package/src/components/ui/section/Section.stories.tsx +12 -21
  422. package/src/components/ui/section/Section.test.tsx +1 -6
  423. package/src/components/ui/section/Section.tsx +1 -3
  424. package/src/components/ui/section/index.ts +1 -5
  425. package/src/components/ui/select/Select.stories.tsx +3 -13
  426. package/src/components/ui/select/Select.test.tsx +2 -11
  427. package/src/components/ui/select/Select.tsx +16 -15
  428. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  429. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  430. package/src/components/ui/skeleton/index.ts +1 -7
  431. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  432. package/src/components/ui/spinner/Spinner.tsx +4 -5
  433. package/src/components/ui/stack/Stack.stories.tsx +8 -8
  434. package/src/components/ui/stack/Stack.tsx +1 -1
  435. package/src/components/ui/surface/Surface.stories.tsx +92 -33
  436. package/src/components/ui/surface/Surface.test.tsx +88 -28
  437. package/src/components/ui/surface/Surface.tsx +37 -87
  438. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  439. package/src/components/ui/surface/index.ts +8 -0
  440. package/src/components/ui/surface/resolveSurface.ts +98 -0
  441. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  442. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  443. package/src/components/ui/switch/Switch.tsx +7 -6
  444. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  445. package/src/components/ui/tabs/Tabs.tsx +8 -21
  446. package/src/components/ui/tabs/index.ts +1 -7
  447. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  448. package/src/components/ui/tile/Tile.tsx +3 -0
  449. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  450. package/src/components/ui/toast/Toast.test.tsx +2 -8
  451. package/src/components/ui/toast/Toast.tsx +49 -57
  452. package/src/components/ui/toast/index.ts +0 -1
  453. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  454. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  455. package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
  456. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  457. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  458. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  459. package/src/components/ui/tooltip/index.ts +1 -1
  460. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  461. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  462. package/src/components/ui/trigger/index.ts +2 -0
  463. package/src/stories/PresetShowcase.stories.tsx +101 -48
  464. package/src/test/no-device-internals.test.ts +3 -3
  465. package/src/test/no-raw-color.test.ts +39 -0
  466. package/src/theme/Alpha.stories.tsx +103 -0
  467. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  468. package/src/theme/ColorPalettes.stories.tsx +62 -45
  469. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  470. package/src/theme/Depth.stories.tsx +132 -65
  471. package/src/theme/DepthCalibration.stories.tsx +23 -21
  472. package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
  473. package/src/theme/ThemeProvider.test.tsx +4 -4
  474. package/src/theme/barrel.ts +7 -6
  475. package/src/theme/color-stories.coverage.test.ts +1 -1
  476. package/src/theme/color-utils.ts +41 -29
  477. package/src/theme/config.completeness.test.ts +1 -1
  478. package/src/theme/config.ts +40 -0
  479. package/src/theme/elevation.test.ts +82 -56
  480. package/src/theme/elevation.ts +77 -561
  481. package/src/theme/global.css +45 -5
  482. package/src/theme/grey-ramp.test.ts +24 -8
  483. package/src/theme/lift.test.ts +39 -0
  484. package/src/theme/lift.ts +102 -0
  485. package/src/theme/materials.test.ts +5 -2
  486. package/src/theme/materials.ts +38 -4
  487. package/src/theme/native-theming-guard.test.ts +5 -5
  488. package/src/theme/presets/apply.ts +4 -0
  489. package/src/theme/presets/audiobook.ts +5 -2
  490. package/src/theme/presets/default.ts +4 -0
  491. package/src/theme/presets/index.ts +14 -1
  492. package/src/theme/presets/types.ts +1 -1
  493. package/src/theme/semantic-contrast.test.ts +13 -4
  494. package/src/theme/status-distinctness.test.ts +66 -0
  495. package/src/theme/subtle-tone-weight.test.ts +163 -0
  496. package/src/theme/surface-planes.test.ts +37 -0
  497. package/src/theme/surface-planes.ts +68 -0
  498. package/src/theme/tailwind-var-opacity.test.ts +163 -0
  499. package/src/theme/token-export-guard.test.ts +1 -3
  500. package/src/theme/tokens/primitives.test.ts +15 -7
  501. package/src/theme/tokens/primitives.ts +98 -33
  502. package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
  503. package/src/theme/tokens/semantic.ts +124 -54
  504. package/src/theme/wash-ladder.test.ts +58 -0
  505. package/src/theme/workout-tokens.ts +1 -7
  506. package/src/types/jest-axe.d.ts +2 -6
  507. package/src/types/raw-md.d.ts +5 -0
  508. package/src/utils/colors.alpha-adoption.test.ts +408 -0
  509. package/src/utils/colors.ts +4 -4
  510. package/src/utils/form.ts +1 -3
  511. package/src/utils/index.ts +2 -7
  512. package/src/utils/number-format.ts +17 -0
  513. package/src/utils/workout-format.ts +15 -6
  514. package/src/web-jsx/jsx-runtime.ts +1 -5
  515. package/tailwind.config.js +55 -9
  516. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  517. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  518. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  519. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  520. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  521. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  522. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  523. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  524. package/src/components/shell/DashboardShell.tsx +0 -75
  525. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  526. package/src/theme/elevation.stories.tsx +0 -346
  527. package/src/utils/useTheme.ts +0 -72
  528. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  529. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  530. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  531. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -1,17 +1,11 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { View } from 'react-native'
3
- import {
4
- Skeleton,
5
- SkeletonText,
6
- SkeletonCircle,
7
- SkeletonCard,
8
- SkeletonListItem,
9
- } from './Skeleton'
3
+ import { Skeleton, SkeletonText, SkeletonCircle, SkeletonCard, SkeletonListItem } from './Skeleton'
10
4
 
11
5
  const meta: Meta<typeof Skeleton> = {
12
6
  title: 'Components/Atoms/Skeleton',
13
7
  component: Skeleton,
14
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
15
9
  argTypes: {
16
10
  variant: {
17
11
  control: 'select',
@@ -64,9 +58,7 @@ export const RectVariant: Story = {
64
58
  }
65
59
 
66
60
  export const RoundedVariant: Story = {
67
- render: () => (
68
- <Skeleton variant="rounded" width={300} height={200} />
69
- ),
61
+ render: () => <Skeleton variant="rounded" width={300} height={200} />,
70
62
  }
71
63
 
72
64
  export const TextBlock: Story = {
@@ -136,11 +136,7 @@ export interface SkeletonCircleProps {
136
136
  /**
137
137
  * Circle skeleton for avatars.
138
138
  */
139
- export function SkeletonCircle({
140
- size = 40,
141
- animation = 'pulse',
142
- className,
143
- }: SkeletonCircleProps) {
139
+ export function SkeletonCircle({ size = 40, animation = 'pulse', className }: SkeletonCircleProps) {
144
140
  return (
145
141
  <Skeleton
146
142
  variant="circle"
@@ -179,12 +175,7 @@ export function SkeletonCard({
179
175
  return (
180
176
  <View className={cn('rounded-lg overflow-hidden bg-surface-elevated', className)}>
181
177
  {hasImage && (
182
- <Skeleton
183
- variant="rect"
184
- width="100%"
185
- height={imageHeight}
186
- animation={animation}
187
- />
178
+ <Skeleton variant="rect" width="100%" height={imageHeight} animation={animation} />
188
179
  )}
189
180
  <View className="p-4 gap-3">
190
181
  <Skeleton variant="text" width="70%" animation={animation} />
@@ -218,9 +209,7 @@ export function SkeletonListItem({
218
209
  }: SkeletonListItemProps) {
219
210
  return (
220
211
  <View className={cn('flex-row items-center gap-3 p-3', className)}>
221
- {hasAvatar && (
222
- <SkeletonCircle size={avatarSize} animation={animation} />
223
- )}
212
+ {hasAvatar && <SkeletonCircle size={avatarSize} animation={animation} />}
224
213
  <View className="flex-1">
225
214
  <SkeletonText lines={lines} animation={animation} />
226
215
  </View>
@@ -1,10 +1,4 @@
1
- export {
2
- Skeleton,
3
- SkeletonText,
4
- SkeletonCircle,
5
- SkeletonCard,
6
- SkeletonListItem,
7
- } from './Skeleton'
1
+ export { Skeleton, SkeletonText, SkeletonCircle, SkeletonCard, SkeletonListItem } from './Skeleton'
8
2
  export type {
9
3
  SkeletonProps,
10
4
  SkeletonTextProps,
@@ -5,7 +5,7 @@ import { Spinner } from './Spinner'
5
5
  const meta: Meta<typeof Spinner> = {
6
6
  title: 'Components/Atoms/Spinner',
7
7
  component: Spinner,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  size: {
11
11
  control: 'select',
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import { ActivityIndicator, View, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
4
  import { SPINNER_PRIMARY, SPINNER_SECONDARY } from '../../../theme/extracted-colors-ui'
5
+ import { primitiveColors } from '../../../theme/tokens/primitives'
5
6
 
6
7
  export type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl'
7
8
  export type SpinnerColor = 'primary' | 'secondary' | 'white' | 'default'
@@ -27,7 +28,8 @@ const sizeMap: Record<SpinnerSize, 'small' | 'large'> = {
27
28
  const colorMap: Record<SpinnerColor, string> = {
28
29
  primary: SPINNER_PRIMARY,
29
30
  secondary: SPINNER_SECONDARY,
30
- white: '#FFFFFF',
31
+ white: primitiveColors.white,
32
+ // VW-82: Tailwind gray-500; no titan grey matches. Left raw, proposed in the PR.
31
33
  default: '#6B7280',
32
34
  }
33
35
 
@@ -64,10 +66,7 @@ export function Spinner({
64
66
  className={cn('items-center justify-center', containerSizes[size], className)}
65
67
  {...props}
66
68
  >
67
- <ActivityIndicator
68
- size={sizeMap[size]}
69
- color={colorMap[color]}
70
- />
69
+ <ActivityIndicator size={sizeMap[size]} color={colorMap[color]} />
71
70
  </View>
72
71
  )
73
72
  }
@@ -5,7 +5,7 @@ import { Stack, HStack, VStack } from './Stack'
5
5
  const meta: Meta<typeof Stack> = {
6
6
  title: 'Components/Atoms/Stack',
7
7
  component: Stack,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  gap: {
11
11
  control: 'select',
@@ -35,7 +35,7 @@ type Story = StoryObj<typeof Stack>
35
35
  function Box({ children }: { children: string }) {
36
36
  return (
37
37
  <View className="rounded bg-brand-primary px-4 py-2">
38
- <Text className="text-sm text-white">{children}</Text>
38
+ <Text className="text-sm text-on-brand-primary">{children}</Text>
39
39
  </View>
40
40
  )
41
41
  }
@@ -76,23 +76,23 @@ export const Vertical: Story = {
76
76
  export const WithAlignment: Story = {
77
77
  render: () => (
78
78
  <VStack gap={6}>
79
- <Text className="text-sm font-medium text-neutral-400">justify=&quot;between&quot;</Text>
79
+ <Text className="text-sm font-medium text-text-secondary">justify=&quot;between&quot;</Text>
80
80
  <HStack gap={2} justify="between" className="w-full">
81
81
  <Box>A</Box>
82
82
  <Box>B</Box>
83
83
  <Box>C</Box>
84
84
  </HStack>
85
85
 
86
- <Text className="text-sm font-medium text-neutral-400">align=&quot;center&quot;</Text>
86
+ <Text className="text-sm font-medium text-text-secondary">align=&quot;center&quot;</Text>
87
87
  <HStack gap={2} align="center">
88
88
  <View className="rounded bg-brand-primary px-4 py-1">
89
- <Text className="text-sm text-white">Short</Text>
89
+ <Text className="text-sm text-on-brand-primary">Short</Text>
90
90
  </View>
91
91
  <View className="rounded bg-brand-primary px-4 py-4">
92
- <Text className="text-sm text-white">Tall</Text>
92
+ <Text className="text-sm text-on-brand-primary">Tall</Text>
93
93
  </View>
94
94
  <View className="rounded bg-brand-primary px-4 py-2">
95
- <Text className="text-sm text-white">Medium</Text>
95
+ <Text className="text-sm text-on-brand-primary">Medium</Text>
96
96
  </View>
97
97
  </HStack>
98
98
  </VStack>
@@ -114,7 +114,7 @@ export const GapScale: Story = {
114
114
  <VStack gap={6}>
115
115
  {([0, 1, 2, 4, 6, 8, 12] as const).map((g) => (
116
116
  <VStack key={g} gap={1}>
117
- <Text className="text-xs text-neutral-400">gap={g}</Text>
117
+ <Text className="text-xs text-text-secondary">gap={g}</Text>
118
118
  <HStack gap={g}>
119
119
  <Box>A</Box>
120
120
  <Box>B</Box>
@@ -58,7 +58,7 @@ export function Stack({
58
58
  align && alignMap[align],
59
59
  justify && justifyMap[justify],
60
60
  wrap && 'flex-wrap',
61
- className,
61
+ className
62
62
  )}
63
63
  {...props}
64
64
  >
@@ -3,25 +3,36 @@ import { View, Text } from 'react-native'
3
3
  import { Surface } from './Surface'
4
4
  import { useOnSurfaceColor, type SurfaceLevel } from './SurfaceContext'
5
5
  import type { ElevationLevel } from '../../../theme/elevation'
6
+ import { semanticColorsLight, semanticColorsDark } from '../../../theme/tokens/semantic'
7
+ import { primitiveRamps } from '../../../theme/tokens/primitives'
6
8
 
7
9
  const meta: Meta<typeof Surface> = {
8
10
  title: 'Components/Atoms/Surface',
9
11
  component: Surface,
10
- tags: ['autodocs'],
12
+ tags: ['autodocs', 'status:stable', '!status:review'],
11
13
  argTypes: {
12
14
  elevation: {
13
15
  control: { type: 'range', min: -2, max: 5, step: 1 },
14
- description: 'Elevation level (-2 to 5)',
16
+ description:
17
+ 'Depth relative to the enclosing Surface: <0 recess, 0 flat, 1–3 lift a plane each, 4–5 float',
18
+ },
19
+ raise: {
20
+ control: { type: 'range', min: 1, max: 3, step: 1 },
21
+ description: 'Planes to step UP from the enclosing Surface, with the lift treatment',
15
22
  },
16
23
  level: {
17
24
  control: 'select',
18
25
  options: ['frame', 'background', 'base', 'elevated', 'raised', 'overlay'],
19
- description: 'Named grey plane (flat background from a semantic token)',
26
+ description: 'Absolute grey plane for a shell root (flat, no lift)',
20
27
  },
21
28
  pressed: {
22
29
  control: 'boolean',
23
30
  description: 'Sunken well: one ramp step DOWN from the parent level + inner-shadow recess',
24
31
  },
32
+ lift: {
33
+ control: 'boolean',
34
+ description: 'Force the rim + shadow treatment on or off',
35
+ },
25
36
  theme: {
26
37
  control: 'select',
27
38
  options: ['light', 'dark'],
@@ -47,45 +58,88 @@ export const Default: Story = {
47
58
  elevation: 2,
48
59
  theme: 'dark',
49
60
  },
50
- render: (args) => (
51
- <Surface {...args} style={{ padding: 24 }}>
52
- <Text style={{ color: '#fff' }}>Default Surface</Text>
53
- </Surface>
54
- ),
61
+ render: function Render(args) {
62
+ return (
63
+ <Surface {...args} style={{ padding: 24 }}>
64
+ <Text style={{ color: useOnSurfaceColor('primary') }}>Default Surface</Text>
65
+ </Surface>
66
+ )
67
+ },
68
+ }
69
+
70
+ /** On-surface elevation label — resolves from whichever Surface encloses it. */
71
+ function ElevationLabel({ level }: { level: ElevationLevel }) {
72
+ return <Text style={{ color: useOnSurfaceColor('primary') }}>Elevation {level}</Text>
55
73
  }
56
74
 
75
+ // Every level is a ramp plane. Negative levels recess, 0 sits flat on the page,
76
+ // 1–3 climb one plane each with the lift treatment, 4–5 float on overlay with a
77
+ // larger shadow. Rendered on a `base` page so the relative model has a host.
57
78
  export const ElevationLevels: Story = {
58
79
  render: () => (
59
- <View style={{ gap: 16, padding: 24 }}>
80
+ <Surface level="base" style={{ gap: 16, padding: 24 }}>
60
81
  {([-2, -1, 0, 1, 2, 3, 4, 5] as ElevationLevel[]).map((level) => (
61
82
  <Surface key={level} elevation={level} style={{ padding: 16 }}>
62
- <Text style={{ color: '#fff' }}>Elevation {level}</Text>
83
+ <ElevationLabel level={level} />
63
84
  </Surface>
64
85
  ))}
65
- </View>
86
+ </Surface>
66
87
  ),
67
88
  }
68
89
 
69
90
  export const WithGlow: Story = {
70
- render: () => (
71
- <View style={{ gap: 16, padding: 24 }}>
72
- <Surface elevation={2} glowColor="#FF7900" glowIntensity="subtle" style={{ padding: 16 }}>
73
- <Text style={{ color: '#fff' }}>Subtle Orange Glow</Text>
74
- </Surface>
75
- <Surface elevation={2} glowColor="#FF7900" glowIntensity="medium" style={{ padding: 16 }}>
76
- <Text style={{ color: '#fff' }}>Medium Orange Glow</Text>
77
- </Surface>
78
- <Surface elevation={2} glowColor="#FF7900" glowIntensity="strong" style={{ padding: 16 }}>
79
- <Text style={{ color: '#fff' }}>Strong Orange Glow</Text>
80
- </Surface>
81
- <Surface elevation={2} glowColor="#22C55E" glowIntensity="medium" style={{ padding: 16 }}>
82
- <Text style={{ color: '#fff' }}>Green Glow (Success)</Text>
83
- </Surface>
84
- <Surface elevation={2} glowColor="#EF4444" glowIntensity="medium" style={{ padding: 16 }}>
85
- <Text style={{ color: '#fff' }}>Red Glow (Error)</Text>
86
- </Surface>
87
- </View>
88
- ),
91
+ render: function Render() {
92
+ const onSurface = useOnSurfaceColor('primary')
93
+ return (
94
+ <View style={{ gap: 16, padding: 24 }}>
95
+ <Surface
96
+ elevation={2}
97
+ glowColor={primitiveRamps.orange[400]}
98
+ glowIntensity="subtle"
99
+ style={{ padding: 16 }}
100
+ >
101
+ <Text style={{ color: onSurface }}>Subtle Orange Glow</Text>
102
+ </Surface>
103
+ <Surface
104
+ elevation={2}
105
+ glowColor={primitiveRamps.orange[400]}
106
+ glowIntensity="medium"
107
+ style={{ padding: 16 }}
108
+ >
109
+ <Text style={{ color: onSurface }}>Medium Orange Glow</Text>
110
+ </Surface>
111
+ <Surface
112
+ elevation={2}
113
+ glowColor={primitiveRamps.orange[400]}
114
+ glowIntensity="strong"
115
+ style={{ padding: 16 }}
116
+ >
117
+ <Text style={{ color: onSurface }}>Strong Orange Glow</Text>
118
+ </Surface>
119
+ <Surface
120
+ elevation={2}
121
+ glowColor={semanticColorsDark['status-success']}
122
+ glowIntensity="medium"
123
+ style={{ padding: 16 }}
124
+ >
125
+ <Text style={{ color: onSurface }}>Green Glow (Success)</Text>
126
+ </Surface>
127
+ <Surface
128
+ elevation={2}
129
+ glowColor={semanticColorsDark['status-error']}
130
+ glowIntensity="medium"
131
+ style={{ padding: 16 }}
132
+ >
133
+ <Text style={{ color: onSurface }}>Red Glow (Error)</Text>
134
+ </Surface>
135
+ </View>
136
+ )
137
+ },
138
+ }
139
+
140
+ /** On-surface plane label — resolves from whichever Surface encloses it. */
141
+ function NamedPlaneLabel({ level }: { level: SurfaceLevel }) {
142
+ return <Text style={{ color: useOnSurfaceColor('primary') }}>level=&quot;{level}&quot;</Text>
89
143
  }
90
144
 
91
145
  // The named-plane model: flat, full-bleed grey planes straight from the
@@ -96,7 +150,7 @@ export const NamedPlanes: Story = {
96
150
  <View style={{ gap: 12, padding: 24 }}>
97
151
  {(['background', 'base', 'elevated', 'raised', 'overlay'] as SurfaceLevel[]).map((level) => (
98
152
  <Surface key={level} level={level} style={{ padding: 16 }}>
99
- <Text style={{ color: '#fff' }}>level=&quot;{level}&quot;</Text>
153
+ <NamedPlaneLabel level={level} />
100
154
  </Surface>
101
155
  ))}
102
156
  </View>
@@ -187,12 +241,17 @@ export const OnSurfaceText: Story = {
187
241
  ),
188
242
  }
189
243
 
244
+ /** On-surface elevation label for the forced-light demo below. */
245
+ function LightElevationLabel({ level }: { level: ElevationLevel }) {
246
+ return <Text style={{ color: useOnSurfaceColor('primary') }}>Light Elevation {level}</Text>
247
+ }
248
+
190
249
  export const LightTheme: Story = {
191
250
  render: () => (
192
- <View style={{ gap: 16, padding: 24, backgroundColor: '#F3F4F6' }}>
251
+ <View style={{ gap: 16, padding: 24, backgroundColor: semanticColorsLight['background-base'] }}>
193
252
  {([0, 1, 2, 3, 4, 5] as ElevationLevel[]).map((level) => (
194
253
  <Surface key={level} elevation={level} theme="light" style={{ padding: 16 }}>
195
- <Text style={{ color: '#111' }}>Light Elevation {level}</Text>
254
+ <LightElevationLabel level={level} />
196
255
  </Surface>
197
256
  ))}
198
257
  </View>
@@ -12,8 +12,21 @@ import {
12
12
  useSurfaceMode,
13
13
  } from './SurfaceContext'
14
14
  import { getSemanticColors } from '../../../theme/tokens/semantic'
15
+ import { greyRamp, primitiveColors } from '../../../theme/tokens/primitives'
15
16
  import { getPressedRecessShadow } from '../../../theme/elevation'
16
17
 
18
+ // Planes by RAMP STEP, never by literal bytes: a re-space of the grey ramp
19
+ // should move these expectations with it, not break them. Which step backs
20
+ // which plane is still asserted — that mapping is the behaviour.
21
+ const FRAME = greyRamp[975]
22
+ const BACKGROUND = greyRamp[950]
23
+ const BASE = greyRamp[925]
24
+ const ELEVATED = greyRamp[900]
25
+ const RAISED = greyRamp[875]
26
+ const OVERLAY = greyRamp[850]
27
+ const LIGHT_BASE = primitiveColors.white
28
+ const LIGHT_TEXT_PRIMARY = getSemanticColors('light')['text-primary']
29
+
17
30
  // A descendant probe that renders the on-surface colour + mode it resolves from
18
31
  // context, so tests can assert what a nested consumer would actually paint.
19
32
  function Probe({ role = 'primary' as const, label = 'probe' }) {
@@ -72,11 +85,56 @@ describe('Surface (card model)', () => {
72
85
  expect(screen.getByTestId('my-surface')).toBeInTheDocument()
73
86
  })
74
87
 
75
- it('paints the default flat dark card surface', () => {
88
+ it('sits flat on the inherited plane by default (dark base, no treatment)', () => {
76
89
  render(<Surface testID="s" />)
77
- // elevation 0 → base surface (surface-elevated) with no lightening.
78
- // TD-surface-tokens S-3 re-space: was #2A2827.
79
- expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: '#2C2A28' })
90
+ const el = screen.getByTestId('s')
91
+ expect(el).toHaveStyle({ backgroundColor: BASE })
92
+ expect(el.style.boxShadow).toBe('')
93
+ })
94
+
95
+ it('lifts onto ramp planes with rim + shadow: elevation 2 from the page is the card plane', () => {
96
+ render(<Surface elevation={2} testID="s" />)
97
+ const el = screen.getByTestId('s')
98
+ expect(el).toHaveStyle({ backgroundColor: RAISED })
99
+ expect(el.style.boxShadow).toContain('inset 0 1px 0')
100
+ expect(el.style.boxShadow).toMatch(/, 0 \d+px \d+px rgba\(0,0,0/)
101
+ })
102
+
103
+ it('raise is relative: one step up from an elevated host lands on raised', () => {
104
+ render(
105
+ <Surface level="elevated">
106
+ <Surface raise={1} testID="s" />
107
+ </Surface>
108
+ )
109
+ expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: RAISED })
110
+ })
111
+
112
+ it('clamps at overlay so raised-on-raised cannot leave the ramp', () => {
113
+ render(
114
+ <Surface level="overlay">
115
+ <Surface raise={2} testID="s" />
116
+ </Surface>
117
+ )
118
+ expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: OVERLAY })
119
+ })
120
+
121
+ it('floats on the overlay plane with a larger shadow and no ring', () => {
122
+ render(<Surface elevation={4} testID="s" />)
123
+ const el = screen.getByTestId('s')
124
+ expect(el).toHaveStyle({ backgroundColor: OVERLAY })
125
+ expect(el.style.boxShadow.split(', ').length).toBe(4)
126
+ expect(el.style.borderWidth).toBe('')
127
+ })
128
+
129
+ it('lets a caller switch the lift off on a raised plane, or on for a named one', () => {
130
+ render(
131
+ <>
132
+ <Surface raise={1} lift={false} testID="flat" />
133
+ <Surface level="raised" lift testID="lifted" />
134
+ </>
135
+ )
136
+ expect(screen.getByTestId('flat').style.boxShadow).toBe('')
137
+ expect(screen.getByTestId('lifted').style.boxShadow).toContain('inset 0 1px 0')
80
138
  })
81
139
 
82
140
  describe('accessibility', () => {
@@ -94,10 +152,10 @@ describe('Surface (card model)', () => {
94
152
 
95
153
  describe('Surface (named plane)', () => {
96
154
  it.each([
97
- ['background', '#1C1916'],
98
- ['base', '#252321'],
99
- ['elevated', '#2C2A28'],
100
- ['raised', '#31302F'],
155
+ ['background', BACKGROUND],
156
+ ['base', BASE],
157
+ ['elevated', ELEVATED],
158
+ ['raised', RAISED],
101
159
  ] as const)('maps level %s to the surface-ramp token %s', (level, hex) => {
102
160
  render(<Surface level={level} testID="s" />)
103
161
  expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: hex })
@@ -105,7 +163,7 @@ describe('Surface (named plane)', () => {
105
163
 
106
164
  it('resolves the light-mode background when theme is overridden', () => {
107
165
  render(<Surface level="base" theme="light" testID="s" />)
108
- expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: '#FFFFFF' })
166
+ expect(screen.getByTestId('s')).toHaveStyle({ backgroundColor: LIGHT_BASE })
109
167
  })
110
168
 
111
169
  it('lets a caller style override the owned background', () => {
@@ -134,12 +192,12 @@ function lstar(hex: string): number {
134
192
 
135
193
  describe('Surface (pressed well)', () => {
136
194
  it.each([
137
- // TD-surface-tokens S-3 re-space: top steps widened (elevated #2C2A28,
138
- // raised #31302F, overlay #373635); base/background unchanged.
139
- ['overlay', '#373635', '#31302F'], // → raised
140
- ['raised', '#31302F', '#2C2A28'], // → elevated
141
- ['elevated', '#2C2A28', '#252321'], // → base
142
- ['base', '#252321', '#1C1916'], // → background
195
+ // TD-surface-tokens S-3 re-space widened the top steps; base and
196
+ // background were unchanged. The pairs below are ramp-adjacent by index.
197
+ ['overlay', OVERLAY, RAISED], // → raised
198
+ ['raised', RAISED, ELEVATED], // → elevated
199
+ ['elevated', ELEVATED, BASE], // → base
200
+ ['base', BASE, BACKGROUND], // → background
143
201
  ] as const)(
144
202
  'in a %s parent renders one ramp step down (%s → %s), darker than its parent',
145
203
  (parent, parentHex, pressedHex) => {
@@ -155,7 +213,7 @@ describe('Surface (pressed well)', () => {
155
213
 
156
214
  it('with no enclosing Surface (default base) presses to the background plane', () => {
157
215
  render(<Surface pressed testID="well" />)
158
- expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: '#1C1916' })
216
+ expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: BACKGROUND })
159
217
  })
160
218
 
161
219
  it('clamps at the frame floor: pressed directly in background does not underflow', () => {
@@ -164,8 +222,8 @@ describe('Surface (pressed well)', () => {
164
222
  <Surface pressed testID="well" />
165
223
  </Surface>
166
224
  )
167
- // background (#1C1916) steps down to the frame floor (#100D0A), the bezel.
168
- expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: '#100D0A' })
225
+ // background steps down to the frame floor, the bezel.
226
+ expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: FRAME })
169
227
  })
170
228
 
171
229
  it('does not step below the floor: pressed within a floor-pressed well stays at frame', () => {
@@ -176,7 +234,7 @@ describe('Surface (pressed well)', () => {
176
234
  </Surface>
177
235
  </Surface>
178
236
  )
179
- expect(screen.getByTestId('deeper')).toHaveStyle({ backgroundColor: '#100D0A' })
237
+ expect(screen.getByTestId('deeper')).toHaveStyle({ backgroundColor: FRAME })
180
238
  })
181
239
 
182
240
  it('publishes the stepped-down level to descendants so a nested press steps again', () => {
@@ -209,8 +267,8 @@ describe('Surface (pressed well)', () => {
209
267
  <Surface pressed testID="well" style={{ boxShadow: undefined }} />
210
268
  </Surface>
211
269
  )
212
- expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: '#1C1916' })
213
- expect(lstar('#1C1916')).toBeLessThan(lstar('#252321'))
270
+ expect(screen.getByTestId('well')).toHaveStyle({ backgroundColor: BACKGROUND })
271
+ expect(lstar(BACKGROUND)).toBeLessThan(lstar(BASE))
214
272
  })
215
273
 
216
274
  it('rounds the well by default and honours an explicit rounded override', () => {
@@ -240,7 +298,7 @@ describe('pressedLevel helper', () => {
240
298
 
241
299
  describe('getPressedRecessShadow', () => {
242
300
  it('returns an inset recess tuned to the fill colour on the web path', () => {
243
- const style = getPressedRecessShadow('#1C1916', 'dark') as { boxShadow?: string }
301
+ const style = getPressedRecessShadow(BACKGROUND, 'dark') as { boxShadow?: string }
244
302
  expect(style.boxShadow).toContain('inset')
245
303
  })
246
304
  })
@@ -262,7 +320,9 @@ describe('Surface on-surface colour context', () => {
262
320
 
263
321
  it('resolves dark on-surface colours even with no enclosing Surface', () => {
264
322
  render(<Probe role="primary" label="p" />)
265
- expect(screen.getByTestId('p')).toHaveStyle({ color: getSemanticColors('dark')['text-primary'] })
323
+ expect(screen.getByTestId('p')).toHaveStyle({
324
+ color: getSemanticColors('dark')['text-primary'],
325
+ })
266
326
  })
267
327
 
268
328
  it('flows an overridden theme to descendant text', () => {
@@ -271,7 +331,7 @@ describe('Surface on-surface colour context', () => {
271
331
  <Probe role="primary" label="p" />
272
332
  </Surface>
273
333
  )
274
- expect(screen.getByTestId('p')).toHaveStyle({ color: '#121828' })
334
+ expect(screen.getByTestId('p')).toHaveStyle({ color: LIGHT_TEXT_PRIMARY })
275
335
  expect(screen.getByTestId('p')).toHaveTextContent('light')
276
336
  })
277
337
 
@@ -283,15 +343,15 @@ describe('Surface on-surface colour context', () => {
283
343
  </Surface>
284
344
  </Surface>
285
345
  )
286
- expect(screen.getByTestId('p')).toHaveStyle({ color: '#121828' })
346
+ expect(screen.getByTestId('p')).toHaveStyle({ color: LIGHT_TEXT_PRIMARY })
287
347
  })
288
348
  })
289
349
 
290
350
  describe('surface colour helpers', () => {
291
351
  it('surfaceBackground returns literal hex per level + mode', () => {
292
- expect(surfaceBackground('elevated', 'dark')).toBe('#2C2A28')
293
- expect(surfaceBackground('background', 'dark')).toBe('#1C1916')
294
- expect(surfaceBackground('base', 'light')).toBe('#FFFFFF')
352
+ expect(surfaceBackground('elevated', 'dark')).toBe(ELEVATED)
353
+ expect(surfaceBackground('background', 'dark')).toBe(BACKGROUND)
354
+ expect(surfaceBackground('base', 'light')).toBe(LIGHT_BASE)
295
355
  })
296
356
 
297
357
  it('resolves the frame floor from its own semantic token', () => {