@titan-design/react-ui 0.5.0 → 0.7.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 (307) hide show
  1. package/dist/bodymap.js +241 -189
  2. package/dist/bodymap.js.map +1 -1
  3. package/dist/bodymap.mjs +241 -189
  4. package/dist/bodymap.mjs.map +1 -1
  5. package/dist/index.d.mts +1017 -130
  6. package/dist/index.d.ts +1017 -130
  7. package/dist/index.js +3058 -1090
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +2992 -1091
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/{pages-MO0JCySL.d.mts → pages-8u_4WbL-.d.mts} +280 -57
  12. package/dist/{pages-D7Jlssvp.d.ts → pages-DaWiBOGa.d.ts} +280 -57
  13. package/dist/pages.d.mts +1 -1
  14. package/dist/pages.d.ts +1 -1
  15. package/dist/pages.js +1797 -1292
  16. package/dist/pages.js.map +1 -1
  17. package/dist/pages.mjs +1797 -1292
  18. package/dist/pages.mjs.map +1 -1
  19. package/dist/theme/index.d.mts +464 -268
  20. package/dist/theme/index.d.ts +464 -268
  21. package/dist/theme/index.js +303 -191
  22. package/dist/theme/index.js.map +1 -1
  23. package/dist/theme/index.mjs +295 -192
  24. package/dist/theme/index.mjs.map +1 -1
  25. package/dist/theme/tokens-css.js +160 -143
  26. package/dist/theme/tokens-css.js.map +1 -1
  27. package/dist/theme/tokens-css.mjs +160 -143
  28. package/dist/theme/tokens-css.mjs.map +1 -1
  29. package/package.json +3 -1
  30. package/src/arch/Architecture.stories.tsx +870 -0
  31. package/src/arch/annotations.json +48 -0
  32. package/src/arch/arch-graph.json +4301 -0
  33. package/src/components/custom/DateTime/DateTime.stories.tsx +83 -7
  34. package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
  35. package/src/components/custom/DateTime/DateTime.tsx +55 -15
  36. package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
  37. package/src/components/custom/Gauge/Gauge.stories.tsx +1 -1
  38. package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
  39. package/src/components/custom/Gauge/Gauge.tsx +6 -3
  40. package/src/components/custom/Metric/Metric.stories.tsx +1 -1
  41. package/src/components/custom/Scatter/Scatter.stories.tsx +1 -1
  42. package/src/components/custom/Scatter/Scatter.tsx +3 -5
  43. package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
  44. package/src/components/custom/Table/Table.stories.tsx +1 -1
  45. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +62 -0
  46. package/src/components/custom/TimerReadout/TimerReadout.test.tsx +72 -0
  47. package/src/components/custom/TimerReadout/TimerReadout.tsx +75 -0
  48. package/src/components/custom/TimerReadout/index.ts +1 -0
  49. package/src/components/custom/Treemap/Treemap.stories.tsx +1 -1
  50. package/src/components/custom/Treemap/Treemap.tsx +3 -5
  51. package/src/components/custom/Typography/Typography.stories.tsx +46 -28
  52. package/src/components/custom/Typography/Typography.test.tsx +13 -3
  53. package/src/components/custom/Typography/Typography.tsx +5 -0
  54. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +21 -13
  55. package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +16 -13
  56. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +11 -16
  57. package/src/components/custom/Workout/BaseBadge.stories.tsx +1 -1
  58. package/src/components/custom/Workout/BodyMap.stories.tsx +1 -1
  59. package/src/components/custom/Workout/BodyMap.tsx +6 -3
  60. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +1 -1
  61. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
  62. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +1 -1
  63. package/src/components/custom/Workout/CapacityBandChart.test.tsx +2 -2
  64. package/src/components/custom/Workout/CapacityBandChart.tsx +9 -6
  65. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  66. package/src/components/custom/Workout/DeviationBar.test.tsx +1 -1
  67. package/src/components/custom/Workout/DeviationBar.tsx +7 -4
  68. package/src/components/custom/Workout/ExerciseCard.stories.tsx +51 -66
  69. package/src/components/custom/Workout/ExerciseCard.test.tsx +146 -143
  70. package/src/components/custom/Workout/ExerciseCard.tsx +176 -198
  71. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +99 -0
  72. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +72 -0
  73. package/src/components/custom/Workout/ExerciseCardHeading.tsx +43 -0
  74. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +151 -0
  75. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +5 -3
  76. package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +4 -4
  77. package/src/components/custom/Workout/ExerciseDetailPage.tsx +6 -6
  78. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +81 -0
  79. package/src/components/custom/Workout/ExerciseHeading.test.tsx +77 -0
  80. package/src/components/custom/Workout/ExerciseHeading.tsx +85 -0
  81. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +110 -0
  82. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +93 -0
  83. package/src/components/custom/Workout/ExerciseIndicator.tsx +120 -0
  84. package/src/components/custom/Workout/FatigueMeter.stories.tsx +51 -0
  85. package/src/components/custom/Workout/FatigueMeter.test.tsx +73 -0
  86. package/src/components/custom/Workout/FatigueMeter.tsx +82 -0
  87. package/src/components/custom/Workout/InputBar.stories.tsx +1 -1
  88. package/src/components/custom/Workout/InputBar.tsx +2 -1
  89. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  90. package/src/components/custom/Workout/IntensityBar.test.tsx +8 -8
  91. package/src/components/custom/Workout/IntensityBar.tsx +10 -6
  92. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +153 -0
  93. package/src/components/custom/Workout/LiveAuraFrame.test.tsx +74 -0
  94. package/src/components/custom/Workout/LiveAuraFrame.tsx +105 -0
  95. package/src/components/custom/Workout/MesoCard.stories.tsx +1 -1
  96. package/src/components/custom/Workout/MesoCard.tsx +8 -3
  97. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  98. package/src/components/custom/Workout/MesoProgressBar.test.tsx +1 -1
  99. package/src/components/custom/Workout/MesoProgressBar.tsx +3 -2
  100. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +1 -1
  101. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
  102. package/src/components/custom/Workout/MetricTiles.stories.tsx +60 -0
  103. package/src/components/custom/Workout/MetricTiles.test.tsx +58 -0
  104. package/src/components/custom/Workout/MetricTiles.tsx +48 -0
  105. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +1 -1
  106. package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
  107. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  108. package/src/components/custom/Workout/PrBadge.stories.tsx +1 -1
  109. package/src/components/custom/Workout/PrBadge.tsx +5 -2
  110. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +1 -1
  111. package/src/components/custom/Workout/PrHistoryModal.tsx +4 -3
  112. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +4 -16
  113. package/src/components/custom/Workout/ProgramPlanningPage.tsx +10 -7
  114. package/src/components/custom/Workout/README.md +146 -4
  115. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +1 -1
  116. package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
  117. package/src/components/custom/Workout/RestTimer.stories.tsx +1 -1
  118. package/src/components/custom/Workout/RestTimer.tsx +17 -11
  119. package/src/components/custom/Workout/RowInventory.stories.tsx +405 -0
  120. package/src/components/custom/Workout/S3FullRail.stories.tsx +34 -0
  121. package/src/components/custom/Workout/S3SessionPace.stories.tsx +95 -0
  122. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +61 -0
  123. package/src/components/custom/Workout/S3SetTypes.stories.tsx +176 -0
  124. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +240 -0
  125. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +40 -0
  126. package/src/components/custom/Workout/ScheduleTiles.test.tsx +34 -0
  127. package/src/components/custom/Workout/ScheduleTiles.tsx +70 -0
  128. package/src/components/custom/Workout/SegmentedBar.stories.tsx +99 -0
  129. package/src/components/custom/Workout/SegmentedBar.test.tsx +77 -0
  130. package/src/components/custom/Workout/SegmentedBar.tsx +172 -0
  131. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +50 -0
  132. package/src/components/custom/Workout/SegmentedProgressBar.test.tsx +80 -0
  133. package/src/components/custom/Workout/SegmentedProgressBar.tsx +67 -0
  134. package/src/components/custom/Workout/SessionHeader.stories.tsx +121 -0
  135. package/src/components/custom/Workout/SessionHeader.test.tsx +122 -0
  136. package/src/components/custom/Workout/SessionHeader.tsx +152 -0
  137. package/src/components/custom/Workout/SessionRail.stories.tsx +153 -0
  138. package/src/components/custom/Workout/SessionRail.test.tsx +86 -0
  139. package/src/components/custom/Workout/SessionRail.tsx +126 -0
  140. package/src/components/custom/Workout/SetBar.stories.tsx +124 -0
  141. package/src/components/custom/Workout/SetBar.test.tsx +123 -0
  142. package/src/components/custom/Workout/SetBar.tsx +171 -0
  143. package/src/components/custom/Workout/SetRow.stories.tsx +50 -100
  144. package/src/components/custom/Workout/SetRow.test.tsx +94 -166
  145. package/src/components/custom/Workout/SetRow.tsx +170 -232
  146. package/src/components/custom/Workout/SetStrip.stories.tsx +154 -0
  147. package/src/components/custom/Workout/SetStrip.test.tsx +109 -0
  148. package/src/components/custom/Workout/SetStrip.tsx +71 -0
  149. package/src/components/custom/Workout/SetTableHeader.stories.tsx +66 -0
  150. package/src/components/custom/Workout/SetTableHeader.test.tsx +47 -0
  151. package/src/components/custom/Workout/SetTableHeader.tsx +88 -0
  152. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +47 -0
  153. package/src/components/custom/Workout/SetsRepsLoad.test.tsx +44 -0
  154. package/src/components/custom/Workout/SetsRepsLoad.tsx +52 -0
  155. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  156. package/src/components/custom/Workout/Sparkline.tsx +2 -1
  157. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  158. package/src/components/custom/Workout/StatusDot.test.tsx +2 -2
  159. package/src/components/custom/Workout/StatusDot.tsx +12 -9
  160. package/src/components/custom/Workout/StatusPill.stories.tsx +59 -0
  161. package/src/components/custom/Workout/StatusPill.test.tsx +63 -0
  162. package/src/components/custom/Workout/StatusPill.tsx +88 -0
  163. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +1 -1
  164. package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
  165. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +1 -1
  166. package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
  167. package/src/components/custom/Workout/TempoBar.stories.tsx +1 -1
  168. package/src/components/custom/Workout/TempoDisplay.stories.tsx +12 -1
  169. package/src/components/custom/Workout/TempoDisplay.tsx +29 -36
  170. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +1 -1
  171. package/src/components/custom/Workout/VelocityStrip.modalities.stories.tsx +254 -0
  172. package/src/components/custom/Workout/VelocityStrip.responsive.stories.tsx +145 -0
  173. package/src/components/custom/Workout/VelocityStrip.stories.tsx +129 -66
  174. package/src/components/custom/Workout/VelocityStrip.test.tsx +379 -144
  175. package/src/components/custom/Workout/VelocityStrip.tsx +508 -120
  176. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +73 -0
  177. package/src/components/custom/Workout/VolumeLandmarkBar.test.tsx +119 -0
  178. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +154 -0
  179. package/src/components/custom/Workout/WeekRow.stories.tsx +1 -1
  180. package/src/components/custom/Workout/WeekRow.tsx +3 -2
  181. package/src/components/custom/Workout/WeightBadge.stories.tsx +1 -1
  182. package/src/components/custom/Workout/WeightBadge.tsx +6 -2
  183. package/src/components/custom/Workout/WorkoutCard.stories.tsx +2 -6
  184. package/src/components/custom/Workout/WorkoutCard.test.tsx +13 -46
  185. package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
  186. package/src/components/custom/Workout/WorkoutPill.stories.tsx +1 -1
  187. package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
  188. package/src/components/custom/Workout/ZoneTrack.stories.tsx +140 -0
  189. package/src/components/custom/Workout/ZoneTrack.test.tsx +200 -0
  190. package/src/components/custom/Workout/ZoneTrack.tsx +315 -0
  191. package/src/components/custom/Workout/icons.tsx +6 -67
  192. package/src/components/custom/Workout/index.ts +55 -2
  193. package/src/components/custom/Workout/metricText.stories.tsx +69 -0
  194. package/src/components/custom/Workout/metricText.tsx +34 -0
  195. package/src/components/custom/Workout/paceTone.test.ts +29 -0
  196. package/src/components/custom/Workout/paceTone.ts +27 -0
  197. package/src/components/custom/Workout/setHeadingKit.tsx +177 -0
  198. package/src/components/custom/index.ts +1 -0
  199. package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
  200. package/src/components/icons/SvgIcon.tsx +50 -0
  201. package/src/components/icons/icons.stories.tsx +122 -0
  202. package/src/components/icons/icons.test.tsx +73 -0
  203. package/src/components/icons/icons.tsx +153 -0
  204. package/src/components/icons/index.ts +4 -0
  205. package/src/components/index.ts +6 -0
  206. package/src/components/shell/BrandLockup.stories.tsx +27 -0
  207. package/src/components/shell/BrandLockup.test.tsx +23 -0
  208. package/src/components/shell/BrandLockup.tsx +47 -0
  209. package/src/components/shell/DashboardShell.stories.tsx +65 -0
  210. package/src/components/shell/DashboardShell.test.tsx +42 -0
  211. package/src/components/shell/DashboardShell.tsx +74 -0
  212. package/src/components/shell/DeviceIndicator.stories.tsx +28 -0
  213. package/src/components/shell/DeviceIndicator.test.tsx +26 -0
  214. package/src/components/shell/DeviceIndicator.tsx +52 -0
  215. package/src/components/shell/DeviceMenu.stories.tsx +47 -0
  216. package/src/components/shell/DeviceMenu.test.tsx +40 -0
  217. package/src/components/shell/DeviceMenu.tsx +65 -0
  218. package/src/components/shell/DeviceRow.stories.tsx +38 -0
  219. package/src/components/shell/DeviceRow.test.tsx +37 -0
  220. package/src/components/shell/DeviceRow.tsx +58 -0
  221. package/src/components/shell/NavItem.stories.tsx +52 -0
  222. package/src/components/shell/NavItem.test.tsx +35 -0
  223. package/src/components/shell/NavItem.tsx +75 -0
  224. package/src/components/shell/README.md +116 -0
  225. package/src/components/shell/SessionRailSpecimen.stories.tsx +753 -0
  226. package/src/components/shell/SessionStatePill.stories.tsx +27 -0
  227. package/src/components/shell/SessionStatePill.test.tsx +25 -0
  228. package/src/components/shell/SessionStatePill.tsx +46 -0
  229. package/src/components/shell/SideNav.stories.tsx +81 -0
  230. package/src/components/shell/SideNav.test.tsx +51 -0
  231. package/src/components/shell/SideNav.tsx +74 -0
  232. package/src/components/shell/TopBar.stories.tsx +49 -0
  233. package/src/components/shell/TopBar.test.tsx +36 -0
  234. package/src/components/shell/TopBar.tsx +89 -0
  235. package/src/components/shell/index.ts +13 -0
  236. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  237. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
  238. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  239. package/src/components/ui/badge/Badge.stories.tsx +1 -1
  240. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  241. package/src/components/ui/button/Button.stories.tsx +1 -1
  242. package/src/components/ui/card/Card.stories.tsx +1 -1
  243. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  244. package/src/components/ui/chip/Chip.stories.tsx +1 -1
  245. package/src/components/ui/collapse/Collapse.stories.tsx +1 -1
  246. package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
  247. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  248. package/src/components/ui/drawer/Drawer.stories.tsx +1 -1
  249. package/src/components/ui/form-field/FormField.stories.tsx +1 -1
  250. package/src/components/ui/help-tip/HelpTip.stories.tsx +1 -1
  251. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  252. package/src/components/ui/index.ts +1 -0
  253. package/src/components/ui/indicator/Indicator.stories.tsx +38 -2
  254. package/src/components/ui/indicator/Indicator.test.tsx +20 -1
  255. package/src/components/ui/indicator/Indicator.tsx +50 -6
  256. package/src/components/ui/indicator/index.ts +1 -1
  257. package/src/components/ui/input/Input.stories.tsx +1 -1
  258. package/src/components/ui/link/Link.stories.tsx +1 -1
  259. package/src/components/ui/list-item/ListItem.stories.tsx +1 -1
  260. package/src/components/ui/menu/Menu.stories.tsx +1 -1
  261. package/src/components/ui/modal/Modal.stories.tsx +1 -1
  262. package/src/components/ui/pill/Pill.stories.tsx +1 -1
  263. package/src/components/ui/popover/Popover.stories.tsx +1 -1
  264. package/src/components/ui/progress/Progress.stories.tsx +1 -1
  265. package/src/components/ui/radio/Radio.stories.tsx +1 -1
  266. package/src/components/ui/section/Section.stories.tsx +1 -1
  267. package/src/components/ui/select/Select.stories.tsx +1 -1
  268. package/src/components/ui/skeleton/Skeleton.stories.tsx +1 -1
  269. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  270. package/src/components/ui/spinner/Spinner.tsx +3 -2
  271. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  272. package/src/components/ui/surface/Surface.stories.tsx +1 -1
  273. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  274. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  275. package/src/components/ui/tile/Tile.stories.tsx +79 -0
  276. package/src/components/ui/tile/Tile.test.tsx +48 -0
  277. package/src/components/ui/tile/Tile.tsx +64 -0
  278. package/src/components/ui/tile/index.ts +2 -0
  279. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  280. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +1 -1
  281. package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
  282. package/src/components/ui/tooltip/Tooltip.stories.tsx +1 -1
  283. package/src/examples/react-hook-form/ReactHookForm.stories.tsx +1 -1
  284. package/src/hooks/index.ts +2 -0
  285. package/src/hooks/useTimer.test.ts +150 -0
  286. package/src/hooks/useTimer.ts +77 -0
  287. package/src/index.ts +3 -0
  288. package/src/pages.ts +1 -1
  289. package/src/stories/PresetShowcase.stories.tsx +1 -1
  290. package/src/stories/ThemePresets.stories.tsx +1 -1
  291. package/src/theme/ColorSystem.stories.tsx +323 -0
  292. package/src/theme/Colors.stories.tsx +74 -9
  293. package/src/theme/barrel.ts +1 -0
  294. package/src/theme/config.ts +20 -3
  295. package/src/theme/elevation.stories.tsx +1 -1
  296. package/src/theme/extracted-colors-dataviz.ts +21 -0
  297. package/src/theme/extracted-colors-ui.ts +20 -0
  298. package/src/theme/global.css +69 -53
  299. package/src/theme/gradients.test.ts +25 -0
  300. package/src/theme/gradients.ts +36 -0
  301. package/src/theme/shadows.stories.tsx +1 -1
  302. package/src/theme/tokens/primitives.test.ts +232 -0
  303. package/src/theme/tokens/primitives.ts +238 -87
  304. package/src/theme/tokens/semantic.ts +101 -81
  305. package/src/theme/workout-tokens.ts +26 -21
  306. package/src/utils/avatar-color.ts +3 -3
  307. package/tailwind.config.js +15 -3
