@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,57 +1,14 @@
1
1
  import React, { useMemo } from 'react'
2
- import { View, type ViewProps, type ViewStyle } from 'react-native'
2
+ import { View, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
- import { type ThemeMode } from '../../../theme/tokens/semantic'
5
- import {
6
- type ElevationLevel,
7
- getElevationSurface,
8
- getElevationShadow,
9
- getPressedRecessShadow,
10
- getBaseSurfaceColor,
11
- type GlowIntensity,
12
- getGlowShadow,
13
- } from '../../../theme/elevation'
14
- import {
15
- SurfaceContext,
16
- surfaceBackground,
17
- pressedLevel,
18
- useSurface,
19
- type SurfaceContextValue,
20
- type SurfaceLevel,
21
- } from './SurfaceContext'
4
+ import { type GlowIntensity, getGlowShadow } from '../../../theme/elevation'
5
+ import { SurfaceContext, type SurfaceContextValue } from './SurfaceContext'
6
+ import { useResolvedSurface, type SurfaceDepthProps } from './resolveSurface'
22
7
 
23
- export interface SurfaceProps extends ViewProps {
24
- /**
25
- * Numeric depth → a computed lighten + shadow (the raised-card model). The
26
- * background is derived from the base surface by lightening. Ignored for the
27
- * background when `level` is set. Default 0 (flat card).
28
- */
29
- elevation?: ElevationLevel
30
- /**
31
- * Named grey plane (shell / rail / stage). Sets the background directly
32
- * from a semantic surface token — reaching the darker nav/page planes the
33
- * lighten model can't — and drops the default rounding + auto shadow so the
34
- * plane reads full-bleed. Composable with `elevation`'s glow.
35
- */
36
- level?: SurfaceLevel
37
- /**
38
- * Sunken "well": render ONE ramp step DOWN from the parent surface's level —
39
- * the symmetric twin of a raised surface stepping up — and add an inner-shadow
40
- * recess so the surface reads pressed (darker fill + inset shadow). Relative to
41
- * the enclosing Surface's level (not this surface's own `level`), and clamped
42
- * at the ramp's `inset` floor so it never underflows. One level of depth only.
43
- */
44
- pressed?: boolean
8
+ export interface SurfaceProps extends ViewProps, SurfaceDepthProps {
45
9
  glowColor?: string
46
10
  glowIntensity?: GlowIntensity
47
- /**
48
- * Theme mode. Also seeds the on-surface colour CONTEXT so descendant text /
49
- * icons resolve their colour from this surface instead of a `text-*` className
50
- * that silently fails to black on raw RN. Inherits the nearest Surface /
51
- * ThemeProvider when omitted (default dark — the wall).
52
- */
53
- theme?: ThemeMode
54
- /** Round the corners. Defaults on for the card model, off for a `level` plane. */
11
+ /** Round the corners. Defaults on for a lifted or pressed surface, off for an absolute plane. */
55
12
  rounded?: boolean
56
13
  className?: string
57
14
  children?: React.ReactNode
@@ -59,17 +16,23 @@ export interface SurfaceProps extends ViewProps {
59
16
 
60
17
  /**
61
18
  * A container that OWNS its background and establishes an on-surface colour
62
- * context. Two grounded ways to pick the background:
63
- * - `elevation` (numeric): the raised-card model lighten-from-base + shadow.
64
- * - `level` (named): a flat grey plane straight from a semantic token,
65
- * for the shell / rail / stage backgrounds.
66
- * Either way, descendants read the surface via {@link useOnSurfaceColor} /
67
- * {@link useSurfaceMode} rather than hard-coding `getSemanticColors('dark')`.
19
+ * context. Depth is relative to the enclosing Surface:
20
+ * - `raise` / positive `elevation`: step up the ramp and wear the lift
21
+ * treatment (rim-light + ambient shadow). Clamps at `overlay`.
22
+ * - `pressed` / negative `elevation`: step down with an inner-shadow recess.
23
+ * - `level` (absolute): a flat grey plane straight from a token, for shell
24
+ * roots only (shell = background, page = base). No lift.
25
+ * - nothing: sit flat on the inherited plane.
26
+ * Descendants read the surface via {@link useOnSurfaceColor} / {@link useSurfaceMode}
27
+ * rather than hard-coding `getSemanticColors('dark')`.
68
28
  */
69
29
  export function Surface({
70
- elevation = 0,
30
+ elevation,
71
31
  level,
32
+ raise,
72
33
  pressed = false,
34
+ lift,
35
+ liftOptions,
73
36
  glowColor,
74
37
  glowIntensity,
75
38
  theme,
@@ -79,39 +42,21 @@ export function Surface({
79
42
  children,
80
43
  ...props
81
44
  }: SurfaceProps) {
82
- const inherited = useSurface()
83
- const mode = theme ?? inherited.mode
84
- const isPlane = level != null
85
-
86
- // Three grounded ways to own a background, in precedence order:
87
- // - pressed: a well ONE ramp step DOWN from the parent level (relative),
88
- // with an inner-shadow recess — clamps at the `inset` floor.
89
- // - level (named plane): a flat grey plane straight from a token.
90
- // - elevation (numeric): the raised-card model — lighten-from-base + shadow.
91
- const baseColor = getBaseSurfaceColor(mode)
92
- const resolvedLevel = pressed ? pressedLevel(inherited.level) : (level ?? inherited.level)
93
-
94
- let backgroundColor: string
95
- let shadowStyle: ViewStyle
96
- if (pressed) {
97
- backgroundColor = surfaceBackground(resolvedLevel, mode)
98
- shadowStyle = getPressedRecessShadow(backgroundColor, mode)
99
- } else if (isPlane) {
100
- backgroundColor = surfaceBackground(level, mode)
101
- // Planes own a flat full-bleed background — no depth shadow.
102
- shadowStyle = {}
103
- } else {
104
- backgroundColor = getElevationSurface(baseColor, elevation, mode)
105
- shadowStyle = getElevationShadow(baseColor, elevation, mode)
106
- }
107
-
45
+ const resolved = useResolvedSurface({
46
+ elevation,
47
+ level,
48
+ raise,
49
+ pressed,
50
+ lift,
51
+ liftOptions,
52
+ theme,
53
+ })
108
54
  const glowStyle = glowColor ? getGlowShadow(glowColor, glowIntensity) : {}
109
- // A pressed well and the card model round by default; a flat plane doesn't.
110
- const applyRounded = rounded ?? (pressed || !isPlane)
55
+ const applyRounded = rounded ?? (pressed || level == null)
111
56
 
112
57
  const value = useMemo<SurfaceContextValue>(
113
- () => ({ mode, level: resolvedLevel }),
114
- [mode, resolvedLevel]
58
+ () => ({ mode: resolved.mode, level: resolved.plane }),
59
+ [resolved.mode, resolved.plane]
115
60
  )
116
61
 
117
62
  return (
@@ -119,7 +64,12 @@ export function Surface({
119
64
  <View
120
65
  className={cn(applyRounded && 'rounded-2xl', className)}
121
66
  // backgroundColor first so a caller `style` can still override it.
122
- style={[{ backgroundColor }, shadowStyle, glowStyle, style]}
67
+ style={[
68
+ { backgroundColor: resolved.backgroundColor },
69
+ resolved.depthStyle,
70
+ glowStyle,
71
+ style,
72
+ ]}
123
73
  {...props}
124
74
  >
125
75
  {children}
@@ -1,52 +1,31 @@
1
1
  // On-surface colour context (TD-05.12).
2
2
  //
3
- // A <Surface> owns a background from a small elevation scale AND publishes the
4
- // current theme mode so descendant text/icons resolve their colour from "what
5
- // surface am I on" instead of a `text-*` className. Those classNames silently
6
- // fail to black when the tree renders as raw RN in the standalone wall SPA
7
- // (no global.css, no nativewind) the bug class this primitive retires.
3
+ // A <Surface> owns a background from the surface ramp AND publishes the current
4
+ // theme mode so descendant text/icons resolve their colour from "what surface am
5
+ // I on" instead of a `text-*` className. Those classNames silently fail to black
6
+ // when the tree renders as raw RN in the standalone wall SPA (no global.css, no
7
+ // nativewind), which is the bug class this primitive retires.
8
8
  import { createContext, useContext } from 'react'
9
9
  import { getSemanticColors, type ThemeMode } from '../../../theme/tokens/semantic'
10
+ import type { SurfaceLevel } from '../../../theme/surface-planes'
10
11
 
11
- type ColorToken = keyof ReturnType<typeof getSemanticColors>
12
+ // The plane vocabulary lives in the theme so `elevation.ts` can resolve levels
13
+ // to planes without importing a component. Re-exported here for callers that
14
+ // reached it through the Surface module.
15
+ export {
16
+ SURFACE_LEVEL_TOKEN,
17
+ PLANE_ORDER,
18
+ surfaceBackground,
19
+ pressedLevel,
20
+ raisedLevel,
21
+ type SurfaceLevel,
22
+ } from '../../../theme/surface-planes'
12
23
 
13
- /**
14
- * A Surface's depth on the dark surface ramp. Each addressable level maps to an
15
- * EXISTING semantic surface/background token (already grounded in the derived
16
- * surface ramp — TD-surface-tokens S-1 — and theme-aware) — Surface introduces
17
- * no new hexes. Darkest → lightest:
18
- * inset (#13100D) < background (#1C1916) < base (#252321) < elevated (#2A2827) < raised (#2D2C2B) < overlay (#302F2E)
19
- *
20
- * `frame` is the bezel the ramp sits inside — the top bar / side nav chrome —
21
- * and the floor a `<Surface pressed>` clamps at (see {@link pressedLevel}).
22
- *
23
- * It replaced a separate `inset` level in TD-07.14. That level was RETIRED, not
24
- * renamed: at ΔE 1.10 from the frame it was an imperceptible duplicate, which is
25
- * exactly why pressed (surface − 1) kept collapsing into it.
26
- */
27
- export type SurfaceLevel = 'frame' | 'background' | 'base' | 'elevated' | 'raised' | 'overlay'
24
+ type ColorToken = keyof ReturnType<typeof getSemanticColors>
28
25
 
29
26
  /** On-surface neutral text roles, resolved for the current surface + theme. */
30
27
  export type OnSurfaceRole = 'primary' | 'secondary' | 'tertiary'
31
28
 
32
- // Which semantic token backs each level. Values live in `semantic.ts` and stay
33
- // in sync with the grey ramp — this map never carries literal hexes. Every level
34
- // is present now: swapping `inset` (which had no token) for `frame` (which does)
35
- // is what made this a total map and removed `surfaceBackground`'s special case.
36
- export const SURFACE_LEVEL_TOKEN = {
37
- frame: 'background-frame',
38
- background: 'background-base',
39
- base: 'surface-base',
40
- elevated: 'surface-elevated',
41
- raised: 'surface-raised',
42
- overlay: 'surface-overlay',
43
- } as const satisfies Record<SurfaceLevel, ColorToken>
44
-
45
- // Darkest → lightest. A `<Surface pressed>` renders one index DOWN from its
46
- // parent's level and clamps at `frame` (index 0). Kept in lockstep with the grey
47
- // ramp and the surface.contract.test PLANE_ORDER.
48
- const PRESSED_RAMP = ['frame', 'background', 'base', 'elevated', 'raised', 'overlay'] as const
49
-
50
29
  const ON_SURFACE_TOKEN = {
51
30
  primary: 'text-primary',
52
31
  secondary: 'text-secondary',
@@ -56,7 +35,7 @@ const ON_SURFACE_TOKEN = {
56
35
  export interface SurfaceContextValue {
57
36
  /** Active theme mode. Defaults to dark (the wall). */
58
37
  mode: ThemeMode
59
- /** Depth of the nearest enclosing Surface. */
38
+ /** Plane of the nearest enclosing Surface. */
60
39
  level: SurfaceLevel
61
40
  }
62
41
 
@@ -78,9 +57,9 @@ export function useSurfaceMode(): ThemeMode {
78
57
 
79
58
  /**
80
59
  * Literal-hex on-surface neutral text colours for a theme mode. Uses
81
- * `getSemanticColors` (literal hex — the TempoBar pattern), never `resolveColor`
82
- * (which returns `var()` under the RNW vitest alias), so values stay real in
83
- * tested component code and on raw-RN surfaces alike.
60
+ * `getSemanticColors` (literal hex), never `resolveColor` (which returns `var()`
61
+ * under the RNW vitest alias), so values stay real in tested component code and
62
+ * on raw-RN surfaces alike.
84
63
  */
85
64
  export function onSurfaceColors(mode: ThemeMode): Record<OnSurfaceRole, string> {
86
65
  const c = getSemanticColors(mode)
@@ -95,22 +74,3 @@ export function onSurfaceColors(mode: ThemeMode): Record<OnSurfaceRole, string>
95
74
  export function useOnSurfaceColor(role: OnSurfaceRole = 'primary'): string {
96
75
  return getSemanticColors(useSurfaceMode())[ON_SURFACE_TOKEN[role]]
97
76
  }
98
-
99
- /** The background hex for a surface level under a theme mode (literal hex). */
100
- export function surfaceBackground(level: SurfaceLevel, mode: ThemeMode): string {
101
- return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]]
102
- }
103
-
104
- /**
105
- * The level a `<Surface pressed>` resolves to: its parent's level stepped one
106
- * index DOWN the ramp — the symmetric twin of a raised surface stepping up —
107
- * clamped at the `frame` floor so a pressed surface never underflows the bezel.
108
- * overlay→raised, raised→elevated, elevated→base, base→background,
109
- * background→frame, frame→frame (clamped).
110
- * Pressed exposes ONE level of depth only (no pressed-2).
111
- */
112
- export function pressedLevel(parent: SurfaceLevel): SurfaceLevel {
113
- const index = PRESSED_RAMP.indexOf(parent)
114
- const down = Math.max(0, index - 1)
115
- return PRESSED_RAMP[down]
116
- }
@@ -1,4 +1,10 @@
1
1
  export { Surface, type SurfaceProps } from './Surface'
2
+ export {
3
+ resolveSurfaceDepth,
4
+ useResolvedSurface,
5
+ type SurfaceDepthProps,
6
+ type ResolvedSurface,
7
+ } from './resolveSurface'
2
8
  export {
3
9
  SurfaceContext,
4
10
  useSurface,
@@ -7,7 +13,9 @@ export {
7
13
  onSurfaceColors,
8
14
  surfaceBackground,
9
15
  pressedLevel,
16
+ raisedLevel,
10
17
  SURFACE_LEVEL_TOKEN,
18
+ PLANE_ORDER,
11
19
  type SurfaceLevel,
12
20
  type OnSurfaceRole,
13
21
  type SurfaceContextValue,
@@ -0,0 +1,98 @@
1
+ // How a container decides which plane it sits on and what it wears there.
2
+ //
3
+ // One resolution path shared by <Surface> and <Card>, so the two can never
4
+ // disagree about depth. Everything is RELATIVE to the enclosing Surface unless
5
+ // an absolute `level` names a shell root.
6
+ import { useMemo } from 'react'
7
+ import type { ViewStyle } from 'react-native'
8
+ import {
9
+ FLOATING_ELEVATION_MIN,
10
+ getPressedRecessShadow,
11
+ type ElevationLevel,
12
+ } from '../../../theme/elevation'
13
+ import { liftStyle, type LiftOptions, type LiftStep } from '../../../theme/lift'
14
+ import {
15
+ pressedLevel,
16
+ raisedLevel,
17
+ surfaceBackground,
18
+ type SurfaceLevel,
19
+ } from '../../../theme/surface-planes'
20
+ import type { ThemeMode } from '../../../theme/tokens/semantic'
21
+ import { useSurface, type SurfaceContextValue } from './SurfaceContext'
22
+
23
+ export interface SurfaceDepthProps {
24
+ /** Absolute plane, for shell roots (shell = background, page = base). No lift. */
25
+ level?: SurfaceLevel
26
+ /** Planes to step UP from the enclosing Surface, with the lift treatment. */
27
+ raise?: 1 | 2 | 3
28
+ /**
29
+ * Numeric depth relative to the enclosing Surface: negative recesses, 0 sits
30
+ * flat on the same plane, 1–3 lift, 4–5 float on the overlay plane.
31
+ */
32
+ elevation?: ElevationLevel
33
+ /** One plane DOWN with an inner-shadow recess. */
34
+ pressed?: boolean
35
+ /** Force the lift treatment on or off regardless of the step taken. */
36
+ lift?: boolean
37
+ /** Tune the lift (rim alpha). Specimens and hero surfaces only. */
38
+ liftOptions?: LiftOptions
39
+ /** Override the inherited theme mode. */
40
+ theme?: ThemeMode
41
+ }
42
+
43
+ export interface ResolvedSurface {
44
+ mode: ThemeMode
45
+ plane: SurfaceLevel
46
+ backgroundColor: string
47
+ /** Recess or lift, to compose after `backgroundColor`. */
48
+ depthStyle: ViewStyle
49
+ /** Planes stepped up (0 when flat, pressed, or an absolute plane). */
50
+ step: number
51
+ lifted: boolean
52
+ }
53
+
54
+ function recessDepth(inherited: SurfaceContextValue, planesDown: number, mode: ThemeMode) {
55
+ let plane = inherited.level
56
+ for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane)
57
+ const backgroundColor = surfaceBackground(plane, mode)
58
+ return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) }
59
+ }
60
+
61
+ /** Pure resolution: the plane, its hex, and the treatment. */
62
+ export function resolveSurfaceDepth(
63
+ inherited: SurfaceContextValue,
64
+ props: SurfaceDepthProps
65
+ ): ResolvedSurface {
66
+ const mode = props.theme ?? inherited.mode
67
+ const elevation = props.elevation ?? 0
68
+ if (props.pressed || elevation < 0) {
69
+ const down = props.pressed ? 1 : -elevation
70
+ return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) }
71
+ }
72
+ const step = props.level != null ? 0 : (props.raise ?? elevation)
73
+ const floating = step >= FLOATING_ELEVATION_MIN
74
+ const plane = props.level ?? (floating ? 'overlay' : raisedLevel(inherited.level, step))
75
+ const lifted = props.lift ?? step > 0
76
+ const liftStep = Math.max(1, Math.min(5, step)) as LiftStep
77
+ const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {}
78
+ return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted }
79
+ }
80
+
81
+ /** The resolved depth of a container at this point in the tree. */
82
+ export function useResolvedSurface(props: SurfaceDepthProps): ResolvedSurface {
83
+ const inherited = useSurface()
84
+ const { level, raise, elevation, pressed, lift, liftOptions, theme } = props
85
+ return useMemo(
86
+ () =>
87
+ resolveSurfaceDepth(inherited, {
88
+ level,
89
+ raise,
90
+ elevation,
91
+ pressed,
92
+ lift,
93
+ liftOptions,
94
+ theme,
95
+ }),
96
+ [inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
97
+ )
98
+ }
@@ -8,7 +8,8 @@ import { getSemanticColors } from '../../../theme/tokens/semantic'
8
8
  * palette locks its eligibility mask with a value-level test.
9
9
  *
10
10
  * Scope: DARK mode only. The north-star diagnosis
11
- * (sources/design/surface-system-north-star.md) measured and
11
+ * (`sources/design/surface-system-north-star.md`, in the `voltras-workspace`
12
+ * active-work initiative rather than this repo) measured and
12
13
  * fixed the dark ramp specifically; light mode has its own latent collisions
13
14
  * (e.g. `surface-overlay` === `surface-base`, both `#FFFFFF`) that were never
14
15
  * part of this investigation — flagged as a follow-up, not silently patched
@@ -91,6 +92,10 @@ describe('surface ramp contract (dark) — token-value guardrails', () => {
91
92
  // Locked values from surface-system-north-star.md (re-spaced S-3) — see
92
93
  // surfaceRampDark in primitives.ts for the derivation this must match
93
94
  // byte-for-byte. background/base are unchanged by the re-space.
95
+ //
96
+ // The literal hexes are the POINT of this one test: it pins the bytes, so a
97
+ // re-space has to come here and say so. Every other test in the suite
98
+ // references the ramp instead.
94
99
  expect(dark['background-frame']).toBe('#100D0A')
95
100
  expect(dark['background-base']).toBe('#1C1916')
96
101
  expect(dark['surface-base']).toBe('#252321')
@@ -5,7 +5,7 @@ import { Switch } from './Switch'
5
5
  const meta: Meta<typeof Switch> = {
6
6
  title: 'Components/Molecules/Switch',
7
7
  component: Switch,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  isChecked: {
11
11
  control: 'boolean',
@@ -1,6 +1,8 @@
1
1
  import React, { forwardRef } from 'react'
2
2
  import { Pressable, View, Text, type PressableProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
+ import { liftStyle } from '../../../theme/lift'
5
+ import { useSurfaceMode } from '../surface'
4
6
 
5
7
  export type SwitchSize = 'sm' | 'md' | 'lg'
6
8
 
@@ -51,6 +53,7 @@ export const Switch = forwardRef<View, SwitchProps>(function Switch(
51
53
  ref
52
54
  ) {
53
55
  const styles = sizeStyles[size]
56
+ const mode = useSurfaceMode()
54
57
 
55
58
  const handlePress = () => {
56
59
  if (!isDisabled) {
@@ -66,12 +69,14 @@ export const Switch = forwardRef<View, SwitchProps>(function Switch(
66
69
  isChecked ? 'bg-brand-primary' : 'bg-hairline-strong'
67
70
  )}
68
71
  >
72
+ {/* The thumb is a raised control resting in its track: one plane of lift. */}
69
73
  <View
70
74
  className={cn(
71
- 'rounded-full bg-white shadow-sm transition-transform',
75
+ 'rounded-full bg-on-brand-primary transition-transform',
72
76
  styles.thumb,
73
77
  isChecked && styles.translate
74
78
  )}
79
+ style={liftStyle(1, mode)}
75
80
  />
76
81
  </View>
77
82
  )
@@ -84,11 +89,7 @@ export const Switch = forwardRef<View, SwitchProps>(function Switch(
84
89
  accessibilityRole="switch"
85
90
  accessibilityState={{ checked: isChecked, disabled: isDisabled }}
86
91
  accessibilityLabel={label}
87
- className={cn(
88
- 'flex-row items-center gap-2',
89
- isDisabled && 'opacity-50',
90
- className
91
- )}
92
+ className={cn('flex-row items-center gap-2', isDisabled && 'opacity-50', className)}
92
93
  {...props}
93
94
  >
94
95
  {label && labelPosition === 'left' && (
@@ -5,7 +5,7 @@ import { Tabs, TabList, Tab, TabPanels, TabPanel } from './Tabs'
5
5
  const meta: Meta<typeof Tabs> = {
6
6
  title: 'Components/Molecules/Tabs',
7
7
  component: Tabs,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  variant: {
11
11
  control: 'select',
@@ -75,10 +75,7 @@ export function Tabs({
75
75
  return (
76
76
  <TabsContext.Provider value={{ activeIndex, setActiveIndex, variant, orientation }}>
77
77
  <View
78
- className={cn(
79
- orientation === 'vertical' ? 'flex-row' : 'flex-col',
80
- className
81
- )}
78
+ className={cn(orientation === 'vertical' ? 'flex-row' : 'flex-col', className)}
82
79
  {...props}
83
80
  >
84
81
  {children}
@@ -99,9 +96,7 @@ export function TabList({ children, className }: TabListProps) {
99
96
  const { variant, orientation } = useContext(TabsContext)
100
97
 
101
98
  const variantStyles = {
102
- line: orientation === 'horizontal'
103
- ? 'border-b border-hairline'
104
- : 'border-r border-hairline',
99
+ line: orientation === 'horizontal' ? 'border-b border-hairline' : 'border-r border-hairline',
105
100
  enclosed: 'bg-surface-raised rounded-lg p-1',
106
101
  'soft-rounded': 'bg-surface-raised rounded-full p-1',
107
102
  }
@@ -151,12 +146,7 @@ export interface TabProps {
151
146
  /**
152
147
  * Individual tab button.
153
148
  */
154
- export function Tab({
155
- index = 0,
156
- isDisabled = false,
157
- className,
158
- children,
159
- }: TabProps) {
149
+ export function Tab({ index = 0, isDisabled = false, className, children }: TabProps) {
160
150
  const { activeIndex, setActiveIndex, variant, orientation } = useContext(TabsContext)
161
151
  const isActive = activeIndex === index
162
152
 
@@ -170,16 +160,17 @@ export function Tab({
170
160
  ? 'border-brand-primary text-brand-primary'
171
161
  : 'border-transparent text-text-secondary web:hover:text-text-primary'
172
162
  ),
163
+ // The active enclosed tab is an indicator, not a plane: tone alone marks it.
173
164
  enclosed: cn(
174
165
  'px-4 py-2 rounded-md',
175
166
  isActive
176
- ? 'bg-surface-elevated text-text-primary shadow-sm'
167
+ ? 'bg-surface-elevated text-text-primary'
177
168
  : 'text-text-secondary web:hover:text-text-primary'
178
169
  ),
179
170
  'soft-rounded': cn(
180
171
  'px-4 py-2 rounded-full',
181
172
  isActive
182
- ? 'bg-brand-primary text-white'
173
+ ? 'bg-brand-primary text-on-brand-primary'
183
174
  : 'text-text-secondary web:hover:text-text-primary'
184
175
  ),
185
176
  }
@@ -202,7 +193,7 @@ export function Tab({
202
193
  'font-medium',
203
194
  isActive
204
195
  ? variant === 'soft-rounded'
205
- ? 'text-white'
196
+ ? 'text-on-brand-primary'
206
197
  : 'text-text-primary'
207
198
  : 'text-text-secondary'
208
199
  )}
@@ -245,9 +236,5 @@ export interface TabPanelProps {
245
236
  * Individual tab panel content.
246
237
  */
247
238
  export function TabPanel({ children, className }: TabPanelProps) {
248
- return (
249
- <View className={cn('py-4', className)}>
250
- {children}
251
- </View>
252
- )
239
+ return <View className={cn('py-4', className)}>{children}</View>
253
240
  }
@@ -1,10 +1,4 @@
1
- export {
2
- Tabs,
3
- TabList,
4
- Tab,
5
- TabPanels,
6
- TabPanel,
7
- } from './Tabs'
1
+ export { Tabs, TabList, Tab, TabPanels, TabPanel } from './Tabs'
8
2
  export type {
9
3
  TabsProps,
10
4
  TabListProps,
@@ -9,7 +9,7 @@ const SUCCESS = getSemanticColors('dark')['status-success']
9
9
  const meta: Meta<typeof Tile> = {
10
10
  title: 'Components/Atoms/Tile',
11
11
  component: Tile,
12
- tags: ['autodocs'],
12
+ tags: ['autodocs', 'status:candidate', '!status:review'],
13
13
  parameters: {
14
14
  docs: {
15
15
  description: {
@@ -23,6 +23,9 @@ export interface TileProps extends ViewProps {
23
23
  * @example
24
24
  * <Tile label="Volume" value="76%" />
25
25
  * <Tile label="Fatigue" value="MOD" valueColor="#F5A623" />
26
+ *
27
+ * @deprecated Use the `Card` stat preset (roadmap decision 1) — removed after
28
+ * AW-127 consumer migration.
26
29
  */
27
30
  export function Tile({
28
31
  label,
@@ -6,7 +6,7 @@ import { Button, ButtonText } from '../button'
6
6
  const meta: Meta<typeof Toast> = {
7
7
  title: 'Components/Molecules/Toast',
8
8
  component: Toast,
9
- tags: ['autodocs'],
9
+ tags: ['autodocs', 'status:stable', '!status:review'],
10
10
  argTypes: {
11
11
  status: {
12
12
  control: 'select',
@@ -90,11 +90,7 @@ describe('ToastProvider', () => {
90
90
  const { addToast, removeAllToasts } = useToast()
91
91
  return (
92
92
  <div>
93
- <button
94
- onClick={() =>
95
- addToast({ title: 'New Toast', status: 'success' })
96
- }
97
- >
93
+ <button onClick={() => addToast({ title: 'New Toast', status: 'success' })}>
98
94
  Add Toast
99
95
  </button>
100
96
  <button onClick={removeAllToasts}>Clear All</button>
@@ -179,9 +175,7 @@ describe('ToastProvider', () => {
179
175
  return null
180
176
  }
181
177
 
182
- expect(() => render(<BadConsumer />)).toThrow(
183
- 'useToast must be used within a ToastProvider'
184
- )
178
+ expect(() => render(<BadConsumer />)).toThrow('useToast must be used within a ToastProvider')
185
179
  })
186
180
 
187
181
  describe('positions', () => {