@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
|
@@ -5,7 +5,16 @@ import { EmptyState } from './EmptyState'
|
|
|
5
5
|
const meta: Meta<typeof EmptyState> = {
|
|
6
6
|
title: 'Components/Molecules/EmptyState',
|
|
7
7
|
component: EmptyState,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'Composes RN primitives only. The `icon` slot takes an icon component and the ' +
|
|
14
|
+
'`action` slot usually takes a **Button**.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
9
18
|
argTypes: {
|
|
10
19
|
title: {
|
|
11
20
|
control: 'text',
|
|
@@ -30,7 +39,7 @@ export const Default: Story = {
|
|
|
30
39
|
export const WithDescription: Story = {
|
|
31
40
|
args: {
|
|
32
41
|
title: 'No messages',
|
|
33
|
-
description:
|
|
42
|
+
description: "You don't have any messages yet. Start a conversation to see them here.",
|
|
34
43
|
},
|
|
35
44
|
}
|
|
36
45
|
|
|
@@ -38,6 +47,7 @@ export const WithDescription: Story = {
|
|
|
38
47
|
function PlaceholderIcon({ size = 32, className }: { size?: number; className?: string }) {
|
|
39
48
|
return (
|
|
40
49
|
<View
|
|
50
|
+
className={className}
|
|
41
51
|
style={{
|
|
42
52
|
width: size,
|
|
43
53
|
height: size,
|
|
@@ -56,7 +66,14 @@ function PlaceholderIcon({ size = 32, className }: { size?: number; className?:
|
|
|
56
66
|
alignItems: 'center',
|
|
57
67
|
}}
|
|
58
68
|
>
|
|
59
|
-
<View
|
|
69
|
+
<View
|
|
70
|
+
style={{
|
|
71
|
+
width: size * 0.3,
|
|
72
|
+
height: 2,
|
|
73
|
+
backgroundColor: 'var(--color-text-tertiary)',
|
|
74
|
+
borderRadius: 1,
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
60
77
|
</View>
|
|
61
78
|
</View>
|
|
62
79
|
)
|
|
@@ -73,12 +90,8 @@ export const WithIcon: Story = {
|
|
|
73
90
|
// Simple action button for story demos
|
|
74
91
|
function ActionButton() {
|
|
75
92
|
return (
|
|
76
|
-
<View
|
|
77
|
-
className="
|
|
78
|
-
>
|
|
79
|
-
<Text className="text-white font-semibold text-sm">
|
|
80
|
-
Create New
|
|
81
|
-
</Text>
|
|
93
|
+
<View className="bg-brand-primary px-4 py-2 rounded-md">
|
|
94
|
+
<Text className="text-white font-semibold text-sm">Create New</Text>
|
|
82
95
|
</View>
|
|
83
96
|
)
|
|
84
97
|
}
|
|
@@ -4,7 +4,11 @@ import { axe } from 'jest-axe'
|
|
|
4
4
|
import { EmptyState } from './EmptyState'
|
|
5
5
|
|
|
6
6
|
function MockIcon({ size, className }: { size?: number; className?: string }) {
|
|
7
|
-
return
|
|
7
|
+
return (
|
|
8
|
+
<span data-testid="mock-icon" data-size={size} className={className}>
|
|
9
|
+
Icon
|
|
10
|
+
</span>
|
|
11
|
+
)
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
describe('EmptyState', () => {
|
|
@@ -14,12 +18,7 @@ describe('EmptyState', () => {
|
|
|
14
18
|
})
|
|
15
19
|
|
|
16
20
|
it('renders with description', () => {
|
|
17
|
-
render(
|
|
18
|
-
<EmptyState
|
|
19
|
-
title="No messages"
|
|
20
|
-
description="You don't have any messages yet."
|
|
21
|
-
/>
|
|
22
|
-
)
|
|
21
|
+
render(<EmptyState title="No messages" description="You don't have any messages yet." />)
|
|
23
22
|
expect(screen.getByText("You don't have any messages yet.")).toBeInTheDocument()
|
|
24
23
|
})
|
|
25
24
|
|
|
@@ -45,12 +44,7 @@ describe('EmptyState', () => {
|
|
|
45
44
|
|
|
46
45
|
it('renders action element', () => {
|
|
47
46
|
const onPress = vi.fn()
|
|
48
|
-
render(
|
|
49
|
-
<EmptyState
|
|
50
|
-
title="No results"
|
|
51
|
-
action={<button onClick={onPress}>Create New</button>}
|
|
52
|
-
/>
|
|
53
|
-
)
|
|
47
|
+
render(<EmptyState title="No results" action={<button onClick={onPress}>Create New</button>} />)
|
|
54
48
|
const actionButton = screen.getByText('Create New')
|
|
55
49
|
expect(actionButton).toBeInTheDocument()
|
|
56
50
|
|
|
@@ -35,34 +35,20 @@ export function EmptyState({
|
|
|
35
35
|
...props
|
|
36
36
|
}: EmptyStateProps) {
|
|
37
37
|
return (
|
|
38
|
-
<View
|
|
39
|
-
className={cn(
|
|
40
|
-
'items-center justify-center py-12 px-6',
|
|
41
|
-
className
|
|
42
|
-
)}
|
|
43
|
-
{...props}
|
|
44
|
-
>
|
|
38
|
+
<View className={cn('items-center justify-center py-12 px-6', className)} {...props}>
|
|
45
39
|
{Icon && (
|
|
46
40
|
<View className="mb-4 p-4 rounded-full bg-background-subtle">
|
|
47
41
|
<Icon size={32} className="text-text-tertiary" />
|
|
48
42
|
</View>
|
|
49
43
|
)}
|
|
50
44
|
|
|
51
|
-
<Text className="text-lg font-semibold text-text-primary text-center mb-2">
|
|
52
|
-
{title}
|
|
53
|
-
</Text>
|
|
45
|
+
<Text className="text-lg font-semibold text-text-primary text-center mb-2">{title}</Text>
|
|
54
46
|
|
|
55
47
|
{description && (
|
|
56
|
-
<Text className="text-sm text-text-secondary text-center max-w-xs mb-6">
|
|
57
|
-
{description}
|
|
58
|
-
</Text>
|
|
48
|
+
<Text className="text-sm text-text-secondary text-center max-w-xs mb-6">{description}</Text>
|
|
59
49
|
)}
|
|
60
50
|
|
|
61
|
-
{action &&
|
|
62
|
-
<View className="mt-2">
|
|
63
|
-
{action}
|
|
64
|
-
</View>
|
|
65
|
-
)}
|
|
51
|
+
{action && <View className="mt-2">{action}</View>}
|
|
66
52
|
</View>
|
|
67
53
|
)
|
|
68
54
|
}
|
|
@@ -12,9 +12,9 @@ const PAGE_BG = greyRamp[975]
|
|
|
12
12
|
const t = getSemanticColors('dark')
|
|
13
13
|
|
|
14
14
|
const meta: Meta<typeof DualGhostSpark> = {
|
|
15
|
-
title: '
|
|
15
|
+
title: 'Custom/Fatigue/Dual Ghost Spark',
|
|
16
16
|
component: DualGhostSpark,
|
|
17
|
-
tags: ['autodocs'],
|
|
17
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
18
18
|
parameters: {
|
|
19
19
|
docs: {
|
|
20
20
|
description: {
|
|
@@ -24,7 +24,8 @@ const meta: Meta<typeof DualGhostSpark> = {
|
|
|
24
24
|
'wings share one time scale and one magnitude scale, so an L/R imbalance reads as bloom size ' +
|
|
25
25
|
'rather than as two independently normalized charts. Each wing is tinted INDEPENDENTLY by its ' +
|
|
26
26
|
'own current rep — silver while the rep stays controlled, warming through shades of red once ' +
|
|
27
|
-
'that side crosses the grind threshold — so one arm can go red while the other stays silver.'
|
|
27
|
+
'that side crosses the grind threshold — so one arm can go red while the other stays silver.' +
|
|
28
|
+
' Composes **GhostBand** · **GhostBloom**.',
|
|
28
29
|
},
|
|
29
30
|
},
|
|
30
31
|
},
|
|
@@ -9,9 +9,9 @@ const PAGE_BG = greyRamp[975]
|
|
|
9
9
|
const t = getSemanticColors('dark')
|
|
10
10
|
|
|
11
11
|
const meta: Meta<typeof FatigueLights> = {
|
|
12
|
-
title: '
|
|
12
|
+
title: 'Custom/Fatigue/Fatigue Lights',
|
|
13
13
|
component: FatigueLights,
|
|
14
|
-
tags: ['autodocs'],
|
|
14
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
15
15
|
parameters: {
|
|
16
16
|
docs: {
|
|
17
17
|
description: {
|
|
@@ -12,9 +12,9 @@ const PAGE_BG = greyRamp[975]
|
|
|
12
12
|
const t = getSemanticColors('dark')
|
|
13
13
|
|
|
14
14
|
const meta: Meta<typeof GhostSpark> = {
|
|
15
|
-
title: '
|
|
15
|
+
title: 'Custom/Fatigue/Ghost Spark',
|
|
16
16
|
component: GhostSpark,
|
|
17
|
-
tags: ['autodocs'],
|
|
17
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
18
18
|
parameters: {
|
|
19
19
|
docs: {
|
|
20
20
|
description: {
|
|
@@ -26,7 +26,8 @@ const meta: Meta<typeof GhostSpark> = {
|
|
|
26
26
|
'collapse), over a soft paper-inspired ground (no hard outline). Given `targetTempoSeconds` ' +
|
|
27
27
|
'the band also PACES: each run fills across `elapsed / target` of its own width and its label ' +
|
|
28
28
|
'takes the ahead / on-pace / over tone. Every story here passes the prescription the mock reps ' +
|
|
29
|
-
'were generated against, so the fill you see is the real relationship, not a decoration.'
|
|
29
|
+
'were generated against, so the fill you see is the real relationship, not a decoration.' +
|
|
30
|
+
' Composes **GhostBand** · **GhostBloom**.',
|
|
30
31
|
},
|
|
31
32
|
},
|
|
32
33
|
},
|
|
@@ -8,9 +8,9 @@ import { FATIGUE_STATES, WARMING_UP_MODEL, buildMockModel } from './fatigue-mock
|
|
|
8
8
|
const t = getSemanticColors('dark')
|
|
9
9
|
|
|
10
10
|
const meta: Meta<typeof LiveFatigueCard> = {
|
|
11
|
-
title: '
|
|
11
|
+
title: 'Custom/Fatigue/Live Fatigue Card',
|
|
12
12
|
component: LiveFatigueCard,
|
|
13
|
-
tags: ['autodocs'],
|
|
13
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
14
14
|
parameters: {
|
|
15
15
|
docs: {
|
|
16
16
|
description: {
|
|
@@ -16,19 +16,22 @@
|
|
|
16
16
|
* grain + crisp top rim-light + soft contact shadow) — the same material the ROM /
|
|
17
17
|
* velocity bars are made of, now carrying the sheet they sit on. Token-sourced fill, no
|
|
18
18
|
* hardcoded surface hex.
|
|
19
|
+
*
|
|
20
|
+
* MODE (TD-03.59). The edge and the paper fill resolve for the mode the enclosing
|
|
21
|
+
* `<Surface>` publishes, not for a module-scope dark pin. Outside any Surface the context
|
|
22
|
+
* still defaults to dark, so the wall display is unchanged.
|
|
19
23
|
*/
|
|
20
24
|
import { View } from 'react-native'
|
|
21
|
-
import { Surface } from '../../ui/surface
|
|
25
|
+
import { Surface, useSurfaceMode } from '../../ui/surface'
|
|
22
26
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
23
27
|
import { barPaper } from '../../../theme/materials'
|
|
28
|
+
import { cardChartHeight } from './panel-layout'
|
|
24
29
|
import { VerdictHero } from './VerdictHero'
|
|
25
30
|
import { FatigueLights } from './FatigueLights'
|
|
26
31
|
import { RomProgressionChart } from './RomProgressionChart'
|
|
27
32
|
import { GhostSpark } from './GhostSpark'
|
|
28
33
|
import type { LiveFatigueModel } from './fatigue-model'
|
|
29
34
|
|
|
30
|
-
const t = getSemanticColors('dark')
|
|
31
|
-
|
|
32
35
|
export interface LiveFatigueCardProps {
|
|
33
36
|
/** The live fatigue read-model for the current set. */
|
|
34
37
|
model: LiveFatigueModel
|
|
@@ -42,8 +45,9 @@ const PAD = 18
|
|
|
42
45
|
const GHOST_GUTTER = 4 // GhostSpark carries this L/R padding internally
|
|
43
46
|
|
|
44
47
|
export function LiveFatigueCard({ model, width = 318, height }: LiveFatigueCardProps) {
|
|
48
|
+
const t = getSemanticColors(useSurfaceMode())
|
|
45
49
|
const chartW = width - PAD * 2 - GHOST_GUTTER * 2
|
|
46
|
-
const chartH =
|
|
50
|
+
const chartH = cardChartHeight(height)
|
|
47
51
|
return (
|
|
48
52
|
<Surface
|
|
49
53
|
level="base"
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View, Text } from 'react-native'
|
|
3
3
|
import { LiveFatiguePanel } from './LiveFatiguePanel'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
4
5
|
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
5
6
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
6
7
|
import { FATIGUE_STATES, buildMockPanelState } from './fatigue-mock'
|
|
8
|
+
import { PANEL_BREAKPOINTS } from './panel-layout'
|
|
7
9
|
|
|
8
10
|
const PAGE_BG = greyRamp[975]
|
|
9
11
|
const t = getSemanticColors('dark')
|
|
10
12
|
|
|
11
13
|
const meta: Meta<typeof LiveFatiguePanel> = {
|
|
12
|
-
title: '
|
|
14
|
+
title: 'Custom/Fatigue/Live Fatigue Panel',
|
|
13
15
|
component: LiveFatiguePanel,
|
|
14
|
-
tags: ['autodocs'],
|
|
16
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
15
17
|
parameters: {
|
|
16
18
|
layout: 'fullscreen',
|
|
17
19
|
docs: {
|
|
@@ -33,18 +35,126 @@ type Story = StoryObj<typeof LiveFatiguePanel>
|
|
|
33
35
|
export const LivePanelV2: Story = {
|
|
34
36
|
name: 'Live panel v2 (composition)',
|
|
35
37
|
render: () => {
|
|
36
|
-
const { model, velocity
|
|
38
|
+
const { model, velocity } = buildMockPanelState(FATIGUE_STATES[3].current, {
|
|
37
39
|
rpe: 10,
|
|
38
40
|
verdict: FATIGUE_STATES[3].model.verdict,
|
|
39
41
|
})
|
|
40
42
|
return (
|
|
41
43
|
<View style={{ backgroundColor: PAGE_BG, padding: 24 }}>
|
|
42
|
-
<LiveFatiguePanel model={model} velocity={velocity}
|
|
44
|
+
<LiveFatiguePanel model={model} velocity={velocity} />
|
|
43
45
|
</View>
|
|
44
46
|
)
|
|
45
47
|
},
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The stack/expand tiers side by side (TD-03.58). Each frame pins `containerWidth` so the
|
|
52
|
+
* tier is deterministic in the visual layer; live, the panel measures itself in `onLayout`
|
|
53
|
+
* and picks the same tier from the real width. Nothing transitions between tiers.
|
|
54
|
+
*/
|
|
55
|
+
export const ResponsiveTiers: Story = {
|
|
56
|
+
name: 'Responsive tiers (stack → row → wall)',
|
|
57
|
+
render: () => {
|
|
58
|
+
const { model, velocity } = buildMockPanelState(FATIGUE_STATES[1].current, {
|
|
59
|
+
rpe: FATIGUE_STATES[1].model.rpe,
|
|
60
|
+
verdict: FATIGUE_STATES[1].model.verdict,
|
|
61
|
+
})
|
|
62
|
+
const frames: Array<{ label: string; width: number; bodyHeight: number }> = [
|
|
63
|
+
{ label: `xs · 480px · stacked`, width: 480, bodyHeight: 560 },
|
|
64
|
+
{
|
|
65
|
+
label: `sm · ${PANEL_BREAKPOINTS.sm}px · stacked`,
|
|
66
|
+
width: PANEL_BREAKPOINTS.sm,
|
|
67
|
+
bodyHeight: 560,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: `md · ${PANEL_BREAKPOINTS.md}px · row`,
|
|
71
|
+
width: PANEL_BREAKPOINTS.md,
|
|
72
|
+
bodyHeight: 508,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: `lg · ${PANEL_BREAKPOINTS.lg}px · row`,
|
|
76
|
+
width: PANEL_BREAKPOINTS.lg,
|
|
77
|
+
bodyHeight: 508,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: `xl · ${PANEL_BREAKPOINTS.xl}px · wall, card expands`,
|
|
81
|
+
width: PANEL_BREAKPOINTS.xl,
|
|
82
|
+
bodyHeight: 620,
|
|
83
|
+
},
|
|
84
|
+
]
|
|
85
|
+
return (
|
|
86
|
+
<View style={{ backgroundColor: PAGE_BG, padding: 24, gap: 24 }}>
|
|
87
|
+
{frames.map((f) => (
|
|
88
|
+
<View key={f.label} style={{ gap: 6, width: f.width }}>
|
|
89
|
+
<Text
|
|
90
|
+
style={{
|
|
91
|
+
fontSize: 9,
|
|
92
|
+
letterSpacing: 1,
|
|
93
|
+
fontFamily: 'monospace',
|
|
94
|
+
color: t['text-tertiary'],
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{f.label}
|
|
98
|
+
</Text>
|
|
99
|
+
<LiveFatiguePanel
|
|
100
|
+
model={model}
|
|
101
|
+
velocity={velocity}
|
|
102
|
+
containerWidth={f.width}
|
|
103
|
+
bodyHeight={f.bodyHeight}
|
|
104
|
+
/>
|
|
105
|
+
</View>
|
|
106
|
+
))}
|
|
107
|
+
</View>
|
|
108
|
+
)
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The wall case on its own, at the real 1920 stage the SPA renders on. This is the frame
|
|
114
|
+
* to look at from across a room: the card expands out of its 318 sliver and the hero keeps
|
|
115
|
+
* the lead.
|
|
116
|
+
*/
|
|
117
|
+
export const WallWidth: Story = {
|
|
118
|
+
name: 'Wall width (1920)',
|
|
119
|
+
render: () => {
|
|
120
|
+
const { model, velocity } = buildMockPanelState(FATIGUE_STATES[2].current, {
|
|
121
|
+
rpe: FATIGUE_STATES[2].model.rpe,
|
|
122
|
+
verdict: FATIGUE_STATES[2].model.verdict,
|
|
123
|
+
})
|
|
124
|
+
return (
|
|
125
|
+
<View style={{ backgroundColor: PAGE_BG, width: PANEL_BREAKPOINTS.xl }}>
|
|
126
|
+
<LiveFatiguePanel
|
|
127
|
+
model={model}
|
|
128
|
+
velocity={velocity}
|
|
129
|
+
containerWidth={PANEL_BREAKPOINTS.xl}
|
|
130
|
+
bodyHeight={820}
|
|
131
|
+
/>
|
|
132
|
+
</View>
|
|
133
|
+
)
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The same panel on a LIGHT surface (TD-03.59). Nothing about the panel changes — the
|
|
139
|
+
* `<Surface theme="light">` publishes the mode and the panel's eyebrow and the card's
|
|
140
|
+
* edge/paper resolve against it. Before the Surface adoption both were pinned to dark
|
|
141
|
+
* and this story rendered dark-on-light.
|
|
142
|
+
*/
|
|
143
|
+
export const OnLightSurface: Story = {
|
|
144
|
+
name: 'On a light surface',
|
|
145
|
+
render: () => {
|
|
146
|
+
const { model, velocity } = buildMockPanelState(FATIGUE_STATES[0].current, {
|
|
147
|
+
rpe: FATIGUE_STATES[0].model.rpe,
|
|
148
|
+
verdict: FATIGUE_STATES[0].model.verdict,
|
|
149
|
+
})
|
|
150
|
+
return (
|
|
151
|
+
<Surface level="background" theme="light" rounded={false} style={{ padding: 24 }}>
|
|
152
|
+
<LiveFatiguePanel model={model} velocity={velocity} />
|
|
153
|
+
</Surface>
|
|
154
|
+
)
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
48
158
|
/** The whole system across the verdict spectrum — GOOD → SLOWING → GRINDING → FORM BREAKING DOWN. */
|
|
49
159
|
export const LiveStates: Story = {
|
|
50
160
|
name: 'Live states (Good → Breaking down)',
|
|
@@ -70,7 +180,7 @@ export const LiveStates: Story = {
|
|
|
70
180
|
</Text>
|
|
71
181
|
</View>
|
|
72
182
|
{FATIGUE_STATES.map((s) => {
|
|
73
|
-
const { model, velocity
|
|
183
|
+
const { model, velocity } = buildMockPanelState(s.current, {
|
|
74
184
|
rpe: s.model.rpe,
|
|
75
185
|
verdict: s.model.verdict,
|
|
76
186
|
})
|
|
@@ -86,7 +196,7 @@ export const LiveStates: Story = {
|
|
|
86
196
|
>
|
|
87
197
|
{s.name}
|
|
88
198
|
</Text>
|
|
89
|
-
<LiveFatiguePanel model={model} velocity={velocity}
|
|
199
|
+
<LiveFatiguePanel model={model} velocity={velocity} />
|
|
90
200
|
</View>
|
|
91
201
|
)
|
|
92
202
|
})}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import { LiveFatiguePanel } from './LiveFatiguePanel'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
5
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
6
|
+
import { buildMockPanelState } from './fatigue-mock'
|
|
7
|
+
import { PANEL_BREAKPOINTS, CARD_WIDTH_BASE, panelLayout } from './panel-layout'
|
|
8
|
+
|
|
9
|
+
const { model, velocity } = buildMockPanelState(3)
|
|
10
|
+
|
|
11
|
+
const dark = getSemanticColors('dark')
|
|
12
|
+
const light = getSemanticColors('light')
|
|
13
|
+
|
|
14
|
+
describe('LiveFatiguePanel', () => {
|
|
15
|
+
it('composes the aura frame, the velocity hero and the fatigue card', () => {
|
|
16
|
+
render(<LiveFatiguePanel model={model} velocity={velocity} />)
|
|
17
|
+
expect(screen.getByTestId('live-fatigue-panel')).toBeInTheDocument()
|
|
18
|
+
expect(screen.getByTestId('live-fatigue-card')).toBeInTheDocument()
|
|
19
|
+
expect(screen.getByText('VELOCITY · this set')).toBeInTheDocument()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// The wall display is the only surface this ships on today, so a colour move here is a
|
|
23
|
+
// regression, not an improvement. Outside any Surface the context defaults to dark.
|
|
24
|
+
it('resolves dark on-surface colours with no enclosing Surface', () => {
|
|
25
|
+
render(<LiveFatiguePanel model={model} velocity={velocity} />)
|
|
26
|
+
expect(screen.getByTestId('live-fatigue-eyebrow')).toHaveStyle({
|
|
27
|
+
color: dark['text-tertiary'],
|
|
28
|
+
})
|
|
29
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
30
|
+
borderTopColor: dark['hairline-default'],
|
|
31
|
+
backgroundColor: dark['surface-base'],
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('resolves the same dark colours inside a dark Surface', () => {
|
|
36
|
+
render(
|
|
37
|
+
<Surface level="background" theme="dark">
|
|
38
|
+
<LiveFatiguePanel model={model} velocity={velocity} />
|
|
39
|
+
</Surface>
|
|
40
|
+
)
|
|
41
|
+
expect(screen.getByTestId('live-fatigue-eyebrow')).toHaveStyle({
|
|
42
|
+
color: dark['text-tertiary'],
|
|
43
|
+
})
|
|
44
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
45
|
+
borderTopColor: dark['hairline-default'],
|
|
46
|
+
backgroundColor: dark['surface-base'],
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// The point of TD-03.59: a light surface used to render dark-pinned text on a light plane.
|
|
51
|
+
it('follows a light Surface instead of staying pinned to dark', () => {
|
|
52
|
+
render(
|
|
53
|
+
<Surface level="background" theme="light">
|
|
54
|
+
<LiveFatiguePanel model={model} velocity={velocity} />
|
|
55
|
+
</Surface>
|
|
56
|
+
)
|
|
57
|
+
expect(screen.getByTestId('live-fatigue-eyebrow')).toHaveStyle({
|
|
58
|
+
color: light['text-tertiary'],
|
|
59
|
+
})
|
|
60
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
61
|
+
borderTopColor: light['hairline-default'],
|
|
62
|
+
backgroundColor: light['surface-base'],
|
|
63
|
+
})
|
|
64
|
+
expect(light['text-tertiary']).not.toBe(dark['text-tertiary'])
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// `onLayout` never fires under jsdom (SIZE-D01 / gotcha 6), so the panel takes an explicit
|
|
69
|
+
// `containerWidth` override and these drive the live wiring through it. The breakpoint
|
|
70
|
+
// arithmetic itself is covered in `panel-layout.test.ts`.
|
|
71
|
+
describe('LiveFatiguePanel responsiveness (TD-03.58)', () => {
|
|
72
|
+
it('renders the shipped row geometry at the md and lg tiers', () => {
|
|
73
|
+
for (const width of [1000, 1440]) {
|
|
74
|
+
const { unmount } = render(
|
|
75
|
+
<LiveFatiguePanel model={model} velocity={velocity} containerWidth={width} />
|
|
76
|
+
)
|
|
77
|
+
expect(screen.getByTestId('live-fatigue-body')).toHaveStyle({
|
|
78
|
+
flexDirection: 'row',
|
|
79
|
+
padding: '24px 24px 24px 24px',
|
|
80
|
+
})
|
|
81
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
82
|
+
width: `${CARD_WIDTH_BASE}px`,
|
|
83
|
+
})
|
|
84
|
+
unmount()
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('stacks the card under the hero below the md edge', () => {
|
|
89
|
+
render(
|
|
90
|
+
<LiveFatiguePanel
|
|
91
|
+
model={model}
|
|
92
|
+
velocity={velocity}
|
|
93
|
+
containerWidth={PANEL_BREAKPOINTS.md - 1}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
expect(screen.getByTestId('live-fatigue-body')).toHaveStyle({ flexDirection: 'column' })
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('gives the stacked card the full content width instead of the 318 column', () => {
|
|
100
|
+
const width = 720
|
|
101
|
+
render(<LiveFatiguePanel model={model} velocity={velocity} containerWidth={width} />)
|
|
102
|
+
const { padding } = panelLayout(width)
|
|
103
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
104
|
+
width: `${width - padding * 2}px`,
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('expands the card column at wall width', () => {
|
|
109
|
+
render(<LiveFatiguePanel model={model} velocity={velocity} containerWidth={1920} />)
|
|
110
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({
|
|
111
|
+
width: `${panelLayout(1920).cardWidth}px`,
|
|
112
|
+
})
|
|
113
|
+
expect(panelLayout(1920).cardWidth).toBeGreaterThan(CARD_WIDTH_BASE)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('still honours an explicit cardWidth over the tier', () => {
|
|
117
|
+
render(
|
|
118
|
+
<LiveFatiguePanel model={model} velocity={velocity} containerWidth={1920} cardWidth={280} />
|
|
119
|
+
)
|
|
120
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({ width: '280px' })
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// TD-03.60 through the rendered tree, not just the pure split.
|
|
124
|
+
it('moves the rendered card height when bodyHeight changes', () => {
|
|
125
|
+
const { rerender } = render(
|
|
126
|
+
<LiveFatiguePanel model={model} velocity={velocity} containerWidth={1440} bodyHeight={400} />
|
|
127
|
+
)
|
|
128
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({ height: '400px' })
|
|
129
|
+
rerender(
|
|
130
|
+
<LiveFatiguePanel model={model} velocity={velocity} containerWidth={1440} bodyHeight={700} />
|
|
131
|
+
)
|
|
132
|
+
expect(screen.getByTestId('live-fatigue-card')).toHaveStyle({ height: '700px' })
|
|
133
|
+
})
|
|
134
|
+
})
|