@titan-design/react-ui 0.3.0 → 0.4.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 (52) hide show
  1. package/dist/bodymap.js +441 -97
  2. package/dist/bodymap.js.map +1 -1
  3. package/dist/bodymap.mjs +49 -62
  4. package/dist/bodymap.mjs.map +1 -1
  5. package/dist/{chunk-TOD2WQBG.mjs → chunk-2SISKTWM.mjs} +22 -43
  6. package/dist/chunk-2SISKTWM.mjs.map +1 -0
  7. package/dist/{chunk-P7TSQUN6.mjs → chunk-SNVKL5WZ.mjs} +42 -5
  8. package/dist/chunk-SNVKL5WZ.mjs.map +1 -0
  9. package/dist/index.d.mts +42 -2
  10. package/dist/index.d.ts +42 -2
  11. package/dist/index.js +431 -328
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +397 -314
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/theme/index.d.mts +28 -2
  16. package/dist/theme/index.d.ts +28 -2
  17. package/dist/theme/index.js +37 -0
  18. package/dist/theme/index.js.map +1 -1
  19. package/dist/theme/index.mjs +1 -1
  20. package/package.json +1 -1
  21. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +10 -15
  22. package/src/components/custom/Workout/BodyMap.tsx +7 -8
  23. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +25 -28
  24. package/src/components/custom/Workout/CapacityBandChart.tsx +2 -3
  25. package/src/components/custom/Workout/ExerciseCard.tsx +12 -27
  26. package/src/components/custom/Workout/ExerciseDetailPage.tsx +21 -27
  27. package/src/components/custom/Workout/InputBar.tsx +10 -11
  28. package/src/components/custom/Workout/MesoCard.tsx +2 -6
  29. package/src/components/custom/Workout/MesoStatusCard.tsx +17 -15
  30. package/src/components/custom/Workout/MuscleGroupChip.tsx +2 -4
  31. package/src/components/custom/Workout/PlaceholderStrip.tsx +2 -3
  32. package/src/components/custom/Workout/PrHistoryModal.tsx +12 -14
  33. package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -12
  34. package/src/components/custom/Workout/ReadinessCheck.tsx +13 -11
  35. package/src/components/custom/Workout/RestTimer.tsx +8 -7
  36. package/src/components/custom/Workout/SetRow.tsx +10 -7
  37. package/src/components/custom/Workout/StrengthTrendChart.tsx +15 -17
  38. package/src/components/custom/Workout/TempoBar.stories.tsx +95 -0
  39. package/src/components/custom/Workout/TempoBar.test.tsx +103 -0
  40. package/src/components/custom/Workout/TempoBar.tsx +215 -0
  41. package/src/components/custom/Workout/TrainingStatusPage.tsx +8 -17
  42. package/src/components/custom/Workout/VelocityStrip.tsx +7 -5
  43. package/src/components/custom/Workout/WeekRow.tsx +2 -1
  44. package/src/components/custom/Workout/WorkoutCard.tsx +3 -8
  45. package/src/components/custom/Workout/index.ts +9 -0
  46. package/src/test/nativewind-stub.ts +13 -0
  47. package/src/theme/ThemeProvider.test.tsx +24 -0
  48. package/src/theme/ThemeProvider.tsx +50 -0
  49. package/src/theme/index.ts +2 -0
  50. package/src/theme/resolve-color.ts +19 -0
  51. package/dist/chunk-P7TSQUN6.mjs.map +0 -1
  52. package/dist/chunk-TOD2WQBG.mjs.map +0 -1
@@ -2,15 +2,14 @@
2
2
  import { View, Text, Pressable, type ViewProps } from 'react-native'
3
3
  import { Star } from 'lucide-react'
4
4
  import { Drawer, DrawerBody } from '../../ui/drawer'
5
+ import { resolveColor } from '../../../theme/resolve-color'
5
6
 
6
7
  const BRAND_PRIMARY = '#FF7900'
7
8
  const RECENT_BORDER = 'rgba(255,176,32,0.3)'
8
9
  const RECENT_GLOW = '0 0 12px rgba(255,176,32,0.06)'