@@ -0,0 +1,109 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { axe } from 'jest-axe'
4
+ import { SetStrip, velocityZoneColor, SET_STRIP_ZONES, type SetStripSet } from './SetStrip'
5
+
6
+ describe('SetStrip', () => {
7
+ describe('velocityZoneColor', () => {
8
+ it('maps velocity ratios to their zone pins', () => {
9
+ expect(velocityZoneColor(0.4)).toBe(SET_STRIP_ZONES.slow)
10
+ expect(velocityZoneColor(0.6)).toBe(SET_STRIP_ZONES.moderate)
11
+ expect(velocityZoneColor(0.85)).toBe(SET_STRIP_ZONES.fast)
12
+ expect(velocityZoneColor(1.2)).toBe(SET_STRIP_ZONES.fastest)
13
+ })
14
+
15
+ it('uses the real titan ramp pins (not ad-hoc hexes)', () => {
16
+ expect(SET_STRIP_ZONES.slow).toBe('#D14343') // red 600
17
+ expect(SET_STRIP_ZONES.moderate).toBe('#FF7900') // orange 400
18
+ expect(SET_STRIP_ZONES.fast).toBe('#F9B415') // amber 300
19
+ expect(SET_STRIP_ZONES.fastest).toBe('#2ED573') // green 300
20
+ })
21
+ })
22
+
23
+ it('renders one bar per set', () => {
24
+ const sets: SetStripSet[] = [
25
+ { status: 'done', velocities: [1, 0.9] },
26
+ { status: 'done', velocities: [0.8] },
27
+ ]
28
+ render(<SetStrip sets={sets} />)
29
+ expect(screen.getAllByTestId('set-strip-set')).toHaveLength(2)
30
+ })
31
+
32
+ describe('set statuses', () => {
33
+ it('done: one colored fill segment per rep, no empties, no pulse', () => {
34
+ render(<SetStrip sets={[{ status: 'done', velocities: [1, 0.8, 0.6, 0.4] }]} />)
35
+ expect(screen.getAllByTestId('set-strip-fill')).toHaveLength(4)
36
+ expect(screen.queryByTestId('set-strip-empty')).not.toBeInTheDocument()
37
+ expect(screen.queryByTestId('set-strip-pulse')).not.toBeInTheDocument()
38
+ })
39
+
40
+ it('active: performed reps pulse, the remainder is greyed', () => {
41
+ render(<SetStrip sets={[{ status: 'active', velocities: [0.9, 0.7, 0.5], planned: 8 }]} />)
42
+ expect(screen.getAllByTestId('set-strip-pulse')).toHaveLength(3)
43
+ expect(screen.getAllByTestId('set-strip-empty')).toHaveLength(5)
44
+ })
45
+
46
+ it('todo: a single grey bar, no fills or pulses', () => {
47
+ render(<SetStrip sets={[{ status: 'todo', planned: 10 }]} />)
48
+ expect(screen.getAllByTestId('set-strip-empty')).toHaveLength(1)
49
+ expect(screen.queryByTestId('set-strip-fill')).not.toBeInTheDocument()
50
+ expect(screen.queryByTestId('set-strip-pulse')).not.toBeInTheDocument()
51
+ })
52
+ })
53
+
54
+ it('defaults to an 8px height and honors the height prop', () => {
55
+ const sets: SetStripSet[] = [{ status: 'todo', planned: 3 }]
56
+ const { rerender } = render(<SetStrip sets={sets} />)
57
+ expect(screen.getByTestId('set-strip')).toHaveStyle({ height: '8px' })
58
+ rerender(<SetStrip sets={sets} height={4} />)
59
+ expect(screen.getByTestId('set-strip')).toHaveStyle({ height: '4px' })
60
+ })
61
+
62
+ it('exposes a set-progress summary label', () => {
63
+ const sets: SetStripSet[] = [
64
+ { status: 'done', velocities: [1] },
65
+ { status: 'active', velocities: [0.9], planned: 3 },
66
+ { status: 'todo', planned: 3 },
67
+ ]
68
+ render(<SetStrip sets={sets} />)
69
+ expect(
70
+ screen.getByLabelText('Set progress: 1 done, 1 in progress, 1 upcoming')
71
+ ).toBeInTheDocument()
72
+ })
73
+
74
+ it('categorises set-type variants in the progress summary', () => {
75
+ // drop + myo read as done · a started range reads in progress · myo-upcoming reads upcoming
76
+ const sets: SetStripSet[] = [
77
+ { status: 'drop', subloads: [[0.8], [0.7]] },
78
+ { status: 'myo', activation: [0.75], clusters: [[0.6]] },
79
+ { status: 'range', floor: 15, max: 20, doneVels: [0.9, 0.85] },
80
+ { status: 'myo-upcoming', activationLen: 12 },
81
+ ]
82
+ render(<SetStrip sets={sets} />)
83
+ expect(
84
+ screen.getByLabelText('Set progress: 2 done, 1 in progress, 1 upcoming')
85
+ ).toBeInTheDocument()
86
+ })
87
+
88
+ it('renders one bar per set across mixed set-type variants', () => {
89
+ const sets: SetStripSet[] = [
90
+ { status: 'drop', subloads: [[0.8, 0.7], [0.6]] },
91
+ { status: 'range', floor: 3, max: 5, doneVels: [] },
92
+ ]
93
+ render(<SetStrip sets={sets} />)
94
+ expect(screen.getAllByTestId('set-strip-set')).toHaveLength(2)
95
+ })
96
+
97
+ describe('accessibility', () => {
98
+ it('has no accessibility violations', async () => {
99
+ const sets: SetStripSet[] = [
100
+ { status: 'done', velocities: [1, 0.8] },
101
+ { status: 'active', velocities: [0.9], planned: 3 },
102
+ { status: 'todo', planned: 3 },
103
+ ]
104
+ const { container } = render(<SetStrip sets={sets} />)
105
+ const results = await axe(container)
106
+ expect(results).toHaveNoViolations()
107
+ })
108
+ })
109
+ })
@@ -0,0 +1,71 @@
1
+ // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
+ import { View, type ViewProps } from 'react-native'
3
+ import { SetBar, type SetStripSet } from './SetBar'
4
+
5
+ // Re-exported so the per-set colour vocabulary stays importable from either the
6
+ // molecule (SetStrip) or the atom (SetBar) it now lives in.
7
+ export {
8
+ SET_STRIP_ZONES,
9
+ SET_STRIP_VARIABLE_COLOR,
10
+ velocityZoneColor,
11
+ SetBar,
12
+ type SetBarProps,
13
+ } from './SetBar'
14
+ export type { SetStripSet } from './SetBar'
15
+
16
+ /** Gap between set bars — ~2× the (zero) rep gap, so sets read as discrete units. */
17
+ const SET_STRIP_GAP = 5
18
+
19
+ /** Collapse a set (flat or set-type) to its glance category for the progress summary. */
20
+ function setCategory(set: SetStripSet): 'done' | 'active' | 'upcoming' {
21
+ switch (set.status) {
22
+ case 'done':
23
+ case 'drop':
24
+ case 'myo':
25
+ return 'done'
26
+ case 'active':
27
+ return 'active'
28
+ case 'range':
29
+ return set.doneVels.length > 0 ? 'active' : 'upcoming'
30
+ case 'todo':
31
+ case 'myo-upcoming':
32
+ return 'upcoming'
33
+ }
34
+ }
35
+
36
+ function describeSets(sets: SetStripSet[]): string {
37
+ const done = sets.filter((s) => setCategory(s) === 'done').length
38
+ const active = sets.filter((s) => setCategory(s) === 'active').length
39
+ const upcoming = sets.filter((s) => setCategory(s) === 'upcoming').length
40
+ return `Set progress: ${done} done, ${active} in progress, ${upcoming} upcoming`
41
+ }
42
+
43
+ export interface SetStripProps extends ViewProps {
44
+ /** Per-set performance data, in set order. */
45
+ sets: SetStripSet[]
46
+ /** Bar height in px. Default 8. */
47
+ height?: number
48
+ className?: string
49
+ }
50
+
51
+ /**
52
+ * The per-set segmented performance strip: one continuous {@link SetBar} per set
53
+ * (rep intensities as butted color segments, no rep gaps), sets separated by a
54
+ * fixed gap. Fills its container width. Colors are the real titan ramp pins.
55
+ */
56
+ export function SetStrip({ sets, height = 8, className, ...props }: SetStripProps) {
57
+ return (
58
+ <View
59
+ className={className}
60
+ style={{ flexDirection: 'row', width: '100%', height, gap: SET_STRIP_GAP }}
61
+ accessibilityRole="image"
62
+ accessibilityLabel={describeSets(sets)}
63
+ testID="set-strip"
64
+ {...props}
65
+ >
66
+ {sets.map((set, i) => (
67
+ <SetBar key={i} set={set} height={height} />
68
+ ))}
69
+ </View>
70
+ )
71
+ }
@@ -0,0 +1,66 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View } from 'react-native'
3
+ import { SetTableHeader } from './SetTableHeader'
4
+
5
+ /**
6
+ * 🚧 WIP / placeholder — `SetTableHeader` (exported as `SetTableHeader`; the generic
7
+ * `TableHeader` name is taken by the DataViz `Table`). The expanded-set-table column
8
+ * header row (SET · PREV · REPS · LOAD · RPE) whose widths mirror `SetRow`. Extracted
9
+ * from `ExerciseCard`; the column set / widths are provisional pending the responsive
10
+ * unification (TD-03.56).
11
+ */
12
+ const meta: Meta<typeof SetTableHeader> = {
13
+ title: 'Workout/SetTableHeader',
14
+ component: SetTableHeader,
15
+ tags: ['autodocs'],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component:
20
+ '**Atom.** The expanded-set-table column header row; per-column widths mirror ' +
21
+ '[SetRow](?path=/docs/workout-setrow--docs) so headers align over the rows. ' +
22
+ 'Used-by ↑ [ExerciseCard](?path=/docs/workout-exercisecard--docs) (expanded), which ' +
23
+ 'renders it with `showPrevious={false}`. ' +
24
+ 'Column set / widths provisional pending TD-03.56 responsive unification.',
25
+ },
26
+ },
27
+ },
28
+ argTypes: {
29
+ unit: { control: 'select', options: ['lbs', 'kg'] },
30
+ showPrevious: { control: 'boolean' },
31
+ },
32
+ decorators: [
33
+ (Story) => (
34
+ <View style={{ width: 320, backgroundColor: '#131313' }}>
35
+ <Story />
36
+ </View>
37
+ ),
38
+ ],
39
+ }
40
+
41
+ export default meta
42
+ type Story = StoryObj<typeof SetTableHeader>
43
+
44
+ export const Lbs: Story = {
45
+ args: { unit: 'lbs' },
46
+ }
47
+
48
+ export const Kg: Story = {
49
+ args: { unit: 'kg' },
50
+ parameters: {
51
+ docs: { description: { story: 'The weight column reflects the `kg` unit.' } },
52
+ },
53
+ }
54
+
55
+ export const NoPrevious: Story = {
56
+ args: { unit: 'lbs', showPrevious: false },
57
+ parameters: {
58
+ docs: {
59
+ description: {
60
+ story:
61
+ 'PREV dropped for rail density (`showPrevious={false}`); the column blanks to a flex ' +
62
+ 'spacer so REPS/LOAD/RPE hold their positions. Pair with `SetRow`’s `showPrevious`.',
63
+ },
64
+ },
65
+ },
66
+ }
@@ -0,0 +1,47 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { axe } from 'jest-axe'
4
+ import { SetTableHeader } from './SetTableHeader'
5
+
6
+ describe('SetTableHeader', () => {
7
+ it('renders the five column labels with the lbs weight column by default', () => {
8
+ render(<SetTableHeader />)
9
+ const header = screen.getByTestId('table-header')
10
+ expect(header).toHaveTextContent('SET')
11
+ expect(header).toHaveTextContent('PREV')
12
+ expect(header).toHaveTextContent('REPS')
13
+ expect(header).toHaveTextContent('LBS')
14
+ expect(header).toHaveTextContent('RPE')
15
+ })
16
+
17
+ it('drops the PREV column when showPrevious is false', () => {
18
+ render(<SetTableHeader showPrevious={false} />)
19
+ const header = screen.getByTestId('table-header')
20
+ expect(header).not.toHaveTextContent('PREV')
21
+ // the other columns remain
22
+ expect(header).toHaveTextContent('SET')
23
+ expect(header).toHaveTextContent('REPS')
24
+ expect(header).toHaveTextContent('RPE')
25
+ })
26
+
27
+ it('shows the KG weight column when unit is kg', () => {
28
+ render(<SetTableHeader unit="kg" />)
29
+ const header = screen.getByTestId('table-header')
30
+ expect(header).toHaveTextContent('KG')
31
+ expect(header).not.toHaveTextContent('LBS')
32
+ })
33
+
34
+ it('honors a custom testID so a host card can keep its own', () => {
35
+ render(<SetTableHeader testID="exercise-card-column-headers" />)
36
+ expect(screen.getByTestId('exercise-card-column-headers')).toBeInTheDocument()
37
+ expect(screen.queryByTestId('table-header')).not.toBeInTheDocument()
38
+ })
39
+
40
+ describe('accessibility', () => {
41
+ it('has no accessibility violations', async () => {
42
+ const { container } = render(<SetTableHeader />)
43
+ const results = await axe(container)
44
+ expect(results).toHaveNoViolations()
45
+ })
46
+ })
47
+ })
@@ -0,0 +1,88 @@
1
+ // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
+ import { View, Text } from 'react-native'
3
+
4
+ // One header column: its label and its fixed width (PREV is the lone flex column,
5
+ // `undefined`). Order + widths mirror SetRow's cells so headers align over rows.
6
+ type Column = { label: string; width: number | undefined }
7
+
8
+ export interface SetTableHeaderProps {
9
+ /** Weight-column label: LBS / KG. Default lbs. */
10
+ unit?: 'lbs' | 'kg'
11
+ /** Show the PREV (previous-best) column. Default true; false drops it for rail density. */
12
+ showPrevious?: boolean
13
+ /** Overridable so a host card can keep its own testID. Default "table-header". */
14
+ testID?: string
15
+ }
16
+
17
+ // The previous-best column is the lone flex column (`undefined` width). When hidden
18
+ // it is dropped entirely (not blanked to a spacer) and the four fixed columns
19
+ // distribute across the full strip width via `justifyContent: space-between`.
20
+ const PREV_COLUMN: Column = { label: 'PREV', width: undefined }
21
+
22
+ /** Columns in order, with the weight column reflecting `unit`; PREV dropped when hidden. */
23
+ function buildColumns(unit: 'lbs' | 'kg', showPrevious: boolean): Column[] {
24
+ return [
25
+ { label: 'SET', width: 36 },
26
+ ...(showPrevious ? [PREV_COLUMN] : []),
27
+ { label: 'REPS', width: 44 },
28
+ { label: unit.toUpperCase(), width: 56 },
29
+ { label: 'RPE', width: 36 },
30
+ ]
31
+ }
32
+
33
+ /**
34
+ * The expanded-set-table column-header row: SET · PREV · REPS · LOAD · RPE, with
35
+ * the weight column reflecting `unit`. `showPrevious={false}` drops PREV (rail
36
+ * density). Its per-column widths mirror {@link SetRow} so headers align over the
37
+ * rows. Extracted from {@link ExerciseCard}'s expanded state for reuse.
38
+ */
39
+ export function SetTableHeader({
40
+ unit = 'lbs',
41
+ showPrevious = true,
42
+ testID = 'table-header',
43
+ }: SetTableHeaderProps) {
44
+ const columns = buildColumns(unit, showPrevious)
45
+
46
+ return (
47
+ <View
48
+ className="flex-row"
49
+ style={{
50
+ paddingVertical: 8,
51
+ paddingHorizontal: 8,
52
+ paddingBottom: 4,
53
+ ...(showPrevious ? {} : { justifyContent: 'space-between' }),
54
+ }}
55
+ testID={testID}
56
+ >
57
+ {columns.map(({ label, width }) => {
58
+ const isFlex = width === undefined
59
+
60
+ return (
61
+ <View
62
+ key={label}
63
+ style={{
64
+ ...(isFlex ? { minWidth: 44 } : { width, flexShrink: 1 }),
65
+ alignItems: 'center',
66
+ justifyContent: 'center',
67
+ gap: 8,
68
+ }}
69
+ {...(isFlex ? { className: 'flex-1' } : {})}
70
+ >
71
+ <Text
72
+ className="text-text-tertiary"
73
+ style={{
74
+ fontSize: 10,
75
+ fontWeight: '600',
76
+ fontFamily: 'Inter, sans-serif',
77
+ textTransform: 'uppercase',
78
+ letterSpacing: 0.8,
79
+ }}
80
+ >
81
+ {label}
82
+ </Text>
83
+ </View>
84
+ )
85
+ })}
86
+ </View>
87
+ )
88
+ }
@@ -0,0 +1,47 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View } from 'react-native'
3
+ import { SetsRepsLoad } from './SetsRepsLoad'
4
+
5
+ /**
6
+ * `SetsRepsLoad` — the `sets × reps @ load` prescription line in the TempoDisplay
7
+ * visual language (Inter · 600 · letter-spacing 1 · value cells with muted
8
+ * separators).
9
+ */
10
+ const meta: Meta<typeof SetsRepsLoad> = {
11
+ title: 'Workout/SetsRepsLoad',
12
+ component: SetsRepsLoad,
13
+ tags: ['autodocs'],
14
+ parameters: {
15
+ docs: {
16
+ description: {
17
+ component:
18
+ '**Atom.** The `sets × reps @ load` prescription line in the TempoDisplay visual ' +
19
+ 'language. Composes [MetricCell](?path=/docs/workout-metriccell--docs) ' +
20
+ '(shared with [TempoDisplay](?path=/docs/workout-tempodisplay--docs)). ' +
21
+ 'Used-by ↑ [ExerciseHeading](?path=/docs/workout-exerciseheading--docs).',
22
+ },
23
+ },
24
+ },
25
+ decorators: [
26
+ (Story) => (
27
+ <View style={{ padding: 16, backgroundColor: '#131313' }}>
28
+ <Story />
29
+ </View>
30
+ ),
31
+ ],
32
+ }
33
+
34
+ export default meta
35
+ type Story = StoryObj<typeof SetsRepsLoad>
36
+
37
+ export const Default: Story = {
38
+ args: { sets: 5, reps: 8, load: 145, unit: 'lb' },
39
+ }
40
+
41
+ export const RepRange: Story = {
42
+ args: { sets: 3, reps: '15-20', load: 40, unit: 'lb' },
43
+ }
44
+
45
+ export const Kilograms: Story = {
46
+ args: { sets: 4, reps: 6, load: 84, unit: 'kg' },
47
+ }
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { axe } from 'jest-axe'
4
+ import { SetsRepsLoad } from './SetsRepsLoad'
5
+
6
+ describe('SetsRepsLoad', () => {
7
+ it('renders the sets, reps and load values', () => {
8
+ render(<SetsRepsLoad sets={5} reps={8} load={145} />)
9
+ const line = screen.getByTestId('sets-reps-load')
10
+ expect(line).toHaveTextContent('5')
11
+ expect(line).toHaveTextContent('8')
12
+ expect(line).toHaveTextContent('145')
13
+ })
14
+
15
+ it('renders the × and @ separators', () => {
16
+ render(<SetsRepsLoad sets={3} reps={10} load={90} />)
17
+ const line = screen.getByTestId('sets-reps-load')
18
+ expect(line).toHaveTextContent('×')
19
+ expect(line).toHaveTextContent('@')
20
+ })
21
+
22
+ it('defaults the unit label to lb', () => {
23
+ render(<SetsRepsLoad sets={3} reps={10} load={90} />)
24
+ expect(screen.getByTestId('sets-reps-load')).toHaveTextContent('lb')
25
+ })
26
+
27
+ it('accepts a custom unit label', () => {
28
+ render(<SetsRepsLoad sets={3} reps={10} load={40} unit="kg" />)
29
+ expect(screen.getByTestId('sets-reps-load')).toHaveTextContent('kg')
30
+ })
31
+
32
+ it('supports rep ranges', () => {
33
+ render(<SetsRepsLoad sets={3} reps="15-20" load={40} />)
34
+ expect(screen.getByTestId('sets-reps-load')).toHaveTextContent('15-20')
35
+ })
36
+
37
+ describe('accessibility', () => {
38
+ it('has no accessibility violations', async () => {
39
+ const { container } = render(<SetsRepsLoad sets={5} reps={8} load={145} />)
40
+ const results = await axe(container)
41
+ expect(results).toHaveNoViolations()
42
+ })
43
+ })
44
+ })
@@ -0,0 +1,52 @@
1
+ // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
+ import { View, type ViewProps } from 'react-native'
3
+ import { getSemanticColors } from '../../../theme/tokens/semantic'
4
+ import { MetricCell } from './metricText'
5
+
6
+ const t = getSemanticColors('dark')
7
+
8
+ const TIMES = '×' // × multiplication sign, padded by muted separators
9
+ const AT = '@'
10
+
11
+ export interface SetsRepsLoadProps extends ViewProps {
12
+ sets: number
13
+ reps: number | string
14
+ load: number
15
+ /** Displayed load unit label (e.g. "lb", "kg"). */
16
+ unit?: string
17
+ className?: string
18
+ }
19
+
20
+ /**
21
+ * The `sets × reps @ load` prescription line, in the TempoDisplay visual language
22
+ * (Inter · 600 · letter-spacing 1 · value cells with muted `×` / `@` separators).
23
+ * Shares the {@link MetricCell} primitive with TempoDisplay so the two stay in step.
24
+ */
25
+ export function SetsRepsLoad({
26
+ sets,
27
+ reps,
28
+ load,
29
+ unit = 'lb',
30
+ className,
31
+ ...props
32
+ }: SetsRepsLoadProps) {
33
+ const value = t['text-primary']
34
+ const sep = t['text-tertiary']
35
+
36
+ return (
37
+ <View
38
+ className={className}
39
+ style={{ flexDirection: 'row', alignItems: 'baseline' }}
40
+ accessibilityLabel={`${sets} sets of ${reps} reps at ${load} ${unit}`}
41
+ testID="sets-reps-load"
42
+ {...props}
43
+ >
44
+ <MetricCell color={value}>{sets}</MetricCell>
45
+ <MetricCell color={sep}>{` ${TIMES} `}</MetricCell>
46
+ <MetricCell color={value}>{reps}</MetricCell>
47
+ <MetricCell color={sep}>{` ${AT} `}</MetricCell>
48
+ <MetricCell color={value}>{load}</MetricCell>
49
+ <MetricCell color={sep}>{` ${unit}`}</MetricCell>
50
+ </View>
51
+ )
52
+ }
@@ -3,7 +3,7 @@ import { View } from 'react-native'
3
3
  import { Sparkline } from './Sparkline'
