@titan-design/react-ui 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. package/README.md +60 -47
  2. package/dist/bodymap.js +856 -736
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +858 -738
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1431 -237
  7. package/dist/index.d.ts +1431 -237
  8. package/dist/index.js +6506 -4781
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +6280 -4642
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
  13. package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1919 -1937
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1927 -1945
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +225 -140
  21. package/dist/theme/index.d.ts +225 -140
  22. package/dist/theme/index.js +298 -319
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +283 -315
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +145 -24
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +145 -24
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +128 -11
  31. package/dist/theme/tokens.d.ts +128 -11
  32. package/dist/theme/tokens.js +126 -26
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +124 -27
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/docs/render-testing-pattern.md +130 -0
  40. package/package.json +1 -1
  41. package/src/arch/Architecture.stories.tsx +3 -1
  42. package/src/arch/arch-graph.freshness.test.ts +52 -0
  43. package/src/arch/arch-graph.json +4989 -1583
  44. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  45. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  46. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  48. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  49. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  51. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  52. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  54. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  55. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  57. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  58. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  60. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  61. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  63. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  64. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  66. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  67. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  69. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  70. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  71. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  73. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  74. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  76. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  77. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  78. package/src/components/custom/ActiveWork/README.md +305 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  80. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  81. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  82. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  83. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  84. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  86. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  87. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  88. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  90. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  91. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  92. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  93. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  94. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  95. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  96. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  97. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  98. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  99. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  100. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  101. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  102. package/src/components/custom/ActiveWork/index.ts +19 -0
  103. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  104. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  105. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  106. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  107. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
  108. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  109. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  110. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  111. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  112. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  113. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  116. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  117. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  119. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  120. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  121. package/src/components/custom/Fatigue/README.md +40 -3
  122. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  123. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  124. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  125. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  126. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  127. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  128. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  129. package/src/components/custom/Fatigue/index.ts +17 -5
  130. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  131. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  132. package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
  133. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  134. package/src/components/custom/Gauge/Gauge.tsx +7 -2
  135. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  136. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  137. package/src/components/custom/Metric/Metric.tsx +5 -20
  138. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  139. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  140. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  141. package/src/components/custom/Prose/README.md +58 -0
  142. package/src/components/custom/Prose/index.ts +1 -0
  143. package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
  144. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  145. package/src/components/custom/Scatter/Scatter.tsx +122 -18
  146. package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
  147. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  148. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  149. package/src/components/custom/Table/Table.stories.tsx +99 -16
  150. package/src/components/custom/Table/Table.test.tsx +273 -86
  151. package/src/components/custom/Table/Table.tsx +159 -67
  152. package/src/components/custom/Table/column-fit.test.ts +75 -0
  153. package/src/components/custom/Table/column-fit.ts +116 -0
  154. package/src/components/custom/Table/index.ts +9 -0
  155. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  156. package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
  157. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  158. package/src/components/custom/Treemap/Treemap.tsx +11 -3
  159. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  160. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  161. package/src/components/custom/Typography/Typography.tsx +6 -0
  162. package/src/components/custom/Typography/index.ts +1 -8
  163. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
  164. package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
  165. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  166. package/src/components/custom/Workout/BaseBadge.tsx +6 -2
  167. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  168. package/src/components/custom/Workout/BodyMap.tsx +8 -4
  169. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
  170. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  171. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
  172. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
  173. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  174. package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
  175. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  176. package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
  177. package/src/components/custom/Workout/DeviationBar.tsx +24 -16
  178. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
  179. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
  180. package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
  181. package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
  182. package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
  183. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
  184. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
  185. package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
  186. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  187. package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
  188. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  189. package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
  190. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
  191. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  192. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  193. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  194. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  195. package/src/components/custom/Workout/InputBar.tsx +4 -2
  196. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  197. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  198. package/src/components/custom/Workout/IntensityBar.tsx +8 -3
  199. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  200. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  201. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  202. package/src/components/custom/Workout/MesoCard.tsx +14 -10
  203. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  204. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  205. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  206. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  207. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  208. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
  209. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  210. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  211. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  212. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  213. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
  214. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  215. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  216. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  217. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  218. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  219. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
  220. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  221. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  222. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  223. package/src/components/custom/Workout/README.md +68 -17
  224. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  225. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  226. package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
  227. package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
  228. package/src/components/custom/Workout/RestTimer.tsx +4 -2
  229. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  230. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  231. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  232. package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
  233. package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
  234. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  235. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  236. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  237. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  238. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  239. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  240. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  241. package/src/components/custom/Workout/SetBar.tsx +38 -12
  242. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  243. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  244. package/src/components/custom/Workout/SetRow.tsx +61 -23
  245. package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
  246. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  247. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  248. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  249. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  250. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  251. package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
  252. package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
  253. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  254. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  255. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  256. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  257. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  258. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  259. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  260. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  261. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
  262. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  263. package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
  264. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  265. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  266. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  267. package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
  268. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  269. package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
  270. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  271. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  272. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
  273. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
  274. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
  275. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  276. package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
  277. package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
  278. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  279. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  280. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  281. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  282. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  283. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  284. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  285. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  286. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  287. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  288. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  289. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  290. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  291. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  292. package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
  293. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  294. package/src/components/custom/Workout/exerciseRowState.ts +29 -0
  295. package/src/components/custom/Workout/index.ts +17 -2
  296. package/src/components/custom/Workout/metricText.stories.tsx +15 -13
  297. package/src/components/custom/Workout/metricText.tsx +8 -2
  298. package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
  299. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  300. package/src/components/custom/charts/README.md +66 -0
  301. package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
  302. package/src/components/custom/charts/SetBarChart.tsx +56 -9
  303. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  304. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  305. package/src/components/custom/charts/SparkBars.tsx +85 -0
  306. package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
  307. package/src/components/custom/charts/flatBarGeometry.ts +32 -0
  308. package/src/components/custom/charts/index.ts +3 -0
  309. package/src/components/custom/index.ts +3 -0
  310. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  311. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  312. package/src/components/custom/stepper/Stepper.tsx +21 -34
  313. package/src/components/icons/icons.stories.tsx +1 -1
  314. package/src/components/icons/icons.tsx +51 -0
  315. package/src/components/shell/AppShell.stories.tsx +150 -0
  316. package/src/components/shell/AppShell.test.tsx +70 -0
  317. package/src/components/shell/AppShell.tsx +90 -0
  318. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  319. package/src/components/shell/BrandLockup.test.tsx +34 -1
  320. package/src/components/shell/BrandLockup.tsx +27 -11
  321. package/src/components/shell/NavItem.stories.tsx +4 -4
  322. package/src/components/shell/NavItem.test.tsx +17 -0
  323. package/src/components/shell/NavItem.tsx +17 -5
  324. package/src/components/shell/README.md +89 -26
  325. package/src/components/shell/SideNav.stories.tsx +38 -7
  326. package/src/components/shell/SideNav.test.tsx +16 -8
  327. package/src/components/shell/SideNav.tsx +17 -17
  328. package/src/components/shell/TopBar.stories.tsx +44 -19
  329. package/src/components/shell/TopBar.test.tsx +34 -12
  330. package/src/components/shell/TopBar.tsx +61 -40
  331. package/src/components/shell/brands.tsx +66 -0
  332. package/src/components/shell/index.ts +9 -8
  333. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  334. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  335. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  336. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  337. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  338. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  339. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  340. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  341. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  342. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  343. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  344. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  345. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  346. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  347. package/src/components/shell/workout/index.ts +9 -0
  348. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  349. package/src/components/ui/README.md +110 -0
  350. package/src/components/ui/alert/Alert.stories.tsx +15 -5
  351. package/src/components/ui/alert/Alert.tsx +24 -3
  352. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  353. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  354. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  355. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  356. package/src/components/ui/avatar/Avatar.tsx +2 -10
  357. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  358. package/src/components/ui/badge/Badge.test.tsx +19 -3
  359. package/src/components/ui/badge/Badge.tsx +48 -55
  360. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  361. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  362. package/src/components/ui/button/Button.stories.tsx +46 -12
  363. package/src/components/ui/button/Button.tsx +44 -37
  364. package/src/components/ui/card/Card.stories.tsx +90 -94
  365. package/src/components/ui/card/Card.test.tsx +80 -6
  366. package/src/components/ui/card/Card.tsx +150 -203
  367. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  368. package/src/components/ui/checkbox/Checkbox.tsx +7 -27
  369. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  370. package/src/components/ui/chip/Chip.test.tsx +10 -6
  371. package/src/components/ui/chip/Chip.tsx +76 -91
  372. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  373. package/src/components/ui/collapse/Collapse.tsx +6 -11
  374. package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
  375. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  376. package/src/components/ui/data-row/DataRow.tsx +18 -7
  377. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  378. package/src/components/ui/divider/Divider.tsx +1 -5
  379. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  380. package/src/components/ui/drawer/Drawer.tsx +13 -27
  381. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  382. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  383. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  384. package/src/components/ui/form-field/FormField.tsx +10 -46
  385. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  386. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  387. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  388. package/src/components/ui/help-tip/index.ts +7 -1
  389. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  390. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  391. package/src/components/ui/icon-box/IconBox.tsx +10 -18
  392. package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
  393. package/src/components/ui/indicator/Indicator.tsx +20 -14
  394. package/src/components/ui/input/Input.stories.tsx +3 -11
  395. package/src/components/ui/input/Input.test.tsx +2 -10
  396. package/src/components/ui/input/Input.tsx +10 -25
  397. package/src/components/ui/input/index.ts +7 -1
  398. package/src/components/ui/link/Link.stories.tsx +19 -7
  399. package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
  400. package/src/components/ui/list-item/ListItem.tsx +2 -9
  401. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  402. package/src/components/ui/menu/Menu.test.tsx +2 -11
  403. package/src/components/ui/menu/Menu.tsx +12 -14
  404. package/src/components/ui/menu/index.ts +8 -1
  405. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  406. package/src/components/ui/modal/Modal.tsx +31 -19
  407. package/src/components/ui/pill/Pill.stories.tsx +111 -23
  408. package/src/components/ui/pill/Pill.test.tsx +101 -3
  409. package/src/components/ui/pill/Pill.tsx +168 -49
  410. package/src/components/ui/pill/index.ts +1 -1
  411. package/src/components/ui/popover/Popover.stories.tsx +6 -8
  412. package/src/components/ui/popover/Popover.test.tsx +1 -6
  413. package/src/components/ui/popover/Popover.tsx +20 -15
  414. package/src/components/ui/popover/index.ts +7 -1
  415. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  416. package/src/components/ui/progress/Progress.test.tsx +1 -5
  417. package/src/components/ui/progress/Progress.tsx +9 -6
  418. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  419. package/src/components/ui/radio/Radio.test.tsx +6 -2
  420. package/src/components/ui/radio/Radio.tsx +23 -22
  421. package/src/components/ui/section/Section.stories.tsx +12 -21
  422. package/src/components/ui/section/Section.test.tsx +1 -6
  423. package/src/components/ui/section/Section.tsx +1 -3
  424. package/src/components/ui/section/index.ts +1 -5
  425. package/src/components/ui/select/Select.stories.tsx +3 -13
  426. package/src/components/ui/select/Select.test.tsx +2 -11
  427. package/src/components/ui/select/Select.tsx +16 -15
  428. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  429. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  430. package/src/components/ui/skeleton/index.ts +1 -7
  431. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  432. package/src/components/ui/spinner/Spinner.tsx +4 -5
  433. package/src/components/ui/stack/Stack.stories.tsx +8 -8
  434. package/src/components/ui/stack/Stack.tsx +1 -1
  435. package/src/components/ui/surface/Surface.stories.tsx +92 -33
  436. package/src/components/ui/surface/Surface.test.tsx +88 -28
  437. package/src/components/ui/surface/Surface.tsx +37 -87
  438. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  439. package/src/components/ui/surface/index.ts +8 -0
  440. package/src/components/ui/surface/resolveSurface.ts +98 -0
  441. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  442. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  443. package/src/components/ui/switch/Switch.tsx +7 -6
  444. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  445. package/src/components/ui/tabs/Tabs.tsx +8 -21
  446. package/src/components/ui/tabs/index.ts +1 -7
  447. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  448. package/src/components/ui/tile/Tile.tsx +3 -0
  449. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  450. package/src/components/ui/toast/Toast.test.tsx +2 -8
  451. package/src/components/ui/toast/Toast.tsx +49 -57
  452. package/src/components/ui/toast/index.ts +0 -1
  453. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  454. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  455. package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
  456. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  457. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  458. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  459. package/src/components/ui/tooltip/index.ts +1 -1
  460. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  461. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  462. package/src/components/ui/trigger/index.ts +2 -0
  463. package/src/stories/PresetShowcase.stories.tsx +101 -48
  464. package/src/test/no-device-internals.test.ts +3 -3
  465. package/src/test/no-raw-color.test.ts +39 -0
  466. package/src/theme/Alpha.stories.tsx +103 -0
  467. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  468. package/src/theme/ColorPalettes.stories.tsx +62 -45
  469. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  470. package/src/theme/Depth.stories.tsx +132 -65
  471. package/src/theme/DepthCalibration.stories.tsx +23 -21
  472. package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
  473. package/src/theme/ThemeProvider.test.tsx +4 -4
  474. package/src/theme/barrel.ts +7 -6
  475. package/src/theme/color-stories.coverage.test.ts +1 -1
  476. package/src/theme/color-utils.ts +41 -29
  477. package/src/theme/config.completeness.test.ts +1 -1
  478. package/src/theme/config.ts +40 -0
  479. package/src/theme/elevation.test.ts +82 -56
  480. package/src/theme/elevation.ts +77 -561
  481. package/src/theme/global.css +45 -5
  482. package/src/theme/grey-ramp.test.ts +24 -8
  483. package/src/theme/lift.test.ts +39 -0
  484. package/src/theme/lift.ts +102 -0
  485. package/src/theme/materials.test.ts +5 -2
  486. package/src/theme/materials.ts +38 -4
  487. package/src/theme/native-theming-guard.test.ts +5 -5
  488. package/src/theme/presets/apply.ts +4 -0
  489. package/src/theme/presets/audiobook.ts +5 -2
  490. package/src/theme/presets/default.ts +4 -0
  491. package/src/theme/presets/index.ts +14 -1
  492. package/src/theme/presets/types.ts +1 -1
  493. package/src/theme/semantic-contrast.test.ts +13 -4
  494. package/src/theme/status-distinctness.test.ts +66 -0
  495. package/src/theme/subtle-tone-weight.test.ts +163 -0
  496. package/src/theme/surface-planes.test.ts +37 -0
  497. package/src/theme/surface-planes.ts +68 -0
  498. package/src/theme/tailwind-var-opacity.test.ts +163 -0
  499. package/src/theme/token-export-guard.test.ts +1 -3
  500. package/src/theme/tokens/primitives.test.ts +15 -7
  501. package/src/theme/tokens/primitives.ts +98 -33
  502. package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
  503. package/src/theme/tokens/semantic.ts +124 -54
  504. package/src/theme/wash-ladder.test.ts +58 -0
  505. package/src/theme/workout-tokens.ts +1 -7
  506. package/src/types/jest-axe.d.ts +2 -6
  507. package/src/types/raw-md.d.ts +5 -0
  508. package/src/utils/colors.alpha-adoption.test.ts +408 -0
  509. package/src/utils/colors.ts +4 -4
  510. package/src/utils/form.ts +1 -3
  511. package/src/utils/index.ts +2 -7
  512. package/src/utils/number-format.ts +17 -0
  513. package/src/utils/workout-format.ts +15 -6
  514. package/src/web-jsx/jsx-runtime.ts +1 -5
  515. package/tailwind.config.js +55 -9
  516. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  517. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  518. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  519. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  520. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  521. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  522. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  523. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  524. package/src/components/shell/DashboardShell.tsx +0 -75
  525. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  526. package/src/theme/elevation.stories.tsx +0 -346
  527. package/src/utils/useTheme.ts +0 -72
  528. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  529. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  530. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  531. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -0,0 +1,81 @@