9
- const SURFACE_RAISED = 'var(--color-surface-raised)'
10
- const BORDER_DEFAULT = 'var(--color-border-default)'
11
- const TEXT_PRIMARY = 'var(--color-text-primary)'
12
- const TEXT_SECONDARY = 'var(--color-text-secondary)'
13
- const TEXT_TERTIARY = 'var(--color-text-tertiary)'
10
+ // Native-safe fallback for the conditional row border (recent uses a computed
11
+ // rgba, so className can't express both branches).
12
+ const BORDER_DEFAULT = resolveColor('border-default')
14
13
 
15
14
  export type PrRecordType = 'e1rm' | 'weight' | 'reps' | 'volume' | 'velocity'
16
15
 
@@ -72,14 +71,13 @@ function PrRecordRow({ record, index }: { record: PrRecord; index: number }) {
72
71
  <View
73
72
  accessibilityRole="text"
74
73
  accessibilityLabel={a11yLabel}
75
- className="flex-row items-center"
74
+ className="flex-row items-center bg-surface-raised"
76
75
  style={{
77
76
  gap: 10,
78
77
  paddingVertical: 10,
79
78
  paddingHorizontal: 12,
80
79
  marginBottom: 8,
81
80
  borderRadius: 8,
82
- backgroundColor: SURFACE_RAISED,
83
81
  borderWidth: 1,
84
82
  borderColor: record.isRecent ? RECENT_BORDER : BORDER_DEFAULT,
85
83
  ...(record.isRecent ? { boxShadow: RECENT_GLOW } : {}),
@@ -88,35 +86,35 @@ function PrRecordRow({ record, index }: { record: PrRecord; index: number }) {
88
86
  >
89
87
  <Star size={16} color={BRAND_PRIMARY} fill={BRAND_PRIMARY} strokeWidth={2} />
90
88
  <Text
89
+ className="text-text-secondary"
91
90
  style={{
92
91
  flex: 1,
93
92
  fontSize: 13,
94
93
  fontFamily: 'Inter, sans-serif',
95
94
  fontWeight: '600',
96
- color: TEXT_SECONDARY,
97
95
  }}
98
96
  testID={`pr-history-modal-record-${index}-type`}
99
97
  >
100
98
  {label}
101
99
  </Text>
102
100
  <Text
101
+ className="text-text-primary"
103
102
  style={{
104
103
  fontSize: 14,
105
104
  fontFamily: '"Space Grotesk", sans-serif',
106
105
  fontWeight: '700',
107
- color: TEXT_PRIMARY,
108
106
  }}
109
107
  testID={`pr-history-modal-record-${index}-value`}
110
108
  >
111
109
  {valueText}
112
110
  </Text>
113
111
  <Text
112
+ className="text-text-tertiary"
114
113
  style={{
115
114
  minWidth: 64,
116
115
  textAlign: 'right',
117
116
  fontSize: 11,
118
117
  fontFamily: 'Inter, sans-serif',
119
- color: TEXT_TERTIARY,
120
118
  }}
121
119
  testID={`pr-history-modal-record-${index}-date`}
122
120
  >
@@ -173,13 +171,13 @@ export function PrHistoryModal({
173
171
  >
174
172
  <View
175
173
  accessibilityElementsHidden
174
+ className="bg-border"
176
175
  style={{
177
176
  alignSelf: 'center',
178
177
  width: 40,
179
178
  height: 4,
180
179
  borderRadius: 2,
181
180
  marginTop: 8,
182
- backgroundColor: BORDER_DEFAULT,
183
181
  }}
184
182
  testID="pr-history-modal-handle"
185
183
  />
@@ -191,11 +189,11 @@ export function PrHistoryModal({
191
189
  >
192
190
  <Text
193
191
  accessibilityRole="header"
192
+ className="text-text-primary"
194
193
  style={{
195
194
  fontSize: 16,
196
195
  fontFamily: '"Space Grotesk", sans-serif',
197
196
  fontWeight: '700',
198
- color: TEXT_PRIMARY,
199
197
  }}
200
198
  testID="pr-history-modal-title"
201
199
  >
@@ -209,7 +207,7 @@ export function PrHistoryModal({
209
207
  style={{ padding: 4, margin: -4 }}
210
208
  testID="pr-history-modal-close"
211
209
  >
212
- <Text style={{ fontSize: 22, lineHeight: 22, color: TEXT_SECONDARY }}>
210
+ <Text className="text-text-secondary" style={{ fontSize: 22, lineHeight: 22 }}>
213
211
  {'×'}
214
212
  </Text>
215
213
  </Pressable>
@@ -219,11 +217,11 @@ export function PrHistoryModal({
219
217
  {records.length === 0 ? (
220
218
  <View style={{ paddingVertical: 24 }} testID="pr-history-modal-empty">
221
219
  <Text
220
+ className="text-text-tertiary"
222
221
  style={{
223
222
  textAlign: 'center',
224
223
  fontSize: 13,
225
224
  fontFamily: 'Inter, sans-serif',
226
- color: TEXT_TERTIARY,
227
225
  }}
228
226
  >
229
227
  No personal records yet
@@ -7,13 +7,9 @@ import { type WeekRowProps, type WeekRowWorkout } from './WeekRow'
7
7
  import { WorkoutCard, type WorkoutStatus, type WorkoutMuscleGroup } from './WorkoutCard'
8
8
  import { type WorkoutPillStatus } from './WorkoutPill'
9
9
  import { type ExerciseCardProps } from './ExerciseCard'
10
+ import { cn } from '../../../utils/cn'
10
11
 
11
- const SURFACE_ELEVATED = 'var(--color-surface-elevated)'
12
- const BORDER_DEFAULT = 'var(--color-border-default)'
13
12
  const BRAND_PRIMARY = '#FF7900'
14
- const TEXT_PRIMARY = 'var(--color-text-primary)'
15
- const TEXT_TERTIARY = 'var(--color-text-tertiary)'
16
- const PAGE_BG = 'var(--color-background-base)'
17
13
 
18
14
  /** A single workout within a planned week, plus its exercise breakdown. */
19
15
  export interface PlanWorkout {
@@ -157,7 +153,7 @@ function Breadcrumbs({ crumbs, onNavigate }: BreadcrumbsProps) {
157
153
  const isLast = index === crumbs.length - 1
158
154
  return (
159
155
  <View key={crumb.key} className="flex-row items-center" style={{ gap: 4 }}>
160
- {index > 0 && <Text style={{ fontSize: 12, color: TEXT_TERTIARY }}>{'›'}</Text>}
156
+ {index > 0 && <Text className="text-text-tertiary" style={{ fontSize: 12 }}>{'›'}</Text>}
161
157
  <Pressable
162
158
  onPress={() => onNavigate(crumb.level)}
163
159
  disabled={isLast}
@@ -165,11 +161,12 @@ function Breadcrumbs({ crumbs, onNavigate }: BreadcrumbsProps) {
165
161
  testID={`program-planning-page-crumb-${crumb.key}`}
166
162
  >
167
163
  <Text
164
+ className={isLast ? 'text-text-primary' : undefined}
168
165
  style={{
169
166
  fontSize: 12,
170
167
  fontFamily: 'Inter, sans-serif',
171
168
  fontWeight: isLast ? '700' : '500',
172
- color: isLast ? TEXT_PRIMARY : BRAND_PRIMARY,
169
+ color: isLast ? undefined : BRAND_PRIMARY,
173
170
  }}
174
171
  >
175
172
  {crumb.label}
@@ -351,8 +348,8 @@ export function ProgramPlanningPage({
351
348
 
352
349
  return (
353
350
  <View
354
- className={className}
355
- style={{ width: 390, backgroundColor: PAGE_BG }}
351
+ className={cn(className, 'bg-background-base')}
352
+ style={{ width: 390 }}
356
353
  accessibilityRole={'main' as ViewProps['accessibilityRole']}
357
354
  aria-label={title}
358
355
  testID="program-planning-page"
@@ -361,11 +358,11 @@ export function ProgramPlanningPage({
361
358
  <View style={{ padding: 16, gap: 14 }} testID="program-planning-page-content">
362
359
  <Text
363
360
  accessibilityRole="header"
361
+ className="text-text-primary"
364
362
  style={{
365
363
  fontSize: 20,
366
364
  fontFamily: '"Space Grotesk", sans-serif',
367
365
  fontWeight: '700',
368
- color: TEXT_PRIMARY,
369
366
  }}
370
367
  testID="program-planning-page-title"
371
368
  >
@@ -388,10 +385,9 @@ export function ProgramPlanningPage({
388
385
  )}
389
386
 
390
387
  <View
388
+ className="bg-surface-elevated border-border"
391
389
  style={{
392
- backgroundColor: SURFACE_ELEVATED,
393
390
  borderWidth: 1,
394
- borderColor: BORDER_DEFAULT,
395
391
  borderRadius: 12,
396
392
  padding: 12,
397
393
  }}
@@ -8,8 +8,6 @@ const BRAND_PRIMARY_SUBTLE = 'rgba(255,121,0,0.12)'
8
8
  const STATUS_SUCCESS = '#14B8A6'
9
9
  const STATUS_WARNING = '#FFB020'
10
10
  const STATUS_ERROR = '#D14343'
11
- const TEXT_PRIMARY = 'var(--color-text-primary)'
12
- const TEXT_SECONDARY = 'var(--color-text-secondary)'
13
11
 
14
12
  /** Emoji option sets per known factor, keyed by lowercase id/label. */
15
13
  const EMOJI_SETS: Record<string, readonly string[]> = {
@@ -91,7 +89,8 @@ function EmojiSlider({ factor }: EmojiSliderProps) {
91
89
  return (
92
90
  <View style={{ marginTop: 14 }} testID={`readiness-check-factor-${factor.id}`}>
93
91
  <Text
94
- style={{ fontSize: 12, fontWeight: '500', fontFamily: 'Inter, sans-serif', color: TEXT_SECONDARY }}
92
+ className="text-text-secondary"
93
+ style={{ fontSize: 12, fontWeight: '500', fontFamily: 'Inter, sans-serif' }}
95
94
  testID="readiness-check-factor-label"
96
95
  >
97
96
  {factor.label}
@@ -114,14 +113,15 @@ function EmojiSlider({ factor }: EmojiSliderProps) {
114
113
  accessibilityLabel={`${factor.label} level ${level} of 5`}
115
114
  aria-checked={selected}
116
115
  testID="readiness-check-emoji"
116
+ className={selected ? undefined : 'border-border bg-surface-raised'}
117
117
  style={({ pressed }) => ({
118
118
  flex: 1,
119
119
  alignItems: 'center',
120
120
  paddingVertical: 8,
121
121
  borderRadius: 8,
122
122
  borderWidth: 1,
123
- borderColor: selected ? BRAND_PRIMARY : 'var(--color-border-default)',
124
- backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : 'var(--color-surface-raised)',
123
+ borderColor: selected ? BRAND_PRIMARY : undefined,
124
+ backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : undefined,
125
125
  opacity: selected ? 1 : pressed ? 0.8 : 0.55,
126
126
  transform: [{ scale: selected ? 1.06 : 1 }],
127
127
  })}
@@ -143,13 +143,13 @@ function ScoreGauge({ score }: { score: number }) {
143
143
  accessibilityRole="image"
144
144
  accessibilityLabel={`Readiness score: ${score} out of 100`}
145
145
  testID="readiness-check-score"
146
+ className="bg-surface-raised"
146
147
  style={{
147
148
  width: 60,
148
149
  height: 60,
149
150
  borderRadius: 30,
150
151
  borderWidth: 4,
151
152
  borderColor: color,
152
- backgroundColor: 'var(--color-surface-raised)',
153
153
  alignItems: 'center',
154
154
  justifyContent: 'center',
155
155
  }}
@@ -169,19 +169,19 @@ function WarmUpCard({ validation }: { validation: WarmUpValidation }) {
169
169
  const badge = WARMUP_BADGE[validation.status]
170
170
  return (
171
171
  <View
172
+ className="border-border bg-surface-raised"
172
173
  style={{
173
174
  marginTop: 16,
174
175
  padding: 12,
175
176
  borderRadius: 8,
176
177
  borderWidth: 1,
177
- borderColor: 'var(--color-border-default)',
178
- backgroundColor: 'var(--color-surface-raised)',
179
178
  }}
180
179
  testID="readiness-check-warmup"
181
180
  >
182
181
  <View className="flex-row items-center justify-between" style={{ gap: 8 }}>
183
182
  <Text
184
- style={{ fontSize: 12, fontWeight: '600', fontFamily: 'Inter, sans-serif', color: TEXT_SECONDARY }}
183
+ className="text-text-secondary"
184
+ style={{ fontSize: 12, fontWeight: '600', fontFamily: 'Inter, sans-serif' }}
185
185
  testID="readiness-check-warmup-deficit"
186
186
  >
187
187
  {velocityDeficitText(validation.velocityDeficit)}
@@ -191,7 +191,8 @@ function WarmUpCard({ validation }: { validation: WarmUpValidation }) {
191
191
  </Badge>
192
192
  </View>
193
193
  <Text
194
- style={{ marginTop: 6, fontSize: 13, fontFamily: 'Inter, sans-serif', color: TEXT_PRIMARY }}
194
+ className="text-text-primary"
195
+ style={{ marginTop: 6, fontSize: 13, fontFamily: 'Inter, sans-serif' }}
195
196
  testID="readiness-check-warmup-recommendation"
196
197
  >
197
198
  {validation.recommendation}
@@ -226,7 +227,8 @@ export function ReadinessCheck({
226
227
  <View style={{ padding: 16 }}>
227
228
  <View className="flex-row items-center justify-between" style={{ gap: 12 }}>
228
229
  <Text
229
- style={{ fontSize: 18, fontWeight: '700', fontFamily: '"Space Grotesk", sans-serif', color: TEXT_PRIMARY }}
230
+ className="text-text-primary"
231
+ style={{ fontSize: 18, fontWeight: '700', fontFamily: '"Space Grotesk", sans-serif' }}
230
232
  testID="readiness-check-title"
231
233
  >
232
234
  How are you feeling?
@@ -1,5 +1,6 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import { View, Text, Pressable } from 'react-native'
3
+ import { resolveColor } from '../../../theme/resolve-color'
3
4
 
4
5
  const BRAND_PRIMARY = '#FF7900'
5
6
 
@@ -34,11 +35,11 @@ export function RestTimer({
34
35
 
35
36
  return (
36
37
  <View
38
+ className="bg-surface-raised"
37
39
  style={{
38
40
  width: '100%',
39
- backgroundColor: 'var(--color-surface-raised)',
40
41
  borderTopWidth: 1,
41
- borderTopColor: 'var(--color-border-default)',
42
+ borderTopColor: resolveColor('border-default'),
42
43
  paddingVertical: 12,
43
44
  paddingHorizontal: 16,
44
45
  }}
@@ -58,13 +59,13 @@ export function RestTimer({
58
59
  {/* Left side */}
59
60
  <View style={{ flexDirection: 'column' }}>
60
61
  <Text
62
+ className="text-text-secondary"
61
63
  style={{
62
64
  fontSize: 11,
63
65
  fontFamily: 'Inter, sans-serif',
64
66
  fontWeight: '600',
65
67
  textTransform: 'uppercase',
66
68
  letterSpacing: 1,
67
- color: 'var(--color-text-secondary)',
68
69
  }}
69
70
  testID="rest-timer-label"
70
71
  >
@@ -72,10 +73,10 @@ export function RestTimer({
72
73
  </Text>
73
74
  {nextSetInfo != null && (
74
75
  <Text
76
+ className="text-text-tertiary"
75
77
  style={{
76
78
  fontSize: 11,
77
79
  fontFamily: 'Inter, sans-serif',
78
- color: 'var(--color-text-tertiary)',
79
80
  marginTop: 2,
80
81
  }}
81
82
  testID="rest-timer-next-set"
@@ -87,11 +88,11 @@ export function RestTimer({
87
88
 
88
89
  {/* Right side - time display */}
89
90
  <Text
91
+ className="text-text-primary"
90
92
  style={{
91
93
  fontSize: 28,
92
94
  fontFamily: '"Space Grotesk", sans-serif',
93
95
  fontWeight: '700',
94
- color: 'var(--color-text-primary)',
95
96
  fontVariant: ['tabular-nums'],
96
97
  letterSpacing: -0.5,
97
98
  }}
@@ -103,9 +104,9 @@ export function RestTimer({
103
104
 
104
105
  {/* Progress bar */}
105
106
  <View
107
+ className="bg-border"
106
108
  style={{
107
109
  height: 3,
108
- backgroundColor: 'var(--color-border-default)',
109
110
  borderRadius: 2,
110
111
  marginBottom: 12,
111
112
  }}
@@ -137,11 +138,11 @@ export function RestTimer({
137
138
  testID="rest-timer-add-time"
138
139
  >
139
140
  <Text
141
+ className="text-text-secondary"
140
142
  style={{
141
143
  fontSize: 11,
142
144
  fontFamily: 'Inter, sans-serif',
143
145
  fontWeight: '600',
144
- color: 'var(--color-text-secondary)',
145
146
  }}
146
147
  >
147
148
  +30s
@@ -106,11 +106,11 @@ export function SetRow({
106
106
  </Text>
107
107
  ) : (
108
108
  <Text
109
+ className="text-text-secondary"
109
110
  style={{
110
111
  fontSize: 13,
111
112
  fontWeight: '600',
112
113
  fontFamily: 'Inter, sans-serif',
113
- color: 'var(--color-text-secondary)',
114
114
  }}
115
115
  >
116
116
  {setNumber}
@@ -123,10 +123,10 @@ export function SetRow({
123
123
  testID="set-row-previous"
124
124
  >
125
125
  <Text
126
+ className="text-text-secondary"
126
127
  style={{
127
128
  fontSize: 12,
128
129
  fontFamily: 'Inter, sans-serif',
129
- color: 'var(--color-text-secondary)',
130
130
  }}
131
131
  >
132
132
  {previous
@@ -141,11 +141,11 @@ export function SetRow({
141
141
  >
142
142
  {isActive && reps == null && targets ? (
143
143
  <Text
144
+ className="text-text-tertiary"
144
145
  style={{
145
146
  fontSize: 13,
146
147
  fontStyle: 'italic',
147
148
  fontFamily: 'Inter, sans-serif',
148
- color: 'var(--color-text-tertiary)',
149
149
  }}
150
150
  testID="set-row-target-reps"
151
151
  >
@@ -153,11 +153,11 @@ export function SetRow({
153
153
  </Text>
154
154
  ) : (
155
155
  <Text
156
+ className={reps != null ? 'text-text-primary' : 'text-text-tertiary'}
156
157
  style={{
157
158
  fontSize: 14,
158
159
  fontWeight: '600',
159
160
  fontFamily: 'Inter, sans-serif',
160
- color: reps != null ? 'var(--color-text-primary)' : 'var(--color-text-tertiary)',
161
161
  }}
162
162
  >
163
163
  {reps != null ? reps : '\u2014'}
@@ -171,11 +171,11 @@ export function SetRow({
171
171
  >
172
172
  {isActive && weight == null && targets ? (
173
173
  <Text
174
+ className="text-text-tertiary"
174
175
  style={{
175
176
  fontSize: 13,
176
177
  fontStyle: 'italic',
177
178
  fontFamily: 'Inter, sans-serif',
178
- color: 'var(--color-text-tertiary)',
179
179
  }}
180
180
  testID="set-row-target-weight"
181
181
  >
@@ -183,11 +183,11 @@ export function SetRow({
183
183
  </Text>
184
184
  ) : (
185
185
  <Text
186
+ className={weight != null ? 'text-text-primary' : 'text-text-tertiary'}
186
187
  style={{
187
188
  fontSize: 14,
188
189
  fontWeight: '600',
189
190
  fontFamily: 'Inter, sans-serif',
190
- color: weight != null ? 'var(--color-text-primary)' : 'var(--color-text-tertiary)',
191
191
  }}
192
192
  >
193
193
  {weight != null ? roundWeight(weight) : '\u2014'}
@@ -200,11 +200,14 @@ export function SetRow({
200
200
  testID="set-row-rpe"
201
201
  >
202
202
  <Text
203
+ className={rpe != null ? undefined : 'text-text-tertiary'}
203
204
  style={{
204
205
  fontSize: 13,
205
206
  fontWeight: '600',
206
207
  fontFamily: 'Inter, sans-serif',
207
- color: rpe != null ? rpeColor(rpe) : 'var(--color-text-tertiary)',
208
+ // rpeColor returns a concrete hex (native-safe); only the tertiary
209
+ // fallback needs the className token.
210
+ color: rpe != null ? rpeColor(rpe) : undefined,
208
211
  }}
209
212
  >
210
213
  {rpe != null ? roundRpe(rpe) : '\u2014'}
@@ -2,17 +2,16 @@
2
2
  import { useEffect, useMemo, useState } from 'react'
3
3
  import { View, Text, Pressable, Animated, Easing, type ViewProps } from 'react-native'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { resolveColor } from '../../../theme/resolve-color'
5
6
 
6
7
  const BRAND_PRIMARY = '#FF7900'
7
- const TEXT_PRIMARY = 'var(--color-text-primary)'
8
- const TEXT_SECONDARY = 'var(--color-text-secondary)'
9
- const TEXT_TERTIARY = 'var(--color-text-tertiary)'
10
- const BORDER_STRONG = 'var(--color-border-strong)'
8
+ // Line/border color for the dashed projection, used where a className cannot
9
+ // apply (passed as a prop into an inline style, and a per-edge borderTopColor).
10
+ const PROJECTION_LINE_COLOR = resolveColor('text-tertiary')
11
11
  const STATUS_SUCCESS = '#14B8A6'
12
12
  const STATUS_ERROR = '#D14343'
13
13
  const STATUS_WARNING = '#FFB020'
14
14
  const GRID_LINE = 'rgba(255,255,255,0.06)'
15
- const TOOLTIP_BG = 'var(--color-surface-elevated)'
16
15
  const SUCCESS_PILL_BG = 'rgba(20,184,166,0.10)'
17
16
  const SUCCESS_PILL_BORDER = 'rgba(20,184,166,0.20)'
18
17
  const ERROR_PILL_BG = 'rgba(209,67,67,0.10)'
@@ -312,7 +311,7 @@ export function StrengthTrendChart({
312
311
  justifyContent: 'center',
313
312
  }}
314
313
  >
315
- <Text style={{ fontSize: 12, fontFamily: 'Inter, sans-serif', color: TEXT_TERTIARY }}>
314
+ <Text className="text-text-tertiary" style={{ fontSize: 12, fontFamily: 'Inter, sans-serif' }}>
316
315
  No strength data yet
317
316
  </Text>
318
317
  </View>
@@ -358,6 +357,7 @@ export function StrengthTrendChart({
358
357
  }}
359
358
  >
360
359
  <Text
360
+ className="text-text-tertiary"
361
361
  style={{
362
362
  position: 'absolute',
363
363
  left: -PLOT_LEFT,
@@ -366,7 +366,6 @@ export function StrengthTrendChart({
366
366
  textAlign: 'right',
367
367
  fontSize: 9,
368
368
  fontFamily: 'Inter, sans-serif',
369
- color: TEXT_TERTIARY,
370
369
  }}
371
370
  >
372
371
  {line.label}
@@ -406,7 +405,7 @@ export function StrengthTrendChart({
406
405
  <View style={{ width, height, position: 'absolute', top: 0, left: 0 }}>
407
406
  <ChartLine
408
407
  coords={geometry.projection}
409
- color={TEXT_TERTIARY}
408
+ color={PROJECTION_LINE_COLOR}
410
409
  strokeWidth={2}
411
410
  dashed
412
411
  testID="strength-trend-chart-projection-segment"
@@ -475,6 +474,7 @@ export function StrengthTrendChart({
475
474
  <View
476
475
  testID="strength-trend-chart-tooltip"
477
476
  accessibilityElementsHidden
477
+ className="bg-surface-elevated border-border-strong"
478
478
  style={{
479
479
  position: 'absolute',
480
480
  left: Math.max(
@@ -483,30 +483,28 @@ export function StrengthTrendChart({
483
483
  ),
484
484
  top: Math.max(0, selectedCoord.y - 52),
485
485
  maxWidth: TOOLTIP_WIDTH,
486
- backgroundColor: TOOLTIP_BG,
487
486
  borderWidth: 1,
488
- borderColor: BORDER_STRONG,
489
487
  borderRadius: 8,
490
488
  paddingVertical: 8,
491
489
  paddingHorizontal: 10,
492
490
  }}
493
491
  >
494
492
  <Text
493
+ className="text-text-tertiary"
495
494
  style={{
496
495
  fontSize: 10,
497
496
  fontFamily: 'Inter, sans-serif',
498
- color: TEXT_TERTIARY,
499
497
  }}
500
498
  >
501
499
  {selectedCoord.point.sessionLabel ?? selectedCoord.point.date}
502
500
  </Text>
503
501
  <Text
502
+ className="text-text-primary"
504
503
  style={{
505
504
  marginTop: 2,
506
505
  fontSize: 13,
507
506
  fontFamily: 'Inter, sans-serif',
508
507
  fontWeight: '700',
509
- color: TEXT_PRIMARY,
510
508
  }}
511
509
  >
512
510
  {`${formatValue(selectedCoord.point.e1rm)} ${unit}`}
@@ -547,6 +545,7 @@ export function StrengthTrendChart({
547
545
  <Text
548
546
  key={`axis-${i}`}
549
547
  testID="strength-trend-chart-axis-label"
548
+ className="text-text-tertiary"
550
549
  style={{
551
550
  position: 'absolute',
552
551
  left: boundary.x - 24,
@@ -554,7 +553,6 @@ export function StrengthTrendChart({
554
553
  textAlign: 'center',
555
554
  fontSize: 10,
556
555
  fontFamily: 'Inter, sans-serif',
557
- color: TEXT_TERTIARY,
558
556
  }}
559
557
  >
560
558
  {boundary.label}
@@ -598,7 +596,7 @@ export function StrengthTrendChart({
598
596
  >
599
597
  <View className="flex-row items-center" style={{ gap: 5 }}>
600
598
  <View style={{ width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY }} />
601
- <Text style={{ fontSize: 10, fontFamily: 'Inter, sans-serif', color: TEXT_SECONDARY }}>
599
+ <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
602
600
  Actual
603
601
  </Text>
604
602
  </View>
@@ -609,16 +607,16 @@ export function StrengthTrendChart({
609
607
  height: 0,
610
608
  borderTopWidth: 2,
611
609
  borderStyle: 'dashed',
612
- borderTopColor: TEXT_TERTIARY,
610
+ borderTopColor: PROJECTION_LINE_COLOR,
613
611
  }}
614
612
  />
615
- <Text style={{ fontSize: 10, fontFamily: 'Inter, sans-serif', color: TEXT_SECONDARY }}>
613
+ <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
616
614
  Projected
617
615
  </Text>
618
616
  </View>
619
617
  <View className="flex-row items-center" style={{ gap: 5 }}>
620
618
  <Text style={{ fontSize: 12, color: STATUS_WARNING }}>★</Text>
621
- <Text style={{ fontSize: 10, fontFamily: 'Inter, sans-serif', color: TEXT_SECONDARY }}>
619
+ <Text className="text-text-secondary" style={{ fontSize: 10, fontFamily: 'Inter, sans-serif' }}>
622
620
  PR
623
621
  </Text>
624
622
  </View>