@titan-design/react-ui 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/README.md +46 -47
  2. package/dist/bodymap.js +768 -701
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +770 -703
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1320 -215
  7. package/dist/index.d.ts +1320 -215
  8. package/dist/index.js +5996 -4498
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +5773 -4357
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
  13. package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1435 -1428
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1443 -1436
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +202 -1042
  21. package/dist/theme/index.d.ts +202 -1042
  22. package/dist/theme/index.js +215 -300
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +202 -296
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +62 -5
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +62 -5
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +972 -0
  31. package/dist/theme/tokens.d.ts +972 -0
  32. package/dist/theme/tokens.js +904 -0
  33. package/dist/theme/tokens.js.map +1 -0
  34. package/dist/theme/tokens.mjs +880 -0
  35. package/dist/theme/tokens.mjs.map +1 -0
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/package.json +7 -1
  40. package/src/arch/arch-graph.freshness.test.ts +52 -0
  41. package/src/arch/arch-graph.json +5021 -1617
  42. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  43. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  44. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  45. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  46. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  48. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  49. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  51. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  52. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  54. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  55. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  57. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  58. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  60. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  61. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
  63. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  64. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  66. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  67. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  69. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  70. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  71. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  73. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  74. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  76. package/src/components/custom/ActiveWork/README.md +305 -0
  77. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  78. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  80. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  81. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  82. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  83. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  84. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  86. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  87. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  88. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  90. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  91. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  92. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  93. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  94. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  95. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  96. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  97. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  98. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  99. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  100. package/src/components/custom/ActiveWork/index.ts +19 -0
  101. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  102. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  103. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  104. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  105. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
  106. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  107. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  108. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  109. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  110. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  111. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  112. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  113. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  116. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  117. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  119. package/src/components/custom/Fatigue/README.md +40 -3
  120. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  121. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  122. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  123. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  124. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  125. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  126. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  127. package/src/components/custom/Fatigue/index.ts +17 -5
  128. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  129. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  130. package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
  131. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  132. package/src/components/custom/Gauge/Gauge.tsx +4 -1
  133. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  134. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  135. package/src/components/custom/Metric/Metric.tsx +5 -20
  136. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  137. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  138. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  139. package/src/components/custom/Prose/README.md +58 -0
  140. package/src/components/custom/Prose/index.ts +1 -0
  141. package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
  142. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  143. package/src/components/custom/Scatter/Scatter.tsx +116 -14
  144. package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
  145. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  146. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  147. package/src/components/custom/Table/Table.stories.tsx +98 -15
  148. package/src/components/custom/Table/Table.test.tsx +273 -86
  149. package/src/components/custom/Table/Table.tsx +159 -67
  150. package/src/components/custom/Table/column-fit.test.ts +75 -0
  151. package/src/components/custom/Table/column-fit.ts +116 -0
  152. package/src/components/custom/Table/index.ts +9 -0
  153. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  154. package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
  155. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  156. package/src/components/custom/Treemap/Treemap.tsx +7 -2
  157. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  158. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  159. package/src/components/custom/Typography/Typography.tsx +6 -0
  160. package/src/components/custom/Typography/index.ts +1 -8
  161. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
  162. package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
  163. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  164. package/src/components/custom/Workout/BaseBadge.tsx +3 -0
  165. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  166. package/src/components/custom/Workout/BodyMap.tsx +3 -1
  167. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
  168. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  169. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
  170. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
  171. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  172. package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
  173. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  174. package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
  175. package/src/components/custom/Workout/DeviationBar.tsx +21 -16
  176. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
  177. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
  178. package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
  179. package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
  180. package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
  181. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
  182. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  183. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  184. package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
  185. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
  186. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  187. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  188. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  189. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  190. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  191. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  192. package/src/components/custom/Workout/IntensityBar.tsx +4 -2
  193. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  194. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  195. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  196. package/src/components/custom/Workout/MesoCard.tsx +12 -9
  197. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  198. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  199. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  200. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  201. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  202. package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
  203. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  204. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  205. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  206. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  207. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  208. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  209. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  210. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  211. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  212. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  213. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
  214. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  215. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  216. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  217. package/src/components/custom/Workout/README.md +12 -7
  218. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  219. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  220. package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
  221. package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
  222. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  223. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  224. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  225. package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
  226. package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
  227. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  228. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  229. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  230. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  231. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  232. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  233. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  234. package/src/components/custom/Workout/SetBar.tsx +38 -12
  235. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  236. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  237. package/src/components/custom/Workout/SetRow.tsx +61 -23
  238. package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
  239. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  240. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  241. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  242. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  243. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  244. package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
  245. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  246. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  247. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  248. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  249. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  250. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  251. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  252. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  253. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  254. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
  255. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  256. package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
  257. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  258. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  259. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  260. package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
  261. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  262. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  263. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  264. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
  265. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
  266. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
  267. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  268. package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
  269. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  270. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  271. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  272. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  273. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  274. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  275. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  276. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  277. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  278. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  279. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  280. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  281. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  282. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  283. package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
  284. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  285. package/src/components/custom/Workout/index.ts +5 -0
  286. package/src/components/custom/Workout/metricText.stories.tsx +6 -5
  287. package/src/components/custom/Workout/metricText.tsx +4 -0
  288. package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
  289. package/src/components/custom/charts/README.md +61 -0
  290. package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
  291. package/src/components/custom/charts/SetBarChart.tsx +42 -4
  292. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  293. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  294. package/src/components/custom/charts/SparkBars.tsx +85 -0
  295. package/src/components/custom/charts/index.ts +3 -0
  296. package/src/components/custom/index.ts +3 -0
  297. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  298. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  299. package/src/components/custom/stepper/Stepper.tsx +13 -28
  300. package/src/components/icons/icons.stories.tsx +1 -1
  301. package/src/components/icons/icons.tsx +51 -0
  302. package/src/components/shell/AppShell.stories.tsx +150 -0
  303. package/src/components/shell/AppShell.test.tsx +70 -0
  304. package/src/components/shell/AppShell.tsx +90 -0
  305. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  306. package/src/components/shell/BrandLockup.test.tsx +34 -1
  307. package/src/components/shell/BrandLockup.tsx +27 -11
  308. package/src/components/shell/NavItem.stories.tsx +4 -4
  309. package/src/components/shell/NavItem.test.tsx +17 -0
  310. package/src/components/shell/NavItem.tsx +17 -5
  311. package/src/components/shell/README.md +90 -27
  312. package/src/components/shell/SideNav.stories.tsx +38 -7
  313. package/src/components/shell/SideNav.test.tsx +16 -8
  314. package/src/components/shell/SideNav.tsx +17 -17
  315. package/src/components/shell/TopBar.stories.tsx +44 -19
  316. package/src/components/shell/TopBar.test.tsx +34 -12
  317. package/src/components/shell/TopBar.tsx +61 -40
  318. package/src/components/shell/brands.tsx +66 -0
  319. package/src/components/shell/index.ts +9 -8
  320. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  321. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  322. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  323. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  324. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  325. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  326. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  327. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  328. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  329. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  330. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  331. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  332. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  333. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  334. package/src/components/shell/workout/index.ts +9 -0
  335. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  336. package/src/components/ui/README.md +110 -0
  337. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  338. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  339. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  340. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  341. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  342. package/src/components/ui/avatar/Avatar.tsx +2 -10
  343. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  344. package/src/components/ui/badge/Badge.test.tsx +19 -3
  345. package/src/components/ui/badge/Badge.tsx +48 -55
  346. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  347. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  348. package/src/components/ui/button/Button.stories.tsx +46 -12
  349. package/src/components/ui/button/Button.tsx +32 -25
  350. package/src/components/ui/card/Card.stories.tsx +90 -94
  351. package/src/components/ui/card/Card.test.tsx +80 -6
  352. package/src/components/ui/card/Card.tsx +150 -203
  353. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  354. package/src/components/ui/checkbox/Checkbox.tsx +6 -26
  355. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  356. package/src/components/ui/chip/Chip.test.tsx +10 -6
  357. package/src/components/ui/chip/Chip.tsx +76 -91
  358. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  359. package/src/components/ui/collapse/Collapse.tsx +6 -11
  360. package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
  361. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  362. package/src/components/ui/data-row/DataRow.tsx +18 -7
  363. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  364. package/src/components/ui/divider/Divider.tsx +1 -5
  365. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  366. package/src/components/ui/drawer/Drawer.tsx +13 -30
  367. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  368. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  369. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  370. package/src/components/ui/form-field/FormField.tsx +10 -46
  371. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  372. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  373. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  374. package/src/components/ui/help-tip/index.ts +7 -1
  375. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  376. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  377. package/src/components/ui/icon-box/IconBox.tsx +2 -12
  378. package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
  379. package/src/components/ui/indicator/Indicator.tsx +20 -14
  380. package/src/components/ui/input/Input.stories.tsx +3 -11
  381. package/src/components/ui/input/Input.test.tsx +2 -10
  382. package/src/components/ui/input/Input.tsx +10 -25
  383. package/src/components/ui/input/index.ts +7 -1
  384. package/src/components/ui/link/Link.stories.tsx +19 -7
  385. package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
  386. package/src/components/ui/list-item/ListItem.tsx +2 -9
  387. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  388. package/src/components/ui/menu/Menu.test.tsx +2 -11
  389. package/src/components/ui/menu/Menu.tsx +12 -14
  390. package/src/components/ui/menu/index.ts +8 -1
  391. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  392. package/src/components/ui/modal/Modal.tsx +29 -19
  393. package/src/components/ui/pill/Pill.stories.tsx +58 -23
  394. package/src/components/ui/pill/Pill.test.tsx +101 -3
  395. package/src/components/ui/pill/Pill.tsx +164 -49
  396. package/src/components/ui/pill/index.ts +1 -1
  397. package/src/components/ui/popover/Popover.stories.tsx +5 -7
  398. package/src/components/ui/popover/Popover.test.tsx +1 -6
  399. package/src/components/ui/popover/Popover.tsx +20 -15
  400. package/src/components/ui/popover/index.ts +7 -1
  401. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  402. package/src/components/ui/progress/Progress.test.tsx +1 -5
  403. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  404. package/src/components/ui/radio/Radio.test.tsx +6 -2
  405. package/src/components/ui/radio/Radio.tsx +23 -22
  406. package/src/components/ui/section/Section.stories.tsx +5 -14
  407. package/src/components/ui/section/Section.test.tsx +1 -6
  408. package/src/components/ui/section/Section.tsx +1 -3
  409. package/src/components/ui/section/index.ts +1 -5
  410. package/src/components/ui/select/Select.stories.tsx +3 -13
  411. package/src/components/ui/select/Select.test.tsx +2 -11
  412. package/src/components/ui/select/Select.tsx +14 -14
  413. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  414. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  415. package/src/components/ui/skeleton/index.ts +1 -7
  416. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  417. package/src/components/ui/spinner/Spinner.tsx +1 -4
  418. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  419. package/src/components/ui/stack/Stack.tsx +1 -1
  420. package/src/components/ui/surface/Surface.stories.tsx +17 -5
  421. package/src/components/ui/surface/Surface.test.tsx +88 -28
  422. package/src/components/ui/surface/Surface.tsx +37 -87
  423. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  424. package/src/components/ui/surface/index.ts +8 -0
  425. package/src/components/ui/surface/resolveSurface.ts +98 -0
  426. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  427. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  428. package/src/components/ui/switch/Switch.tsx +7 -6
  429. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  430. package/src/components/ui/tabs/Tabs.tsx +7 -22
  431. package/src/components/ui/tabs/index.ts +1 -7
  432. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  433. package/src/components/ui/tile/Tile.tsx +3 -0
  434. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  435. package/src/components/ui/toast/Toast.test.tsx +2 -8
  436. package/src/components/ui/toast/Toast.tsx +43 -53
  437. package/src/components/ui/toast/index.ts +0 -1
  438. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  439. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  440. package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
  441. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  442. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  443. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  444. package/src/components/ui/tooltip/index.ts +1 -1
  445. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  446. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  447. package/src/components/ui/trigger/index.ts +2 -0
  448. package/src/stories/PresetShowcase.stories.tsx +100 -47
  449. package/src/test/no-device-internals.test.ts +3 -3
  450. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  451. package/src/theme/ColorPalettes.stories.tsx +62 -45
  452. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  453. package/src/theme/Depth.stories.tsx +132 -65
  454. package/src/theme/DepthCalibration.stories.tsx +24 -22
  455. package/src/theme/ThemeProvider.test.tsx +4 -4
  456. package/src/theme/barrel.ts +7 -6
  457. package/src/theme/color-stories.coverage.test.ts +1 -1
  458. package/src/theme/color-utils.ts +41 -29
  459. package/src/theme/config.completeness.test.ts +1 -1
  460. package/src/theme/config.ts +28 -0
  461. package/src/theme/elevation.test.ts +82 -56
  462. package/src/theme/elevation.ts +77 -561
  463. package/src/theme/global.css +30 -2
  464. package/src/theme/grey-ramp.test.ts +24 -8
  465. package/src/theme/lift.test.ts +39 -0
  466. package/src/theme/lift.ts +102 -0
  467. package/src/theme/materials.test.ts +5 -2
  468. package/src/theme/materials.ts +38 -4
  469. package/src/theme/native-theming-guard.test.ts +5 -5
  470. package/src/theme/presets/apply.ts +4 -0
  471. package/src/theme/presets/audiobook.ts +5 -2
  472. package/src/theme/presets/default.ts +4 -0
  473. package/src/theme/presets/index.ts +14 -1
  474. package/src/theme/presets/types.ts +1 -1
  475. package/src/theme/semantic-contrast.test.ts +13 -4
  476. package/src/theme/status-distinctness.test.ts +66 -0
  477. package/src/theme/surface-planes.test.ts +37 -0
  478. package/src/theme/surface-planes.ts +68 -0
  479. package/src/theme/token-export-guard.test.ts +102 -0
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +67 -35
  482. package/src/theme/tokens/semantic.ts +71 -37
  483. package/src/theme/wash-ladder.test.ts +58 -0
  484. package/src/theme/workout-tokens.ts +1 -7
  485. package/src/types/jest-axe.d.ts +2 -6
  486. package/src/types/raw-md.d.ts +5 -0
  487. package/src/utils/colors.ts +4 -4
  488. package/src/utils/form.ts +1 -3
  489. package/src/utils/index.ts +2 -7
  490. package/src/utils/number-format.ts +17 -0
  491. package/src/utils/workout-format.ts +15 -6
  492. package/src/web-jsx/jsx-runtime.ts +1 -5
  493. package/tailwind.config.js +5 -0
  494. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  495. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  496. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  497. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  498. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  499. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  500. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  501. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  502. package/src/components/shell/DashboardShell.tsx +0 -75
  503. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  504. package/src/theme/elevation.stories.tsx +0 -346
  505. package/src/utils/useTheme.ts +0 -72
  506. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  507. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  508. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  509. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -0,0 +1,143 @@
