@titan-design/react-ui 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -47
- package/dist/bodymap.js +768 -701
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +770 -703
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1320 -215
- package/dist/index.d.ts +1320 -215
- package/dist/index.js +5996 -4498
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5773 -4357
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
- package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1435 -1428
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1443 -1436
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +202 -1042
- package/dist/theme/index.d.ts +202 -1042
- package/dist/theme/index.js +215 -300
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +202 -296
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +62 -5
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +62 -5
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +972 -0
- package/dist/theme/tokens.d.ts +972 -0
- package/dist/theme/tokens.js +904 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/tokens.mjs +880 -0
- package/dist/theme/tokens.mjs.map +1 -0
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/package.json +7 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +5021 -1617
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +4 -1
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +116 -14
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +98 -15
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +7 -2
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +3 -0
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +3 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +21 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
- package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +4 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +12 -9
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +12 -7
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/index.ts +5 -0
- package/src/components/custom/Workout/metricText.stories.tsx +6 -5
- package/src/components/custom/Workout/metricText.tsx +4 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
- package/src/components/custom/charts/README.md +61 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
- package/src/components/custom/charts/SetBarChart.tsx +42 -4
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +13 -28
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +90 -27
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +32 -25
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +6 -26
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -30
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +2 -12
- package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +29 -19
- package/src/components/ui/pill/Pill.stories.tsx +58 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +164 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +5 -7
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +5 -14
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +14 -14
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +1 -4
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +17 -5
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +7 -22
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +43 -53
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +100 -47
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +24 -22
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +28 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +30 -2
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/token-export-guard.test.ts +102 -0
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +67 -35
- package/src/theme/tokens/semantic.ts +71 -37
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +5 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
3
|
+
import { View, Text } from 'react-native'
|
|
4
|
+
import { DualVelocityStrip } from './VelocityStrip'
|
|
5
|
+
import { greyRamp, primitiveColors } from '../../../theme/tokens/primitives'
|
|
6
|
+
|
|
7
|
+
const PAGE_BG = greyRamp[975]
|
|
8
|
+
const PANEL_BG = greyRamp[950]
|
|
9
|
+
const LIST_BG = greyRamp[925]
|
|
10
|
+
|
|
11
|
+
/** Bilateral cable chest press, LEFT dominant / RIGHT lagging, 6 of 8 reps done. */
|
|
12
|
+
const LEFT = [0.54, 0.52, 0.5, 0.48, 0.46, 0.44]
|
|
13
|
+
const RIGHT = [0.49, 0.47, 0.45, 0.42, 0.4, 0.38]
|
|
14
|
+
|
|
15
|
+
const meta: Meta<typeof DualVelocityStrip> = {
|
|
16
|
+
title: 'Custom/Workout/DataViz/DualVelocityStrip',
|
|
17
|
+
component: DualVelocityStrip,
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
parameters: {
|
|
20
|
+
layout: 'fullscreen',
|
|
21
|
+
docs: {
|
|
22
|
+
description: {
|
|
23
|
+
component:
|
|
24
|
+
'The dual-voltra (bilateral) DIVERGING per-rep velocity chart. LEFT reps grow UP, ' +
|
|
25
|
+
'RIGHT reps grow DOWN from one shared centre axis — one mirrored pair per rep index — ' +
|
|
26
|
+
'so a left-dominant / right-lagging set reads pre-attentively as an asymmetric ' +
|
|
27
|
+
'silhouette. Reuses VelocityStrip’s slot vocabulary (rep / todo / variable / ' +
|
|
28
|
+
'continue), its velocity-zone colors, hero geometry, and the live-rep pop. Color is ' +
|
|
29
|
+
'ALWAYS the velocity zone; SIDE is encoded by position only, never hue. `variant="hero"` ' +
|
|
30
|
+
'is the wall scale (value labels + per-side running-best reference lines); `variant="rail"` ' +
|
|
31
|
+
'is the compact rail-expanded scale. Single-voltra sets keep using VelocityStrip.',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
argTypes: {
|
|
36
|
+
variant: { control: 'inline-radio', options: ['hero', 'rail'] },
|
|
37
|
+
targetReps: { control: 'number' },
|
|
38
|
+
liveRepIndex: { control: 'number' },
|
|
39
|
+
height: { control: { type: 'number', min: 48, max: 320, step: 4 } },
|
|
40
|
+
scale: { control: 'inline-radio', options: ['peak', 'fixed'] },
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
export default meta
|
|
44
|
+
type Story = StoryObj<typeof DualVelocityStrip>
|
|
45
|
+
|
|
46
|
+
function Panel({ children, width }: { children: React.ReactNode; width?: number }) {
|
|
47
|
+
return (
|
|
48
|
+
<View style={{ width, backgroundColor: PANEL_BG, borderRadius: 12, padding: 20, gap: 12 }}>
|
|
49
|
+
{children}
|
|
50
|
+
</View>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function Page({ children }: { children: React.ReactNode }) {
|
|
55
|
+
return (
|
|
56
|
+
<View style={{ padding: 28, backgroundColor: PAGE_BG, minHeight: '100%', gap: 24 }}>
|
|
57
|
+
{children}
|
|
58
|
+
</View>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** HERO — the across-the-room bilateral live chart, L up / R down from the centre axis. */
|
|
63
|
+
export const Hero: Story = {
|
|
64
|
+
args: { variant: 'hero', targetReps: 8, liveRepIndex: 5, height: 280, scale: 'peak' },
|
|
65
|
+
render: (args) => (
|
|
66
|
+
<Page>
|
|
67
|
+
<Panel width={760}>
|
|
68
|
+
<Text
|
|
69
|
+
style={{
|
|
70
|
+
color: primitiveColors.white,
|
|
71
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
72
|
+
fontSize: 15,
|
|
73
|
+
fontWeight: '700',
|
|
74
|
+
}}
|
|
75
|
+
>
|
|
76
|
+
Hero — dual diverging velocity
|
|
77
|
+
</Text>
|
|
78
|
+
<DualVelocityStrip {...args} left={{ velocities: LEFT }} right={{ velocities: RIGHT }} />
|
|
79
|
+
</Panel>
|
|
80
|
+
</Page>
|
|
81
|
+
),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** RAIL — the same diverging language at the compact rail-expanded scale (no labels/refs). */
|
|
85
|
+
export const RailExpanded: Story = {
|
|
86
|
+
args: { variant: 'rail', targetReps: 8, height: 84 },
|
|
87
|
+
render: (args) => (
|
|
88
|
+
<Page>
|
|
89
|
+
<Panel width={320}>
|
|
90
|
+
<Text
|
|
91
|
+
style={{
|
|
92
|
+
color: primitiveColors.white,
|
|
93
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
94
|
+
fontSize: 13,
|
|
95
|
+
fontWeight: '700',
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
Rail expanded — same language, smaller
|
|
99
|
+
</Text>
|
|
100
|
+
<View style={{ backgroundColor: LIST_BG, borderRadius: 8, padding: 12 }}>
|
|
101
|
+
<DualVelocityStrip {...args} left={{ velocities: LEFT }} right={{ velocities: RIGHT }} />
|
|
102
|
+
</View>
|
|
103
|
+
</Panel>
|
|
104
|
+
</Page>
|
|
105
|
+
),
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A completed, narrow-panel set ending on its OWN peak on both sides (TD-07.10 repro): the last
|
|
110
|
+
* rep's value label has no sibling column to its right, and its bar sits at the running-best
|
|
111
|
+
* reference-line height — the two crowd together at the plot's right edge. Narrow enough
|
|
112
|
+
* (~420px panel, 8 reps/side) that the last column's bar width is under the label's estimated
|
|
113
|
+
* width, so the flip rule fires: the last label anchors right (grows left) instead of centering
|
|
114
|
+
* and bleeding past the edge.
|
|
115
|
+
*/
|
|
116
|
+
const ASCENDING_LEFT = [
|
|
117
|
+
0.55, 0.58, 0.6, 0.63, 0.66, 0.68, 0.71, 0.74, 0.77, 0.79, 0.82, 0.85, 0.87, 0.9,
|
|
118
|
+
]
|
|
119
|
+
const ASCENDING_RIGHT = [
|
|
120
|
+
0.53, 0.56, 0.58, 0.61, 0.64, 0.66, 0.69, 0.72, 0.75, 0.77, 0.8, 0.83, 0.85, 0.88,
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
export const CrowdedRightEdgeLabel: Story = {
|
|
124
|
+
args: { variant: 'hero', height: 300, scale: 'peak' },
|
|
125
|
+
render: (args) => (
|
|
126
|
+
<Page>
|
|
127
|
+
<Panel width={420}>
|
|
128
|
+
<Text
|
|
129
|
+
style={{
|
|
130
|
+
color: primitiveColors.white,
|
|
131
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
132
|
+
fontSize: 15,
|
|
133
|
+
fontWeight: '700',
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
Peak on the last rep, narrow panel — the flip rule (TD-07.10)
|
|
137
|
+
</Text>
|
|
138
|
+
<DualVelocityStrip
|
|
139
|
+
{...args}
|
|
140
|
+
left={{ velocities: ASCENDING_LEFT }}
|
|
141
|
+
right={{ velocities: ASCENDING_RIGHT }}
|
|
142
|
+
/>
|
|
143
|
+
</Panel>
|
|
144
|
+
</Page>
|
|
145
|
+
),
|
|
146
|
+
parameters: {
|
|
147
|
+
docs: {
|
|
148
|
+
description: {
|
|
149
|
+
story:
|
|
150
|
+
"Before the fix, the last rep's centered label bled past the plot's right edge and sat " +
|
|
151
|
+
"on top of the running-best reference line. The flip rule right-anchors that column's " +
|
|
152
|
+
'label instead, so it clears both.',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A range set on both sides — shows the cyan variable-window slots mirrored past the floor. */
|
|
159
|
+
export const RangeSet: Story = {
|
|
160
|
+
args: { variant: 'hero', height: 260, scale: 'peak' },
|
|
161
|
+
render: (args) => (
|
|
162
|
+
<Page>
|
|
163
|
+
<Panel width={760}>
|
|
164
|
+
<Text
|
|
165
|
+
style={{
|
|
166
|
+
color: primitiveColors.white,
|
|
167
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
168
|
+
fontSize: 15,
|
|
169
|
+
fontWeight: '700',
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
Range set — variable window mirrored both sides
|
|
173
|
+
</Text>
|
|
174
|
+
<DualVelocityStrip
|
|
175
|
+
{...args}
|
|
176
|
+
left={{ set: { type: 'range', velocities: LEFT.slice(0, 5), floor: 6, max: 10 } }}
|
|
177
|
+
right={{ set: { type: 'range', velocities: RIGHT.slice(0, 5), floor: 6, max: 10 } }}
|
|
178
|
+
/>
|
|
179
|
+
</Panel>
|
|
180
|
+
</Page>
|
|
181
|
+
),
|
|
182
|
+
}
|
|
@@ -17,8 +17,9 @@ const liveEntranceCalls = vi.hoisted(
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
vi.mock('../charts/live-rep-growth', async () => {
|
|
20
|
-
const actual =
|
|
21
|
-
|
|
20
|
+
const actual = await vi.importActual<typeof import('../charts/live-rep-growth')>(
|
|
21
|
+
'../charts/live-rep-growth'
|
|
22
|
+
)
|
|
22
23
|
return {
|
|
23
24
|
...actual,
|
|
24
25
|
useLiveRepGrowth: (
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { ExerciseCard } from './ExerciseCard'
|
|
4
3
|
import type { SetRowProps } from './SetRow'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof ExerciseCard> = {
|
|
7
|
-
title: 'Workout/ExerciseCard',
|
|
7
|
+
title: 'Custom/Workout/ExerciseCard',
|
|
8
8
|
component: ExerciseCard,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
parameters: {
|
|
@@ -14,10 +14,11 @@ const meta: Meta<typeof ExerciseCard> = {
|
|
|
14
14
|
'**Organism** (data-contract card). Three representations: `upcoming` (a dimmed, ' +
|
|
15
15
|
'not-yet-reached row), collapsed (name + summary + per-set velocity strips), and expanded ' +
|
|
16
16
|
'— the unified card whose persistent header is the real ' +
|
|
17
|
-
'[ExerciseCardHeading](?path=/docs/workout-exercisecardheading--docs) over a SET · REPS · ' +
|
|
18
|
-
'LBS · RPE body of [SetRow](?path=/docs/workout-setrow--docs)s (compact spotlight on the ' +
|
|
17
|
+
'[ExerciseCardHeading](?path=/docs/custom-workout-exercisecardheading--docs) over a SET · REPS · ' +
|
|
18
|
+
'LBS · RPE body of [SetRow](?path=/docs/custom-workout-setrow--docs)s (compact spotlight on the ' +
|
|
19
19
|
'live set). Expand is controlled (`expanded` + `onExpandedChange`) or uncontrolled ' +
|
|
20
|
-
'(`defaultExpanded`); `upcoming` overrides expand.'
|
|
20
|
+
'(`defaultExpanded`); `upcoming` overrides expand.' +
|
|
21
|
+
' Composes **VelocityStrip** · **PlaceholderStrip** · **PrBadge** · **SetRow** · **SetTableHeader** · **ExerciseCardHeading**.',
|
|
21
22
|
},
|
|
22
23
|
},
|
|
23
24
|
},
|
|
@@ -33,9 +34,9 @@ const meta: Meta<typeof ExerciseCard> = {
|
|
|
33
34
|
},
|
|
34
35
|
decorators: [
|
|
35
36
|
(Story) => (
|
|
36
|
-
<
|
|
37
|
+
<Surface level="base" style={{ maxWidth: 400, padding: 16 }}>
|
|
37
38
|
<Story />
|
|
38
|
-
</
|
|
39
|
+
</Surface>
|
|
39
40
|
),
|
|
40
41
|
],
|
|
41
42
|
}
|
|
@@ -3,7 +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 {
|
|
6
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
7
7
|
|
|
8
8
|
const baseCollapsedProps = {
|
|
9
9
|
name: 'Bench Press',
|
|
@@ -87,8 +87,10 @@ describe('ExerciseCard', () => {
|
|
|
87
87
|
sets: unifiedSets,
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
// Read from the tokens, not pinned
|
|
91
|
-
|
|
90
|
+
// Read from the tokens, not pinned, and through resolveColor as SetRow now
|
|
91
|
+
// renders them (see SetRow.test.tsx).
|
|
92
|
+
const T_ACTIVE = resolveColor('text-primary')
|
|
93
|
+
const T_MUTED = resolveColor('text-secondary')
|
|
92
94
|
|
|
93
95
|
it('renders exercise name via the real ExerciseCardHeading header', () => {
|
|
94
96
|
render(<ExerciseCard {...expandedProps} />)
|
|
@@ -102,6 +104,14 @@ describe('ExerciseCard', () => {
|
|
|
102
104
|
expect(screen.getByTestId('exercise-card-body')).toBeInTheDocument()
|
|
103
105
|
})
|
|
104
106
|
|
|
107
|
+
// No baseline covers the expanded card, so the seam's token is asserted here.
|
|
108
|
+
it('draws the header/body seam from the hairline-subtle token', () => {
|
|
109
|
+
render(<ExerciseCard {...expandedProps} />)
|
|
110
|
+
expect(screen.getByTestId('exercise-card-body')).toHaveStyle({
|
|
111
|
+
borderTopColor: resolveColor('hairline-subtle'),
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
105
115
|
it('renders the header per-set strip derived from the set rows', () => {
|
|
106
116
|
render(<ExerciseCard {...expandedProps} />)
|
|
107
117
|
expect(screen.getByTestId('exercise-card-strip')).toBeInTheDocument()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { useState } from 'react'
|
|
3
|
-
import { View,
|
|
3
|
+
import { View, Pressable } from 'react-native'
|
|
4
4
|
import { VelocityStrip, type VelocityZoneBandProp } from './VelocityStrip'
|
|
5
5
|
import { PlaceholderStrip } from './PlaceholderStrip'
|
|
6
6
|
import { PrBadge } from './PrBadge'
|
|
@@ -9,8 +9,9 @@ import { type SetStripSet } from './SetStrip'
|
|
|
9
9
|
import { SetTableHeader } from './SetTableHeader'
|
|
10
10
|
import { ExerciseCardHeading } from './ExerciseCardHeading'
|
|
11
11
|
import { type ExerciseIndicatorKind } from './ExerciseIndicator'
|
|
12
|
+
import { Typography } from '../Typography'
|
|
12
13
|
import { roundWeight } from '../../../utils/workout-format'
|
|
13
|
-
import {
|
|
14
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
14
15
|
|
|
15
16
|
export interface ExerciseCardProps {
|
|
16
17
|
name: string
|
|
@@ -155,30 +156,28 @@ function CollapsedCard({
|
|
|
155
156
|
}}
|
|
156
157
|
>
|
|
157
158
|
<View className="flex-row items-center" testID="exercise-card-header">
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}}
|
|
159
|
+
{/* 14px/700 Space Grotesk is `h6` at the `sm` step; the face and the heading
|
|
160
|
+
role come from the variant, the weight and size from the scale. */}
|
|
161
|
+
<Typography
|
|
162
|
+
variant="h6"
|
|
163
|
+
color="primary"
|
|
164
|
+
className="text-sm font-bold leading-[normal]"
|
|
165
165
|
testID="exercise-card-name"
|
|
166
166
|
>
|
|
167
167
|
{name}
|
|
168
|
-
</
|
|
168
|
+
</Typography>
|
|
169
169
|
<View className="flex-1" />
|
|
170
170
|
{summary && (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}}
|
|
171
|
+
/* The demo's "body" face is Inter, which is the library's `font-sans`
|
|
172
|
+
(the mapping B1 established for PrBadge), not Typography's `font-body`. */
|
|
173
|
+
<Typography
|
|
174
|
+
variant="caption"
|
|
175
|
+
color="secondary"
|
|
176
|
+
className="font-sans mr-2 leading-[normal]"
|
|
178
177
|
testID="exercise-card-summary"
|
|
179
178
|
>
|
|
180
179
|
{formatSummary(summary)}
|
|
181
|
-
</
|
|
180
|
+
</Typography>
|
|
182
181
|
)}
|
|
183
182
|
{isPR && (
|
|
184
183
|
<View style={{ marginLeft: 4 }}>
|
|
@@ -218,10 +217,6 @@ function CollapsedCard({
|
|
|
218
217
|
// is the real ExerciseCardHeading, and the revealed body drops PREV and renders
|
|
219
218
|
// one real SetRow per set (muted done/todo, brightened live spotlight).
|
|
220
219
|
|
|
221
|
-
const DARK = getSemanticColors('dark')
|
|
222
|
-
/** The header↔body seam. */
|
|
223
|
-
const BODY_DIVIDER = DARK['hairline-subtle']
|
|
224
|
-
|
|
225
220
|
/** Project the set rows onto the heading strip's per-set state (done / active / todo). */
|
|
226
221
|
function deriveHeaderSetStates(sets: SetRowProps[]): SetStripSet[] {
|
|
227
222
|
return sets.map((set): SetStripSet => {
|
|
@@ -284,8 +279,13 @@ function ExpandedCard({
|
|
|
284
279
|
testID="exercise-card-heading"
|
|
285
280
|
/>
|
|
286
281
|
|
|
282
|
+
{/* The header↔body seam. */}
|
|
287
283
|
<View
|
|
288
|
-
style={{
|
|
284
|
+
style={{
|
|
285
|
+
borderTopWidth: 1,
|
|
286
|
+
borderTopColor: resolveColor('hairline-subtle'),
|
|
287
|
+
paddingBottom: 6,
|
|
288
|
+
}}
|
|
289
289
|
testID="exercise-card-body"
|
|
290
290
|
>
|
|
291
291
|
<SetTableHeader unit={unit} showPrevious={false} testID="exercise-card-column-headers" />
|
|
@@ -327,47 +327,38 @@ function UpcomingCard({
|
|
|
327
327
|
>
|
|
328
328
|
<View className="flex-row items-center">
|
|
329
329
|
{/* Name never truncates (no numberOfLines); prescription + previousBest ellipsize first. */}
|
|
330
|
-
<
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
fontSize: 14,
|
|
335
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
336
|
-
fontWeight: '700',
|
|
337
|
-
}}
|
|
330
|
+
<Typography
|
|
331
|
+
variant="h6"
|
|
332
|
+
color="primary"
|
|
333
|
+
className="shrink-0 text-sm font-bold leading-[normal]"
|
|
338
334
|
testID="exercise-card-name"
|
|
339
335
|
>
|
|
340
336
|
{name}
|
|
341
|
-
</
|
|
337
|
+
</Typography>
|
|
342
338
|
{prescription && (
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
fontSize: 12,
|
|
349
|
-
fontFamily: 'Inter, sans-serif',
|
|
350
|
-
marginLeft: 8,
|
|
351
|
-
}}
|
|
339
|
+
<Typography
|
|
340
|
+
variant="caption"
|
|
341
|
+
color="secondary"
|
|
342
|
+
maxLines={1}
|
|
343
|
+
className="font-sans shrink ml-2 leading-[normal]"
|
|
352
344
|
testID="exercise-card-prescription"
|
|
353
345
|
>
|
|
354
346
|
{prescription}
|
|
355
|
-
</
|
|
347
|
+
</Typography>
|
|
356
348
|
)}
|
|
357
349
|
<View className="flex-1" style={{ minWidth: 8 }} />
|
|
358
350
|
{previousBest && (
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}}
|
|
351
|
+
/* 11px is off the type scale; `2xs` (10px) is the step below, as B2's
|
|
352
|
+
WorkoutCard date took for the same size. */
|
|
353
|
+
<Typography
|
|
354
|
+
variant="caption"
|
|
355
|
+
color="tertiary"
|
|
356
|
+
maxLines={1}
|
|
357
|
+
className="font-sans shrink text-2xs leading-[normal]"
|
|
367
358
|
testID="exercise-card-previous-best"
|
|
368
359
|
>
|
|
369
360
|
{previousBest}
|
|
370
|
-
</
|
|
361
|
+
</Typography>
|
|
371
362
|
)}
|
|
372
363
|
</View>
|
|
373
364
|
</View>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { ExerciseCardHeading } from './ExerciseCardHeading'
|
|
4
3
|
import type { SetStripSet } from './SetStrip'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* `ExerciseCardHeading` — the complete, standalone session-rail heading: an
|
|
@@ -10,7 +10,7 @@ import type { SetStripSet } from './SetStrip'
|
|
|
10
10
|
* An empty `setStates` renders no strip.
|
|
11
11
|
*/
|
|
12
12
|
const meta: Meta<typeof ExerciseCardHeading> = {
|
|
13
|
-
title: 'Workout/ExerciseCardHeading',
|
|
13
|
+
title: 'Custom/Workout/ExerciseCardHeading',
|
|
14
14
|
component: ExerciseCardHeading,
|
|
15
15
|
tags: ['autodocs'],
|
|
16
16
|
parameters: {
|
|
@@ -18,10 +18,10 @@ const meta: Meta<typeof ExerciseCardHeading> = {
|
|
|
18
18
|
description: {
|
|
19
19
|
component:
|
|
20
20
|
'**Molecule.** The complete standalone session-rail heading. Composes ' +
|
|
21
|
-
'[ExerciseHeading](?path=/docs/workout-exerciseheading--docs) + ' +
|
|
22
|
-
'[SetStrip](?path=/docs/workout-setstrip--docs). ' +
|
|
21
|
+
'[ExerciseHeading](?path=/docs/custom-workout-exerciseheading--docs) + ' +
|
|
22
|
+
'[SetStrip](?path=/docs/custom-workout-setstrip--docs). ' +
|
|
23
23
|
'Used-by ↑ [SessionRail](?path=/docs/shell-sessionrail--docs); ' +
|
|
24
|
-
'[ExerciseCard](?path=/docs/workout-exercisecard--docs) `state="rail"` delegates here.',
|
|
24
|
+
'[ExerciseCard](?path=/docs/custom-workout-exercisecard--docs) `state="rail"` delegates here.',
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
},
|
|
@@ -37,9 +37,9 @@ const meta: Meta<typeof ExerciseCardHeading> = {
|
|
|
37
37
|
},
|
|
38
38
|
decorators: [
|
|
39
39
|
(Story) => (
|
|
40
|
-
<
|
|
40
|
+
<Surface level="base" style={{ width: 246 }}>
|
|
41
41
|
<Story />
|
|
42
|
-
</
|
|
42
|
+
</Surface>
|
|
43
43
|
),
|
|
44
44
|
],
|
|
45
45
|
}
|
|
@@ -192,7 +192,15 @@ const vbt: ExerciseVbt = {
|
|
|
192
192
|
const meta: Meta<typeof ExerciseDetailPage> = {
|
|
193
193
|
title: 'Pages/Exercise Detail',
|
|
194
194
|
component: ExerciseDetailPage,
|
|
195
|
-
parameters: {
|
|
195
|
+
parameters: {
|
|
196
|
+
layout: 'fullscreen',
|
|
197
|
+
docs: {
|
|
198
|
+
description: {
|
|
199
|
+
component:
|
|
200
|
+
'Composes **MesoStatusCard** · **StrengthTrendChart** · **CapacityBandChart** · **ExerciseCard** · **VelocityStrip**.',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
196
204
|
tags: ['autodocs'],
|
|
197
205
|
args: {
|
|
198
206
|
exercise: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { ExerciseHeading } from './ExerciseHeading'
|
|
3
|
+
import { Surface } from '../../ui/surface'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `ExerciseHeading` — the exercise-heading info block (no strip): the name +
|
|
@@ -9,7 +9,7 @@ import { ExerciseHeading } from './ExerciseHeading'
|
|
|
9
9
|
* target; TempoDisplay is a sibling (it is itself a Pressable).
|
|
10
10
|
*/
|
|
11
11
|
const meta: Meta<typeof ExerciseHeading> = {
|
|
12
|
-
title: 'Workout/ExerciseHeading',
|
|
12
|
+
title: 'Custom/Workout/ExerciseHeading',
|
|
13
13
|
component: ExerciseHeading,
|
|
14
14
|
tags: ['autodocs'],
|
|
15
15
|
parameters: {
|
|
@@ -17,10 +17,10 @@ const meta: Meta<typeof ExerciseHeading> = {
|
|
|
17
17
|
description: {
|
|
18
18
|
component:
|
|
19
19
|
'**Molecule.** The exercise-heading info block (no strip). Composes ' +
|
|
20
|
-
'[ExerciseIndicator](?path=/docs/workout-exerciseindicator--docs) + ' +
|
|
21
|
-
'[SetsRepsLoad](?path=/docs/workout-setsrepsload--docs) + ' +
|
|
22
|
-
'[TempoDisplay](?path=/docs/workout-tempodisplay--docs). ' +
|
|
23
|
-
'Used-by ↑ [ExerciseCardHeading](?path=/docs/workout-exercisecardheading--docs).',
|
|
20
|
+
'[ExerciseIndicator](?path=/docs/custom-workout-exerciseindicator--docs) + ' +
|
|
21
|
+
'[SetsRepsLoad](?path=/docs/custom-workout-setsrepsload--docs) + ' +
|
|
22
|
+
'[TempoDisplay](?path=/docs/custom-workout-tempodisplay--docs). ' +
|
|
23
|
+
'Used-by ↑ [ExerciseCardHeading](?path=/docs/custom-workout-exercisecardheading--docs).',
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
},
|
|
@@ -35,9 +35,9 @@ const meta: Meta<typeof ExerciseHeading> = {
|
|
|
35
35
|
},
|
|
36
36
|
decorators: [
|
|
37
37
|
(Story) => (
|
|
38
|
-
<
|
|
38
|
+
<Surface level="base" style={{ width: 246, padding: 16 }}>
|
|
39
39
|
<Story />
|
|
40
|
-
</
|
|
40
|
+
</Surface>
|
|
41
41
|
),
|
|
42
42
|
],
|
|
43
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import { View,
|
|
2
|
+
import { View, Pressable } from 'react-native'
|
|
3
|
+
import { Typography } from '../Typography'
|
|
3
4
|
import { roundWeight } from '../../../utils/workout-format'
|
|
4
5
|
import { SetsRepsLoad } from './SetsRepsLoad'
|
|
5
6
|
import { TempoDisplay } from './TempoDisplay'
|
|
@@ -62,13 +63,15 @@ export function ExerciseHeading({
|
|
|
62
63
|
style={{ gap: 8 }}
|
|
63
64
|
testID="exercise-card-header"
|
|
64
65
|
>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
{/* The row is a button label, not a heading, so `boldLabel` carries the weight and
|
|
67
|
+
no header role has to be undone. Size and the Space Grotesk face are pinned. */}
|
|
68
|
+
<Typography
|
|
69
|
+
variant="boldLabel"
|
|
70
|
+
className="font-heading text-sm leading-[normal]"
|
|
68
71
|
testID="exercise-card-name"
|
|
69
72
|
>
|
|
70
73
|
{name}
|
|
71
|
-
</
|
|
74
|
+
</Typography>
|
|
72
75
|
<View className="flex-1" />
|
|
73
76
|
{indicator && <ExerciseIndicator kind={indicator} />}
|
|
74
77
|
</Pressable>
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
INDICATOR_PRECEDENCE,
|
|
7
7
|
type ExerciseIndicatorKind,
|
|
8
8
|
} from './ExerciseIndicator'
|
|
9
|
+
import { Surface } from '../../ui/surface'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* `ExerciseIndicator` — a small circular OUTLINED chip in an exercise heading's
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
* picks the highest-precedence active signal.
|
|
16
17
|
*/
|
|
17
18
|
const meta: Meta<typeof ExerciseIndicator> = {
|
|
18
|
-
title: 'Workout/ExerciseIndicator',
|
|
19
|
+
title: 'Custom/Workout/ExerciseIndicator',
|
|
19
20
|
component: ExerciseIndicator,
|
|
20
21
|
tags: ['autodocs'],
|
|
21
22
|
parameters: {
|
|
@@ -26,7 +27,8 @@ const meta: Meta<typeof ExerciseIndicator> = {
|
|
|
26
27
|
'precedence-ranked kinds (imbalance › overshoot › velocity-loss › missed-reps › pr › ' +
|
|
27
28
|
'info) over four status-token tier colors; glyph = signal, color = severity tier. ' +
|
|
28
29
|
'`resolveIndicator()` selects the single chip to show. Used-by ↑ ' +
|
|
29
|
-
'[ExerciseHeading](?path=/docs/workout-exerciseheading--docs).'
|
|
30
|
+
'[ExerciseHeading](?path=/docs/custom-workout-exerciseheading--docs).' +
|
|
31
|
+
' Composes **Icons**.',
|
|
30
32
|
},
|
|
31
33
|
},
|
|
32
34
|
},
|
|
@@ -36,9 +38,9 @@ const meta: Meta<typeof ExerciseIndicator> = {
|
|
|
36
38
|
},
|
|
37
39
|
decorators: [
|
|
38
40
|
(Story) => (
|
|
39
|
-
<
|
|
41
|
+
<Surface level="base" style={{ padding: 24 }}>
|
|
40
42
|
<Story />
|
|
41
|
-
</
|
|
43
|
+
</Surface>
|
|
42
44
|
),
|
|
43
45
|
],
|
|
44
46
|
}
|
|
@@ -7,18 +7,30 @@ import {
|
|
|
7
7
|
INDICATOR_PRECEDENCE,
|
|
8
8
|
type ExerciseIndicatorKind,
|
|
9
9
|
} from './ExerciseIndicator'
|
|
10
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{ kind: '
|
|
18
|
-
{ kind: '
|
|
19
|
-
{ kind: '
|
|
12
|
+
type StatusToken = 'status-error' | 'status-warning' | 'status-success' | 'status-info'
|
|
13
|
+
|
|
14
|
+
// tier color = titan status token, applied as the glyph's SVG stroke. The component
|
|
15
|
+
// resolves it through `resolveColor`, so on web the stroke is the CSS var and the
|
|
16
|
+
// theme drives the value; the dark hex is asserted separately below.
|
|
17
|
+
const kinds: { kind: ExerciseIndicatorKind; label: string; tier: StatusToken }[] = [
|
|
18
|
+
{ kind: 'imbalance', label: 'Left/right imbalance', tier: 'status-error' },
|
|
19
|
+
{ kind: 'overshoot', label: 'Load overshoot', tier: 'status-error' },
|
|
20
|
+
{ kind: 'velocity-loss', label: 'Velocity loss', tier: 'status-warning' },
|
|
21
|
+
{ kind: 'missed-reps', label: 'Missed reps', tier: 'status-warning' },
|
|
22
|
+
{ kind: 'pr', label: 'Personal record', tier: 'status-success' },
|
|
23
|
+
{ kind: 'info', label: 'More info', tier: 'status-info' },
|
|
20
24
|
]
|
|
21
25
|
|
|
26
|
+
// The dark-mode values the tier tokens must keep resolving to (the pre-port literals).
|
|
27
|
+
const DARK_TIER: Record<StatusToken, string> = {
|
|
28
|
+
'status-error': '#D14343',
|
|
29
|
+
'status-warning': '#F9B415',
|
|
30
|
+
'status-success': '#2ED573',
|
|
31
|
+
'status-info': '#2196F3',
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
describe('ExerciseIndicator', () => {
|
|
23
35
|
it.each(kinds)('renders the $kind chip glyph and accessible label', ({ kind, label }) => {
|
|
24
36
|
const { container } = render(<ExerciseIndicator kind={kind} />)
|
|
@@ -27,9 +39,13 @@ describe('ExerciseIndicator', () => {
|
|
|
27
39
|
expect(screen.getByLabelText(label)).toBeInTheDocument()
|
|
28
40
|
})
|
|
29
41
|
|
|
30
|
-
it.each(kinds)('tints the $kind glyph with its tier
|
|
42
|
+
it.each(kinds)('tints the $kind glyph with its tier token', ({ kind, tier }) => {
|
|
31
43
|
const { container } = render(<ExerciseIndicator kind={kind} />)
|
|
32
|
-
expect(container.querySelector('svg')!.getAttribute('stroke')).toBe(tier)
|
|
44
|
+
expect(container.querySelector('svg')!.getAttribute('stroke')).toBe(`var(--color-${tier})`)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it.each(kinds)('keeps the $kind tier on its dark-mode value', ({ tier }) => {
|
|
48
|
+
expect(getSemanticColors('dark')[tier]).toBe(DARK_TIER[tier])
|
|
33
49
|
})
|
|
34
50
|
|
|
35
51
|
it('renders a decorative (aria-hidden) glyph so the chip owns the label', () => {
|