@titan-design/react-ui 0.12.1 → 0.14.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 +60 -47
- package/dist/bodymap.js +856 -736
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +858 -738
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1431 -237
- package/dist/index.d.ts +1431 -237
- package/dist/index.js +6506 -4781
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6280 -4642
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
- package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1919 -1937
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1927 -1945
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +225 -140
- package/dist/theme/index.d.ts +225 -140
- package/dist/theme/index.js +298 -319
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +283 -315
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +145 -24
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +145 -24
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +128 -11
- package/dist/theme/tokens.d.ts +128 -11
- package/dist/theme/tokens.js +126 -26
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +124 -27
- 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/docs/render-testing-pattern.md +130 -0
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +3 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +4989 -1583
- 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 +182 -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 +12 -6
- 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 +6 -3
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +7 -2
- 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 +55 -14
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +122 -18
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
- 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 +99 -16
- 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 +15 -12
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +11 -3
- 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 +11 -2
- package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +6 -2
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +8 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
- package/src/components/custom/Workout/DeviationBar.tsx +24 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
- package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
- package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
- 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/InputBar.tsx +4 -2
- 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 +8 -3
- 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 +14 -10
- 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 +20 -33
- 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 +9 -4
- 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 +16 -3
- 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 +68 -17
- 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 +22 -4
- package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
- package/src/components/custom/Workout/RestTimer.tsx +4 -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 +21 -17
- package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
- 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 +63 -7
- 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 +24 -12
- package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
- 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 +11 -4
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
- 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 +26 -10
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
- 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 +10 -6
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
- 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 +10 -7
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/exerciseRowState.ts +29 -0
- package/src/components/custom/Workout/index.ts +17 -2
- package/src/components/custom/Workout/metricText.stories.tsx +15 -13
- package/src/components/custom/Workout/metricText.tsx +8 -2
- package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/README.md +66 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
- package/src/components/custom/charts/SetBarChart.tsx +56 -9
- 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/flatBarGeometry.test.ts +41 -0
- package/src/components/custom/charts/flatBarGeometry.ts +32 -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 +21 -34
- 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 +15 -5
- package/src/components/ui/alert/Alert.tsx +24 -3
- 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 +44 -37
- 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 +7 -27
- 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 +14 -3
- 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 -27
- 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 +10 -18
- package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
- 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 +17 -5
- 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 +31 -19
- package/src/components/ui/pill/Pill.stories.tsx +111 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +168 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +6 -8
- 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/progress/Progress.tsx +9 -6
- 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 +12 -21
- 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 +16 -15
- 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 +4 -5
- package/src/components/ui/stack/Stack.stories.tsx +8 -8
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +92 -33
- 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 +8 -21
- 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 +49 -57
- 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 +38 -49
- 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 +101 -48
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/test/no-raw-color.test.ts +39 -0
- package/src/theme/Alpha.stories.tsx +103 -0
- 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/ProposedTokensVW82.stories.tsx +414 -0
- 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 +40 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +45 -5
- 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/subtle-tone-weight.test.ts +163 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/tailwind-var-opacity.test.ts +163 -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 +98 -33
- package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
- package/src/theme/tokens/semantic.ts +124 -54
- 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.alpha-adoption.test.ts +408 -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 +55 -9
- 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,8 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View, Text } from 'react-native'
|
|
3
3
|
import { SetStrip, type SetStripSet } from './SetStrip'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
5
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* `SetStrip` — the per-set segmented performance strip. One continuous bar per
|
|
@@ -9,7 +11,7 @@ import { SetStrip, type SetStripSet } from './SetStrip'
|
|
|
9
11
|
* amber-300 · green-300).
|
|
10
12
|
*/
|
|
11
13
|
const meta: Meta<typeof SetStrip> = {
|
|
12
|
-
title: 'Workout/SetStrip',
|
|
14
|
+
title: 'Custom/Workout/SetStrip',
|
|
13
15
|
component: SetStrip,
|
|
14
16
|
tags: ['autodocs'],
|
|
15
17
|
parameters: {
|
|
@@ -18,8 +20,8 @@ const meta: Meta<typeof SetStrip> = {
|
|
|
18
20
|
component:
|
|
19
21
|
'**Molecule.** The per-set segmented performance strip — one bar per set, rep ' +
|
|
20
22
|
'intensities as butted ramp-pin segments (no rep gaps), active set pulses. Composes ' +
|
|
21
|
-
'[SetBar](?path=/docs/workout-setbar--docs) × N. ' +
|
|
22
|
-
'Used-by ↑ [ExerciseCardHeading](?path=/docs/workout-exercisecardheading--docs).',
|
|
23
|
+
'[SetBar](?path=/docs/custom-workout-setbar--docs) × N. ' +
|
|
24
|
+
'Used-by ↑ [ExerciseCardHeading](?path=/docs/custom-workout-exercisecardheading--docs).',
|
|
23
25
|
},
|
|
24
26
|
},
|
|
25
27
|
},
|
|
@@ -28,9 +30,9 @@ const meta: Meta<typeof SetStrip> = {
|
|
|
28
30
|
},
|
|
29
31
|
decorators: [
|
|
30
32
|
(Story) => (
|
|
31
|
-
<
|
|
33
|
+
<Surface level="base" style={{ width: 210, padding: 16 }}>
|
|
32
34
|
<Story />
|
|
33
|
-
</
|
|
35
|
+
</Surface>
|
|
34
36
|
),
|
|
35
37
|
],
|
|
36
38
|
}
|
|
@@ -78,13 +80,67 @@ export const ShortStrip: Story = {
|
|
|
78
80
|
},
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
// ---- prescribed rep range (VMCP-03.04) — optional on `todo`/`active` only
|
|
84
|
+
|
|
85
|
+
export const RepRange: Story = {
|
|
86
|
+
args: {
|
|
87
|
+
height: 8,
|
|
88
|
+
sets: [
|
|
89
|
+
{ status: 'done', velocities: decay(8, 0.9) },
|
|
90
|
+
{ status: 'active', velocities: decay(3, 0.75), planned: 8, repsLow: 8, repsHigh: 12 },
|
|
91
|
+
{ status: 'todo', planned: 8, repsLow: 8, repsHigh: 12 },
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
parameters: {
|
|
95
|
+
docs: {
|
|
96
|
+
description: {
|
|
97
|
+
story:
|
|
98
|
+
"The plan's prescribed rep RANGE (VMCP-03.04): `8–12` on the active and todo sets. " +
|
|
99
|
+
"Independent of the `range` set-type's value range (isokinetic bands).",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const RepRangeSingleNumber: Story = {
|
|
106
|
+
args: {
|
|
107
|
+
height: 8,
|
|
108
|
+
sets: [
|
|
109
|
+
{ status: 'active', velocities: decay(3, 0.75), planned: 8, repsLow: 8, repsHigh: 8 },
|
|
110
|
+
{ status: 'todo', planned: 8, repsLow: 8 },
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
parameters: {
|
|
114
|
+
docs: {
|
|
115
|
+
description: {
|
|
116
|
+
story: 'Equal bounds (or only one given) collapse to a single number: `8`, not `8–8`.',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const RepRangeAbsent: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
height: 8,
|
|
125
|
+
sets: [
|
|
126
|
+
{ status: 'active', velocities: decay(3, 0.75), planned: 8 },
|
|
127
|
+
{ status: 'todo', planned: 8 },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
parameters: {
|
|
131
|
+
docs: {
|
|
132
|
+
description: { story: 'No prescription on the set — no label renders (the default today).' },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
81
137
|
// ---- set-type variant sheet: every variant at the real rail width, for eyeballing
|
|
82
138
|
function SheetRow({ label, meta, sets }: { label: string; meta: string; sets: SetStripSet[] }) {
|
|
83
139
|
return (
|
|
84
140
|
<View style={{ gap: 6 }}>
|
|
85
141
|
<View style={{ flexDirection: 'row', alignItems: 'baseline', gap: 8 }}>
|
|
86
|
-
<Text style={{ color:
|
|
87
|
-
<Text style={{ color:
|
|
142
|
+
<Text style={{ color: greyRamp[50], fontSize: 13, fontWeight: '800' }}>{label}</Text>
|
|
143
|
+
<Text style={{ color: greyRamp[600], fontSize: 10, fontFamily: 'monospace' }}>{meta}</Text>
|
|
88
144
|
</View>
|
|
89
145
|
<SetStrip sets={sets} />
|
|
90
146
|
</View>
|
|
@@ -94,6 +94,31 @@ describe('SetStrip', () => {
|
|
|
94
94
|
expect(screen.getAllByTestId('set-strip-set')).toHaveLength(2)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
+
describe('prescribed rep range (VMCP-03.04)', () => {
|
|
98
|
+
it('todo: renders the range when both bounds are given', () => {
|
|
99
|
+
render(<SetStrip sets={[{ status: 'todo', planned: 10, repsLow: 8, repsHigh: 12 }]} />)
|
|
100
|
+
expect(screen.getByTestId('set-strip-reps-label')).toHaveTextContent('8–12')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('active: renders a single number when the bounds are equal or only one is given', () => {
|
|
104
|
+
const { rerender } = render(
|
|
105
|
+
<SetStrip
|
|
106
|
+
sets={[{ status: 'active', velocities: [0.9], planned: 8, repsLow: 8, repsHigh: 8 }]}
|
|
107
|
+
/>
|
|
108
|
+
)
|
|
109
|
+
expect(screen.getByTestId('set-strip-reps-label')).toHaveTextContent('8')
|
|
110
|
+
rerender(
|
|
111
|
+
<SetStrip sets={[{ status: 'active', velocities: [0.9], planned: 8, repsLow: 8 }]} />
|
|
112
|
+
)
|
|
113
|
+
expect(screen.getByTestId('set-strip-reps-label')).toHaveTextContent('8')
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('renders no label when neither bound is given', () => {
|
|
117
|
+
render(<SetStrip sets={[{ status: 'todo', planned: 10 }]} />)
|
|
118
|
+
expect(screen.queryByTestId('set-strip-reps-label')).not.toBeInTheDocument()
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
97
122
|
describe('accessibility', () => {
|
|
98
123
|
it('has no accessibility violations', async () => {
|
|
99
124
|
const sets: SetStripSet[] = [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import { View, type ViewProps } from 'react-native'
|
|
2
|
+
import { View, Text, type ViewProps } from 'react-native'
|
|
3
3
|
import { SetBar, type SetStripSet } from './SetBar'
|
|
4
|
+
import { formatRepsRange } from '../../../utils/workout-format'
|
|
4
5
|
|
|
5
6
|
// Re-exported so the per-set colour vocabulary stays importable from either the
|
|
6
7
|
// molecule (SetStrip) or the atom (SetBar) it now lives in.
|
|
@@ -40,6 +41,12 @@ function describeSets(sets: SetStripSet[]): string {
|
|
|
40
41
|
return `Set progress: ${done} done, ${active} in progress, ${upcoming} upcoming`
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
/** The prescribed rep-range label for a `todo`/`active` set, or `null` when unset. */
|
|
45
|
+
function repsRangeLabel(set: SetStripSet): string | null {
|
|
46
|
+
if (set.status !== 'todo' && set.status !== 'active') return null
|
|
47
|
+
return formatRepsRange(set.repsLow, set.repsHigh)
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
export interface SetStripProps extends ViewProps {
|
|
44
51
|
/** Per-set performance data, in set order. */
|
|
45
52
|
sets: SetStripSet[]
|
|
@@ -63,9 +70,22 @@ export function SetStrip({ sets, height = 8, className, ...props }: SetStripProp
|
|
|
63
70
|
testID="set-strip"
|
|
64
71
|
{...props}
|
|
65
72
|
>
|
|
66
|
-
{sets.map((set, i) =>
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
{sets.map((set, i) => {
|
|
74
|
+
const label = repsRangeLabel(set)
|
|
75
|
+
if (label == null) return <SetBar key={i} set={set} height={height} />
|
|
76
|
+
return (
|
|
77
|
+
<View key={i} style={{ flex: 1, minWidth: 0, position: 'relative' }}>
|
|
78
|
+
<Text
|
|
79
|
+
className="text-text-secondary text-2xs font-semibold text-center"
|
|
80
|
+
style={{ position: 'absolute', bottom: height + 3, left: 0, right: 0 }}
|
|
81
|
+
testID="set-strip-reps-label"
|
|
82
|
+
>
|
|
83
|
+
{label}
|
|
84
|
+
</Text>
|
|
85
|
+
<SetBar set={set} height={height} />
|
|
86
|
+
</View>
|
|
87
|
+
)
|
|
88
|
+
})}
|
|
69
89
|
</View>
|
|
70
90
|
)
|
|
71
91
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { SetTableHeader } from './SetTableHeader'
|
|
3
|
+
import { Surface } from '../../ui/surface'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 🚧 WIP / placeholder — `SetTableHeader` (exported as `SetTableHeader`; the generic
|
|
@@ -10,7 +10,7 @@ import { SetTableHeader } from './SetTableHeader'
|
|
|
10
10
|
* unification (TD-03.56).
|
|
11
11
|
*/
|
|
12
12
|
const meta: Meta<typeof SetTableHeader> = {
|
|
13
|
-
title: 'Workout/SetTableHeader',
|
|
13
|
+
title: 'Custom/Workout/SetTableHeader',
|
|
14
14
|
component: SetTableHeader,
|
|
15
15
|
tags: ['autodocs'],
|
|
16
16
|
parameters: {
|
|
@@ -18,8 +18,8 @@ const meta: Meta<typeof SetTableHeader> = {
|
|
|
18
18
|
description: {
|
|
19
19
|
component:
|
|
20
20
|
'**Atom.** The expanded-set-table column header row; per-column widths mirror ' +
|
|
21
|
-
'[SetRow](?path=/docs/workout-setrow--docs) so headers align over the rows. ' +
|
|
22
|
-
'Used-by ↑ [ExerciseCard](?path=/docs/workout-exercisecard--docs) (expanded), which ' +
|
|
21
|
+
'[SetRow](?path=/docs/custom-workout-setrow--docs) so headers align over the rows. ' +
|
|
22
|
+
'Used-by ↑ [ExerciseCard](?path=/docs/custom-workout-exercisecard--docs) (expanded), which ' +
|
|
23
23
|
'renders it with `showPrevious={false}`. ' +
|
|
24
24
|
'Column set / widths provisional pending TD-03.56 responsive unification.',
|
|
25
25
|
},
|
|
@@ -31,9 +31,9 @@ const meta: Meta<typeof SetTableHeader> = {
|
|
|
31
31
|
},
|
|
32
32
|
decorators: [
|
|
33
33
|
(Story) => (
|
|
34
|
-
<
|
|
34
|
+
<Surface level="base" style={{ width: 320 }}>
|
|
35
35
|
<Story />
|
|
36
|
-
</
|
|
36
|
+
</Surface>
|
|
37
37
|
),
|
|
38
38
|
],
|
|
39
39
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import { View
|
|
2
|
+
import { View } from 'react-native'
|
|
3
|
+
import { Typography } from '../Typography'
|
|
3
4
|
|
|
4
5
|
// One header column: its label and its fixed width (PREV is the lone flex column,
|
|
5
6
|
// `undefined`). Order + widths mirror SetRow's cells so headers align over rows.
|
|
@@ -19,6 +20,11 @@ export interface SetTableHeaderProps {
|
|
|
19
20
|
// distribute across the full strip width via `justifyContent: space-between`.
|
|
20
21
|
const PREV_COLUMN: Column = { label: 'PREV', width: undefined }
|
|
21
22
|
|
|
23
|
+
// `microLabel` is the 10px step of the scale (TOKENS.md §4), in the same Inter face as
|
|
24
|
+
// the table's value cells. Only the row's line box is pinned: the raw <Text> this
|
|
25
|
+
// replaced carried no lineHeight, and the variant's `leading-normal` would grow the row.
|
|
26
|
+
const COLUMN_LABEL = 'leading-[normal]'
|
|
27
|
+
|
|
22
28
|
/** Columns in order, with the weight column reflecting `unit`; PREV dropped when hidden. */
|
|
23
29
|
function buildColumns(unit: 'lbs' | 'kg', showPrevious: boolean): Column[] {
|
|
24
30
|
return [
|
|
@@ -68,18 +74,9 @@ export function SetTableHeader({
|
|
|
68
74
|
}}
|
|
69
75
|
{...(isFlex ? { className: 'flex-1' } : {})}
|
|
70
76
|
>
|
|
71
|
-
<
|
|
72
|
-
className="text-text-tertiary"
|
|
73
|
-
style={{
|
|
74
|
-
fontSize: 10,
|
|
75
|
-
fontWeight: '600',
|
|
76
|
-
fontFamily: 'Inter, sans-serif',
|
|
77
|
-
textTransform: 'uppercase',
|
|
78
|
-
letterSpacing: 0.8,
|
|
79
|
-
}}
|
|
80
|
-
>
|
|
77
|
+
<Typography variant="microLabel" color="tertiary" className={COLUMN_LABEL}>
|
|
81
78
|
{label}
|
|
82
|
-
</
|
|
79
|
+
</Typography>
|
|
83
80
|
</View>
|
|
84
81
|
)
|
|
85
82
|
})}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
2
|
import { SetsRepsLoad } from './SetsRepsLoad'
|
|
3
|
+
import { Surface } from '../../ui/surface'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `SetsRepsLoad` — the `sets × reps @ load` prescription line in the TempoDisplay
|
|
@@ -8,7 +8,7 @@ import { SetsRepsLoad } from './SetsRepsLoad'
|
|
|
8
8
|
* separators).
|
|
9
9
|
*/
|
|
10
10
|
const meta: Meta<typeof SetsRepsLoad> = {
|
|
11
|
-
title: 'Workout/SetsRepsLoad',
|
|
11
|
+
title: 'Custom/Workout/SetsRepsLoad',
|
|
12
12
|
component: SetsRepsLoad,
|
|
13
13
|
tags: ['autodocs'],
|
|
14
14
|
parameters: {
|
|
@@ -16,17 +16,17 @@ const meta: Meta<typeof SetsRepsLoad> = {
|
|
|
16
16
|
description: {
|
|
17
17
|
component:
|
|
18
18
|
'**Atom.** The `sets × reps @ load` prescription line in the TempoDisplay visual ' +
|
|
19
|
-
'language. Composes [MetricCell](?path=/docs/workout-metriccell--docs) ' +
|
|
20
|
-
'(shared with [TempoDisplay](?path=/docs/workout-tempodisplay--docs)). ' +
|
|
21
|
-
'Used-by ↑ [ExerciseHeading](?path=/docs/workout-exerciseheading--docs).',
|
|
19
|
+
'language. Composes [MetricCell](?path=/docs/custom-workout-metriccell--docs) ' +
|
|
20
|
+
'(shared with [TempoDisplay](?path=/docs/custom-workout-tempodisplay--docs)). ' +
|
|
21
|
+
'Used-by ↑ [ExerciseHeading](?path=/docs/custom-workout-exerciseheading--docs).',
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
decorators: [
|
|
26
26
|
(Story) => (
|
|
27
|
-
<
|
|
27
|
+
<Surface level="base" style={{ padding: 16 }}>
|
|
28
28
|
<Story />
|
|
29
|
-
</
|
|
29
|
+
</Surface>
|
|
30
30
|
),
|
|
31
31
|
],
|
|
32
32
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import { View, type ViewProps } from 'react-native'
|
|
3
|
-
import {
|
|
3
|
+
import { useOnSurfaceColor } from '../../ui/surface/SurfaceContext'
|
|
4
4
|
import { MetricCell } from './metricText'
|
|
5
5
|
|
|
6
|
-
const t = getSemanticColors('dark')
|
|
7
|
-
|
|
8
6
|
const TIMES = '×' // × multiplication sign, padded by muted separators
|
|
9
7
|
const AT = '@'
|
|
10
8
|
|
|
@@ -17,12 +15,18 @@ export interface SetsRepsLoadProps extends ViewProps {
|
|
|
17
15
|
unit?: string
|
|
18
16
|
/** Cell font size (px). Default 11 — the compact rail/card scale. Raise for a wall read-out. */
|
|
19
17
|
fontSize?: number
|
|
18
|
+
/**
|
|
19
|
+
* Flatten the whole run to one dimmer, regular-weight tone (the collapsed/upcoming
|
|
20
|
+
* card row) instead of the bright bold value / muted separator split (the rail).
|
|
21
|
+
* Also drops the `×` separator's padding spaces — "3×6", not "3 × 6".
|
|
22
|
+
*/
|
|
23
|
+
muted?: boolean
|
|
20
24
|
className?: string
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* The `sets × reps @ load` prescription line, in the TempoDisplay visual language
|
|
25
|
-
* (Inter ·
|
|
29
|
+
* (Inter · letter-spacing 1 · value cells with muted `×` / `@` separators).
|
|
26
30
|
* Shares the {@link MetricCell} primitive with TempoDisplay so the two stay in step.
|
|
27
31
|
*/
|
|
28
32
|
export function SetsRepsLoad({
|
|
@@ -31,11 +35,17 @@ export function SetsRepsLoad({
|
|
|
31
35
|
load,
|
|
32
36
|
unit = 'lb',
|
|
33
37
|
fontSize,
|
|
38
|
+
muted = false,
|
|
34
39
|
className,
|
|
35
40
|
...props
|
|
36
41
|
}: SetsRepsLoadProps) {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
42
|
+
const primary = useOnSurfaceColor('primary')
|
|
43
|
+
const tertiary = useOnSurfaceColor('tertiary')
|
|
44
|
+
const secondary = useOnSurfaceColor('secondary')
|
|
45
|
+
const value = muted ? secondary : primary
|
|
46
|
+
const sep = muted ? secondary : tertiary
|
|
47
|
+
const weight = muted ? 400 : 600
|
|
48
|
+
const times = muted ? TIMES : ` ${TIMES} `
|
|
39
49
|
|
|
40
50
|
return (
|
|
41
51
|
<View
|
|
@@ -45,18 +55,20 @@ export function SetsRepsLoad({
|
|
|
45
55
|
testID="sets-reps-load"
|
|
46
56
|
{...props}
|
|
47
57
|
>
|
|
48
|
-
<MetricCell color={value} fontSize={fontSize}>
|
|
58
|
+
<MetricCell color={value} fontSize={fontSize} weight={weight}>
|
|
49
59
|
{sets}
|
|
50
60
|
</MetricCell>
|
|
51
|
-
<MetricCell color={sep} fontSize={fontSize}
|
|
52
|
-
|
|
61
|
+
<MetricCell color={sep} fontSize={fontSize} weight={weight}>
|
|
62
|
+
{times}
|
|
63
|
+
</MetricCell>
|
|
64
|
+
<MetricCell color={value} fontSize={fontSize} weight={weight}>
|
|
53
65
|
{reps}
|
|
54
66
|
</MetricCell>
|
|
55
|
-
<MetricCell color={sep} fontSize={fontSize}>{` ${AT} `}</MetricCell>
|
|
56
|
-
<MetricCell color={value} fontSize={fontSize}>
|
|
67
|
+
<MetricCell color={sep} fontSize={fontSize} weight={weight}>{` ${AT} `}</MetricCell>
|
|
68
|
+
<MetricCell color={value} fontSize={fontSize} weight={weight}>
|
|
57
69
|
{load}
|
|
58
70
|
</MetricCell>
|
|
59
|
-
<MetricCell color={sep} fontSize={fontSize}>{` ${unit}`}</MetricCell>
|
|
71
|
+
<MetricCell color={sep} fontSize={fontSize} weight={weight}>{` ${unit}`}</MetricCell>
|
|
60
72
|
</View>
|
|
61
73
|
)
|
|
62
74
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View } from 'react-native'
|
|
3
3
|
import { Sparkline } from './Sparkline'
|
|
4
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
5
|
+
|
|
6
|
+
const t = getSemanticColors('dark')
|
|
4
7
|
|
|
5
8
|
const meta: Meta<typeof Sparkline> = {
|
|
6
|
-
title: 'Workout/DataViz/Sparkline',
|
|
9
|
+
title: 'Custom/Workout/DataViz/Sparkline',
|
|
7
10
|
component: Sparkline,
|
|
8
11
|
tags: ['autodocs'],
|
|
9
12
|
argTypes: {
|
|
@@ -56,7 +59,7 @@ export const Descending: Story = {
|
|
|
56
59
|
args: {
|
|
57
60
|
data: descending,
|
|
58
61
|
showDots: true,
|
|
59
|
-
color: '
|
|
62
|
+
color: t['status-error-vivid'],
|
|
60
63
|
},
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -64,7 +67,7 @@ export const UCurve: Story = {
|
|
|
64
67
|
args: {
|
|
65
68
|
data: uCurve,
|
|
66
69
|
showDots: true,
|
|
67
|
-
color: '
|
|
70
|
+
color: t['status-success'],
|
|
68
71
|
},
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -72,7 +75,7 @@ export const Flat: Story = {
|
|
|
72
75
|
args: {
|
|
73
76
|
data: flat,
|
|
74
77
|
showDots: true,
|
|
75
|
-
color: '
|
|
78
|
+
color: t['status-warning-light'],
|
|
76
79
|
},
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -81,8 +84,8 @@ export const WithReferenceLines: Story = {
|
|
|
81
84
|
data: ascending,
|
|
82
85
|
showDots: true,
|
|
83
86
|
referenceLines: [
|
|
84
|
-
{ value: 30, color: '
|
|
85
|
-
{ value: 45, color: '
|
|
87
|
+
{ value: 30, color: t['status-error-vivid'], dashed: true },
|
|
88
|
+
{ value: 45, color: t['status-success'], dashed: false },
|
|
86
89
|
],
|
|
87
90
|
},
|
|
88
91
|
}
|
|
@@ -99,7 +102,7 @@ export const DotsAndHighlightLast: Story = {
|
|
|
99
102
|
data: volatile,
|
|
100
103
|
showDots: true,
|
|
101
104
|
highlightLast: true,
|
|
102
|
-
color: '
|
|
105
|
+
color: t['status-warning'],
|
|
103
106
|
},
|
|
104
107
|
}
|
|
105
108
|
|
|
@@ -116,10 +119,10 @@ export const AllShapes: Story = {
|
|
|
116
119
|
render: () => (
|
|
117
120
|
<View style={{ gap: 16, padding: 16 }}>
|
|
118
121
|
<Sparkline data={ascending} showDots highlightLast />
|
|
119
|
-
<Sparkline data={descending} showDots color=
|
|
120
|
-
<Sparkline data={uCurve} showDots color=
|
|
121
|
-
<Sparkline data={flat} showDots color=
|
|
122
|
-
<Sparkline data={volatile} showDots color=
|
|
122
|
+
<Sparkline data={descending} showDots color={t['status-error-vivid']} />
|
|
123
|
+
<Sparkline data={uCurve} showDots color={t['status-success']} />
|
|
124
|
+
<Sparkline data={flat} showDots color={t['status-warning-light']} />
|
|
125
|
+
<Sparkline data={volatile} showDots color={t['status-warning']} highlightLast />
|
|
123
126
|
</View>
|
|
124
127
|
),
|
|
125
128
|
}
|
|
@@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest'
|
|
|
2
2
|
import { render, screen } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
4
|
import { Sparkline } from './Sparkline'
|
|
5
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
5
6
|
|
|
6
7
|
const sampleData = [10, 25, 15, 30, 20]
|
|
7
8
|
|
|
@@ -19,9 +20,7 @@ describe('Sparkline', () => {
|
|
|
19
20
|
it('renders line segments between points', () => {
|
|
20
21
|
render(<Sparkline data={sampleData} />)
|
|
21
22
|
for (let i = 1; i < sampleData.length; i++) {
|
|
22
|
-
expect(
|
|
23
|
-
screen.getByTestId(`sparkline-segment-${i}`),
|
|
24
|
-
).toBeInTheDocument()
|
|
23
|
+
expect(screen.getByTestId(`sparkline-segment-${i}`)).toBeInTheDocument()
|
|
25
24
|
}
|
|
26
25
|
})
|
|
27
26
|
|
|
@@ -40,9 +39,7 @@ describe('Sparkline', () => {
|
|
|
40
39
|
it('highlights last dot when highlightLast is true', () => {
|
|
41
40
|
render(<Sparkline data={sampleData} highlightLast />)
|
|
42
41
|
const lastIndex = sampleData.length - 1
|
|
43
|
-
expect(
|
|
44
|
-
screen.getByTestId(`sparkline-dot-${lastIndex}`),
|
|
45
|
-
).toBeInTheDocument()
|
|
42
|
+
expect(screen.getByTestId(`sparkline-dot-${lastIndex}`)).toBeInTheDocument()
|
|
46
43
|
// Other dots should not be present (showDots is false)
|
|
47
44
|
expect(screen.queryByTestId('sparkline-dot-0')).not.toBeInTheDocument()
|
|
48
45
|
})
|
|
@@ -62,7 +59,7 @@ describe('Sparkline', () => {
|
|
|
62
59
|
{ value: 20, color: '#ff0000' },
|
|
63
60
|
{ value: 25, color: '#00ff00', dashed: true },
|
|
64
61
|
]}
|
|
65
|
-
|
|
62
|
+
/>
|
|
66
63
|
)
|
|
67
64
|
expect(screen.getByTestId('sparkline-reference-0')).toBeInTheDocument()
|
|
68
65
|
expect(screen.getByTestId('sparkline-reference-1')).toBeInTheDocument()
|
|
@@ -70,9 +67,36 @@ describe('Sparkline', () => {
|
|
|
70
67
|
|
|
71
68
|
it('does not render reference lines when not provided', () => {
|
|
72
69
|
render(<Sparkline data={sampleData} />)
|
|
73
|
-
expect(
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
expect(screen.queryByTestId('sparkline-reference-0')).not.toBeInTheDocument()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('defaults the trace to the brand-primary token', () => {
|
|
74
|
+
render(<Sparkline data={sampleData} highlightLast />)
|
|
75
|
+
expect(screen.getByTestId('sparkline-segment-1')).toHaveStyle({
|
|
76
|
+
backgroundColor: resolveColor('brand-primary'),
|
|
77
|
+
})
|
|
78
|
+
expect(screen.getByTestId('sparkline-dot-4')).toHaveStyle({
|
|
79
|
+
backgroundColor: resolveColor('brand-primary'),
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('lets a caller override the trace colour', () => {
|
|
84
|
+
render(<Sparkline data={sampleData} color="#00ff00" />)
|
|
85
|
+
expect(screen.getByTestId('sparkline-segment-1')).toHaveStyle({
|
|
86
|
+
backgroundColor: '#00ff00',
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('renders a reference-line label in the caller colour', () => {
|
|
91
|
+
render(
|
|
92
|
+
<Sparkline
|
|
93
|
+
data={sampleData}
|
|
94
|
+
referenceLines={[{ value: 20, color: '#ff0000', label: 'MAV' }]}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
const label = screen.getByTestId('sparkline-reference-label-0')
|
|
98
|
+
expect(label).toHaveTextContent('MAV')
|
|
99
|
+
expect(label).toHaveStyle({ color: '#ff0000' })
|
|
76
100
|
})
|
|
77
101
|
|
|
78
102
|
it('uses default dimensions', () => {
|
|
@@ -89,23 +113,17 @@ describe('Sparkline', () => {
|
|
|
89
113
|
|
|
90
114
|
it('sets accessibility label', () => {
|
|
91
115
|
render(<Sparkline data={sampleData} />)
|
|
92
|
-
expect(
|
|
93
|
-
screen.getByLabelText('Sparkline chart with 5 data points'),
|
|
94
|
-
).toBeInTheDocument()
|
|
116
|
+
expect(screen.getByLabelText('Sparkline chart with 5 data points')).toBeInTheDocument()
|
|
95
117
|
})
|
|
96
118
|
|
|
97
119
|
it('sets empty accessibility label for no data', () => {
|
|
98
120
|
render(<Sparkline data={[]} />)
|
|
99
|
-
expect(
|
|
100
|
-
screen.getByLabelText('Sparkline chart, no data'),
|
|
101
|
-
).toBeInTheDocument()
|
|
121
|
+
expect(screen.getByLabelText('Sparkline chart, no data')).toBeInTheDocument()
|
|
102
122
|
})
|
|
103
123
|
|
|
104
124
|
describe('accessibility', () => {
|
|
105
125
|
it('has no accessibility violations', async () => {
|
|
106
|
-
const { container } = render(
|
|
107
|
-
<Sparkline data={sampleData} showDots highlightLast />,
|
|
108
|
-
)
|
|
126
|
+
const { container } = render(<Sparkline data={sampleData} showDots highlightLast />)
|
|
109
127
|
const results = await axe(container)
|
|
110
128
|
expect(results).toHaveNoViolations()
|
|
111
129
|
})
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
-
import
|
|
3
|
-
import { View, Text, type ViewProps } from 'react-native'
|
|
2
|
+
import { View, type ViewProps } from 'react-native'
|
|
4
3
|
import { cn } from '../../../utils/cn'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
const BRAND_PRIMARY = getSemanticColors('dark')['brand-primary']
|
|
4
|
+
import { Typography } from '../Typography'
|
|
5
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
8
6
|
|
|
9
7
|
export interface SparklineProps extends ViewProps {
|
|
10
8
|
data: number[]
|
|
@@ -22,10 +20,7 @@ export interface SparklineProps extends ViewProps {
|
|
|
22
20
|
className?: string
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
function normalizeData(
|
|
26
|
-
data: number[],
|
|
27
|
-
height: number,
|
|
28
|
-
): number[] {
|
|
23
|
+
function normalizeData(data: number[], height: number): number[] {
|
|
29
24
|
if (data.length === 0) return []
|
|
30
25
|
const min = Math.min(...data)
|
|
31
26
|
const max = Math.max(...data)
|
|
@@ -33,11 +28,7 @@ function normalizeData(
|
|
|
33
28
|
return data.map((v) => height - ((v - min) / range) * height)
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
function normalizeValue(
|
|
37
|
-
value: number,
|
|
38
|
-
data: number[],
|
|
39
|
-
height: number,
|
|
40
|
-
): number {
|
|
31
|
+
function normalizeValue(value: number, data: number[], height: number): number {
|
|
41
32
|
const min = Math.min(...data)
|
|
42
33
|
const max = Math.max(...data)
|
|
43
34
|
const range = max - min || 1
|
|
@@ -67,7 +58,7 @@ export function Sparkline({
|
|
|
67
58
|
)
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
const resolvedColor = color ??
|
|
61
|
+
const resolvedColor = color ?? resolveColor('brand-primary')
|
|
71
62
|
const normalized = normalizeData(data, height)
|
|
72
63
|
const stepX = data.length > 1 ? width / (data.length - 1) : 0
|
|
73
64
|
|
|
@@ -112,19 +103,24 @@ export function Sparkline({
|
|
|
112
103
|
testID={`sparkline-reference-${i}`}
|
|
113
104
|
>
|
|
114
105
|
{line.label && (
|
|
115
|
-
|
|
106
|
+
// `3xs` (9px) is the scale floor; the label was 7px, which is off it
|
|
107
|
+
// entirely (TOKENS.md §4). The line box stays unpinned, as the raw
|
|
108
|
+
// <Text> this replaced was, so the absolute offset still lands.
|
|
109
|
+
<Typography
|
|
110
|
+
variant="caption"
|
|
111
|
+
color="inherit"
|
|
112
|
+
className="text-3xs leading-[normal]"
|
|
116
113
|
style={{
|
|
117
114
|
position: 'absolute',
|
|
118
115
|
right: 0,
|
|
119
116
|
top: -10,
|
|
120
|
-
fontSize: 7,
|
|
121
117
|
color: line.color,
|
|
122
118
|
opacity: 1,
|
|
123
119
|
}}
|
|
124
120
|
testID={`sparkline-reference-label-${i}`}
|
|
125
121
|
>
|
|
126
122
|
{line.label}
|
|
127
|
-
</
|
|
123
|
+
</Typography>
|
|
128
124
|
)}
|
|
129
125
|
</View>
|
|
130
126
|
)
|