1
+ // The depth contract every floating overlay owes the lift model (E1).
2
+ //
3
+ // One panel, one recipe: the overlay plane from the grey ramp, the rim-light,
4
+ // the three-layer ambient shadow, and NO hairline ring — a ring is an edge, not
5
+ // a lift, and stays the divider's job. The panels are asserted as INLINE STYLE
6
+ // because `<Surface>` writes background and shadow into `style`; a `bg-*` or
7
+ // `shadow-*` className on one would be discarded, so asserting the class would
8
+ // pass while the render was wrong. The plane comes from the ramp, so a re-space
9
+ // moves these expectations rather than breaking them.
10
+ import { describe, it, expect, vi } from 'vitest'
11
+ import { render, screen, fireEvent } from '@testing-library/react'
12
+ import { greyRamp } from '../../theme/tokens/primitives'
13
+ import { Autocomplete } from './autocomplete'
14
+ import { Drawer, DrawerBody } from './drawer'
15
+ import { HelpTip } from './help-tip'
16
+ import { Menu, MenuTrigger, MenuList, MenuItem } from './menu'
17
+ import { Modal, ModalContent, ModalBody } from './modal'
18
+ import { Popover, PopoverTrigger, PopoverContent } from './popover'
19
+ import { Select } from './select'
20
+ import { Toast } from './toast'
21
+ import { Tooltip } from './tooltip'
22
+
23
+ /** The plane every floating overlay shares: past the top of the ramp. */
24
+ const OVERLAY = greyRamp[850]
25
+
26
+ /** The nearest ancestor that paints a plane of its own — the floating panel. */
27
+ function panelAround(child: HTMLElement): HTMLElement {
28
+ let el: HTMLElement | null = child
29
+ while (el && !el.style.boxShadow) el = el.parentElement
30
+ if (!el) throw new Error('no element with an inline boxShadow above the panel content')
31
+ return el
32
+ }
33
+
34
+ /** Split a boxShadow on its layer commas, ignoring the ones inside `rgba(...)`. */
35
+ function shadowLayers(boxShadow: string): string[] {
36
+ return boxShadow.split(/,(?![^(]*\))/).filter((layer) => layer.trim())
37
+ }
38
+
39
+ function expectFloating(panel: HTMLElement) {
40
+ expect(panel).toHaveStyle({ backgroundColor: OVERLAY })
41
+ const layers = shadowLayers(panel.style.boxShadow)
42
+ expect(layers[0]).toContain('inset 0 1px 0 rgba(255,255,255,0.12)')
43
+ // Three ambient layers under the rim: the floating shadow, not a content lift.
44
+ expect(layers.slice(1)).toHaveLength(3)
45
+ expect(panel.style.borderTopWidth).toBe('')
46
+ }
47
+
48
+ /** Open the overlay, then assert the panel wrapping `contentText`. */
49
+ function expectFloatingPanelAround(contentText: string) {
50
+ expectFloating(panelAround(screen.getByText(contentText)))
51
+ }
52
+
53
+ const options = [
54
+ { value: '1', label: 'Apple' },
55
+ { value: '2', label: 'Banana' },
56
+ ]
57
+
58
+ describe('floating overlay depth', () => {
59
+ it('Menu list floats on the overlay plane with no ring', () => {
60
+ render(
61
+ <Menu>
62
+ <MenuTrigger>
63
+ <button>Options</button>
64
+ </MenuTrigger>
65
+ <MenuList>
66
+ <MenuItem>Edit</MenuItem>
67
+ </MenuList>
68
+ </Menu>
69
+ )
70
+ fireEvent.click(screen.getByText('Options'))
71
+ expectFloatingPanelAround('Edit')
72
+ })
73
+
74
+ it('Popover content floats on the overlay plane with no ring', () => {
75
+ render(
76
+ <Popover>
77
+ <PopoverTrigger>
78
+ <button>Open</button>
79
+ </PopoverTrigger>
80
+ <PopoverContent>
81
+ <span>Popover body</span>
82
+ </PopoverContent>
83
+ </Popover>
84
+ )
85
+ fireEvent.click(screen.getByText('Open'))
86
+ expectFloatingPanelAround('Popover body')
87
+ })
88
+
89
+ it('Tooltip box floats on the overlay plane with no ring', () => {
90
+ render(
91
+ <Tooltip label="Tooltip text">
92
+ <button>Hover me</button>
93
+ </Tooltip>
94
+ )
95
+ fireEvent.mouseEnter(screen.getByText('Hover me').closest('[tabindex]')!)
96
+ expectFloatingPanelAround('Tooltip text')
97
+ })
98
+
99
+ it('HelpTip bubble floats on the overlay plane with no ring', () => {
100
+ render(<HelpTip content="Help text" />)
101
+ fireEvent.click(screen.getByRole('button', { name: 'Show help information' }))
102
+ expectFloatingPanelAround('Help text')
103
+ })
104
+
105
+ it('Select dropdown floats on the overlay plane with no ring', () => {
106
+ render(<Select options={options} />)
107
+ fireEvent.click(screen.getByRole('combobox'))
108
+ expectFloatingPanelAround('Banana')
109
+ })
110
+
111
+ it('Autocomplete dropdown floats on the overlay plane with no ring', () => {
112
+ render(<Autocomplete options={options} placeholder="Search" />)
113
+ fireEvent.focus(screen.getByPlaceholderText('Search'))
114
+ expectFloatingPanelAround('Banana')
115
+ })
116
+
117
+ it('Drawer panel floats on the overlay plane with no ring', () => {
118
+ render(
119
+ <Drawer isOpen onClose={vi.fn()} title="Test Drawer">
120
+ <DrawerBody>Drawer body</DrawerBody>
121
+ </Drawer>
122
+ )
123
+ expectFloatingPanelAround('Drawer body')
124
+ })
125
+
126
+ it('Modal content floats on the deepest lift with no ring', () => {
127
+ render(
128
+ <Modal isOpen onClose={vi.fn()}>
129
+ <ModalContent>
130
+ <ModalBody>Modal body</ModalBody>
131
+ </ModalContent>
132
+ </Modal>
133
+ )
134
+ expectFloatingPanelAround('Modal body')
135
+ })
136
+
137
+ it('Toast floats on the deepest lift with no ring', () => {
138
+ render(<Toast title="Saved" />)
139
+ // Its `border-l-4` status stripe is a colour accent on one edge, not a ring,
140
+ // and rides the className rather than the inline style asserted here.
141
+ expectFloatingPanelAround('Saved')
142
+ })
143
+ })
@@ -2,12 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { View, Text, TextInput } from 'react-native'
3
3
  import { FormField, FormSection, FormActions, FormRow } from './FormField'
