@titan-design/react-ui 0.11.0 → 0.12.1
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.
- package/dist/bodymap.js +173 -343
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +173 -343
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +27 -22
- package/dist/index.d.ts +27 -22
- package/dist/index.js +366 -561
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +360 -553
- package/dist/index.mjs.map +1 -1
- package/dist/pages.js +242 -407
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +242 -407
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +250 -1157
- package/dist/theme/index.d.ts +250 -1157
- package/dist/theme/index.js +234 -408
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +227 -399
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +141 -140
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +141 -140
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +904 -0
- package/dist/theme/tokens.d.ts +904 -0
- package/dist/theme/tokens.js +856 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/tokens.mjs +833 -0
- package/dist/theme/tokens.mjs.map +1 -0
- package/package.json +7 -1
- package/src/arch/Architecture.stories.tsx +9 -9
- package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +3 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +3 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +1 -1
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +2 -2
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +4 -4
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +3 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -12
- package/src/components/custom/Sidebar/Sidebar.tsx +4 -4
- package/src/components/custom/Table/Table.tsx +2 -2
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +3 -3
- package/src/components/custom/Workout/BaseBadge.test.tsx +6 -1
- package/src/components/custom/Workout/BaseBadge.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.tsx +2 -2
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +2 -2
- package/src/components/custom/Workout/DeviationBar.test.tsx +2 -1
- package/src/components/custom/Workout/DeviationBar.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.test.tsx +3 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +2 -2
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +4 -4
- package/src/components/custom/Workout/InputBar.tsx +2 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +1 -1
- package/src/components/custom/Workout/LiveAuraFrame.test.tsx +1 -1
- package/src/components/custom/Workout/LiveAuraFrame.tsx +3 -3
- package/src/components/custom/Workout/MesoCard.tsx +3 -1
- package/src/components/custom/Workout/MuscleGroupChip.tsx +4 -3
- package/src/components/custom/Workout/PrHistoryModal.tsx +2 -2
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +1 -1
- package/src/components/custom/Workout/README.md +1 -1
- package/src/components/custom/Workout/ReadinessCheck.tsx +2 -2
- package/src/components/custom/Workout/RestTimer.tsx +2 -2
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +3 -3
- package/src/components/custom/Workout/SessionHeader.stories.tsx +2 -2
- package/src/components/custom/Workout/SessionHeader.tsx +1 -1
- package/src/components/custom/Workout/SessionRail.stories.tsx +2 -2
- package/src/components/custom/Workout/SessionRail.tsx +13 -5
- package/src/components/custom/Workout/SetBar.tsx +3 -3
- package/src/components/custom/Workout/SetRow.test.tsx +6 -3
- package/src/components/custom/Workout/StatusDot.tsx +5 -4
- package/src/components/custom/Workout/StrengthTrendChart.tsx +1 -1
- package/src/components/custom/Workout/TrainingStatusPage.tsx +2 -2
- package/src/components/custom/Workout/VelocityStrip.test.tsx +5 -2
- package/src/components/custom/Workout/VelocityStrip.tsx +4 -4
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +3 -3
- package/src/components/custom/Workout/WeightBadge.test.tsx +6 -1
- package/src/components/custom/Workout/WeightBadge.tsx +2 -1
- package/src/components/custom/Workout/WorkoutCard.tsx +3 -1
- package/src/components/custom/Workout/WorkoutPill.tsx +5 -2
- package/src/components/custom/Workout/ZoneTrack.tsx +4 -4
- package/src/components/custom/Workout/setHeadingKit.tsx +14 -8
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/SetBarChart.tsx +3 -3
- package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
- package/src/components/custom/stepper/Stepper.tsx +3 -3
- package/src/components/shell/DeviceMenu.tsx +2 -2
- package/src/components/shell/README.md +1 -1
- package/src/components/shell/SessionRailSpecimen.stories.tsx +1 -1
- package/src/components/shell/SideNav.tsx +1 -1
- package/src/components/shell/TopBar.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -2
- package/src/components/ui/badge/Badge.tsx +2 -2
- package/src/components/ui/card/Card.tsx +3 -3
- package/src/components/ui/checkbox/Checkbox.tsx +1 -1
- package/src/components/ui/collapse/Collapse.tsx +1 -1
- package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
- package/src/components/ui/drawer/Drawer.tsx +3 -3
- package/src/components/ui/form-field/FormField.tsx +1 -1
- package/src/components/ui/help-tip/HelpTip.tsx +1 -1
- package/src/components/ui/menu/Menu.tsx +2 -2
- package/src/components/ui/pill/Pill.tsx +2 -2
- package/src/components/ui/popover/Popover.stories.tsx +2 -2
- package/src/components/ui/popover/Popover.tsx +1 -1
- package/src/components/ui/progress/Progress.tsx +3 -3
- package/src/components/ui/radio/Radio.stories.tsx +1 -1
- package/src/components/ui/radio/Radio.tsx +4 -4
- package/src/components/ui/select/Select.tsx +3 -3
- package/src/components/ui/surface/Surface.stories.tsx +3 -3
- package/src/components/ui/surface/Surface.test.tsx +32 -19
- package/src/components/ui/surface/Surface.tsx +3 -3
- package/src/components/ui/surface/SurfaceContext.ts +19 -29
- package/src/components/ui/surface/surface.contract.test.ts +58 -45
- package/src/components/ui/switch/Switch.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +2 -2
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +5 -5
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +36 -22
- package/src/stories/PresetShowcase.stories.tsx +21 -21
- package/src/theme/ColorPalettes.stories.tsx +41 -38
- package/src/theme/ColorPrimitives.stories.tsx +89 -41
- package/src/theme/Depth.stories.tsx +312 -0
- package/src/theme/DepthCalibration.stories.tsx +655 -0
- package/src/theme/ThemeProvider.tsx +1 -1
- package/src/theme/barrel.ts +7 -14
- package/src/theme/color-stories.coverage.test.ts +15 -20
- package/src/theme/color-story-kit.tsx +1 -1
- package/src/theme/color-utils.ts +197 -0
- package/src/theme/config.ts +0 -8
- package/src/theme/depth-calibration.test.tsx +97 -0
- package/src/theme/elevation.test.ts +62 -1
- package/src/theme/elevation.ts +34 -8
- package/src/theme/global.css +47 -53
- package/src/theme/grey-ramp.test.ts +166 -0
- package/src/theme/materials.test.ts +106 -0
- package/src/theme/materials.ts +211 -0
- package/src/theme/presets/audiobook.ts +4 -4
- package/src/theme/presets/types.ts +3 -3
- package/src/theme/semantic-contrast.test.ts +83 -0
- package/src/theme/token-export-guard.test.ts +104 -0
- package/src/theme/tokens/primitives.ts +63 -116
- package/src/theme/tokens/semantic.ts +130 -82
- package/src/utils/colors.ts +1 -1
- package/tailwind.config.js +2 -5
- package/src/theme/bar-paper.ts +0 -59
- package/src/theme/shadows.stories.tsx +0 -523
- package/src/theme/shadows.ts +0 -439
|
@@ -220,7 +220,7 @@ export function BodyMapDetailPanel({
|
|
|
220
220
|
testID="body-map-detail-panel-handle"
|
|
221
221
|
>
|
|
222
222
|
<View
|
|
223
|
-
className="bg-
|
|
223
|
+
className="bg-hairline-strong"
|
|
224
224
|
style={{ width: 40, height: 4, borderRadius: 2 }}
|
|
225
225
|
accessibilityElementsHidden
|
|
226
226
|
/>
|
|
@@ -380,7 +380,7 @@ export function BodyMapDetailPanel({
|
|
|
380
380
|
{contributingExercises!.map((exercise, index) => (
|
|
381
381
|
<View
|
|
382
382
|
key={`${exercise.name}-${index}`}
|
|
383
|
-
className="flex-row items-center justify-between bg-surface-raised border-
|
|
383
|
+
className="flex-row items-center justify-between bg-surface-raised border-hairline"
|
|
384
384
|
style={{
|
|
385
385
|
gap: 10,
|
|
386
386
|
paddingVertical: 8,
|
|
@@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest'
|
|
|
2
2
|
import { render, screen } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { DeviationBar } from './DeviationBar'
|
|
5
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
5
6
|
|
|
6
7
|
describe('DeviationBar', () => {
|
|
7
8
|
it('renders the bar and dot', () => {
|
|
@@ -62,7 +63,7 @@ describe('DeviationBar', () => {
|
|
|
62
63
|
const { getByTestId } = render(<DeviationBar deviation={0} />)
|
|
63
64
|
const dot = getByTestId('deviation-dot')
|
|
64
65
|
expect(dot).toHaveStyle({ width: '8px', height: '8px' })
|
|
65
|
-
expect(dot).toHaveStyle({ borderTopWidth: '1.5px', borderTopColor:
|
|
66
|
+
expect(dot).toHaveStyle({ borderTopWidth: '1.5px', borderTopColor: greyRamp[50] })
|
|
66
67
|
expect(dot).toHaveStyle({ boxShadow: '0 0 4px rgba(0,0,0,0.5)' })
|
|
67
68
|
})
|
|
68
69
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { View, type ViewProps, type ViewStyle } from 'react-native'
|
|
3
3
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
4
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
5
|
|
|
5
6
|
const t = getSemanticColors('dark')
|
|
6
7
|
|
|
@@ -13,7 +14,7 @@ export interface DeviationBarProps extends ViewProps {
|
|
|
13
14
|
function getDotColor(deviation: number): string {
|
|
14
15
|
const abs = Math.abs(deviation)
|
|
15
16
|
if (deviation < -0.3) return t['status-success']
|
|
16
|
-
if (abs <= 0.3) return
|
|
17
|
+
if (abs <= 0.3) return greyRamp[500]
|
|
17
18
|
if (abs <= 0.7) return t['status-warning']
|
|
18
19
|
return t['status-error']
|
|
19
20
|
}
|
|
@@ -68,7 +69,7 @@ export function DeviationBar({
|
|
|
68
69
|
height: dotSize,
|
|
69
70
|
borderRadius: 9999,
|
|
70
71
|
borderWidth: 1.5,
|
|
71
|
-
borderColor:
|
|
72
|
+
borderColor: greyRamp[50],
|
|
72
73
|
boxShadow: '0 0 4px rgba(0,0,0,0.5)',
|
|
73
74
|
backgroundColor: getDotColor(clamped),
|
|
74
75
|
left: Math.max(0, Math.min(dotPosition - dotSize / 2, resolvedWidth - dotSize)),
|
|
@@ -3,6 +3,7 @@ import { render, screen, fireEvent, within } from '@testing-library/react'
|
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { ExerciseCard } from './ExerciseCard'
|
|
5
5
|
import type { SetRowProps } from './SetRow'
|
|
6
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
6
7
|
|
|
7
8
|
const baseCollapsedProps = {
|
|
8
9
|
name: 'Bench Press',
|
|
@@ -86,9 +87,8 @@ describe('ExerciseCard', () => {
|
|
|
86
87
|
sets: unifiedSets,
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
//
|
|
90
|
-
const T_ACTIVE = '
|
|
91
|
-
const T_MUTED = '#9CA3AF'
|
|
90
|
+
// Read from the tokens, not pinned (see SetRow.test.tsx).
|
|
91
|
+
const { 'text-primary': T_ACTIVE, 'text-secondary': T_MUTED } = getSemanticColors('dark')
|
|
92
92
|
|
|
93
93
|
it('renders exercise name via the real ExerciseCardHeading header', () => {
|
|
94
94
|
render(<ExerciseCard {...expandedProps} />)
|
|
@@ -220,7 +220,7 @@ function CollapsedCard({
|
|
|
220
220
|
|
|
221
221
|
const DARK = getSemanticColors('dark')
|
|
222
222
|
/** The header↔body seam. */
|
|
223
|
-
const BODY_DIVIDER = DARK['
|
|
223
|
+
const BODY_DIVIDER = DARK['hairline-subtle']
|
|
224
224
|
|
|
225
225
|
/** Project the set rows onto the heading strip's per-set state (done / active / todo). */
|
|
226
226
|
function deriveHeaderSetStates(sets: SetRowProps[]): SetStripSet[] {
|
|
@@ -262,7 +262,7 @@ function ExpandedCard({
|
|
|
262
262
|
|
|
263
263
|
return (
|
|
264
264
|
<View
|
|
265
|
-
className="bg-surface-elevated border-
|
|
265
|
+
className="bg-surface-elevated border-hairline"
|
|
266
266
|
style={{
|
|
267
267
|
borderWidth: 1,
|
|
268
268
|
...borderRadius,
|
|
@@ -193,7 +193,7 @@ function TabBar({ active, onSelect }: TabBarProps) {
|
|
|
193
193
|
className="flex-row"
|
|
194
194
|
style={{
|
|
195
195
|
borderBottomWidth: 1,
|
|
196
|
-
borderBottomColor: resolveColor('
|
|
196
|
+
borderBottomColor: resolveColor('hairline-default'),
|
|
197
197
|
}}
|
|
198
198
|
accessibilityRole={'tablist' as ViewProps['accessibilityRole']}
|
|
199
199
|
testID="exercise-detail-page-tabs"
|
|
@@ -247,7 +247,7 @@ function StatStrip({ stats, unit }: { stats: ExerciseDetailStats; unit: 'lbs' |
|
|
|
247
247
|
return (
|
|
248
248
|
<View
|
|
249
249
|
key={key}
|
|
250
|
-
className="bg-surface-elevated border-
|
|
250
|
+
className="bg-surface-elevated border-hairline"
|
|
251
251
|
style={{
|
|
252
252
|
flex: 1,
|
|
253
253
|
padding: 12,
|
|
@@ -297,7 +297,7 @@ function SectionCard({
|
|
|
297
297
|
}) {
|
|
298
298
|
return (
|
|
299
299
|
<View
|
|
300
|
-
className="bg-surface-elevated border-
|
|
300
|
+
className="bg-surface-elevated border-hairline"
|
|
301
301
|
style={{
|
|
302
302
|
borderWidth: 1,
|
|
303
303
|
borderRadius: 12,
|
|
@@ -421,7 +421,7 @@ function VbtSummaryRow({ summary }: { summary: VbtSummary }) {
|
|
|
421
421
|
{cells.map((cell) => (
|
|
422
422
|
<View
|
|
423
423
|
key={cell.label}
|
|
424
|
-
className="bg-surface-elevated border-
|
|
424
|
+
className="bg-surface-elevated border-hairline"
|
|
425
425
|
style={{
|
|
426
426
|
flex: 1,
|
|
427
427
|
padding: 12,
|
|
@@ -19,7 +19,7 @@ export interface InputBarProps {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
|
|
22
|
-
const INPUT_CLASSNAME = 'bg-surface-raised border-
|
|
22
|
+
const INPUT_CLASSNAME = 'bg-surface-raised border-hairline-strong text-text-primary'
|
|
23
23
|
|
|
24
24
|
const inputStyle = {
|
|
25
25
|
fontSize: 14,
|
|
@@ -55,7 +55,7 @@ export function InputBar({
|
|
|
55
55
|
style={{
|
|
56
56
|
width: '100%',
|
|
57
57
|
borderTopWidth: 1,
|
|
58
|
-
borderTopColor: resolveColor('
|
|
58
|
+
borderTopColor: resolveColor('hairline-default'),
|
|
59
59
|
paddingTop: 10,
|
|
60
60
|
paddingHorizontal: 16,
|
|
61
61
|
paddingBottom: 12,
|
|
@@ -82,7 +82,7 @@ const meta: Meta<typeof LiveAuraFrame> = {
|
|
|
82
82
|
docs: {
|
|
83
83
|
description: {
|
|
84
84
|
component:
|
|
85
|
-
'Full-surface color-flood frame tied to a coaching category. Wraps content on a
|
|
85
|
+
'Full-surface color-flood frame tied to a coaching category. Wraps content on a grey ' +
|
|
86
86
|
'base and layers a radial wash — amber at threshold (VL20), red at stop (VL28+, pulsing) — ' +
|
|
87
87
|
'derived from the semantic warning / error tokens via `alpha()`. Children pass through. ' +
|
|
88
88
|
'Rendered here at live-screen size so the flood reads (it is meant to tint a whole panel, ' +
|
|
@@ -19,7 +19,7 @@ describe('LiveAuraFrame', () => {
|
|
|
19
19
|
expect(screen.getByText('Cable Row')).toBeInTheDocument()
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
it('sits on the
|
|
22
|
+
it('sits on the grey base surface', () => {
|
|
23
23
|
render(<LiveAuraFrame category="productive" />)
|
|
24
24
|
expect(screen.getByTestId('live-aura-frame')).toHaveStyle({
|
|
25
25
|
backgroundColor: t['background-base'],
|
|
@@ -45,7 +45,7 @@ export function liveAuraColor(category: LiveAuraCategory): string | null {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Full-surface color-flood frame tied to a coaching category. Wraps `children`
|
|
48
|
-
* on a
|
|
48
|
+
* on a grey base and layers a radial wash (amber at threshold, red at stop)
|
|
49
49
|
* as a decorative, pointer-transparent overlay. The wash uses a solid
|
|
50
50
|
* `backgroundColor` fallback (native) plus a web-only `backgroundImage` radial
|
|
51
51
|
* gradient; both derive from the same semantic token via `alpha()`.
|
|
@@ -62,7 +62,7 @@ export function LiveAuraFrame({
|
|
|
62
62
|
const tint = color ? alpha(color, floodOpacity[category]) : 'transparent'
|
|
63
63
|
|
|
64
64
|
// Match R2's canonical aura: a top-down radial wash that FADES TO TRANSPARENT
|
|
65
|
-
// by ~62%, so the
|
|
65
|
+
// by ~62%, so the grey base shows through the lower panel — NOT a flat
|
|
66
66
|
// full-surface tint. On web (the target: MCP dashboard + Storybook) render the
|
|
67
67
|
// gradient only; native has no gradient support, so fall back to a solid tint.
|
|
68
68
|
const floodStyle = {
|
|
@@ -84,7 +84,7 @@ export function LiveAuraFrame({
|
|
|
84
84
|
borderRadius: 10,
|
|
85
85
|
backgroundColor: t['background-base'],
|
|
86
86
|
borderWidth: 1,
|
|
87
|
-
borderColor: t['
|
|
87
|
+
borderColor: t['hairline-default'],
|
|
88
88
|
},
|
|
89
89
|
style,
|
|
90
90
|
]}
|
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
MESO_ACCENT_GRADIENT_LIGHT,
|
|
11
11
|
} from '../../../theme/extracted-colors-dataviz'
|
|
12
12
|
|
|
13
|
+
const HAIRLINE_DEFAULT = getSemanticColors('dark')['hairline-default']
|
|
14
|
+
|
|
13
15
|
const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
|
|
14
16
|
const BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK
|
|
15
17
|
const BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT
|
|
16
|
-
const BORDER_DEFAULT =
|
|
18
|
+
const BORDER_DEFAULT = HAIRLINE_DEFAULT
|
|
17
19
|
|
|
18
20
|
/** Gradient stops for the 3px top accent: dark -> primary -> light. */
|
|
19
21
|
const ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY, BRAND_PRIMARY_LIGHT]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { View, Text, Pressable, type ViewProps } from 'react-native'
|
|
3
3
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
4
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
5
|
|
|
5
6
|
const t = getSemanticColors('dark')
|
|
6
7
|
|
|
@@ -15,7 +16,7 @@ export interface MuscleGroupChipProps extends ViewProps {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const dotColorMap: Record<VolumeStatus, string> = {
|
|
18
|
-
untrained:
|
|
19
|
+
untrained: greyRamp[900],
|
|
19
20
|
behind: t['brand-secondary'],
|
|
20
21
|
ontrack: t['status-success'],
|
|
21
22
|
target: t['brand-primary'],
|
|
@@ -31,13 +32,13 @@ export function MuscleGroupChip({
|
|
|
31
32
|
}: MuscleGroupChipProps) {
|
|
32
33
|
const dotColor = volumeStatus
|
|
33
34
|
? dotColorMap[volumeStatus]
|
|
34
|
-
:
|
|
35
|
+
: greyRamp[900]
|
|
35
36
|
|
|
36
37
|
const statusLabel = volumeStatus ?? 'no status'
|
|
37
38
|
|
|
38
39
|
const content = (
|
|
39
40
|
<View
|
|
40
|
-
className={['bg-surface-raised border-
|
|
41
|
+
className={['bg-surface-raised border-hairline', className].filter(Boolean).join(' ')}
|
|
41
42
|
style={{
|
|
42
43
|
flexDirection: 'row',
|
|
43
44
|
alignItems: 'center',
|
|
@@ -10,7 +10,7 @@ const RECENT_BORDER = 'rgba(249,180,21,0.3)'
|
|
|
10
10
|
const RECENT_GLOW = '0 0 12px rgba(249,180,21,0.06)'
|
|
11
11
|
// Native-safe fallback for the conditional row border (recent uses a computed
|
|
12
12
|
// rgba, so className can't express both branches).
|
|
13
|
-
const BORDER_DEFAULT = resolveColor('
|
|
13
|
+
const BORDER_DEFAULT = resolveColor('hairline-default')
|
|
14
14
|
|
|
15
15
|
export type PrRecordType = 'e1rm' | 'weight' | 'reps' | 'volume' | 'velocity'
|
|
16
16
|
|
|
@@ -172,7 +172,7 @@ export function PrHistoryModal({
|
|
|
172
172
|
>
|
|
173
173
|
<View
|
|
174
174
|
accessibilityElementsHidden
|
|
175
|
-
className="bg-
|
|
175
|
+
className="bg-hairline"
|
|
176
176
|
style={{
|
|
177
177
|
alignSelf: 'center',
|
|
178
178
|
width: 40,
|
|
@@ -105,7 +105,7 @@ type props without pulling the dependency.
|
|
|
105
105
|
`SetStrip`/`SetBar` colors are the real titan ramp pins (`primitiveRamps` red-600 /
|
|
106
106
|
orange-400 / amber-300 / green-300); the rail surfaces bind to the charcoal ramp +
|
|
107
107
|
a subtle neumorphic inset (`neumorphicShadows.charcoal.pressed.subtle`). The heading
|
|
108
|
-
design is locked in `
|
|
108
|
+
design is locked in `sources/design/shell/S3-sessionrail/DECISIONS-ExerciseRow.md`; the
|
|
109
109
|
exploration specimens live under `Custom/Workout/Explorations/*` (do not repoint yet).
|
|
110
110
|
In Storybook the family nests by composition under **`Shell/SessionRail/…`**
|
|
111
111
|
(organism → `ExerciseCardHeading` → `ExerciseHeading` → its atoms/molecules →
|
|
@@ -116,7 +116,7 @@ function EmojiSlider({ factor }: EmojiSliderProps) {
|
|
|
116
116
|
accessibilityLabel={`${factor.label} level ${level} of 5`}
|
|
117
117
|
aria-checked={selected}
|
|
118
118
|
testID="readiness-check-emoji"
|
|
119
|
-
className={selected ? undefined : 'border-
|
|
119
|
+
className={selected ? undefined : 'border-hairline bg-surface-raised'}
|
|
120
120
|
style={({ pressed }) => ({
|
|
121
121
|
flex: 1,
|
|
122
122
|
alignItems: 'center',
|
|
@@ -172,7 +172,7 @@ function WarmUpCard({ validation }: { validation: WarmUpValidation }) {
|
|
|
172
172
|
const badge = WARMUP_BADGE[validation.status]
|
|
173
173
|
return (
|
|
174
174
|
<View
|
|
175
|
-
className="border-
|
|
175
|
+
className="border-hairline bg-surface-raised"
|
|
176
176
|
style={{
|
|
177
177
|
marginTop: 16,
|
|
178
178
|
padding: 12,
|
|
@@ -188,7 +188,7 @@ export function RestTimer({
|
|
|
188
188
|
style={{
|
|
189
189
|
width: '100%',
|
|
190
190
|
borderTopWidth: 1,
|
|
191
|
-
borderTopColor: resolveColor('
|
|
191
|
+
borderTopColor: resolveColor('hairline-default'),
|
|
192
192
|
paddingVertical: 12,
|
|
193
193
|
paddingHorizontal: 16,
|
|
194
194
|
}}
|
|
@@ -253,7 +253,7 @@ export function RestTimer({
|
|
|
253
253
|
|
|
254
254
|
{/* Progress bar */}
|
|
255
255
|
<View
|
|
256
|
-
className="bg-
|
|
256
|
+
className="bg-hairline"
|
|
257
257
|
style={{
|
|
258
258
|
height: 3,
|
|
259
259
|
borderRadius: 2,
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
11
11
|
import { Fragment } from 'react'
|
|
12
|
-
import {
|
|
12
|
+
import { primitiveRamps as ramp, greyRamp } from '../../../theme/tokens/primitives'
|
|
13
13
|
import { GREY, RAIL_W, SET_GAP, T_PRIMARY, T_SECONDARY, T_TERTIARY, INSET, velColor, reps, Page, sectionTitle } from './setHeadingKit'
|
|
14
14
|
|
|
15
15
|
// ---- variable-zone (floor→max) upcoming color — real ramp candidates (no invented hex)
|
|
16
|
-
const VAR_GREY =
|
|
16
|
+
const VAR_GREY = greyRamp[800] // #3C3C3C — lighter grey (the paler-grey reference)
|
|
17
17
|
const VAR_BLUE_800 = ramp.blue[800] // #14407E — clearly blue, a touch brighter
|
|
18
18
|
const VAR_BLUE_900 = ramp.blue[900] // #112C5A — dark muted navy, recessive
|
|
19
19
|
const VAR_CYAN_900 = ramp.cyan[900] // #0B3149 — teal alt, sidesteps info-blue adjacency
|
|
@@ -115,7 +115,7 @@ function Sheet() {
|
|
|
115
115
|
{/* 1. variable rep-range — real ramp candidates for the variable zone */}
|
|
116
116
|
<Col label="1 · variable rep-range — LOCKED: cyan 900">
|
|
117
117
|
{([
|
|
118
|
-
['grey ·
|
|
118
|
+
['grey · grey 200', VAR_GREY],
|
|
119
119
|
['blue 800 · #14407E', VAR_BLUE_800],
|
|
120
120
|
['blue 900 · #112C5A', VAR_BLUE_900],
|
|
121
121
|
['cyan 900 · #0B3149', VAR_CYAN_900],
|
|
@@ -9,7 +9,7 @@ import { SessionHeader, type SessionHeaderPlanEntry } from './SessionHeader'
|
|
|
9
9
|
* bar (fill ∝ sets done, coloured against the elapsed-vs-budget pace with a live marker),
|
|
10
10
|
* a mono `n/total sets` label and a ⏱ elapsed readout. Upcoming, the tiles become
|
|
11
11
|
* Date/Time/Until, the bar is the empty plan shape, and the readout shows the planned
|
|
12
|
-
* duration. Rendered on the raised
|
|
12
|
+
* duration. Rendered on the raised grey plane.
|
|
13
13
|
*/
|
|
14
14
|
const meta: Meta<typeof SessionHeader> = {
|
|
15
15
|
title: 'Shell/SessionRail/SessionHeader',
|
|
@@ -20,7 +20,7 @@ const meta: Meta<typeof SessionHeader> = {
|
|
|
20
20
|
description: {
|
|
21
21
|
component:
|
|
22
22
|
'**Molecule** (shell S3). The session-rail heading — title, stat tiles, chunked ' +
|
|
23
|
-
'pace bar, sets label + ⏱ readout, on the raised
|
|
23
|
+
'pace bar, sets label + ⏱ readout, on the raised grey plane. Composes ' +
|
|
24
24
|
'[MetricTiles](?path=/docs/workout-metrictiles--docs) / ' +
|
|
25
25
|
'[ScheduleTiles](?path=/docs/workout-scheduletiles--docs) + ' +
|
|
26
26
|
'[SegmentedProgressBar](?path=/docs/workout-segmentedprogressbar--docs) + ' +
|
|
@@ -51,7 +51,7 @@ export interface SessionHeaderProps extends ViewProps {
|
|
|
51
51
|
* done, coloured green/amber against the elapsed-vs-budget pace, with a live marker),
|
|
52
52
|
* a mono `n/total sets` label and a ⏱ elapsed readout. Upcoming (`next` set), the tiles
|
|
53
53
|
* become Date/Time/Until, the bar is the empty plan shape, and the readout shows the
|
|
54
|
-
* planned duration. Rendered on the raised
|
|
54
|
+
* planned duration. Rendered on the raised grey plane; presentational. Composes
|
|
55
55
|
* {@link MetricTiles} / {@link ScheduleTiles} + {@link SegmentedProgressBar} +
|
|
56
56
|
* {@link TimerReadout}.
|
|
57
57
|
*/
|
|
@@ -10,7 +10,7 @@ const t = getSemanticColors('dark')
|
|
|
10
10
|
* `SessionRail` (shell organism) — the live-workout exercise list: a flat raised
|
|
11
11
|
* `SessionHeader` glance (title, stat tiles, chunked pace bar) over a sunk, inset list
|
|
12
12
|
* of ExerciseCard rail headings. The header plan (chunk widths ∝ sets) is derived from
|
|
13
|
-
* `exercises`. Surfaces bind to the
|
|
13
|
+
* `exercises`. Surfaces bind to the grey ramp; the list depth is a subtle neumorphic
|
|
14
14
|
* inset. Driven entirely by props.
|
|
15
15
|
*/
|
|
16
16
|
const meta: Meta<typeof SessionRail> = {
|
|
@@ -37,7 +37,7 @@ const meta: Meta<typeof SessionRail> = {
|
|
|
37
37
|
description: {
|
|
38
38
|
component:
|
|
39
39
|
'**Organism** (shell S3). The live-workout exercise list: raised header glance over ' +
|
|
40
|
-
'a sunk inset list, subtle neumorphic depth (
|
|
40
|
+
'a sunk inset list, subtle neumorphic depth (grey ramp + `neumorphicShadows`). ' +
|
|
41
41
|
'Composes ' +
|
|
42
42
|
'[SessionHeader](?path=/docs/shell-sessionrail-sessionheader--docs) + ' +
|
|
43
43
|
'[ExerciseCardHeading](?path=/docs/workout-exercisecardheading--docs) × N. ' +
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { View, type ViewProps } from 'react-native'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
|
+
import { insetWell } from '../../../theme/materials'
|
|
5
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
5
6
|
import { Surface } from '../../ui/surface'
|
|
6
7
|
import { ExerciseCardHeading } from './ExerciseCardHeading'
|
|
7
8
|
import { ExerciseCard } from './ExerciseCard'
|
|
@@ -17,7 +18,9 @@ import type { ExerciseIndicatorKind } from './ExerciseIndicator'
|
|
|
17
18
|
// recessed via its inner shadow yet paler than the header, so the transparent
|
|
18
19
|
// exercise headings on it never blend into the header plane. Surface owns both backgrounds,
|
|
19
20
|
// so the rail no longer hand-sets them.
|
|
20
|
-
const
|
|
21
|
+
const SEMANTIC = getSemanticColors('dark')
|
|
22
|
+
/** Row divider — one step up from the well it sits in so the line reads. */
|
|
23
|
+
const DIVIDER = greyRamp[875]
|
|
21
24
|
|
|
22
25
|
const DEFAULT_WIDTH = 246
|
|
23
26
|
|
|
@@ -124,9 +127,14 @@ export function SessionRail({
|
|
|
124
127
|
next={next}
|
|
125
128
|
/>
|
|
126
129
|
|
|
130
|
+
{/* The list is a WELL cut into the rail: one plane down from the rail's
|
|
131
|
+
`elevated`, recessed by the shared inset material rather than by a
|
|
132
|
+
neumorphic pressed shadow (which had no room to read at this
|
|
133
|
+
lightness). `level` follows the well's tone so on-surface text
|
|
134
|
+
resolves against what is actually painted. */}
|
|
127
135
|
<Surface
|
|
128
|
-
level="
|
|
129
|
-
style={[{ flex: 1 },
|
|
136
|
+
level="base"
|
|
137
|
+
style={[{ flex: 1 }, insetWell(SEMANTIC['surface-base'])]}
|
|
130
138
|
testID="session-rail-list"
|
|
131
139
|
>
|
|
132
140
|
{exercises.map((ex, i) => (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import {
|
|
2
|
+
import { primitiveRamps, greyRamp } from '../../../theme/tokens/primitives'
|
|
3
3
|
import { SegmentedBar, type SegmentedBarSegment } from './SegmentedBar'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -13,8 +13,8 @@ export const SET_STRIP_ZONES = {
|
|
|
13
13
|
fastest: primitiveRamps.green[300],
|
|
14
14
|
} as const
|
|
15
15
|
|
|
16
|
-
/** Grey fill for planned-but-unperformed reps / upcoming sets (
|
|
17
|
-
const TODO_COLOR =
|
|
16
|
+
/** Grey fill for planned-but-unperformed reps / upcoming sets (grey placeholder). */
|
|
17
|
+
const TODO_COLOR = greyRamp[900]
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* The learned "variable / unknown / opportunity" semantic (cyan-900, a real ramp
|
|
@@ -3,10 +3,13 @@ import { render, screen } from '@testing-library/react'
|
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { View } from 'react-native'
|
|
5
5
|
import { SetRow, type SetRowProps } from './SetRow'
|
|
6
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Text treatments, read from the tokens rather than pinned as hexes. These
|
|
9
|
+
// used to be hand-copied literals and silently desynced when the greys moved
|
|
10
|
+
// to the warm ramp (TD-07.14). The assertion still bites — it checks the
|
|
11
|
+
// component reaches for the right ROLE — it just no longer restates the value.
|
|
12
|
+
const { 'text-primary': T_ACTIVE, 'text-secondary': T_MUTED } = getSemanticColors('dark')
|
|
10
13
|
|
|
11
14
|
const doneRow: SetRowProps = {
|
|
12
15
|
state: 'done',
|
|
@@ -1,6 +1,7 @@
|
|
|
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
3
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
4
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
5
|
|
|
5
6
|
const t = getSemanticColors('dark')
|
|
6
7
|
|
|
@@ -28,7 +29,7 @@ const solidVariantColors: Record<string, string> = {
|
|
|
28
29
|
success: t['status-success'],
|
|
29
30
|
warning: t['status-warning'],
|
|
30
31
|
error: t['status-error'],
|
|
31
|
-
neutral:
|
|
32
|
+
neutral: greyRamp[500],
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
const ringVariantStyles: Record<string, Record<string, unknown>> = {
|
|
@@ -71,10 +72,10 @@ const iconColors: Record<StatusDotVariant, string> = {
|
|
|
71
72
|
success: '#0A5C52',
|
|
72
73
|
warning: '#6B4000',
|
|
73
74
|
error: '#5C1A1A',
|
|
74
|
-
neutral:
|
|
75
|
+
neutral: greyRamp[200],
|
|
75
76
|
'on-track': t['status-success'],
|
|
76
77
|
deviation: t['status-warning'],
|
|
77
|
-
future:
|
|
78
|
+
future: greyRamp[500],
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
const sizeDimensions = {
|
|
@@ -146,7 +147,7 @@ export function StatusDot({
|
|
|
146
147
|
>
|
|
147
148
|
<View accessibilityElementsHidden>{dot}</View>
|
|
148
149
|
<Text
|
|
149
|
-
style={{ fontSize: 12, lineHeight: 16, color:
|
|
150
|
+
style={{ fontSize: 12, lineHeight: 16, color: greyRamp[400] }}
|
|
150
151
|
accessibilityElementsHidden
|
|
151
152
|
>
|
|
152
153
|
{label}
|
|
@@ -477,7 +477,7 @@ export function StrengthTrendChart({
|
|
|
477
477
|
<View
|
|
478
478
|
testID="strength-trend-chart-tooltip"
|
|
479
479
|
accessibilityElementsHidden
|
|
480
|
-
className="bg-surface-elevated border-
|
|
480
|
+
className="bg-surface-elevated border-hairline-strong"
|
|
481
481
|
style={{
|
|
482
482
|
position: 'absolute',
|
|
483
483
|
left: Math.max(
|
|
@@ -114,7 +114,7 @@ function SummaryCards({ summary }: { summary: TrainingStatusSummary }) {
|
|
|
114
114
|
return (
|
|
115
115
|
<View
|
|
116
116
|
key={key}
|
|
117
|
-
className="bg-surface-elevated border-
|
|
117
|
+
className="bg-surface-elevated border-hairline"
|
|
118
118
|
style={{
|
|
119
119
|
flexGrow: 1,
|
|
120
120
|
flexBasis: '46%',
|
|
@@ -265,7 +265,7 @@ export function TrainingStatusPage({
|
|
|
265
265
|
<SummaryCards summary={summary} />
|
|
266
266
|
|
|
267
267
|
<View
|
|
268
|
-
className="bg-surface-elevated border-
|
|
268
|
+
className="bg-surface-elevated border-hairline"
|
|
269
269
|
style={{
|
|
270
270
|
borderWidth: 1,
|
|
271
271
|
borderRadius: 12,
|
|
@@ -414,8 +414,11 @@ describe('VelocityStrip all-zero velocities (NaN guard)', () => {
|
|
|
414
414
|
|
|
415
415
|
// Literal-hex slot colors (must match the component's tokens exactly).
|
|
416
416
|
// TODO_SOLID = the LANDED surface-relative solid to-do tone (base/dark plane blended toward the
|
|
417
|
-
// on-surface neutral) — replaced the old fixed
|
|
418
|
-
|
|
417
|
+
// on-surface neutral) — replaced the old fixed grey #2C2C2C. Solid fill, not a dashed outline.
|
|
418
|
+
// Pinned rather than recomputed on purpose: deriving it here would just mirror
|
|
419
|
+
// SetBarChart's mixHex and stop catching a change to the blend itself.
|
|
420
|
+
// = mixHex(grey-925, text-tertiary, 0.55); moved with the warm ramp (TD-07.14).
|
|
421
|
+
const TODO_SOLID = '#5B5957'
|
|
419
422
|
const VARIABLE_CYAN = '#0B3149'
|
|
420
423
|
const CONTINUE_OUTLINE = '#22465F'
|
|
421
424
|
describe('VelocityStrip set-type modes (compact)', () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useEffect, useState } from 'react'
|
|
3
3
|
import { View, Text, Pressable, Animated, type ViewProps, type ViewStyle } from 'react-native'
|
|
4
4
|
import { WORKOUT_TOKENS } from '../../../theme/workout-tokens'
|
|
5
|
-
import {
|
|
5
|
+
import { sequentialEffort, greyRamp } from '../../../theme/tokens/primitives'
|
|
6
6
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
7
7
|
import { alpha } from '../../../utils/colors'
|
|
8
8
|
import { formatVelocity } from '../../../utils/workout-format'
|
|
@@ -456,14 +456,14 @@ const EXPANDED_HEIGHT = 60
|
|
|
456
456
|
/** Default `compact` (flat resting strip) height (px) — a THIN radius-2 pill row, the resting glance. */
|
|
457
457
|
const COMPACT_HEIGHT = 8
|
|
458
458
|
|
|
459
|
-
/** The dashed running-best reference line color (the lightest
|
|
460
|
-
const HERO_REFERENCE_COLOR =
|
|
459
|
+
/** The dashed running-best reference line color (the lightest grey step). */
|
|
460
|
+
const HERO_REFERENCE_COLOR = greyRamp[600]
|
|
461
461
|
|
|
462
462
|
/**
|
|
463
463
|
* A dashed running-best reference line spanning the plot width, absolutely positioned a
|
|
464
464
|
* pixel `offset` from the given `anchor` edge. Shared by the single `hero` chart (anchored
|
|
465
465
|
* to the baseline, `bottom`) and BOTH wings of the diverging dual chart (anchored to the
|
|
466
|
-
* centre axis, `top`) so the three sites render one line treatment (
|
|
466
|
+
* centre axis, `top`) so the three sites render one line treatment (grey-0, 1px dashed).
|
|
467
467
|
* Presentation-only + non-interactive — the numeric best lives in each chart's container
|
|
468
468
|
* accessibility label, so the line itself is hidden from the a11y tree.
|
|
469
469
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
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
3
|
import { WORKOUT_TOKENS } from '../../../theme/workout-tokens'
|
|
4
|
-
import {
|
|
4
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
5
5
|
import { ZoneTrack } from './ZoneTrack'
|
|
6
6
|
import { DataRow } from '../../ui/data-row/DataRow'
|
|
7
7
|
import type { VolumeLandmarks } from './muscleTaxonomy'
|
|
@@ -11,9 +11,9 @@ import type { VolumeLandmarks } from './muscleTaxonomy'
|
|
|
11
11
|
// BodyMap / MesoProgressBar so a muscle reads identically across the app.
|
|
12
12
|
const HEAT = WORKOUT_TOKENS.heatmap
|
|
13
13
|
|
|
14
|
-
// The muted, un-reached track colour — the same
|
|
14
|
+
// The muted, un-reached track colour — the same grey step ZoneTrack defaults
|
|
15
15
|
// to, so the bar sits on the shared gauge-track surface.
|
|
16
|
-
const NEUTRAL_TRACK =
|
|
16
|
+
const NEUTRAL_TRACK = greyRamp[800]
|
|
17
17
|
const MONO = 'monospace'
|
|
18
18
|
|
|
19
19
|
export type VolumeZone = 'under' | 'maintenance' | 'productive' | 'approaching' | 'over'
|
|
@@ -2,6 +2,11 @@ import { describe, it, expect, vi } from 'vitest'
|
|
|
2
2
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { WeightBadge } from './WeightBadge'
|
|
5
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
6
|
+
|
|
7
|
+
// Read from the token, not pinned: these used to be hand-copied hexes and
|
|
8
|
+
// silently desynced when borders became alpha hairlines (TD-07.16).
|
|
9
|
+
const T = getSemanticColors('dark')
|
|
5
10
|
|
|
6
11
|
describe('WeightBadge', () => {
|
|
7
12
|
it('renders value and default unit', () => {
|
|
@@ -71,7 +76,7 @@ describe('WeightBadge', () => {
|
|
|
71
76
|
it('uses default border color when not a PR', () => {
|
|
72
77
|
render(<WeightBadge value={225} />)
|
|
73
78
|
expect(screen.getByTestId('weight-badge')).toHaveStyle({
|
|
74
|
-
borderTopColor: '
|
|
79
|
+
borderTopColor: T['hairline-default'],
|
|
75
80
|
})
|
|
76
81
|
})
|
|
77
82
|
|