@titan-design/react-ui 0.12.1 → 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 +1319 -216
- package/dist/index.d.ts +1319 -216
- 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 +195 -134
- package/dist/theme/index.d.ts +195 -134
- 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 +73 -5
- package/dist/theme/tokens.d.ts +73 -5
- package/dist/theme/tokens.js +55 -7
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +55 -8
- package/dist/theme/tokens.mjs.map +1 -1
- 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 +1 -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 +11 -6
- 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 +89 -26
- 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 +23 -21
- 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 +1 -3
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +65 -33
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View } from 'react-native'
|
|
3
|
-
import {
|
|
3
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
4
4
|
import { SessionHeader, type SessionHeaderPlanEntry } from './SessionHeader'
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -21,10 +21,10 @@ const meta: Meta<typeof SessionHeader> = {
|
|
|
21
21
|
component:
|
|
22
22
|
'**Molecule** (shell S3). The session-rail heading — title, stat tiles, chunked ' +
|
|
23
23
|
'pace bar, sets label + ⏱ readout, on the raised grey plane. Composes ' +
|
|
24
|
-
'[MetricTiles](?path=/docs/workout-metrictiles--docs) / ' +
|
|
25
|
-
'[ScheduleTiles](?path=/docs/workout-scheduletiles--docs) + ' +
|
|
26
|
-
'[SegmentedProgressBar](?path=/docs/workout-segmentedprogressbar--docs) + ' +
|
|
27
|
-
'[TimerReadout](?path=/docs/
|
|
24
|
+
'[MetricTiles](?path=/docs/custom-workout-metrictiles--docs) / ' +
|
|
25
|
+
'[ScheduleTiles](?path=/docs/custom-workout-scheduletiles--docs) + ' +
|
|
26
|
+
'[SegmentedProgressBar](?path=/docs/custom-workout-segmentedprogressbar--docs) + ' +
|
|
27
|
+
'[TimerReadout](?path=/docs/custom-timerreadout--docs). ' +
|
|
28
28
|
'Used-by ↑ [SessionRail](?path=/docs/shell-sessionrail--docs).',
|
|
29
29
|
},
|
|
30
30
|
},
|
|
@@ -41,7 +41,7 @@ const meta: Meta<typeof SessionHeader> = {
|
|
|
41
41
|
export default meta
|
|
42
42
|
type Story = StoryObj<typeof SessionHeader>
|
|
43
43
|
|
|
44
|
-
const AMBER =
|
|
44
|
+
const AMBER = resolveColor('status-warning')
|
|
45
45
|
|
|
46
46
|
const PLAN: SessionHeaderPlanEntry[] = [
|
|
47
47
|
{ name: 'Seated Row', sets: 3 },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import { View,
|
|
2
|
+
import { View, type ViewProps } from 'react-native'
|
|
3
3
|
import { Surface, onSurfaceColors, useSurfaceMode } from '../../ui/surface'
|
|
4
4
|
import { Typography } from '../Typography'
|
|
5
5
|
import { TimerReadout } from '../TimerReadout'
|
|
@@ -97,20 +97,18 @@ export function SessionHeader({
|
|
|
97
97
|
testID="session-rail-header"
|
|
98
98
|
{...props}
|
|
99
99
|
>
|
|
100
|
-
|
|
100
|
+
{/* `h6` carries the heading face and role; the rail title is 16px/700 on a
|
|
101
|
+
tight 18px line box, which is one step below `h6`'s own 18px/600. */}
|
|
102
|
+
<Typography
|
|
103
|
+
variant="h6"
|
|
104
|
+
color="inherit"
|
|
105
|
+
className="text-base font-bold leading-[18px]"
|
|
101
106
|
accessibilityRole="header"
|
|
102
|
-
style={{
|
|
103
|
-
fontSize: 16,
|
|
104
|
-
lineHeight: 18,
|
|
105
|
-
fontWeight: '700',
|
|
106
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
107
|
-
color: onSurface.primary,
|
|
108
|
-
marginBottom: 10,
|
|
109
|
-
}}
|
|
107
|
+
style={{ color: onSurface.primary, marginBottom: 10 }}
|
|
110
108
|
testID="session-rail-title"
|
|
111
109
|
>
|
|
112
110
|
{title}
|
|
113
|
-
</
|
|
111
|
+
</Typography>
|
|
114
112
|
|
|
115
113
|
{upcoming ? <ScheduleTiles when={next} /> : <MetricTiles metrics={metrics} />}
|
|
116
114
|
|
|
@@ -132,7 +130,9 @@ export function SessionHeader({
|
|
|
132
130
|
>
|
|
133
131
|
<Typography
|
|
134
132
|
variant="mono"
|
|
135
|
-
|
|
133
|
+
color="inherit"
|
|
134
|
+
className="text-2xs"
|
|
135
|
+
style={{ color: setsLabelColor }}
|
|
136
136
|
testID="session-rail-sets"
|
|
137
137
|
>
|
|
138
138
|
{setsLabel}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View
|
|
2
|
+
import { View } from 'react-native'
|
|
3
3
|
import { primitiveRamps } from '../../../theme/tokens/primitives'
|
|
4
|
-
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
5
4
|
import { SessionRail, type SessionRailExercise } from './SessionRail'
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { Surface } from '../../ui/surface'
|
|
6
|
+
import { Typography } from '../Typography'
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* `SessionRail` (shell organism) — the live-workout exercise list: a flat raised
|
|
11
10
|
* `SessionHeader` glance (title, stat tiles, chunked pace bar) over a sunk, inset list
|
|
12
11
|
* of ExerciseCard rail headings. The header plan (chunk widths ∝ sets) is derived from
|
|
13
|
-
* `exercises`. Surfaces bind to the grey ramp; the list
|
|
14
|
-
*
|
|
12
|
+
* `exercises`. Surfaces bind to the grey ramp; the list is a well cut into the rail
|
|
13
|
+
* with the shared `insetWell` material. Driven entirely by props.
|
|
15
14
|
*/
|
|
16
15
|
const meta: Meta<typeof SessionRail> = {
|
|
17
16
|
title: 'Shell/SessionRail',
|
|
@@ -23,12 +22,14 @@ const meta: Meta<typeof SessionRail> = {
|
|
|
23
22
|
},
|
|
24
23
|
decorators: [
|
|
25
24
|
(Story) => (
|
|
26
|
-
<
|
|
25
|
+
<Surface level="background" className="min-h-screen flex-row">
|
|
27
26
|
<Story />
|
|
28
27
|
<View className="flex-1 items-center justify-center">
|
|
29
|
-
<
|
|
28
|
+
<Typography variant="caption" color="tertiary">
|
|
29
|
+
main viewport
|
|
30
|
+
</Typography>
|
|
30
31
|
</View>
|
|
31
|
-
</
|
|
32
|
+
</Surface>
|
|
32
33
|
),
|
|
33
34
|
],
|
|
34
35
|
parameters: {
|
|
@@ -37,10 +38,10 @@ const meta: Meta<typeof SessionRail> = {
|
|
|
37
38
|
description: {
|
|
38
39
|
component:
|
|
39
40
|
'**Organism** (shell S3). The live-workout exercise list: raised header glance over ' +
|
|
40
|
-
'a sunk inset list
|
|
41
|
+
'a sunk inset list (grey ramp + the `insetWell` material). ' +
|
|
41
42
|
'Composes ' +
|
|
42
43
|
'[SessionHeader](?path=/docs/shell-sessionrail-sessionheader--docs) + ' +
|
|
43
|
-
'[ExerciseCardHeading](?path=/docs/workout-exercisecardheading--docs) × N. ' +
|
|
44
|
+
'[ExerciseCardHeading](?path=/docs/custom-workout-exercisecardheading--docs) × N. ' +
|
|
44
45
|
'Sits beside [SideNav](?path=/docs/shell-sidenav--docs) in the dashboard shell.',
|
|
45
46
|
},
|
|
46
47
|
},
|
|
@@ -13,11 +13,11 @@ import type { SetStripSet } from './SetStrip'
|
|
|
13
13
|
import type { ExerciseIndicatorKind } from './ExerciseIndicator'
|
|
14
14
|
|
|
15
15
|
// Warm-tapered ramp surfaces (the locked S3 shell shades): the nav + the heading plane read as
|
|
16
|
-
// ONE dark plane
|
|
17
|
-
// The exercise list is a
|
|
18
|
-
// recessed
|
|
19
|
-
// exercise headings on it never blend into the header plane. Surface owns both
|
|
20
|
-
// so the rail no longer hand-sets them.
|
|
16
|
+
// ONE dark plane, the shell `background`, owned by SessionHeader's `<Surface level="background">`.
|
|
17
|
+
// The exercise list is a well cut into the rail — `<Surface level="base">` with the shared
|
|
18
|
+
// `insetWell` material — recessed by its inner shadow yet paler than the header, so the
|
|
19
|
+
// transparent exercise headings on it never blend into the header plane. Surface owns both
|
|
20
|
+
// backgrounds, so the rail no longer hand-sets them.
|
|
21
21
|
const SEMANTIC = getSemanticColors('dark')
|
|
22
22
|
/** Row divider — one step up from the well it sits in so the line reads. */
|
|
23
23
|
const DIVIDER = greyRamp[875]
|
|
@@ -128,10 +128,8 @@ export function SessionRail({
|
|
|
128
128
|
/>
|
|
129
129
|
|
|
130
130
|
{/* The list is a WELL cut into the rail: one plane down from the rail's
|
|
131
|
-
`elevated`, recessed by the shared inset material
|
|
132
|
-
|
|
133
|
-
lightness). `level` follows the well's tone so on-surface text
|
|
134
|
-
resolves against what is actually painted. */}
|
|
131
|
+
`elevated`, recessed by the shared inset material. `level` follows the
|
|
132
|
+
well's tone so on-surface text resolves against what is painted. */}
|
|
135
133
|
<Surface
|
|
136
134
|
level="base"
|
|
137
135
|
style={[{ flex: 1 }, insetWell(SEMANTIC['surface-base'])]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { SetBar, type SetStripSet } from './SetBar'
|
|
3
|
+
import { Surface } from '../../ui/surface'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `SetBar` — ONE set's multi-coloured bar: the butted per-rep colour segments for a
|
|
@@ -9,7 +9,7 @@ import { SetBar, type SetStripSet } from './SetBar'
|
|
|
9
9
|
* (red-600 · orange-400 · amber-300 · green-300). {@link SetStrip} lays several side by side.
|
|
10
10
|
*/
|
|
11
11
|
const meta: Meta<typeof SetBar> = {
|
|
12
|
-
title: 'Workout/SetBar',
|
|
12
|
+
title: 'Custom/Workout/SetBar',
|
|
13
13
|
component: SetBar,
|
|
14
14
|
tags: ['autodocs'],
|
|
15
15
|
parameters: {
|
|
@@ -18,7 +18,8 @@ const meta: Meta<typeof SetBar> = {
|
|
|
18
18
|
component:
|
|
19
19
|
'**Atom.** ONE set’s multi-coloured bar — the per-rep colour segments for a ' +
|
|
20
20
|
'single set (done / active-with-pulse / todo). Colours are the real titan ramp pins. ' +
|
|
21
|
-
'Used-by ↑ [SetStrip](?path=/docs/workout-setstrip--docs).'
|
|
21
|
+
'Used-by ↑ [SetStrip](?path=/docs/custom-workout-setstrip--docs).' +
|
|
22
|
+
' Composes **SegmentedBar**.',
|
|
22
23
|
},
|
|
23
24
|
},
|
|
24
25
|
},
|
|
@@ -27,9 +28,9 @@ const meta: Meta<typeof SetBar> = {
|
|
|
27
28
|
},
|
|
28
29
|
decorators: [
|
|
29
30
|
(Story) => (
|
|
30
|
-
<
|
|
31
|
+
<Surface level="base" style={{ width: 180, flexDirection: 'row', padding: 16 }}>
|
|
31
32
|
<Story />
|
|
32
|
-
</
|
|
33
|
+
</Surface>
|
|
33
34
|
),
|
|
34
35
|
],
|
|
35
36
|
}
|
|
@@ -78,7 +79,10 @@ export const Range: Story = {
|
|
|
78
79
|
export const Drop: Story = {
|
|
79
80
|
args: {
|
|
80
81
|
height: 8,
|
|
81
|
-
set: {
|
|
82
|
+
set: {
|
|
83
|
+
status: 'drop',
|
|
84
|
+
subloads: [decay(10, 0.85), decay(8, 0.7), decay(6, 0.6)],
|
|
85
|
+
} as SetStripSet,
|
|
82
86
|
},
|
|
83
87
|
parameters: {
|
|
84
88
|
docs: {
|
|
@@ -2,6 +2,8 @@ import { describe, it, expect } from 'vitest'
|
|
|
2
2
|
import { render, screen } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { SetBar, velocityZoneColor, SET_STRIP_ZONES, SET_STRIP_VARIABLE_COLOR } from './SetBar'
|
|
5
|
+
import { WORKOUT_TOKENS } from '../../../theme/workout-tokens'
|
|
6
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
5
7
|
|
|
6
8
|
/** The slot wrapper (carrier of the leading-gap margin) is a fill segment's parent. */
|
|
7
9
|
const slotOf = (fill: HTMLElement) => fill.parentElement as HTMLElement
|
|
@@ -36,10 +38,30 @@ describe('SetBar', () => {
|
|
|
36
38
|
expect(screen.queryByTestId('set-strip-pulse')).not.toBeInTheDocument()
|
|
37
39
|
})
|
|
38
40
|
|
|
41
|
+
// SetBar has no visual baseline. The placeholder fill was `greyRamp[900]` — the
|
|
42
|
+
// `surface-elevated` plane used as a mark — so its role is asserted here.
|
|
43
|
+
it('fills unperformed reps from the border role, not a surface plane', () => {
|
|
44
|
+
render(<SetBar set={{ status: 'todo', planned: 10 }} />)
|
|
45
|
+
expect(screen.getByTestId('set-strip-empty')).toHaveStyle({
|
|
46
|
+
backgroundColor: resolveColor('border-prominent'),
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('sources the four zone pins from the canonical effort scale', () => {
|
|
51
|
+
expect(SET_STRIP_ZONES).toEqual({
|
|
52
|
+
slow: WORKOUT_TOKENS.scale.red,
|
|
53
|
+
moderate: WORKOUT_TOKENS.scale.orange,
|
|
54
|
+
fast: WORKOUT_TOKENS.scale.yellow,
|
|
55
|
+
fastest: WORKOUT_TOKENS.scale.green,
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
39
59
|
describe('range (variable rep-range)', () => {
|
|
40
60
|
it('renders range-max segments; committed-todo grey, variable-todo cyan', () => {
|
|
41
61
|
// floor 15, max 20, 12 done → 12 velocity fills · 3 grey (committed) · 5 cyan (variable)
|
|
42
|
-
render(
|
|
62
|
+
render(
|
|
63
|
+
<SetBar set={{ status: 'range', floor: 15, max: 20, doneVels: Array(12).fill(0.9) }} />
|
|
64
|
+
)
|
|
43
65
|
expect(screen.getAllByTestId('set-strip-fill')).toHaveLength(12)
|
|
44
66
|
expect(screen.getAllByTestId('set-strip-empty')).toHaveLength(3)
|
|
45
67
|
expect(screen.getAllByTestId('set-strip-variable')).toHaveLength(5)
|
|
@@ -47,7 +69,9 @@ describe('SetBar', () => {
|
|
|
47
69
|
|
|
48
70
|
it('counts a done rep past the floor as a real velocity rep (not variable)', () => {
|
|
49
71
|
// 17 done into the variable zone → 17 velocity fills, 3 cyan, 0 grey
|
|
50
|
-
render(
|
|
72
|
+
render(
|
|
73
|
+
<SetBar set={{ status: 'range', floor: 15, max: 20, doneVels: Array(17).fill(0.8) }} />
|
|
74
|
+
)
|
|
51
75
|
expect(screen.getAllByTestId('set-strip-fill')).toHaveLength(17)
|
|
52
76
|
expect(screen.getAllByTestId('set-strip-variable')).toHaveLength(3)
|
|
53
77
|
expect(screen.queryByTestId('set-strip-empty')).not.toBeInTheDocument()
|
|
@@ -64,7 +88,17 @@ describe('SetBar', () => {
|
|
|
64
88
|
|
|
65
89
|
describe('drop set', () => {
|
|
66
90
|
it('renders one fill per rep across sub-loads, split by 2px notches', () => {
|
|
67
|
-
render(
|
|
91
|
+
render(
|
|
92
|
+
<SetBar
|
|
93
|
+
set={{
|
|
94
|
+
status: 'drop',
|
|
95
|
+
subloads: [
|
|
96
|
+
[0.85, 0.8, 0.7],
|
|
97
|
+
[0.7, 0.6],
|
|
98
|
+
],
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
68
102
|
const fills = screen.getAllByTestId('set-strip-fill')
|
|
69
103
|
expect(fills).toHaveLength(5)
|
|
70
104
|
expect(slotOf(fills[0])).not.toHaveStyle({ marginLeft: '2px' }) // first sub-load butts the edge
|
|
@@ -74,7 +108,18 @@ describe('SetBar', () => {
|
|
|
74
108
|
|
|
75
109
|
describe('myo-rep / rest-pause (done)', () => {
|
|
76
110
|
it('renders activation + clusters, split by 3px cluster gaps', () => {
|
|
77
|
-
render(
|
|
111
|
+
render(
|
|
112
|
+
<SetBar
|
|
113
|
+
set={{
|
|
114
|
+
status: 'myo',
|
|
115
|
+
activation: [0.75, 0.7, 0.65],
|
|
116
|
+
clusters: [
|
|
117
|
+
[0.6, 0.55],
|
|
118
|
+
[0.5, 0.45],
|
|
119
|
+
],
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
)
|
|
78
123
|
const fills = screen.getAllByTestId('set-strip-fill')
|
|
79
124
|
expect(fills).toHaveLength(7)
|
|
80
125
|
expect(slotOf(fills[3])).toHaveStyle({ marginLeft: '3px' }) // first cluster
|
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import { primitiveRamps
|
|
2
|
+
import { primitiveRamps } from '../../../theme/tokens/primitives'
|
|
3
|
+
import { WORKOUT_TOKENS } from '../../../theme/workout-tokens'
|
|
4
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
3
5
|
import { SegmentedBar, type SegmentedBarSegment } from './SegmentedBar'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* The four canonical rep-intensity zone pins
|
|
7
|
-
*
|
|
8
|
+
* The four canonical rep-intensity zone pins. A rep's mean velocity ratio maps to
|
|
9
|
+
* one of these; butted together they form a set's bar.
|
|
10
|
+
*
|
|
11
|
+
* Sourced from {@link WORKOUT_TOKENS}.`scale`, which its own docs already call the
|
|
12
|
+
* single source for the velocity zone bars — this used to re-read the same four
|
|
13
|
+
* ramp steps independently, so the two could drift apart silently. Byte-identical.
|
|
8
14
|
*/
|
|
9
15
|
export const SET_STRIP_ZONES = {
|
|
10
|
-
slow:
|
|
11
|
-
moderate:
|
|
12
|
-
fast:
|
|
13
|
-
fastest:
|
|
16
|
+
slow: WORKOUT_TOKENS.scale.red,
|
|
17
|
+
moderate: WORKOUT_TOKENS.scale.orange,
|
|
18
|
+
fast: WORKOUT_TOKENS.scale.yellow,
|
|
19
|
+
fastest: WORKOUT_TOKENS.scale.green,
|
|
14
20
|
} as const
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
// Fill for planned-but-unperformed reps / upcoming sets. Was `greyRamp[900]` — the
|
|
23
|
+
// `surface-elevated` plane borrowed as a MARK colour, the same anti-pattern the
|
|
24
|
+
// specimen's `--dot-inactive` note calls out. It takes the border role instead, which
|
|
25
|
+
// is where B2 landed PlaceholderStrip: the two placeholder languages now match.
|
|
26
|
+
const TODO_COLOR = resolveColor('border-prominent')
|
|
18
27
|
|
|
19
28
|
/**
|
|
20
29
|
* The learned "variable / unknown / opportunity" semantic (cyan-900, a real ramp
|
|
21
30
|
* pin): an unperformed rep in a range's variable zone, and the fading trail of a
|
|
22
31
|
* myo set whose cluster count isn't yet known.
|
|
32
|
+
*
|
|
33
|
+
* FINDING for E3: no semantic role expresses this. `brand-secondary` is cyan-600
|
|
34
|
+
* and `brand-secondary-dark` cyan-700; neither reaches cyan-900, and pinning this
|
|
35
|
+
* to either would restyle the mark rather than migrate it.
|
|
23
36
|
*/
|
|
24
37
|
export const SET_STRIP_VARIABLE_COLOR = primitiveRamps.cyan[900]
|
|
25
38
|
|
|
@@ -39,6 +52,10 @@ const MYO_UPCOMING_FADE = 0.6
|
|
|
39
52
|
/**
|
|
40
53
|
* Active-set pulse range per zone: each segment eases between its pin's adjacent
|
|
41
54
|
* lighter/darker ramp steps, keeping the intensity reading while signalling "live".
|
|
55
|
+
*
|
|
56
|
+
* Literal ramp steps, not tokens: `Animated.interpolate` parses its own endpoints
|
|
57
|
+
* and cannot read a `var()` ref — the same exception SegmentedBar's `pulseColor`
|
|
58
|
+
* documents (B2).
|
|
42
59
|
*/
|
|
43
60
|
const PULSE_RANGE: Record<string, [string, string]> = {
|
|
44
61
|
[SET_STRIP_ZONES.slow]: [primitiveRamps.red[500], primitiveRamps.red[700]],
|
|
@@ -58,7 +75,10 @@ export function velocityZoneColor(v: number): string {
|
|
|
58
75
|
/**
|
|
59
76
|
* One set's data. Flat variants: `done` = every rep performed; `active` = reps-so-far
|
|
60
77
|
* performed against a planned count (remainder greyed, performed reps pulse); `todo` =
|
|
61
|
-
* a planned but unstarted set (solid grey bar).
|
|
78
|
+
* a planned but unstarted set (solid grey bar). `active`/`todo` optionally carry the
|
|
79
|
+
* plan's prescribed rep RANGE (`repsLow`/`repsHigh`, VMCP-03.04) — a value range
|
|
80
|
+
* (isokinetic bands), not a rep count, so it's independent of `range`'s `floor`/`max`.
|
|
81
|
+
* Set-type variants:
|
|
62
82
|
* - `range` — variable rep-range (e.g. 15–20): `max` segments; committed zone
|
|
63
83
|
* `0..floor` (done = velocity, todo = grey), variable zone `floor..max` (done =
|
|
64
84
|
* velocity, todo = the variable/opportunity cyan). `doneVels` may run past `floor`.
|
|
@@ -69,8 +89,14 @@ export function velocityZoneColor(v: number): string {
|
|
|
69
89
|
*/
|
|
70
90
|
export type SetStripSet =
|
|
71
91
|
| { status: 'done'; velocities: number[] }
|
|
72
|
-
| {
|
|
73
|
-
|
|
92
|
+
| {
|
|
93
|
+
status: 'active'
|
|
94
|
+
velocities: number[]
|
|
95
|
+
planned: number
|
|
96
|
+
repsLow?: number
|
|
97
|
+
repsHigh?: number
|
|
98
|
+
}
|
|
99
|
+
| { status: 'todo'; planned: number; repsLow?: number; repsHigh?: number }
|
|
74
100
|
| { status: 'range'; floor: number; max: number; doneVels: number[] }
|
|
75
101
|
| { status: 'drop'; subloads: number[][] }
|
|
76
102
|
| { status: 'myo'; activation: number[]; clusters: number[][] }
|
|
@@ -4,7 +4,7 @@ import { SetRow } from './SetRow'
|
|
|
4
4
|
import { SetTableHeader } from './SetTableHeader'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof SetRow> = {
|
|
7
|
-
title: 'Workout/SetRow',
|
|
7
|
+
title: 'Custom/Workout/SetRow',
|
|
8
8
|
component: SetRow,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
parameters: {
|
|
@@ -16,7 +16,8 @@ const meta: Meta<typeof SetRow> = {
|
|
|
16
16
|
'(logged), `live` (performing now — brightened, compact velocity-height spotlight), `todo` ' +
|
|
17
17
|
'(planned — muted grey stub). Done + upcoming share one muted treatment; only `live` is ' +
|
|
18
18
|
'brightened. No PREV column. Composed by ' +
|
|
19
|
-
'[ExerciseCard](?path=/docs/workout-exercisecard--docs) (expanded).'
|
|
19
|
+
'[ExerciseCard](?path=/docs/custom-workout-exercisecard--docs) (expanded).' +
|
|
20
|
+
' Composes **VelocityStrip**.',
|
|
20
21
|
},
|
|
21
22
|
},
|
|
22
23
|
},
|
|
@@ -3,13 +3,16 @@ import { render, screen } from '@testing-library/react'
|
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { View } from 'react-native'
|
|
5
5
|
import { SetRow, type SetRowProps } from './SetRow'
|
|
6
|
-
import {
|
|
6
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
7
7
|
|
|
8
8
|
// Text treatments, read from the tokens rather than pinned as hexes. These
|
|
9
9
|
// used to be hand-copied literals and silently desynced when the greys moved
|
|
10
10
|
// to the warm ramp (TD-07.14). The assertion still bites — it checks the
|
|
11
11
|
// component reaches for the right ROLE — it just no longer restates the value.
|
|
12
|
-
|
|
12
|
+
// Now through `resolveColor`, which is what the row renders after the B3 port:
|
|
13
|
+
// the same role, but the theme-switching `var()` ref rather than a dark hex.
|
|
14
|
+
const T_ACTIVE = resolveColor('text-primary')
|
|
15
|
+
const T_MUTED = resolveColor('text-secondary')
|
|
13
16
|
|
|
14
17
|
const doneRow: SetRowProps = {
|
|
15
18
|
state: 'done',
|
|
@@ -116,6 +119,17 @@ describe('SetRow', () => {
|
|
|
116
119
|
expect(screen.getByTestId('set-row-type-badge')).toHaveTextContent('W')
|
|
117
120
|
})
|
|
118
121
|
|
|
122
|
+
// SetRow has no visual baseline, so the chip's tokens are asserted here. It
|
|
123
|
+
// used to borrow `WORKOUT_TOKENS.scale.orange` — the EFFORT scale — for a
|
|
124
|
+
// label that reads set type, over a hand-mixed 0.12 wash off a different hue.
|
|
125
|
+
it('draws the type badge from the brand role, not the effort scale', () => {
|
|
126
|
+
render(<SetRow {...doneRow} setType="DROP" />)
|
|
127
|
+
expect(screen.getByTestId('set-row-type-badge')).toHaveStyle({
|
|
128
|
+
color: resolveColor('brand-primary'),
|
|
129
|
+
backgroundColor: resolveColor('brand-primary-subtle'),
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
119
133
|
it('does not render the type badge when setType is absent', () => {
|
|
120
134
|
render(<SetRow {...doneRow} />)
|
|
121
135
|
expect(screen.queryByTestId('set-row-type-badge')).not.toBeInTheDocument()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { type ReactNode } from 'react'
|
|
3
|
-
import { View
|
|
3
|
+
import { View } from 'react-native'
|
|
4
4
|
import { VelocityStrip, type VelocityZoneBandProp } from './VelocityStrip'
|
|
5
|
+
import { Typography } from '../Typography'
|
|
5
6
|
import { roundWeight, roundRpe } from '../../../utils/workout-format'
|
|
6
|
-
import {
|
|
7
|
-
import { WORKOUT_TOKENS } from '../../../theme/workout-tokens'
|
|
7
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
8
8
|
|
|
9
9
|
export type SetRowUnit = 'lbs' | 'kg'
|
|
10
10
|
|
|
@@ -61,20 +61,23 @@ export type SetRowProps =
|
|
|
61
61
|
planned?: number
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
const TEXT_MUTED = DARK['text-secondary']
|
|
64
|
+
/** Live set — brightest. Done + upcoming share the muted role. */
|
|
65
|
+
const TEXT_ACTIVE = 'text-primary'
|
|
66
|
+
const TEXT_MUTED = 'text-secondary'
|
|
68
67
|
|
|
69
68
|
/** Column widths mirror SetTableHeader(showPrevious=false) so cells align under it. */
|
|
70
69
|
const COL = { set: 36, reps: 44, load: 56, rpe: 36 } as const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
|
|
71
|
+
// 13px is off the type scale (TOKENS.md §4); `boldLabel` is the 12px font-sans step
|
|
72
|
+
// and `font-semibold` holds the original 600 — Inter is `font-sans` here, per B1.
|
|
73
|
+
const CELL_CLASS = 'font-semibold leading-[normal]'
|
|
74
|
+
|
|
75
|
+
// The set-type chip was `WORKOUT_TOKENS.scale.orange` on a hand-mixed
|
|
76
|
+
// rgba(255,165,2,0.12). That pin is `sequentialEffort[3]` — the EFFORT scale, borrowed
|
|
77
|
+
// for a label that reads set type, not intensity. It resolves to orange-400, which is
|
|
78
|
+
// `brand-primary`, so the chip takes the brand role and the `-subtle` rung its 0.12 wash
|
|
79
|
+
// was already reaching for. The wash's own base (255,165,2) is off the orange ramp.
|
|
80
|
+
const typeBadgeStyle = {
|
|
78
81
|
paddingVertical: 1,
|
|
79
82
|
paddingHorizontal: 5,
|
|
80
83
|
borderRadius: 3,
|
|
@@ -163,7 +166,8 @@ function RowStrip({ set }: { set: SetRowProps }) {
|
|
|
163
166
|
*/
|
|
164
167
|
export function SetRow(set: SetRowProps) {
|
|
165
168
|
const live = set.state === 'live'
|
|
166
|
-
const valueColor = live ? TEXT_ACTIVE : TEXT_MUTED
|
|
169
|
+
const valueColor = resolveColor(live ? TEXT_ACTIVE : TEXT_MUTED)
|
|
170
|
+
const mutedColor = resolveColor(TEXT_MUTED)
|
|
167
171
|
const rpe = set.state === 'todo' ? null : set.rpe
|
|
168
172
|
|
|
169
173
|
return (
|
|
@@ -175,25 +179,59 @@ export function SetRow(set: SetRowProps) {
|
|
|
175
179
|
<View className="flex-row items-center" style={{ justifyContent: 'space-between' }}>
|
|
176
180
|
<Cell width={COL.set} testID="set-row-set-number">
|
|
177
181
|
{set.setType ? (
|
|
178
|
-
<
|
|
182
|
+
<Typography
|
|
183
|
+
variant="boldLabel"
|
|
184
|
+
color="inherit"
|
|
185
|
+
className="text-2xs leading-[normal]"
|
|
186
|
+
style={{
|
|
187
|
+
...typeBadgeStyle,
|
|
188
|
+
color: resolveColor('brand-primary'),
|
|
189
|
+
backgroundColor: resolveColor('brand-primary-subtle'),
|
|
190
|
+
}}
|
|
191
|
+
testID="set-row-type-badge"
|
|
192
|
+
>
|
|
179
193
|
{set.setType}
|
|
180
|
-
</
|
|
194
|
+
</Typography>
|
|
181
195
|
) : (
|
|
182
|
-
<
|
|
196
|
+
<Typography
|
|
197
|
+
variant="boldLabel"
|
|
198
|
+
color="inherit"
|
|
199
|
+
className={live ? 'font-bold leading-[normal]' : CELL_CLASS}
|
|
200
|
+
style={{ color: valueColor }}
|
|
201
|
+
>
|
|
183
202
|
{set.setNumber}
|
|
184
|
-
</
|
|
203
|
+
</Typography>
|
|
185
204
|
)}
|
|
186
205
|
</Cell>
|
|
187
206
|
<Cell width={COL.reps} testID="set-row-reps">
|
|
188
|
-
<
|
|
207
|
+
<Typography
|
|
208
|
+
variant="boldLabel"
|
|
209
|
+
color="inherit"
|
|
210
|
+
className={CELL_CLASS}
|
|
211
|
+
style={{ color: valueColor }}
|
|
212
|
+
>
|
|
213
|
+
{displayReps(set)}
|
|
214
|
+
</Typography>
|
|
189
215
|
</Cell>
|
|
190
216
|
<Cell width={COL.load} testID="set-row-weight">
|
|
191
|
-
<
|
|
217
|
+
<Typography
|
|
218
|
+
variant="boldLabel"
|
|
219
|
+
color="inherit"
|
|
220
|
+
className={CELL_CLASS}
|
|
221
|
+
style={{ color: valueColor }}
|
|
222
|
+
>
|
|
223
|
+
{roundWeight(displayWeight(set))}
|
|
224
|
+
</Typography>
|
|
192
225
|
</Cell>
|
|
193
226
|
<Cell width={COL.rpe} testID="set-row-rpe">
|
|
194
|
-
<
|
|
227
|
+
<Typography
|
|
228
|
+
variant="boldLabel"
|
|
229
|
+
color="inherit"
|
|
230
|
+
className={CELL_CLASS}
|
|
231
|
+
style={{ color: mutedColor }}
|
|
232
|
+
>
|
|
195
233
|
{rpe != null ? roundRpe(rpe) : '—'}
|
|
196
|
-
</
|
|
234
|
+
</Typography>
|
|
197
235
|
</Cell>
|
|
198
236
|
</View>
|
|
199
237
|
<View style={{ marginTop: live ? 6 : 4 }} testID="set-row-strip">
|