4
4
  import { Button, ButtonText } from '../button'
5
- import { Input } from '../input'
6
5
 
7
6
  const meta: Meta<typeof FormField> = {
8
7
  title: 'Components/Molecules/FormField',
9
8
  component: FormField,
10
- tags: ['autodocs'],
9
+ parameters: {},
10
+ tags: ['autodocs', 'status:stable', '!status:review'],
11
11
  argTypes: {
12
12
  labelSize: {
13
13
  control: 'select',
@@ -70,10 +70,7 @@ export const Required: Story = {
70
70
  export const WithHelperText: Story = {
71
71
  render: () => (
72
72
  <View className="w-80">
73
- <FormField
74
- label="Username"
75
- helperText="Choose a unique username between 3-20 characters"
76
- >
73
+ <FormField label="Username" helperText="Choose a unique username between 3-20 characters">
77
74
  <SimpleInput placeholder="Enter username" />
78
75
  </FormField>
79
76
  </View>
@@ -83,11 +80,7 @@ export const WithHelperText: Story = {
83
80
  export const WithError: Story = {
84
81
  render: () => (
85
82
  <View className="w-80">
86
- <FormField
87
- label="Password"
88
- isRequired
89
- errorMessage="Password must be at least 8 characters"
90
- >
83
+ <FormField label="Password" isRequired errorMessage="Password must be at least 8 characters">
91
84
  <SimpleInput placeholder="Enter password" isInvalid />
92
85
  </FormField>
93
86
  </View>
@@ -159,10 +152,7 @@ export const FormRowExample: Story = {
159
152
  export const FormSectionExample: Story = {
160
153
  render: () => (
161
154
  <View className="w-full max-w-lg">
162
- <FormSection
163
- title="Personal Information"
164
- description="Please provide your personal details"
165
- >
155
+ <FormSection title="Personal Information" description="Please provide your personal details">
166
156
  <FormRow>
167
157
  <FormField label="First Name" isRequired className="flex-1">
168
158
  <SimpleInput placeholder="John" />
@@ -240,11 +230,7 @@ export const ValidationStates: Story = {
240
230
  </View>
241
231
  </FormField>
242
232
 
243
- <FormField
244
- label="Invalid Input"
245
- isRequired
246
- errorMessage="Please enter a valid email address"
247
- >
233
+ <FormField label="Invalid Input" isRequired errorMessage="Please enter a valid email address">
248
234
  <View className="border border-status-error rounded-md px-3 py-2 bg-surface-input">
249
235
  <Text className="text-text-primary">not-an-email</Text>
250
236
  </View>
@@ -64,11 +64,7 @@ describe('FormField', () => {
64
64
 
65
65
  it('shows error message instead of helper text when both are provided', () => {
66
66
  render(
67
- <FormField
68
- label="Email"
69
- helperText="Enter a valid email"
70
- errorMessage="Invalid email"
71
- >
67
+ <FormField label="Email" helperText="Enter a valid email" errorMessage="Invalid email">
72
68
  <input />
73
69
  </FormField>
74
70
  )
@@ -95,22 +95,12 @@ export function FormField({
95
95
  {/* Label Section */}
96
96
  {label && (
97
97
  <View
98
- className={cn(
99
- 'flex-row items-center',
100
- isHorizontal ? 'pt-2' : 'mb-1.5'
101
- )}
98
+ className={cn('flex-row items-center', isHorizontal ? 'pt-2' : 'mb-1.5')}
102
99
  style={isHorizontal && labelWidth ? { width: labelWidth as number } : undefined}
103
100
  >
104
- <Text
105
- className={cn(
106
- 'font-medium text-text-primary',
107
- labelSizeStyles[labelSize]
108
- )}
109
- >
101
+ <Text className={cn('font-medium text-text-primary', labelSizeStyles[labelSize])}>
110
102
  {label}
111
- {isRequired && (
112
- <Text className="text-status-error ml-0.5">*</Text>
113
- )}
103
+ {isRequired && <Text className="text-status-error ml-0.5">*</Text>}
114
104
  </Text>
115
105
 
116
106
  {helpContent && (
@@ -147,10 +137,7 @@ export function FormField({
147
137
  {(helperText || errorMessage) && (
148
138
  <Text
149
139
  id={isInvalid ? errorId : helperId}
150
- className={cn(
151
- 'text-xs mt-1.5',
152
- isInvalid ? 'text-status-error' : 'text-text-tertiary'
153
- )}
140
+ className={cn('text-xs mt-1.5', isInvalid ? 'text-status-error' : 'text-text-tertiary')}
154
141
  >
155
142
  {errorMessage || helperText}
156
143
  </Text>
@@ -199,22 +186,12 @@ export function FormSection({
199
186
  >
200
187
  {(title || description) && (
201
188
  <View className="mb-4">
202
- {title && (
203
- <Text className="text-lg font-semibold text-text-primary">
204
- {title}
205
- </Text>
206
- )}
207
- {description && (
208
- <Text className="text-sm text-text-secondary mt-1">
209
- {description}
210
- </Text>
211
- )}
189
+ {title && <Text className="text-lg font-semibold text-text-primary">{title}</Text>}
190
+ {description && <Text className="text-sm text-text-secondary mt-1">{description}</Text>}
212
191
  </View>
213
192
  )}
214
193
 
215
- <View className="gap-4">
216
- {children}
217
- </View>
194
+ <View className="gap-4">{children}</View>
218
195
  </View>
219
196
  )
220
197
  }
@@ -243,12 +220,7 @@ const alignStyles = {
243
220
  * <Button>Submit</Button>
244
221
  * </FormActions>
245
222
  */
246
- export function FormActions({
247
- align = 'right',
248
- className,
249
- children,
250
- ...props
251
- }: FormActionsProps) {
223
+ export function FormActions({ align = 'right', className, children, ...props }: FormActionsProps) {
252
224
  return (
253
225
  <View
254
226
  className={cn(
@@ -291,17 +263,9 @@ const gapStyles = {
291
263
  * </FormField>
292
264
  * </FormRow>
293
265
  */
294
- export function FormRow({
295
- gap = 'md',
296
- className,
297
- children,
298
- ...props
299
- }: FormRowProps) {
266
+ export function FormRow({ gap = 'md', className, children, ...props }: FormRowProps) {
300
267
  return (
301
- <View
302
- className={cn('flex-row items-start', gapStyles[gap], className)}
303
- {...props}
304
- >
268
+ <View className={cn('flex-row items-start', gapStyles[gap], className)} {...props}>
305
269
  {children}
306
270
  </View>
307
271
  )
@@ -5,7 +5,7 @@ import { HelpTip, LabelWithHelp } from './HelpTip'
5
5
  const meta: Meta<typeof HelpTip> = {
6
6
  title: 'Components/Molecules/HelpTip',
7
7
  component: HelpTip,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:candidate', '!status:review'],
9
9
  argTypes: {
10
10
  size: {
11
11
  control: 'select',
@@ -115,7 +115,8 @@ export const AllPlacements: Story = {
115
115
 
116
116
  export const WithLongContent: Story = {
117
117
  args: {
118
- content: 'This is a longer tooltip that contains more detailed information about the feature. It will wrap to multiple lines if needed, and you can customize the max width.',
118
+ content:
119
+ 'This is a longer tooltip that contains more detailed information about the feature. It will wrap to multiple lines if needed, and you can customize the max width.',
119
120
  maxWidth: 300,
120
121
  },
121
122
  }
@@ -126,15 +127,9 @@ export const WithRichContent: Story = {
126
127
  content={
127
128
  <View className="gap-1">
128
129
  <Text className="text-sm font-semibold text-text-primary">API Rate Limits</Text>
129
- <Text className="text-xs text-text-secondary">
130
- Free tier: 100 requests/hour
131
- </Text>
132
- <Text className="text-xs text-text-secondary">
133
- • Pro tier: 1000 requests/hour
134
- </Text>
135
- <Text className="text-xs text-text-secondary">
136
- • Enterprise: Unlimited
137
- </Text>
130
+ <Text className="text-xs text-text-secondary">• Free tier: 100 requests/hour</Text>
131
+ <Text className="text-xs text-text-secondary">• Pro tier: 1000 requests/hour</Text>
132
+ <Text className="text-xs text-text-secondary">• Enterprise: Unlimited</Text>
138
133
  </View>
139
134
  }
140
135
  icon="info"
@@ -148,10 +143,7 @@ export const InlineWithLabel: Story = {
148
143
  <View className="gap-4">
149
144
  <View className="flex-row items-center gap-1">
150
145
  <Text className="text-sm font-medium text-text-primary">Email Address</Text>
151
- <HelpTip
152
- content="We'll never share your email with third parties."
153
- size="sm"
154
- />
146
+ <HelpTip content="We'll never share your email with third parties." size="sm" />
155
147
  </View>
156
148
 
157
149
  <View className="flex-row items-center gap-1">
@@ -178,10 +170,7 @@ export const InlineWithLabel: Story = {
178
170
  export const LabelWithHelpComponent: Story = {
179
171
  render: () => (
180
172
  <View className="gap-4">
181
- <LabelWithHelp
182
- label="Username"
183
- helpContent="Choose a unique username for your account."
184
- />
173
+ <LabelWithHelp label="Username" helpContent="Choose a unique username for your account." />
185
174
 
186
175
  <LabelWithHelp
187
176
  label="Email Address"
@@ -28,9 +28,7 @@ describe('HelpTip', () => {
28
28
  })
29
29
 
30
30
  it('renders custom ReactNode content', () => {
31
- render(
32
- <HelpTip content={<span data-testid="custom-content">Rich content</span>} />
33
- )
31
+ render(<HelpTip content={<span data-testid="custom-content">Rich content</span>} />)
34
32
 
35
33
  fireEvent.click(screen.getByRole('button', { name: 'Show help information' }))
36
34
  expect(screen.getByTestId('custom-content')).toBeInTheDocument()
@@ -1,6 +1,7 @@
1
1
  import React, { useState } from 'react'
2
2
  import { View, Text, Pressable, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
+ import { Surface } from '../surface'
4
5
 
5
6
  export type HelpTipSize = 'sm' | 'md' | 'lg'
6
7
  export type HelpTipPlacement = 'top' | 'bottom' | 'left' | 'right'
@@ -56,10 +57,12 @@ const placementStyles: Record<HelpTipPlacement, string> = {
56
57
  }
57
58
 
58
59
  const arrowStyles: Record<HelpTipPlacement, string> = {
59
- top: 'bottom-0 left-1/2 -translate-x-1/2 translate-y-full border-t-surface-elevated border-x-transparent border-b-transparent',
60
- bottom: 'top-0 left-1/2 -translate-x-1/2 -translate-y-full border-b-surface-elevated border-x-transparent border-t-transparent',
61
- left: 'right-0 top-1/2 -translate-y-1/2 translate-x-full border-l-surface-elevated border-y-transparent border-r-transparent',
62
- right: 'left-0 top-1/2 -translate-y-1/2 -translate-x-full border-r-surface-elevated border-y-transparent border-l-transparent',
60
+ top: 'bottom-0 left-1/2 -translate-x-1/2 translate-y-full border-t-surface-overlay border-x-transparent border-b-transparent',
61
+ bottom:
62
+ 'top-0 left-1/2 -translate-x-1/2 -translate-y-full border-b-surface-overlay border-x-transparent border-t-transparent',
63
+ left: 'right-0 top-1/2 -translate-y-1/2 translate-x-full border-l-surface-overlay border-y-transparent border-r-transparent',
64
+ right:
65
+ 'left-0 top-1/2 -translate-y-1/2 -translate-x-full border-r-surface-overlay border-y-transparent border-l-transparent',
63
66
  }
64
67
 
65
68
  /**
@@ -87,6 +90,9 @@ const arrowStyles: Record<HelpTipPlacement, string> = {
87
90
  * <Text>Email Address</Text>
88
91
  * <HelpTip content="We'll never share your email with anyone." size="sm" />
89
92
  * </View>
93
+ *
94
+ * @deprecated Use `Tooltip` (roadmap decision 5) — removed after AW-127
95
+ * consumer migration.
90
96
  */
91
97
  export function HelpTip({
92
98
  content,
@@ -144,43 +150,33 @@ export function HelpTip({
144
150
  iconClassName
145
151
  )}
146
152
  >
147
- <Text className={cn('font-semibold', iconSize, colorStyles[color])}>
148
- {iconMap[icon]}
149
- </Text>
153
+ <Text className={cn('font-semibold', iconSize, colorStyles[color])}>{iconMap[icon]}</Text>
150
154
  </Pressable>
151
155
 
152
156
  {/* Tooltip */}
153
157
  {isOpen && (
154
- <View
158
+ <Surface
159
+ elevation={4}
160
+ rounded={false}
155
161
  className={cn(
156
162
  'absolute z-50',
157
- 'bg-surface-elevated rounded-lg shadow-lg',
158
- 'border border-hairline',
159
- 'px-3 py-2',
163
+ 'rounded-lg px-3 py-2',
160
164
  placementStyles[placement],
161
165
  tooltipClassName
162
166
  )}
163
167
  style={{ maxWidth }}
164
168
  >
165
169
  {typeof content === 'string' ? (
166
- <Text className={cn('text-text-primary', textSize)}>
167
- {content}
168
- </Text>
170
+ <Text className={cn('text-text-primary', textSize)}>{content}</Text>
169
171
  ) : (
170
172
  content
171
173
  )}
172
174
 
173
175
  {/* Arrow */}
174
176
  {hasArrow && (
175
- <View
176
- className={cn(
177
- 'absolute w-0 h-0',
178
- 'border-4',
179
- arrowStyles[placement]
180
- )}
181
- />
177
+ <View className={cn('absolute w-0 h-0', 'border-4', arrowStyles[placement])} />
182
178
  )}
183
- </View>
179
+ </Surface>
184
180
  )}
185
181
  </View>
186
182
  )
@@ -208,6 +204,9 @@ export interface LabelWithHelpProps extends ViewProps {
208
204
  * helpContent="Your API key can be found in the developer settings."
209
205
  * isRequired
210
206
  * />
207
+ *
208
+ * @deprecated Use `Tooltip` beside your own label (roadmap decision 5) —
209
+ * removed after AW-127 consumer migration.
211
210
  */
212
211
  export function LabelWithHelp({
213
212
  label,
@@ -1,2 +1,8 @@
1
1
  export { HelpTip, LabelWithHelp } from './HelpTip'
2
- export type { HelpTipProps, LabelWithHelpProps, HelpTipSize, HelpTipPlacement, HelpTipIcon } from './HelpTip'
2
+ export type {
3
+ HelpTipProps,
4
+ LabelWithHelpProps,
5
+ HelpTipSize,
6
+ HelpTipPlacement,
7
+ HelpTipIcon,
8
+ } from './HelpTip'
@@ -55,7 +55,7 @@ function BoltIcon({ size = 20, className }: { size?: number; className?: string
55
55
  const meta: Meta<typeof IconBox> = {
56
56
  title: 'Components/Atoms/IconBox',
57
57
  component: IconBox,
58
- tags: ['autodocs'],
58
+ tags: ['autodocs', 'status:stable', '!status:review'],
59
59
  argTypes: {
60
60
  color: {
61
61
  control: 'select',
@@ -98,13 +98,7 @@ describe('IconBox', () => {
98
98
 
99
99
  it('renders with all props combined', () => {
100
100
  render(
101
- <IconBox
102
- icon={MockIcon}
103
- color="success"
104
- size="lg"
105
- className="mt-2"
106
- testID="full-icon-box"
107
- />,
101
+ <IconBox icon={MockIcon} color="success" size="lg" className="mt-2" testID="full-icon-box" />
108
102
  )
109
103
  expect(screen.getByTestId('full-icon-box')).toBeInTheDocument()
110
104
  expect(screen.getByTestId('icon')).toHaveAttribute('data-size', '24')
@@ -2,14 +2,7 @@ import React from 'react'
2
2
  import { View, type ViewProps } from 'react-native'
3
3
  import { cn } from '../../../utils/cn'
4
4
 
5
- type IconBoxColor =
6
- | 'primary'
7
- | 'secondary'
8
- | 'success'
9
- | 'error'
10
- | 'warning'
11
- | 'info'
12
- | 'neutral'
5
+ type IconBoxColor = 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'neutral'
13
6
 
14
7
  type IconBoxSize = 'sm' | 'md' | 'lg'
15
8
 
@@ -47,10 +40,7 @@ export function IconBox({
47
40
  const sizes = sizeClasses[size]
48
41
 
49
42
  return (
50
- <View
51
- className={cn('items-center justify-center', colors.bg, sizes.box, className)}
52
- {...props}
53
- >
43
+ <View className={cn('items-center justify-center', colors.bg, sizes.box, className)} {...props}>
54
44
  <Icon size={sizes.iconSize} className={colors.icon} />
55
45
  </View>
56
46
  )
@@ -5,7 +5,7 @@ import { Indicator } from './Indicator'
5
5
  const meta: Meta<typeof Indicator> = {
6
6
  title: 'Components/Atoms/Indicator',
7
7
  component: Indicator,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  size: { control: 'select', options: ['xs', 'sm', 'md', 'lg'] },
11
11
  color: {
@@ -1,5 +1,8 @@
1
1
  import { View, type ViewProps } from 'react-native'
2
2
  import { cn } from '../../../utils/cn'
3
+ import { getGlowShadow } from '../../../theme/elevation'
4
+ import { getSemanticColors } from '../../../theme/tokens/semantic'
5
+ import { greyRamp } from '../../../theme/tokens/primitives'
3
6
 
4
7
  export type IndicatorSize = 'xs' | 'sm' | 'md' | 'lg'
5
8
  export type IndicatorColor =
@@ -50,6 +53,21 @@ const colorStyles: Record<IndicatorColor, string> = {
50
53
  'error-vivid': 'bg-status-error-vivid',
51
54
  }
52
55
 
56
+ // Glow is EMPHASIS, not depth: the dot's own colour, through the shared builder.
57
+ // Literal hex (not `resolveColor`) because getGlowShadow does colour maths on it.
58
+ const t = getSemanticColors('dark')
59
+
60
+ const glowColors: Record<IndicatorColor, string> = {
61
+ default: greyRamp[500],
62
+ primary: t['brand-primary'],
63
+ success: t['status-success'],
64
+ live: t['status-live'],
65
+ error: t['status-error'],
66
+ warning: t['status-warning'],
67
+ info: t['status-info'],
68
+ 'error-vivid': t['status-error-vivid'],
69
+ }
70
+
53
71
  export function Indicator({
54
72
  size = 'sm',
55
73
  color = 'default',
@@ -86,11 +104,7 @@ export function Indicator({
86
104
  )
87
105
  }
88
106
 
89
- const dynamicStyle = {
90
- ...(typeof style === 'object' ? style : {}),
91
- ...(colorStyle ?? {}),
92
- ...(glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}),
93
- }
107
+ const glowStyle = glow ? getGlowShadow(customColor ?? glowColors[color], 'subtle') : null
94
108
 
95
109
  return (
96
110
  <View
@@ -100,17 +114,9 @@ export function Indicator({
100
114
  colorClass,
101
115
  pulseMode === 'opacity' && 'animate-pulse',
102
116
  ring && 'border-2 border-background-base',
103
- glow &&
104
- !customColor &&
105
- (color === 'success' || color === 'live') &&
106
- 'shadow-[0_0_6px_rgba(46,213,115,0.6)]',
107
- glow && !customColor && color === 'error' && 'shadow-[0_0_6px_rgba(239,68,68,0.6)]',
108
- glow && !customColor && color === 'warning' && 'shadow-[0_0_6px_rgba(245,158,11,0.6)]',
109
- glow && !customColor && color === 'primary' && 'shadow-[0_0_6px_rgba(255,121,0,0.6)]',
110
- glow && !customColor && color === 'error-vivid' && 'shadow-[0_0_6px_rgba(255,71,87,0.6)]',
111
117
  className
112
118
  )}
113
- style={Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style}
119
+ style={[style, colorStyle, glowStyle]}
114
120
  {...props}
115
121
  />
116
122
  )
@@ -5,7 +5,7 @@ import { Input, InputGroup, PasswordInput } from './Input'
5
5
  const meta: Meta<typeof Input> = {
6
6
  title: 'Components/Molecules/Input',
7
7
  component: Input,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'status:stable', '!status:review'],
9
9
  argTypes: {
10
10
  variant: {
11
11
  control: 'select',
@@ -161,10 +161,7 @@ function SearchIcon() {
161
161
  export const WithLeftElement: Story = {
162
162
  render: () => (
163
163
  <View style={{ gap: 16, width: 300 }}>
164
- <Input
165
- placeholder="Search..."
166
- leftElement={<SearchIcon />}
167
- />
164
+ <Input placeholder="Search..." leftElement={<SearchIcon />} />
168
165
  </View>
169
166
  ),
170
167
  }
@@ -181,12 +178,7 @@ export const FormExample: Story = {
181
178
  helperText="Must be at least 8 characters"
182
179
  isRequired
183
180
  />
184
- <Input
185
- label="Bio"
186
- placeholder="Tell us about yourself..."
187
- multiline
188
- numberOfLines={3}
189
- />
181
+ <Input label="Bio" placeholder="Tell us about yourself..." multiline numberOfLines={3} />
190
182
  </InputGroup>
191
183
  ),
192
184
  }