@titan-design/react-ui 0.6.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.
- package/dist/bodymap.js +12 -7
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +12 -7
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +855 -124
- package/dist/index.d.ts +855 -124
- package/dist/index.js +2276 -801
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2230 -802
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-MO0JCySL.d.mts → pages-8u_4WbL-.d.mts} +280 -57
- package/dist/{pages-D7Jlssvp.d.ts → pages-DaWiBOGa.d.ts} +280 -57
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1255 -798
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1255 -798
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +16 -82
- package/dist/theme/index.d.ts +16 -82
- package/dist/theme/index.js +13 -115
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +13 -115
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +14 -6
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +14 -6
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +870 -0
- package/src/arch/annotations.json +48 -0
- package/src/arch/arch-graph.json +4301 -0
- package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +1 -1
- package/src/components/custom/Metric/Metric.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +1 -1
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
- package/src/components/custom/Table/Table.stories.tsx +1 -1
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +62 -0
- package/src/components/custom/TimerReadout/TimerReadout.test.tsx +72 -0
- package/src/components/custom/TimerReadout/TimerReadout.tsx +75 -0
- package/src/components/custom/TimerReadout/index.ts +1 -0
- package/src/components/custom/Treemap/Treemap.stories.tsx +1 -1
- package/src/components/custom/Typography/Typography.stories.tsx +1 -1
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +21 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +16 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +9 -15
- package/src/components/custom/Workout/BaseBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +1 -1
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +51 -66
- package/src/components/custom/Workout/ExerciseCard.test.tsx +146 -143
- package/src/components/custom/Workout/ExerciseCard.tsx +176 -198
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +99 -0
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +72 -0
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +43 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +151 -0
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +5 -3
- package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +4 -4
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +4 -5
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +81 -0
- package/src/components/custom/Workout/ExerciseHeading.test.tsx +77 -0
- package/src/components/custom/Workout/ExerciseHeading.tsx +85 -0
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +110 -0
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +93 -0
- package/src/components/custom/Workout/ExerciseIndicator.tsx +120 -0
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +51 -0
- package/src/components/custom/Workout/FatigueMeter.test.tsx +73 -0
- package/src/components/custom/Workout/FatigueMeter.tsx +82 -0
- package/src/components/custom/Workout/InputBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +153 -0
- package/src/components/custom/Workout/LiveAuraFrame.test.tsx +74 -0
- package/src/components/custom/Workout/LiveAuraFrame.tsx +105 -0
- package/src/components/custom/Workout/MesoCard.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +1 -1
- package/src/components/custom/Workout/MetricTiles.stories.tsx +60 -0
- package/src/components/custom/Workout/MetricTiles.test.tsx +58 -0
- package/src/components/custom/Workout/MetricTiles.tsx +48 -0
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +1 -1
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +4 -16
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -6
- package/src/components/custom/Workout/README.md +146 -4
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +1 -1
- package/src/components/custom/Workout/RestTimer.stories.tsx +1 -1
- package/src/components/custom/Workout/RestTimer.tsx +15 -10
- package/src/components/custom/Workout/RowInventory.stories.tsx +405 -0
- package/src/components/custom/Workout/S3FullRail.stories.tsx +34 -0
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +95 -0
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +61 -0
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +176 -0
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +240 -0
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +40 -0
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +34 -0
- package/src/components/custom/Workout/ScheduleTiles.tsx +70 -0
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +99 -0
- package/src/components/custom/Workout/SegmentedBar.test.tsx +77 -0
- package/src/components/custom/Workout/SegmentedBar.tsx +172 -0
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +50 -0
- package/src/components/custom/Workout/SegmentedProgressBar.test.tsx +80 -0
- package/src/components/custom/Workout/SegmentedProgressBar.tsx +67 -0
- package/src/components/custom/Workout/SessionHeader.stories.tsx +121 -0
- package/src/components/custom/Workout/SessionHeader.test.tsx +122 -0
- package/src/components/custom/Workout/SessionHeader.tsx +152 -0
- package/src/components/custom/Workout/SessionRail.stories.tsx +153 -0
- package/src/components/custom/Workout/SessionRail.test.tsx +86 -0
- package/src/components/custom/Workout/SessionRail.tsx +126 -0
- package/src/components/custom/Workout/SetBar.stories.tsx +124 -0
- package/src/components/custom/Workout/SetBar.test.tsx +123 -0
- package/src/components/custom/Workout/SetBar.tsx +171 -0
- package/src/components/custom/Workout/SetRow.stories.tsx +50 -100
- package/src/components/custom/Workout/SetRow.test.tsx +94 -166
- package/src/components/custom/Workout/SetRow.tsx +169 -232
- package/src/components/custom/Workout/SetStrip.stories.tsx +154 -0
- package/src/components/custom/Workout/SetStrip.test.tsx +109 -0
- package/src/components/custom/Workout/SetStrip.tsx +71 -0
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +66 -0
- package/src/components/custom/Workout/SetTableHeader.test.tsx +47 -0
- package/src/components/custom/Workout/SetTableHeader.tsx +88 -0
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +47 -0
- package/src/components/custom/Workout/SetsRepsLoad.test.tsx +44 -0
- package/src/components/custom/Workout/SetsRepsLoad.tsx +52 -0
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.stories.tsx +59 -0
- package/src/components/custom/Workout/StatusPill.test.tsx +63 -0
- package/src/components/custom/Workout/StatusPill.tsx +88 -0
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +1 -1
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +1 -1
- package/src/components/custom/Workout/TempoBar.stories.tsx +1 -1
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +12 -1
- package/src/components/custom/Workout/TempoDisplay.tsx +23 -33
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +1 -1
- package/src/components/custom/Workout/VelocityStrip.modalities.stories.tsx +254 -0
- package/src/components/custom/Workout/VelocityStrip.responsive.stories.tsx +145 -0
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +129 -66
- package/src/components/custom/Workout/VelocityStrip.test.tsx +376 -141
- package/src/components/custom/Workout/VelocityStrip.tsx +508 -120
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +73 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.test.tsx +119 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +154 -0
- package/src/components/custom/Workout/WeekRow.stories.tsx +1 -1
- package/src/components/custom/Workout/WeightBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +2 -6
- package/src/components/custom/Workout/WorkoutCard.test.tsx +13 -46
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +1 -1
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +140 -0
- package/src/components/custom/Workout/ZoneTrack.test.tsx +200 -0
- package/src/components/custom/Workout/ZoneTrack.tsx +315 -0
- package/src/components/custom/Workout/index.ts +55 -2
- package/src/components/custom/Workout/metricText.stories.tsx +69 -0
- package/src/components/custom/Workout/metricText.tsx +34 -0
- package/src/components/custom/Workout/paceTone.test.ts +29 -0
- package/src/components/custom/Workout/paceTone.ts +27 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +177 -0
- package/src/components/custom/index.ts +1 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
- package/src/components/icons/icons.stories.tsx +67 -2
- package/src/components/icons/icons.test.tsx +32 -2
- package/src/components/icons/icons.tsx +108 -0
- package/src/components/shell/BrandLockup.stories.tsx +3 -3
- package/src/components/shell/DashboardShell.stories.tsx +65 -0
- package/src/components/shell/DashboardShell.test.tsx +42 -0
- package/src/components/shell/DashboardShell.tsx +74 -0
- package/src/components/shell/DeviceIndicator.stories.tsx +2 -2
- package/src/components/shell/DeviceMenu.stories.tsx +5 -5
- package/src/components/shell/DeviceRow.stories.tsx +3 -3
- package/src/components/shell/NavItem.stories.tsx +52 -0
- package/src/components/shell/NavItem.test.tsx +35 -0
- package/src/components/shell/NavItem.tsx +75 -0
- package/src/components/shell/README.md +30 -0
- package/src/components/shell/SessionRailSpecimen.stories.tsx +753 -0
- package/src/components/shell/SessionStatePill.stories.tsx +3 -3
- package/src/components/shell/SessionStatePill.tsx +1 -1
- package/src/components/shell/SideNav.stories.tsx +81 -0
- package/src/components/shell/SideNav.test.tsx +51 -0
- package/src/components/shell/SideNav.tsx +74 -0
- package/src/components/shell/TopBar.stories.tsx +5 -5
- package/src/components/shell/index.ts +5 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/badge/Badge.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/button/Button.stories.tsx +1 -1
- package/src/components/ui/card/Card.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/chip/Chip.stories.tsx +1 -1
- package/src/components/ui/collapse/Collapse.stories.tsx +1 -1
- package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/drawer/Drawer.stories.tsx +1 -1
- package/src/components/ui/form-field/FormField.stories.tsx +1 -1
- package/src/components/ui/help-tip/HelpTip.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/indicator/Indicator.stories.tsx +2 -2
- package/src/components/ui/indicator/Indicator.test.tsx +1 -0
- package/src/components/ui/indicator/Indicator.tsx +6 -1
- package/src/components/ui/input/Input.stories.tsx +1 -1
- package/src/components/ui/link/Link.stories.tsx +1 -1
- package/src/components/ui/list-item/ListItem.stories.tsx +1 -1
- package/src/components/ui/menu/Menu.stories.tsx +1 -1
- package/src/components/ui/modal/Modal.stories.tsx +1 -1
- package/src/components/ui/pill/Pill.stories.tsx +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +1 -1
- package/src/components/ui/progress/Progress.stories.tsx +1 -1
- package/src/components/ui/radio/Radio.stories.tsx +1 -1
- package/src/components/ui/section/Section.stories.tsx +1 -1
- package/src/components/ui/select/Select.stories.tsx +1 -1
- package/src/components/ui/skeleton/Skeleton.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.stories.tsx +79 -0
- package/src/components/ui/tile/Tile.test.tsx +48 -0
- package/src/components/ui/tile/Tile.tsx +64 -0
- package/src/components/ui/tile/index.ts +2 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +1 -1
- package/src/components/ui/tooltip/Tooltip.stories.tsx +1 -1
- package/src/examples/react-hook-form/ReactHookForm.stories.tsx +1 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTimer.test.ts +150 -0
- package/src/hooks/useTimer.ts +77 -0
- package/src/index.ts +3 -0
- package/src/pages.ts +1 -1
- package/src/stories/PresetShowcase.stories.tsx +1 -1
- package/src/stories/ThemePresets.stories.tsx +1 -1
- package/src/theme/ColorSystem.stories.tsx +1 -1
- package/src/theme/Colors.stories.tsx +5 -8
- package/src/theme/config.ts +4 -0
- package/src/theme/elevation.stories.tsx +1 -1
- package/src/theme/global.css +5 -1
- package/src/theme/shadows.stories.tsx +1 -1
- package/src/theme/tokens/primitives.ts +11 -107
- package/src/theme/tokens/semantic.ts +8 -0
- package/src/theme/workout-tokens.ts +11 -7
- package/tailwind.config.js +5 -0
|
@@ -11,170 +11,137 @@ import {
|
|
|
11
11
|
|
|
12
12
|
const sampleVelocities = [1.1, 0.95, 0.82, 0.68, 0.45]
|
|
13
13
|
|
|
14
|
-
describe('VelocityStrip', () => {
|
|
15
|
-
it('renders
|
|
14
|
+
describe('VelocityStrip expanded (framed chart)', () => {
|
|
15
|
+
it('renders the open chart with bars, labels and info by default', () => {
|
|
16
16
|
render(<VelocityStrip velocities={sampleVelocities} />)
|
|
17
|
+
expect(screen.getByTestId('velocity-strip')).toBeInTheDocument()
|
|
18
|
+
expect(screen.getByTestId('velocity-info-row')).toBeInTheDocument()
|
|
17
19
|
for (let i = 0; i < sampleVelocities.length; i++) {
|
|
18
20
|
expect(screen.getByTestId(`velocity-bar-${i}`)).toBeInTheDocument()
|
|
21
|
+
expect(screen.getByTestId(`velocity-label-${i}`)).toBeInTheDocument()
|
|
19
22
|
}
|
|
20
23
|
})
|
|
21
24
|
|
|
22
|
-
it('
|
|
23
|
-
render(<VelocityStrip velocities={sampleVelocities}
|
|
24
|
-
expect(
|
|
25
|
-
|
|
25
|
+
it('labels the open chart as tap-to-collapse (open by default)', () => {
|
|
26
|
+
render(<VelocityStrip velocities={sampleVelocities} />)
|
|
27
|
+
expect(
|
|
28
|
+
screen.getByLabelText('Velocity chart for set, 5 reps, tap to collapse')
|
|
29
|
+
).toBeInTheDocument()
|
|
26
30
|
})
|
|
27
31
|
|
|
28
|
-
it('
|
|
29
|
-
render(<VelocityStrip velocities={sampleVelocities} expanded />)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
it('renders the 3px collapsed strip when expanded is false', () => {
|
|
33
|
+
render(<VelocityStrip velocities={sampleVelocities} expanded={false} />)
|
|
34
|
+
expect(
|
|
35
|
+
screen.getByLabelText('Velocity chart for set, 5 reps, tap to expand')
|
|
36
|
+
).toBeInTheDocument()
|
|
37
|
+
expect(screen.queryByTestId('velocity-info-row')).not.toBeInTheDocument()
|
|
33
38
|
})
|
|
34
39
|
|
|
35
40
|
it('fires onToggle on press', () => {
|
|
36
41
|
const onToggle = vi.fn()
|
|
37
|
-
render(
|
|
38
|
-
|
|
39
|
-
)
|
|
40
|
-
const pressable = screen.getByTestId('velocity-strip-pressable')
|
|
41
|
-
fireEvent.click(pressable)
|
|
42
|
+
render(<VelocityStrip velocities={sampleVelocities} onToggle={onToggle} />)
|
|
43
|
+
fireEvent.click(screen.getByTestId('velocity-strip-pressable'))
|
|
42
44
|
expect(onToggle).toHaveBeenCalledOnce()
|
|
43
45
|
})
|
|
44
46
|
|
|
45
|
-
it('fires onRepPress with correct index when bar is tapped', () => {
|
|
47
|
+
it('fires onRepPress with the correct index when a bar is tapped', () => {
|
|
46
48
|
const onRepPress = vi.fn()
|
|
47
|
-
render(
|
|
48
|
-
|
|
49
|
-
velocities={sampleVelocities}
|
|
50
|
-
expanded
|
|
51
|
-
onRepPress={onRepPress}
|
|
52
|
-
/>,
|
|
53
|
-
)
|
|
54
|
-
const bar = screen.getByTestId('velocity-bar-pressable-2')
|
|
55
|
-
fireEvent.click(bar)
|
|
49
|
+
render(<VelocityStrip velocities={sampleVelocities} onRepPress={onRepPress} />)
|
|
50
|
+
fireEvent.click(screen.getByTestId('velocity-bar-pressable-2'))
|
|
56
51
|
expect(onRepPress).toHaveBeenCalledWith(2, 0.82)
|
|
57
52
|
})
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
screen.getByLabelText(
|
|
63
|
-
'Velocity chart for set, 5 reps, tap to expand',
|
|
64
|
-
),
|
|
65
|
-
).toBeInTheDocument()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('sets expanded accessibility label when expanded', () => {
|
|
69
|
-
render(<VelocityStrip velocities={sampleVelocities} expanded />)
|
|
70
|
-
expect(
|
|
71
|
-
screen.getByLabelText(
|
|
72
|
-
'Velocity chart for set, 5 reps, tap to collapse',
|
|
73
|
-
),
|
|
74
|
-
).toBeInTheDocument()
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
describe('showInfo prop', () => {
|
|
78
|
-
it('shows info row when expanded and showInfo is true (default)', () => {
|
|
79
|
-
render(<VelocityStrip velocities={sampleVelocities} expanded />)
|
|
54
|
+
describe('showInfo', () => {
|
|
55
|
+
it('shows the info row by default', () => {
|
|
56
|
+
render(<VelocityStrip velocities={sampleVelocities} />)
|
|
80
57
|
expect(screen.getByTestId('velocity-info-row')).toBeInTheDocument()
|
|
81
58
|
})
|
|
82
59
|
|
|
83
|
-
it('hides info row when
|
|
84
|
-
render(<VelocityStrip velocities={sampleVelocities}
|
|
85
|
-
expect(screen.queryByTestId('velocity-info-row')).not.toBeInTheDocument()
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('does not show info row when collapsed regardless of showInfo', () => {
|
|
89
|
-
render(<VelocityStrip velocities={sampleVelocities} showInfo />)
|
|
60
|
+
it('hides the info row when showInfo is false', () => {
|
|
61
|
+
render(<VelocityStrip velocities={sampleVelocities} showInfo={false} />)
|
|
90
62
|
expect(screen.queryByTestId('velocity-info-row')).not.toBeInTheDocument()
|
|
91
63
|
})
|
|
92
64
|
})
|
|
93
65
|
|
|
94
|
-
describe('
|
|
95
|
-
it('
|
|
96
|
-
render(<VelocityStrip velocities={sampleVelocities}
|
|
97
|
-
expect(screen.getByTestId('velocity-
|
|
66
|
+
describe('showNumbers', () => {
|
|
67
|
+
it('shows per-bar labels by default', () => {
|
|
68
|
+
render(<VelocityStrip velocities={sampleVelocities} />)
|
|
69
|
+
expect(screen.getByTestId('velocity-label-0')).toBeInTheDocument()
|
|
98
70
|
})
|
|
99
71
|
|
|
100
|
-
it('
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
variant="mini"
|
|
106
|
-
onToggle={onToggle}
|
|
107
|
-
/>,
|
|
108
|
-
)
|
|
109
|
-
expect(
|
|
110
|
-
screen.queryByTestId('velocity-strip-pressable'),
|
|
111
|
-
).not.toBeInTheDocument()
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('renders correct number of segments', () => {
|
|
115
|
-
render(<VelocityStrip velocities={sampleVelocities} variant="mini" />)
|
|
116
|
-
for (let i = 0; i < sampleVelocities.length; i++) {
|
|
117
|
-
expect(screen.getByTestId(`velocity-bar-${i}`)).toBeInTheDocument()
|
|
118
|
-
}
|
|
72
|
+
it('hides per-bar labels when showNumbers is false (but keeps the framed chart via showInfo)', () => {
|
|
73
|
+
render(<VelocityStrip velocities={sampleVelocities} showNumbers={false} />)
|
|
74
|
+
expect(screen.queryByTestId('velocity-label-0')).not.toBeInTheDocument()
|
|
75
|
+
expect(screen.getByTestId('velocity-strip')).toBeInTheDocument()
|
|
76
|
+
expect(screen.getByTestId('velocity-info-row')).toBeInTheDocument()
|
|
119
77
|
})
|
|
120
78
|
})
|
|
121
79
|
|
|
122
|
-
describe('
|
|
123
|
-
it('
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
)
|
|
127
|
-
const results = await axe(container)
|
|
128
|
-
expect(results).toHaveNoViolations()
|
|
80
|
+
describe('scale', () => {
|
|
81
|
+
it('peak (default) scales the tallest rep to full height', () => {
|
|
82
|
+
// maxV=1.0 -> denom 1.15 -> 1.0/1.15 = 87%.
|
|
83
|
+
render(<VelocityStrip velocities={[1.0, 0.5]} showInfo={false} />)
|
|
84
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ height: '87%' })
|
|
129
85
|
})
|
|
130
86
|
|
|
131
|
-
it('
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
expect(results).toHaveNoViolations()
|
|
87
|
+
it('fixed scales against the 1.15 ceiling regardless of the set max', () => {
|
|
88
|
+
// fixed denom 1.15 -> 1.0/1.15 = 87%, 0.5/1.15 = 43%.
|
|
89
|
+
render(<VelocityStrip velocities={[1.0, 0.5]} scale="fixed" showInfo={false} />)
|
|
90
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ height: '87%' })
|
|
91
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ height: '43%' })
|
|
137
92
|
})
|
|
93
|
+
})
|
|
138
94
|
|
|
139
|
-
|
|
95
|
+
describe('accessibility', () => {
|
|
96
|
+
it('has no violations (open, interactive)', async () => {
|
|
140
97
|
const { container } = render(
|
|
141
|
-
<VelocityStrip
|
|
142
|
-
velocities={sampleVelocities}
|
|
143
|
-
expanded
|
|
144
|
-
onRepPress={() => {}}
|
|
145
|
-
/>,
|
|
98
|
+
<VelocityStrip velocities={sampleVelocities} onToggle={() => {}} />
|
|
146
99
|
)
|
|
147
|
-
|
|
148
|
-
expect(results).toHaveNoViolations()
|
|
100
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
149
101
|
})
|
|
150
102
|
|
|
151
|
-
it('has no
|
|
103
|
+
it('has no violations with rep press', async () => {
|
|
152
104
|
const { container } = render(
|
|
153
|
-
<VelocityStrip velocities={sampleVelocities}
|
|
105
|
+
<VelocityStrip velocities={sampleVelocities} onRepPress={() => {}} />
|
|
154
106
|
)
|
|
155
|
-
|
|
156
|
-
expect(results).toHaveNoViolations()
|
|
107
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
157
108
|
})
|
|
158
109
|
|
|
159
|
-
it('
|
|
160
|
-
render(<VelocityStrip velocities={sampleVelocities}
|
|
110
|
+
it('rep pressables carry accessibility labels', () => {
|
|
111
|
+
render(<VelocityStrip velocities={sampleVelocities} onRepPress={() => {}} />)
|
|
161
112
|
expect(
|
|
162
|
-
screen.getByLabelText('
|
|
113
|
+
screen.getByLabelText('Rep 1: 1.10 meters per second, tap for details')
|
|
163
114
|
).toBeInTheDocument()
|
|
164
115
|
})
|
|
116
|
+
})
|
|
117
|
+
})
|
|
165
118
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
119
|
+
describe('VelocityStrip mini variant', () => {
|
|
120
|
+
it('renders the flat mini strip', () => {
|
|
121
|
+
render(<VelocityStrip velocities={sampleVelocities} variant="mini" />)
|
|
122
|
+
expect(screen.getByTestId('velocity-strip-mini')).toBeInTheDocument()
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('does not respond to press', () => {
|
|
126
|
+
render(<VelocityStrip velocities={sampleVelocities} variant="mini" onToggle={() => {}} />)
|
|
127
|
+
expect(screen.queryByTestId('velocity-strip-pressable')).not.toBeInTheDocument()
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('renders one bar per rep', () => {
|
|
131
|
+
render(<VelocityStrip velocities={sampleVelocities} variant="mini" />)
|
|
132
|
+
for (let i = 0; i < sampleVelocities.length; i++) {
|
|
133
|
+
expect(screen.getByTestId(`velocity-bar-${i}`)).toBeInTheDocument()
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('has no accessibility violations', async () => {
|
|
138
|
+
const { container } = render(<VelocityStrip velocities={sampleVelocities} variant="mini" />)
|
|
139
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('does not apply live marking', () => {
|
|
143
|
+
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0} variant="mini" />)
|
|
144
|
+
expect(screen.queryByLabelText(/latest rep/)).not.toBeInTheDocument()
|
|
178
145
|
})
|
|
179
146
|
})
|
|
180
147
|
|
|
@@ -211,13 +178,10 @@ describe('getVelocityZoneName', () => {
|
|
|
211
178
|
|
|
212
179
|
describe('calculateVelocityLoss', () => {
|
|
213
180
|
it('calculates percentage loss from running-best to last rep', () => {
|
|
214
|
-
// Best is the first rep here, so best->last matches the legacy result.
|
|
215
181
|
expect(calculateVelocityLoss([1.0, 0.8])).toBe(20)
|
|
216
182
|
})
|
|
217
183
|
|
|
218
184
|
it('uses the best rep (not the first) as the reference for non-monotonic sets', () => {
|
|
219
|
-
// best = 1.0 (rep 2), last = 0.6 -> (1.0 - 0.6) / 1.0 = 40%.
|
|
220
|
-
// Legacy first->last would have been (0.8 - 0.6) / 0.8 = 25%.
|
|
221
185
|
expect(calculateVelocityLoss([0.8, 1.0, 0.6])).toBe(40)
|
|
222
186
|
})
|
|
223
187
|
|
|
@@ -226,7 +190,6 @@ describe('calculateVelocityLoss', () => {
|
|
|
226
190
|
})
|
|
227
191
|
|
|
228
192
|
it('clamps to 0 when a later rep exceeds the first rep', () => {
|
|
229
|
-
// best = 1.2 (last), so loss is negative pre-clamp -> 0.
|
|
230
193
|
expect(calculateVelocityLoss([1.0, 0.9, 1.2])).toBe(0)
|
|
231
194
|
})
|
|
232
195
|
|
|
@@ -265,14 +228,18 @@ const compoundBands = [
|
|
|
265
228
|
describe('VelocityStrip zones prop', () => {
|
|
266
229
|
it('colors bars from the supplied bands (mini)', () => {
|
|
267
230
|
render(<VelocityStrip velocities={[1.1, 0.45]} zones={compoundBands} variant="mini" />)
|
|
268
|
-
// 1.1 -> speed -> green; 0.45 -> maximalStrength -> red (shared with grinding).
|
|
269
231
|
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ backgroundColor: '#2ED573' })
|
|
270
232
|
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ backgroundColor: '#D14343' })
|
|
271
233
|
})
|
|
272
234
|
|
|
273
|
-
it('
|
|
274
|
-
|
|
275
|
-
|
|
235
|
+
it('gives grinding and maximalStrength DISTINCT reds (5-band, no collapse)', () => {
|
|
236
|
+
render(<VelocityStrip velocities={[0.45, 0.2]} zones={compoundBands} variant="mini" />)
|
|
237
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ backgroundColor: '#D14343' })
|
|
238
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ backgroundColor: '#A4221C' })
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('labels the info row with the band containing the mean velocity', () => {
|
|
242
|
+
render(<VelocityStrip velocities={sampleVelocities} zones={compoundBands} />)
|
|
276
243
|
expect(screen.getByTestId('velocity-info-row')).toHaveTextContent('Power')
|
|
277
244
|
})
|
|
278
245
|
|
|
@@ -291,16 +258,14 @@ describe('VelocityStrip live mode', () => {
|
|
|
291
258
|
})
|
|
292
259
|
|
|
293
260
|
it('marks the latest rep bar in its accessibility label', () => {
|
|
294
|
-
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={3}
|
|
295
|
-
expect(
|
|
296
|
-
screen.getByLabelText(/Rep 4: 0\.68 meters per second, latest rep$/),
|
|
297
|
-
).toBeInTheDocument()
|
|
261
|
+
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={3} />)
|
|
262
|
+
expect(screen.getByLabelText(/Rep 4: 0\.68 meters per second, latest rep$/)).toBeInTheDocument()
|
|
298
263
|
})
|
|
299
264
|
|
|
300
265
|
it('flags a new set peak on the latest bar', () => {
|
|
301
|
-
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0}
|
|
266
|
+
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0} />)
|
|
302
267
|
expect(
|
|
303
|
-
screen.getByLabelText(/Rep 1: 1\.10 meters per second, latest rep, new set peak$/)
|
|
268
|
+
screen.getByLabelText(/Rep 1: 1\.10 meters per second, latest rep, new set peak$/)
|
|
304
269
|
).toBeInTheDocument()
|
|
305
270
|
})
|
|
306
271
|
|
|
@@ -310,22 +275,292 @@ describe('VelocityStrip live mode', () => {
|
|
|
310
275
|
addEventListener: vi.fn(),
|
|
311
276
|
removeEventListener: vi.fn(),
|
|
312
277
|
}) as unknown as typeof window.matchMedia
|
|
313
|
-
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0}
|
|
278
|
+
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0} />)
|
|
314
279
|
expect(screen.getByTestId('velocity-bar-0')).toBeInTheDocument()
|
|
315
280
|
})
|
|
316
|
-
|
|
317
|
-
it('does not apply live marking in the mini variant', () => {
|
|
318
|
-
render(<VelocityStrip velocities={sampleVelocities} liveRepIndex={0} variant="mini" />)
|
|
319
|
-
expect(screen.queryByLabelText(/latest rep/)).not.toBeInTheDocument()
|
|
320
|
-
})
|
|
321
281
|
})
|
|
322
282
|
|
|
323
283
|
describe('VelocityStrip all-zero velocities (NaN guard)', () => {
|
|
324
|
-
it('emits a valid 0% bar height (not NaN) when every velocity is zero
|
|
325
|
-
render(<VelocityStrip velocities={[0, 0, 0]}
|
|
326
|
-
// Without the guard, 0 / (0 * 1.15) === NaN and the bar height becomes
|
|
327
|
-
// 'NaN%' (dropped by jsdom, leaving no height); the guard flattens to '0%'.
|
|
284
|
+
it('emits a valid 0% bar height (not NaN) when every velocity is zero', () => {
|
|
285
|
+
render(<VelocityStrip velocities={[0, 0, 0]} showInfo={false} />)
|
|
328
286
|
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ height: '0%' })
|
|
329
287
|
expect(screen.getByTestId('velocity-bar-2')).toHaveStyle({ height: '0%' })
|
|
330
288
|
})
|
|
331
289
|
})
|
|
290
|
+
|
|
291
|
+
// Literal-hex slot colors (must match the component's tokens exactly).
|
|
292
|
+
const TODO_GREY = '#2C2C2C'
|
|
293
|
+
const VARIABLE_CYAN = '#0B3149'
|
|
294
|
+
const CONTINUE_OUTLINE = '#22465F'
|
|
295
|
+
const CONTAINER_GAP_PX = '2px'
|
|
296
|
+
const REP_SLOT_ML = '0px'
|
|
297
|
+
const WIDE_SLOT_ML = '6px'
|
|
298
|
+
|
|
299
|
+
describe('VelocityStrip set-type modes (mini)', () => {
|
|
300
|
+
it('straight: done reps colored + grey todo remainder to the planned count', () => {
|
|
301
|
+
render(
|
|
302
|
+
<VelocityStrip
|
|
303
|
+
set={{ type: 'straight', velocities: [1.1, 0.9, 0.8], planned: 5 }}
|
|
304
|
+
variant="mini"
|
|
305
|
+
/>
|
|
306
|
+
)
|
|
307
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(3)
|
|
308
|
+
expect(screen.getAllByTestId('velocity-slot-todo')).toHaveLength(2)
|
|
309
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ backgroundColor: '#2ED573' })
|
|
310
|
+
expect(screen.getAllByTestId('velocity-slot-todo')[0]).toHaveStyle({
|
|
311
|
+
backgroundColor: TODO_GREY,
|
|
312
|
+
})
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('range: committed grey todo + a cyan variable window floor..max', () => {
|
|
316
|
+
render(
|
|
317
|
+
<VelocityStrip
|
|
318
|
+
set={{ type: 'range', velocities: [1.1, 1.0, 0.9, 0.85, 0.8, 0.7], floor: 8, max: 12 }}
|
|
319
|
+
variant="mini"
|
|
320
|
+
/>
|
|
321
|
+
)
|
|
322
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(6)
|
|
323
|
+
expect(screen.getAllByTestId('velocity-slot-todo')).toHaveLength(2)
|
|
324
|
+
expect(screen.getAllByTestId('velocity-slot-variable')).toHaveLength(4)
|
|
325
|
+
expect(screen.getAllByTestId('velocity-slot-variable')[0]).toHaveStyle({
|
|
326
|
+
backgroundColor: VARIABLE_CYAN,
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('amrap: done reps + one trailing outlined cyan continue slot', () => {
|
|
331
|
+
render(<VelocityStrip set={{ type: 'amrap', velocities: [1.1, 1.0, 0.9] }} variant="mini" />)
|
|
332
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(3)
|
|
333
|
+
const cont = screen.getByTestId('velocity-slot-continue')
|
|
334
|
+
expect(cont).toHaveStyle({ backgroundColor: VARIABLE_CYAN })
|
|
335
|
+
expect(cont).toHaveStyle({ borderTopColor: CONTINUE_OUTLINE })
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
it('drop: sub-loads split by a WIDE gap before each load after the first', () => {
|
|
339
|
+
render(
|
|
340
|
+
<VelocityStrip
|
|
341
|
+
set={{
|
|
342
|
+
type: 'drop',
|
|
343
|
+
subloads: [
|
|
344
|
+
[1.0, 0.9],
|
|
345
|
+
[0.8, 0.7],
|
|
346
|
+
[0.6, 0.5],
|
|
347
|
+
],
|
|
348
|
+
}}
|
|
349
|
+
variant="mini"
|
|
350
|
+
/>
|
|
351
|
+
)
|
|
352
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(6)
|
|
353
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ marginLeft: '0px' })
|
|
354
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ marginLeft: REP_SLOT_ML })
|
|
355
|
+
expect(screen.getByTestId('velocity-bar-2')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
356
|
+
expect(screen.getByTestId('velocity-bar-4')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it('myo: activation + clusters split by WIDE gaps, open adds a cyan continue', () => {
|
|
360
|
+
render(
|
|
361
|
+
<VelocityStrip
|
|
362
|
+
set={{
|
|
363
|
+
type: 'myo',
|
|
364
|
+
activation: [1.0, 0.9, 0.8],
|
|
365
|
+
clusters: [
|
|
366
|
+
[0.7, 0.6],
|
|
367
|
+
[0.6, 0.5],
|
|
368
|
+
],
|
|
369
|
+
open: true,
|
|
370
|
+
}}
|
|
371
|
+
variant="mini"
|
|
372
|
+
/>
|
|
373
|
+
)
|
|
374
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(7)
|
|
375
|
+
expect(screen.getByTestId('velocity-bar-3')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
376
|
+
expect(screen.getByTestId('velocity-bar-5')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
377
|
+
expect(screen.getByTestId('velocity-slot-continue')).toBeInTheDocument()
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it('cluster: fixed count grouped by WIDE intra-rest gaps, grey planned remainder', () => {
|
|
381
|
+
render(
|
|
382
|
+
<VelocityStrip
|
|
383
|
+
set={{
|
|
384
|
+
type: 'cluster',
|
|
385
|
+
velocities: [1.0, 0.95, 0.9, 0.88, 0.85],
|
|
386
|
+
groupSize: 2,
|
|
387
|
+
planned: 8,
|
|
388
|
+
}}
|
|
389
|
+
variant="mini"
|
|
390
|
+
/>
|
|
391
|
+
)
|
|
392
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(5)
|
|
393
|
+
expect(screen.getAllByTestId('velocity-slot-todo')).toHaveLength(3)
|
|
394
|
+
expect(screen.getByTestId('velocity-bar-2')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
395
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ marginLeft: REP_SLOT_ML })
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('back-compat: a velocities-only mini strip is unchanged (rep colors, rep gaps only)', () => {
|
|
399
|
+
render(<VelocityStrip velocities={sampleVelocities} variant="mini" />)
|
|
400
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(sampleVelocities.length)
|
|
401
|
+
expect(screen.queryByTestId('velocity-slot-todo')).not.toBeInTheDocument()
|
|
402
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ marginLeft: '0px' })
|
|
403
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ backgroundColor: '#2ED573' })
|
|
404
|
+
expect(screen.getByTestId('velocity-strip-mini')).toHaveStyle({ gap: CONTAINER_GAP_PX })
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('derives the summary from a set descriptor (mean / loss info row)', () => {
|
|
408
|
+
render(<VelocityStrip set={{ type: 'straight', velocities: [1.0, 0.8], planned: 5 }} />)
|
|
409
|
+
expect(screen.getByTestId('velocity-info-row')).toHaveTextContent('Loss: 20%')
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it('labels the strip per set type', () => {
|
|
413
|
+
render(<VelocityStrip set={{ type: 'amrap', velocities: [1.0, 0.9] }} variant="mini" />)
|
|
414
|
+
expect(
|
|
415
|
+
screen.getByLabelText('Velocity strip, AMRAP set, 2 reps and counting')
|
|
416
|
+
).toBeInTheDocument()
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
it('renders nothing when neither velocities nor set is provided', () => {
|
|
420
|
+
const { container } = render(<VelocityStrip variant="mini" />)
|
|
421
|
+
expect(container.firstChild).toBeNull()
|
|
422
|
+
})
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
describe('VelocityStrip set-type modes (expanded framed)', () => {
|
|
426
|
+
it('straight: velocity-height done reps + short grey planned stubs', () => {
|
|
427
|
+
render(<VelocityStrip set={{ type: 'straight', velocities: [1.1, 0.8], planned: 4 }} />)
|
|
428
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(2)
|
|
429
|
+
expect(screen.getAllByTestId('velocity-slot-todo')).toHaveLength(2)
|
|
430
|
+
expect(screen.getAllByTestId('velocity-slot-todo')[0]).toHaveStyle({
|
|
431
|
+
backgroundColor: TODO_GREY,
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
it('advanced types render their slot encoding in the framed view', () => {
|
|
436
|
+
render(
|
|
437
|
+
<VelocityStrip
|
|
438
|
+
set={{
|
|
439
|
+
type: 'drop',
|
|
440
|
+
subloads: [
|
|
441
|
+
[1.0, 0.9],
|
|
442
|
+
[0.8, 0.7],
|
|
443
|
+
],
|
|
444
|
+
}}
|
|
445
|
+
/>
|
|
446
|
+
)
|
|
447
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(4)
|
|
448
|
+
expect(screen.getByTestId('velocity-bar-2')).toBeInTheDocument()
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
describe('VelocityStrip expanded bare strip (spotlight: numbers + info off)', () => {
|
|
453
|
+
const bareProps = { variant: 'expanded' as const, showNumbers: false, showInfo: false }
|
|
454
|
+
|
|
455
|
+
it('renders the bare strip container (no framed chart, no mini)', () => {
|
|
456
|
+
render(
|
|
457
|
+
<VelocityStrip
|
|
458
|
+
{...bareProps}
|
|
459
|
+
set={{ type: 'straight', velocities: [1.0, 0.8], planned: 2 }}
|
|
460
|
+
/>
|
|
461
|
+
)
|
|
462
|
+
expect(screen.getByTestId('velocity-strip-compact')).toBeInTheDocument()
|
|
463
|
+
expect(screen.queryByTestId('velocity-strip-mini')).not.toBeInTheDocument()
|
|
464
|
+
expect(screen.queryByTestId('velocity-strip')).not.toBeInTheDocument()
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
it('scales bar height to velocity against the fixed ceiling at the given height', () => {
|
|
468
|
+
render(
|
|
469
|
+
<VelocityStrip
|
|
470
|
+
{...bareProps}
|
|
471
|
+
scale="fixed"
|
|
472
|
+
height={24}
|
|
473
|
+
set={{ type: 'straight', velocities: [1.15, 0.575], planned: 2 }}
|
|
474
|
+
/>
|
|
475
|
+
)
|
|
476
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ height: '24px' })
|
|
477
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ height: '12px' })
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
it('honors height for the scaling', () => {
|
|
481
|
+
render(
|
|
482
|
+
<VelocityStrip
|
|
483
|
+
{...bareProps}
|
|
484
|
+
scale="fixed"
|
|
485
|
+
height={40}
|
|
486
|
+
set={{ type: 'straight', velocities: [1.15], planned: 1 }}
|
|
487
|
+
/>
|
|
488
|
+
)
|
|
489
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ height: '40px' })
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
it('draws planned-but-undone reps as short grey todo stubs (set-type aware)', () => {
|
|
493
|
+
render(
|
|
494
|
+
<VelocityStrip
|
|
495
|
+
{...bareProps}
|
|
496
|
+
height={24}
|
|
497
|
+
set={{ type: 'straight', velocities: [1.0], planned: 3 }}
|
|
498
|
+
/>
|
|
499
|
+
)
|
|
500
|
+
expect(screen.getAllByTestId(/^velocity-bar-\d+$/)).toHaveLength(1)
|
|
501
|
+
const stubs = screen.getAllByTestId('velocity-slot-todo')
|
|
502
|
+
expect(stubs).toHaveLength(2)
|
|
503
|
+
expect(stubs[0]).toHaveStyle({ height: '3px', backgroundColor: TODO_GREY })
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
it('colors performed reps from the default effort scale', () => {
|
|
507
|
+
render(
|
|
508
|
+
<VelocityStrip
|
|
509
|
+
{...bareProps}
|
|
510
|
+
set={{ type: 'straight', velocities: [1.1, 0.45], planned: 2 }}
|
|
511
|
+
/>
|
|
512
|
+
)
|
|
513
|
+
expect(screen.getByTestId('velocity-bar-0')).toHaveStyle({ backgroundColor: '#2ED573' })
|
|
514
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ backgroundColor: '#D14343' })
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
it('carries the set-type WIDE-gap chunk encoding (drop sub-loads)', () => {
|
|
518
|
+
render(
|
|
519
|
+
<VelocityStrip
|
|
520
|
+
{...bareProps}
|
|
521
|
+
set={{
|
|
522
|
+
type: 'drop',
|
|
523
|
+
subloads: [
|
|
524
|
+
[1.0, 0.9],
|
|
525
|
+
[0.8, 0.7],
|
|
526
|
+
],
|
|
527
|
+
}}
|
|
528
|
+
/>
|
|
529
|
+
)
|
|
530
|
+
expect(screen.getByTestId('velocity-bar-1')).toHaveStyle({ marginLeft: REP_SLOT_ML })
|
|
531
|
+
expect(screen.getByTestId('velocity-bar-2')).toHaveStyle({ marginLeft: WIDE_SLOT_ML })
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
it('has no chrome: no per-bar labels, no info row, no pressable', () => {
|
|
535
|
+
render(
|
|
536
|
+
<VelocityStrip
|
|
537
|
+
{...bareProps}
|
|
538
|
+
onToggle={() => {}}
|
|
539
|
+
set={{ type: 'straight', velocities: [1.0, 0.8], planned: 3 }}
|
|
540
|
+
/>
|
|
541
|
+
)
|
|
542
|
+
expect(screen.queryByTestId('velocity-label-0')).not.toBeInTheDocument()
|
|
543
|
+
expect(screen.queryByTestId('velocity-info-row')).not.toBeInTheDocument()
|
|
544
|
+
expect(screen.queryByTestId('velocity-strip-pressable')).not.toBeInTheDocument()
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
it('labels the strip per set type for accessibility', () => {
|
|
548
|
+
render(
|
|
549
|
+
<VelocityStrip
|
|
550
|
+
{...bareProps}
|
|
551
|
+
set={{ type: 'straight', velocities: [1.0, 0.8], planned: 3 }}
|
|
552
|
+
/>
|
|
553
|
+
)
|
|
554
|
+
expect(screen.getByLabelText('Velocity strip, straight set, 2 reps')).toBeInTheDocument()
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
it('has no accessibility violations', async () => {
|
|
558
|
+
const { container } = render(
|
|
559
|
+
<VelocityStrip
|
|
560
|
+
{...bareProps}
|
|
561
|
+
set={{ type: 'straight', velocities: [1.0, 0.8], planned: 3 }}
|
|
562
|
+
/>
|
|
563
|
+
)
|
|
564
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
565
|
+
})
|
|
566
|
+
})
|