4
4
 
5
5
  const meta: Meta<typeof Sparkline> = {
6
- title: 'Custom/Workout/Sparkline',
6
+ title: 'Workout/DataViz/Sparkline',
7
7
  component: Sparkline,
8
8
  tags: ['autodocs'],
9
9
  argTypes: {
@@ -2,8 +2,9 @@
2
2
  import React from 'react'
3
3
  import { View, Text, type ViewProps } from 'react-native'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { getSemanticColors } from '../../../theme/tokens/semantic'
5
6
 
6
- const BRAND_PRIMARY = '#FF7900'
7
+ const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
7
8
 
8
9
  export interface SparklineProps extends ViewProps {
9
10
  data: number[]
@@ -3,7 +3,7 @@ import { View } from 'react-native'
3
3
  import { StatusDot } from './StatusDot'
4
4
 
5
5
  const meta: Meta<typeof StatusDot> = {
6
- title: 'Custom/Workout/StatusDot',
6
+ title: 'Components/Atoms/StatusDot',
7
7
  component: StatusDot,
8
8
  tags: ['autodocs'],
9
9
  argTypes: {
@@ -103,13 +103,13 @@ describe('StatusDot', () => {
103
103
  it('applies a box-shadow when glow is set on a solid variant', () => {
104
104
  render(<StatusDot variant="success" glow />)
105
105
  const dot = screen.getByTestId('status-dot')
106
- expect(dot.style.boxShadow).toContain('rgba(20,184,166,0.4)')
106
+ expect(dot.style.boxShadow).toContain('rgba(46,213,115,0.4)')
107
107
  })
108
108
 
109
109
  it('applies a box-shadow when glow is set on a ring variant', () => {
110
110
  render(<StatusDot variant="on-track" glow />)
111
111
  const dot = screen.getByTestId('status-dot')
112
- expect(dot.style.boxShadow).toContain('rgba(20,184,166,0.4)')
112
+ expect(dot.style.boxShadow).toContain('rgba(46,213,115,0.4)')
113
113
  })
114
114
 
115
115
  it('applies a gray box-shadow when glow is set on the future variant', () => {
@@ -1,5 +1,8 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import { View, Text, type ViewProps } from 'react-native'
3
+ import { getSemanticColors } from '../../../theme/tokens/semantic'
4
+
5
+ const t = getSemanticColors('dark')
3
6
 
4
7
  export type StatusDotVariant =
5
8
  | 'success'
@@ -22,17 +25,17 @@ export interface StatusDotProps extends ViewProps {
22
25
  }
23
26
 
24
27
  const solidVariantColors: Record<string, string> = {
25
- success: '#14B8A6',
26
- warning: '#FFB020',
27
- error: '#D14343',
28
+ success: t['status-success'],
29
+ warning: t['status-warning'],
30
+ error: t['status-error'],
28
31
  neutral: '#6B7280',
29
32
  }
30
33
 
31
34
  const ringVariantStyles: Record<string, Record<string, unknown>> = {
32
35
  'on-track': {
33
- backgroundColor: 'rgba(20,184,166,0.15)',
36
+ backgroundColor: 'rgba(46,213,115,0.15)',
34
37
  borderWidth: 1,
35
- borderColor: 'rgba(20,184,166,0.3)',
38
+ borderColor: 'rgba(46,213,115,0.3)',
36
39
  },
37
40
  deviation: {
38
41
  backgroundColor: 'rgba(245,158,11,0.15)',
@@ -48,11 +51,11 @@ const ringVariantStyles: Record<string, Record<string, unknown>> = {
48
51
  }
49
52
 
50
53
  const glowStyles: Record<StatusDotVariant, Record<string, unknown>> = {
51
- success: { boxShadow: '0 0 4px rgba(20,184,166,0.4)' },
54
+ success: { boxShadow: '0 0 4px rgba(46,213,115,0.4)' },
52
55
  warning: { boxShadow: '0 0 4px rgba(245,158,11,0.4)' },
53
56
  error: { boxShadow: '0 0 4px rgba(239,68,68,0.4)' },
54
57
  neutral: { boxShadow: '0 0 4px rgba(107,114,128,0.4)' },
55
- 'on-track': { boxShadow: '0 0 4px rgba(20,184,166,0.4)' },
58
+ 'on-track': { boxShadow: '0 0 4px rgba(46,213,115,0.4)' },
56
59
  deviation: { boxShadow: '0 0 4px rgba(245,158,11,0.4)' },
57
60
  future: { boxShadow: '0 0 4px rgba(107,114,128,0.4)' },
58
61
  }
@@ -69,8 +72,8 @@ const iconColors: Record<StatusDotVariant, string> = {
69
72
  warning: '#6B4000',
70
73
  error: '#5C1A1A',
71
74
  neutral: '#D1D5DB',
72
- 'on-track': '#14B8A6',
73
- deviation: '#FFB020',
75
+ 'on-track': t['status-success'],
76
+ deviation: t['status-warning'],
74
77
  future: '#6B7280',
75
78
  }
76
79