1
+ import React, { isValidElement, cloneElement } from 'react'
2
+ import { Pressable, type AccessibilityState } from 'react-native'
3
+
4
+ type Handler = (...args: never[]) => void
5
+ type Handlers = Record<string, Handler | undefined>
6
+
7
+ export interface TriggerSurfaceProps {
8
+ /** Pressable handlers (onPress, onHoverIn, …) for whichever element owns the interaction. */
9
+ handlers: Handlers
10
+ /** Role for the wrapper when it is the one handling the interaction. */
11
+ accessibilityRole?: 'button'
12
+ /** Merged onto whichever element ends up owning the interaction. */
13
+ accessibilityState?: AccessibilityState
14
+ className?: string
15
+ children: React.ReactNode
16
+ }
17
+
18
+ type ComposableChildProps = Handlers & { accessibilityState?: AccessibilityState }
19
+
20
+ function chain(childHandler: Handler | undefined, ownHandler: Handler | undefined): Handler {
21
+ return (...args: never[]) => {
22
+ childHandler?.(...args)
23
+ ownHandler?.(...args)
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Give interaction handling to a composed child instead of wrapping it in a second Pressable.
29
+ *
30
+ * React Native Web lets only the innermost pressable in a chain handle a gesture:
31
+ * PressResponder calls `stopPropagation()` on the click that drives `onPress`,
32
+ * and `useHover` contains hover the same way. A trigger that wraps a `Pressable`
33
+ * child (a `Button`, say) in its own `Pressable` therefore never sees the
34
+ * interaction — in a browser the trigger looks completely dead.
35
+ *
36
+ * A component child may be a Pressable, so the handlers are cloned onto it and
37
+ * the wrapper drops the button role — that also leaves one `[role=button]`
38
+ * rather than an invalid button-inside-button pair. The wrapper stays a
39
+ * Pressable, out of the tab order, to still catch children that turn out not to
40
+ * be pressable. Host elements (`<button>`, `<span>`) cannot take these handlers
41
+ * and do not swallow the gesture, so for those the wrapper handles it.
42
+ */
43
+ export function TriggerSurface({
44
+ handlers,
45
+ accessibilityRole,
46
+ accessibilityState,
47
+ className,
48
+ children,
49
+ }: TriggerSurfaceProps) {
50
+ const child = isValidElement(children) ? children : null
51
+ const childCanCompose = child !== null && typeof child.type !== 'string'
52
+
53
+ if (!childCanCompose) {
54
+ return (
55
+ <Pressable
56
+ accessibilityRole={accessibilityRole}
57
+ accessibilityState={accessibilityState}
58
+ className={className}
59
+ {...handlers}
60
+ >
61
+ {children}
62
+ </Pressable>
63
+ )
64
+ }
65
+
66
+ const childElement = child as React.ReactElement<ComposableChildProps>
67
+ const composed: ComposableChildProps = {}
68
+ for (const [name, handler] of Object.entries(handlers)) {
69
+ composed[name] = chain(childElement.props[name], handler)
70
+ }
71
+ composed.accessibilityState = {
72
+ ...childElement.props.accessibilityState,
73
+ ...accessibilityState,
74
+ }
75
+
76
+ return (
77
+ <Pressable focusable={false} tabIndex={-1} className={className} {...handlers}>
78
+ {cloneElement(childElement, composed)}
79
+ </Pressable>
80
+ )
81
+ }
@@ -0,0 +1,2 @@
1
+ export { TriggerSurface } from './TriggerSurface'
2
+ export type { TriggerSurfaceProps } from './TriggerSurface'
@@ -70,9 +70,7 @@ function SideBySideShowcase() {
70
70
  return (
71
71
  <View className="gap-6 p-6 bg-background-default min-h-screen">
72
72
  <View className="gap-2">
73
- <Text className="text-3xl font-bold text-text-primary font-heading">
74
- Preset Showcase
75
- </Text>
73
+ <Text className="text-3xl font-bold text-text-primary font-heading">Preset Showcase</Text>
76
74
  <Text className="text-text-secondary text-base">
77
75
  Toggle between presets to see how the entire design system adapts.
78
76
  </Text>
@@ -89,14 +87,14 @@ function SideBySideShowcase() {
89
87
  Subheading (font-heading)
90
88
  </Text>
91
89
  <Text className="text-base text-text-primary font-body">
92
- Body text using font-body. The quick brown fox jumps over the lazy dog. This
93
- demonstrates how paragraph text renders under the current preset.
90
+ Body text using font-body. The quick brown fox jumps over the lazy dog. This demonstrates
91
+ how paragraph text renders under the current preset.
94
92
  </Text>
95
93
  <Text className="text-sm text-text-secondary font-body">
96
94
  Secondary body text for captions and supporting content.
97
95
  </Text>
98
96
  <Text className="text-sm text-text-primary font-mono">
99
- {'const monospace = \'font-mono rendering\''}
97
+ {"const monospace = 'font-mono rendering'"}
100
98
  </Text>
101
99
  </Section>
102
100
 
@@ -195,20 +193,40 @@ function SideBySideShowcase() {
195
193
  {/* Toasts */}
196
194
  <Section title="Toasts">
197
195
  <View className="gap-3">
198
- <Toast title="Operation successful" description="Your changes have been saved." status="success" />
199
- <Toast title="Something went wrong" description="Please try again later." status="error" />
196
+ <Toast
197
+ title="Operation successful"
198
+ description="Your changes have been saved."
199
+ status="success"
200
+ />
201
+ <Toast
202
+ title="Something went wrong"
203
+ description="Please try again later."
204
+ status="error"
205
+ />
200
206
  <Toast title="Heads up" description="This action cannot be undone." status="warning" />
201
- <Toast title="New update available" description="Version 2.0 is ready to install." status="info" />
207
+ <Toast
208
+ title="New update available"
209
+ description="Version 2.0 is ready to install."
210
+ status="info"
211
+ />
202
212
  </View>
203
213
  </Section>
204
214
 
205
215
  {/* Status Colors */}
206
216
  <Section title="Status Colors">
207
217
  <View className="flex-row gap-3 flex-wrap">
208
- <Badge color="success" size="lg">Success</Badge>
209
- <Badge color="error" size="lg">Error</Badge>
210
- <Badge color="warning" size="lg">Warning</Badge>
211
- <Badge color="info" size="lg">Info</Badge>
218
+ <Badge color="success" size="lg">
219
+ Success
220
+ </Badge>
221
+ <Badge color="error" size="lg">
222
+ Error
223
+ </Badge>
224
+ <Badge color="warning" size="lg">
225
+ Warning
226
+ </Badge>
227
+ <Badge color="info" size="lg">
228
+ Info
229
+ </Badge>
212
230
  </View>
213
231
  </Section>
214
232
  </View>
@@ -225,9 +243,7 @@ function TypographyShowcase() {
225
243
  return (
226
244
  <View className="gap-6 p-6 bg-background-default min-h-screen">
227
245
  <View className="gap-2">
228
- <Text className="text-3xl font-bold text-text-primary font-heading">
229
- Typography
230
- </Text>
246
+ <Text className="text-3xl font-bold text-text-primary font-heading">Typography</Text>
231
247
  <Text className="text-text-secondary text-base">
232
248
  How fonts and text styles change across presets.
233
249
  </Text>
@@ -252,9 +268,9 @@ function TypographyShowcase() {
252
268
 
253
269
  <Section title="Body Font (font-body)">
254
270
  <Text className="text-base text-text-primary font-body">
255
- Regular body text. Design systems provide a shared language for product teams.
256
- By codifying decisions into reusable components and tokens, teams move faster
257
- while maintaining visual consistency across every surface.
271
+ Regular body text. Design systems provide a shared language for product teams. By
272
+ codifying decisions into reusable components and tokens, teams move faster while
273
+ maintaining visual consistency across every surface.
258
274
  </Text>
259
275
  <Text className="text-base font-semibold text-text-primary font-body">
260
276
  Bold body text. Emphasis and hierarchy within paragraph content.
@@ -263,8 +279,8 @@ function TypographyShowcase() {
263
279
  Italic body text. Used for quotations, citations, and emphasis.
264
280
  </Text>
265
281
  <Text className="text-sm text-text-secondary font-body">
266
- Small / secondary text. Captions, labels, and supporting information
267
- that supplements the main content without competing for attention.
282
+ Small / secondary text. Captions, labels, and supporting information that supplements the
283
+ main content without competing for attention.
268
284
  </Text>
269
285
  <Text className="text-xs text-text-tertiary font-body">
270
286
  Extra-small / tertiary text. Timestamps, metadata, fine print.
@@ -287,19 +303,14 @@ function TypographyShowcase() {
287
303
 
288
304
  <Section title="Mixed Typography">
289
305
  <Card className="p-5 gap-3">
290
- <Text className="text-2xl font-bold text-text-primary font-heading">
291
- Chapter One
292
- </Text>
306
+ <Text className="text-2xl font-bold text-text-primary font-heading">Chapter One</Text>
293
307
  <Text className="text-base text-text-secondary font-body">
294
- It was a bright cold day in April, and the clocks were striking thirteen.
295
- Winston Smith, his chin nuzzled into his breast in an effort to escape the
296
- vile wind, slipped quickly through the glass doors of Victory Mansions,
297
- though not quickly enough to prevent a swirl of gritty dust from entering
298
- along with him.
299
- </Text>
300
- <Text className="text-xs text-text-tertiary font-mono">
301
- George Orwell, 1984
308
+ It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith,
309
+ his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly
310
+ through the glass doors of Victory Mansions, though not quickly enough to prevent a
311
+ swirl of gritty dust from entering along with him.
302
312
  </Text>
313
+ <Text className="text-xs text-text-tertiary font-mono">George Orwell, 1984</Text>
303
314
  </Card>
304
315
  </Section>
305
316
  </View>
@@ -313,7 +324,7 @@ function TypographyShowcase() {
313
324
  function ColorSwatch({
314
325
  label,
315
326
  className,
316
- textClass = 'text-white',
327
+ textClass = 'text-on-brand-primary',
317
328
  }: {
318
329
  label: string
319
330
  className: string
@@ -332,9 +343,7 @@ function ColorPaletteShowcase() {
332
343
  return (
333
344
  <View className="gap-6 p-6 bg-background-default min-h-screen">
334
345
  <View className="gap-2">
335
- <Text className="text-3xl font-bold text-text-primary font-heading">
336
- Color Palette
337
- </Text>
346
+ <Text className="text-3xl font-bold text-text-primary font-heading">Color Palette</Text>
338
347
  <Text className="text-text-secondary text-base">
339
348
  Semantic color tokens rendered as swatches. Toggle presets to compare palettes.
340
349
  </Text>
@@ -347,13 +356,21 @@ function ColorPaletteShowcase() {
347
356
  <ColorSwatch label="brand-primary" className="bg-brand-primary" />
348
357
  <ColorSwatch label="brand-primary-light" className="bg-brand-primary-light" />
349
358
  <ColorSwatch label="brand-primary-dark" className="bg-brand-primary-dark" />
350
- <ColorSwatch label="brand-primary-subtle" className="bg-brand-primary-subtle" textClass="text-text-primary" />
359
+ <ColorSwatch
360
+ label="brand-primary-subtle"
361
+ className="bg-brand-primary-subtle"
362
+ textClass="text-text-primary"
363
+ />
351
364
  </View>
352
365
  <View className="flex-row gap-3 flex-wrap mt-2">
353
366
  <ColorSwatch label="brand-secondary" className="bg-brand-secondary" />
354
367
  <ColorSwatch label="brand-secondary-light" className="bg-brand-secondary-light" />
355
368
  <ColorSwatch label="brand-secondary-dark" className="bg-brand-secondary-dark" />
356
- <ColorSwatch label="brand-secondary-subtle" className="bg-brand-secondary-subtle" textClass="text-text-primary" />
369
+ <ColorSwatch
370
+ label="brand-secondary-subtle"
371
+ className="bg-brand-secondary-subtle"
372
+ textClass="text-text-primary"
373
+ />
357
374
  </View>
358
375
  </Section>
359
376
 
@@ -372,7 +389,9 @@ function ColorPaletteShowcase() {
372
389
  <Text className="text-xs font-mono font-medium text-text-primary">text-primary</Text>
373
390
  </View>
374
391
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-elevated border border-hairline">
375
- <Text className="text-xs font-mono font-medium text-text-secondary">text-secondary</Text>
392
+ <Text className="text-xs font-mono font-medium text-text-secondary">
393
+ text-secondary
394
+ </Text>
376
395
  </View>
377
396
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-elevated border border-hairline">
378
397
  <Text className="text-xs font-mono font-medium text-text-tertiary">text-tertiary</Text>
@@ -382,26 +401,60 @@ function ColorPaletteShowcase() {
382
401
 
383
402
  <Section title="Surface Colors">
384
403
  <View className="flex-row gap-3 flex-wrap">
385
- <ColorSwatch label="surface-base" className="bg-surface-base border border-hairline" textClass="text-text-primary" />
386
- <ColorSwatch label="surface-elevated" className="bg-surface-elevated border border-hairline" textClass="text-text-primary" />
387
- <ColorSwatch label="surface-raised" className="bg-surface-raised border border-hairline" textClass="text-text-primary" />
388
- <ColorSwatch label="surface-overlay" className="bg-surface-overlay border border-hairline" textClass="text-text-primary" />
389
- <ColorSwatch label="surface-input" className="bg-surface-input border border-hairline" textClass="text-text-primary" />
404
+ <ColorSwatch
405
+ label="surface-base"
406
+ className="bg-surface-base border border-hairline"
407
+ textClass="text-text-primary"
408
+ />
409
+ <ColorSwatch
410
+ label="surface-elevated"
411
+ className="bg-surface-elevated border border-hairline"
412
+ textClass="text-text-primary"
413
+ />
414
+ <ColorSwatch
415
+ label="surface-raised"
416
+ className="bg-surface-raised border border-hairline"
417
+ textClass="text-text-primary"
418
+ />
419
+ <ColorSwatch
420
+ label="surface-overlay"
421
+ className="bg-surface-overlay border border-hairline"
422
+ textClass="text-text-primary"
423
+ />
424
+ <ColorSwatch
425
+ label="surface-input"
426
+ className="bg-surface-input border border-hairline"
427
+ textClass="text-text-primary"
428
+ />
390
429
  </View>
391
430
  </Section>
392
431
 
393
432
  <Section title="Background Colors">
394
433
  <View className="flex-row gap-3 flex-wrap">
395
- <ColorSwatch label="background-base" className="bg-background-base border border-hairline" textClass="text-text-primary" />
396
- <ColorSwatch label="background-default" className="bg-background-default border border-hairline" textClass="text-text-primary" />
397
- <ColorSwatch label="background-subtle" className="bg-background-subtle border border-hairline" textClass="text-text-primary" />
434
+ <ColorSwatch
435
+ label="background-base"
436
+ className="bg-background-base border border-hairline"
437
+ textClass="text-text-primary"
438
+ />
439
+ <ColorSwatch
440
+ label="background-default"
441
+ className="bg-background-default border border-hairline"
442
+ textClass="text-text-primary"
443
+ />
444
+ <ColorSwatch
445
+ label="background-subtle"
446
+ className="bg-background-subtle border border-hairline"
447
+ textClass="text-text-primary"
448
+ />
398
449
  </View>
399
450
  </Section>
400
451
 
401
452
  <Section title="Border Colors">
402
453
  <View className="flex-row gap-3 flex-wrap">
403
454
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-base border-2 border-hairline-default">
404
- <Text className="text-xs font-mono font-medium text-text-primary">hairline-default</Text>
455
+ <Text className="text-xs font-mono font-medium text-text-primary">
456
+ hairline-default
457
+ </Text>
405
458
  </View>
406
459
  <View className="rounded-lg p-3 min-w-[120px] min-h-[60px] justify-end bg-surface-base border-2 border-hairline-subtle">
407
460
  <Text className="text-xs font-mono font-medium text-text-primary">hairline-subtle</Text>
@@ -21,13 +21,13 @@ describe('no-device-internals', () => {
21
21
  // Dimension and ratio strings: the `\b` guard before `0x` means a digit
22
22
  // followed by `x` never reads as a hex literal. These exact strings
23
23
  // tripped an earlier, looser sweep.
24
- { code: "// icons render at 20x20" },
25
- { code: "// 200x400 intrinsic -> ~160x320 px" },
24
+ { code: '// icons render at 20x20' },
25
+ { code: '// 200x400 intrinsic -> ~160x320 px' },
26
26
  // SVG path coordinates — digit-only runs are not byte frames.
27
27
  { code: 'const d = "M12 2 22 12 12 22 2 12Z"' },
28
28
  { code: 'const d = "M7 7 17 17 12 22 12 2 17 7 7 17"' },
29
29
  // Timestamps — `-` and `:` are not byte separators.
30
- { code: "// datetime // 2024-01-15 14:30" },
30
+ { code: '// datetime // 2024-01-15 14:30' },
31
31
  // "cascade" in its CSS sense is ordinary styling vocabulary.
32
32
  { code: "// RN doesn't cascade text color, so hand-color the text" },
33
33
  // Plain numbers and durations.
@@ -0,0 +1,39 @@
1
+ import { RuleTester } from 'eslint'
2
+ import rule from '../../eslint-rules/no-raw-color'
3
+
4
+ const ruleTester = new RuleTester({
5
+ languageOptions: {
6
+ ecmaVersion: 2022,
7
+ sourceType: 'module',
8
+ parserOptions: { ecmaFeatures: { jsx: true } },
9
+ },
10
+ })
11
+
12
+ describe('no-raw-color', () => {
13
+ it('skips false positives while still flagging real raw colour', () => {
14
+ ruleTester.run('no-raw-color', rule as never, {
15
+ valid: [
16
+ // (a) enum-typed prop value: a bare colour word passed as color/variant/tone.
17
+ { code: '<Spinner color="white" />' },
18
+ // (a) the same enum's members listed in a Storybook argTypes options array.
19
+ {
20
+ code: "const meta = { argTypes: { color: { control: 'select', options: ['primary', 'white'] } } }",
21
+ },
22
+ // (b) { value, label } demo data reusing colour words as IDs.
23
+ { code: "const colorOptions = [{ value: 'red', label: 'Red' }]" },
24
+ // (c) documentation text in a <Text> element's children.
25
+ { code: '<Text>{`background-color: #3C3C3C;`}</Text>' },
26
+ ],
27
+ invalid: [
28
+ // Positive control: a real raw hex in a style prop must still be flagged,
29
+ // including on a <Text> element — only its *children* are exempt.
30
+ {
31
+ code: "<Text style={{ backgroundColor: '#123456' }} />",
32
+ errors: [{ messageId: 'hex' }],
33
+ },
34
+ // Positive control: a bare colour word outside any exempt shape is still named.
35
+ { code: "const bg = 'white'", errors: [{ messageId: 'named' }] },
36
+ ],
37
+ })
38
+ })
39
+ })
@@ -0,0 +1,103 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View, Text } from 'react-native'
3
+ import { alpha } from '../utils/colors'
4
+ import { getSemanticColors } from './tokens/semantic'
5
+ import { primitiveColors } from './tokens/primitives'
6
+ import { SectionIntro, SectionTitle, SWATCH_BORDER } from './color-story-kit'
7
+
8
+ const t = getSemanticColors('dark')
9
+
10
+ /**
11
+ * Foundations/Color/Alpha — deriving a translucent colour from a token instead
12
+ * of hardcoding an `rgba(...)` triple.
13
+ *
14
+ * `alpha(color, opacity)` (`packages/ui/src/utils/colors.ts`) takes a RESOLVED
15
+ * colour — a hex string or an `rgb()`/`rgba()` string, e.g. a semantic token's
16
+ * value or a primitive — and returns it as `rgba(r, g, b, opacity)`. It does
17
+ * NOT take a token name: `alpha('brand-primary', 0.1)` would try to parse the
18
+ * literal string `'brand-primary'` as a colour and fail. Resolve the token
19
+ * first (`t['brand-primary']`, `primitiveColors.white`, …), then wrap it.
20
+ *
21
+ * The payoff over a hand-picked `rgba(255, 121, 0, 0.1)`: when a ramp gets
22
+ * re-spaced or a semantic mapping moves, every `alpha()` call built on that
23
+ * token moves with it. A literal triple silently drifts from the token it was
24
+ * copied from and stays wrong until someone notices — the failure mode VW-78
25
+ * was opened to burn down (see `eslint-rules/raw-color-baseline.json`,
26
+ * enforced by `no-raw-color`'s `functional` rule).
27
+ */
28
+ const meta: Meta = {
29
+ title: 'Foundations/Color/Alpha',
30
+ tags: ['autodocs'],
31
+ }
32
+
33
+ export default meta
34
+
35
+ const EXAMPLES = [
36
+ { name: 'brand-primary @ 0.12', value: alpha(t['brand-primary'], 0.12) },
37
+ { name: 'status-success @ 0.15', value: alpha(t['status-success'], 0.15) },
38
+ { name: 'status-warning @ 0.25', value: alpha(t['status-warning'], 0.25) },
39
+ { name: 'status-error @ 0.3', value: alpha(t['status-error'], 0.3) },
40
+ { name: 'primitiveColors.white @ 0.08', value: alpha(primitiveColors.white, 0.08) },
41
+ ] as const
42
+
43
+ function AlphaSwatch({ name, value }: { name: string; value: string }) {
44
+ return (
45
+ <View style={{ alignItems: 'center', width: 96 }}>
46
+ <View
47
+ style={{
48
+ width: 96,
49
+ height: 64,
50
+ borderRadius: 8,
51
+ backgroundColor: t['surface-elevated'],
52
+ borderWidth: 1,
53
+ borderColor: SWATCH_BORDER,
54
+ overflow: 'hidden',
55
+ }}
56
+ >
57
+ <View style={{ flex: 1, backgroundColor: value }} />
58
+ </View>
59
+ <Text className="text-text-secondary text-xs mt-1" style={{ textAlign: 'center' }}>
60
+ {name}
61
+ </Text>
62
+ <Text className="text-text-tertiary" style={{ fontSize: 9, marginTop: 1 }}>
63
+ {value}
64
+ </Text>
65
+ </View>
66
+ )
67
+ }
68
+
69
+ export const Default: StoryObj = {
70
+ render: () => (
71
+ <View style={{ padding: 24 }}>
72
+ <Text className="text-2xl font-bold text-text-primary mb-2">Alpha</Text>
73
+ <SectionIntro>
74
+ `alpha(color, opacity)` derives a translucent colour from a RESOLVED token or primitive
75
+ instead of a hand-picked `rgba(...)` triple, so the wash tracks the token it came from. Each
76
+ swatch below is rendered over the elevated surface plane so the translucency is visible.
77
+ </SectionIntro>
78
+
79
+ <SectionTitle>Usage</SectionTitle>
80
+ <View
81
+ style={{
82
+ backgroundColor: t['surface-raised'],
83
+ borderRadius: 8,
84
+ padding: 12,
85
+ marginBottom: 20,
86
+ }}
87
+ >
88
+ <Text className="text-text-secondary" style={{ fontFamily: 'monospace', fontSize: 12 }}>
89
+ {"import { alpha } from '@/utils/colors'\n\n"}
90
+ {"const t = getSemanticColors('dark')\n"}
91
+ {"const wash = alpha(t['brand-primary'], 0.12)"}
92
+ </Text>
93
+ </View>
94
+
95
+ <SectionTitle>Examples</SectionTitle>
96
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
97
+ {EXAMPLES.map((example) => (
98
+ <AlphaSwatch key={example.name} {...example} />
99
+ ))}
100
+ </View>
101
+ </View>
102
+ ),
103
+ }
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View, Text } from 'react-native'
3
+ import tokensDoc from '../../TOKENS.md?raw'
4
+ import { Typography } from '../components/custom/Typography'
5
+
6
+ /**
7
+ * Rendered straight from `packages/ui/TOKENS.md` via Vite's `?raw`, deliberately
8
+ * as its markdown source rather than a hand-built React page. A prettier page
9
+ * would be a second copy of the rules that can drift from the file — and a token
10
+ * guide that disagrees with itself is worse than a plain one. The content is
11
+ * mostly aligned tables, which read fine in mono.
12
+ */
13
+ function ChoosingTokens() {
14
+ return (
15
+ <View className="gap-4 p-6">
16
+ <Typography variant="h3" className="text-text-primary">
17
+ Choosing tokens
18
+ </Typography>
19
+ <Typography variant="body2" className="text-text-secondary">
20
+ The decision table to read before writing a component. Source of truth:{' '}
21
+ <Text className="font-mono text-text-primary">packages/ui/TOKENS.md</Text> — this page
22
+ renders that file, so the two cannot disagree.
23
+ </Typography>
24
+ <View className="rounded-lg bg-surface-raised p-4">
25
+ <Text className="font-mono text-xs leading-5 text-text-secondary">{tokensDoc}</Text>
26
+ </View>
27
+ </View>
28
+ )
29
+ }
30
+
31
+ const meta: Meta<typeof ChoosingTokens> = {
32
+ title: 'Foundations/Choosing Tokens',
33
+ component: ChoosingTokens,
34
+ parameters: {
35
+ layout: 'fullscreen',
36
+ docs: {
37
+ description: {
38
+ component:
39
+ 'Which palette for which meaning, how to resolve a colour in code, and the type/spacing ' +
40
+ 'scales. Rendered from `packages/ui/TOKENS.md`.',
41
+ },
42
+ },
43
+ },
44
+ }
45
+ export default meta
46
+ type Story = StoryObj<typeof ChoosingTokens>
47
+
48
+ export const Default: Story = {}