@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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { SparkBars } from './SparkBars'
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof SparkBars> = {
|
|
5
|
+
title: 'Custom/Charts/SparkBars',
|
|
6
|
+
component: SparkBars,
|
|
7
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
'**Atom.** A tiny bar-mark sparkline for a signed series — the counterpart to ' +
|
|
13
|
+
'[Sparkline](?path=/docs/custom-workout-dataviz-sparkline--docs). Where a line reads a *trajectory*, ' +
|
|
14
|
+
'bars read *discrete per-period magnitude*. Bars scale on absolute value so a negative ' +
|
|
15
|
+
'period is as tall as an equally large positive one, with the sign carried by fill colour.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
values: [120, 340, -80, 910, 420, 0, 1580, 260, -310, 740, 1120, 90],
|
|
21
|
+
height: 22,
|
|
22
|
+
barWidth: 3,
|
|
23
|
+
gap: 2,
|
|
24
|
+
maxBars: 24,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
export default meta
|
|
28
|
+
type Story = StoryObj<typeof SparkBars>
|
|
29
|
+
|
|
30
|
+
export const Default: Story = {}
|
|
31
|
+
|
|
32
|
+
/** All-positive — the plain growth case. */
|
|
33
|
+
export const AllPositive: Story = {
|
|
34
|
+
args: { values: [40, 120, 260, 310, 480, 520, 900] },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** All-negative — every bar takes the error token. */
|
|
38
|
+
export const AllNegative: Story = {
|
|
39
|
+
args: { values: [-40, -120, -260, -310, -480] },
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Taller field, as used in the file-history growth block. */
|
|
43
|
+
export const Tall: Story = {
|
|
44
|
+
args: { height: 34, barWidth: 5, gap: 3 },
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `maxBars` keeps only the most recent values — a sparkline is a glance, not an archive. */
|
|
48
|
+
export const Truncated: Story = {
|
|
49
|
+
args: { values: Array.from({ length: 60 }, (_, i) => (i % 7) * 30 - 40), maxBars: 12 },
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** An empty series renders an empty field rather than collapsing the layout. */
|
|
53
|
+
export const Empty: Story = {
|
|
54
|
+
args: { values: [] },
|
|
55
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import { axe } from 'jest-axe'
|
|
4
|
+
import { SparkBars } from './SparkBars'
|
|
5
|
+
|
|
6
|
+
describe('SparkBars', () => {
|
|
7
|
+
it('renders one bar per value', () => {
|
|
8
|
+
render(<SparkBars values={[1, 2, 3, 4]} />)
|
|
9
|
+
expect(screen.getAllByTestId(/^spark-bars-bar-/)).toHaveLength(4)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('keeps only the last maxBars values', () => {
|
|
13
|
+
render(<SparkBars values={[1, 2, 3, 4, 5, 6]} maxBars={2} />)
|
|
14
|
+
expect(screen.getAllByTestId(/^spark-bars-bar-/)).toHaveLength(2)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('renders no bars for an empty series but keeps the field', () => {
|
|
18
|
+
render(<SparkBars values={[]} />)
|
|
19
|
+
expect(screen.queryByTestId(/^spark-bars-bar-/)).not.toBeInTheDocument()
|
|
20
|
+
expect(screen.getByTestId('spark-bars')).toBeInTheDocument()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('tints bars by sign with the result-* tokens', () => {
|
|
24
|
+
// Asserts the token, not its current value: resolveColor emits the CSS var on
|
|
25
|
+
// web, which is what keeps the chart theme-correct.
|
|
26
|
+
render(<SparkBars values={[10, -10]} />)
|
|
27
|
+
expect(screen.getByTestId('spark-bars-bar-0')).toHaveStyle({
|
|
28
|
+
backgroundColor: 'var(--color-result-improve)',
|
|
29
|
+
})
|
|
30
|
+
expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({
|
|
31
|
+
backgroundColor: 'var(--color-result-degrade)',
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('honours explicit color overrides', () => {
|
|
36
|
+
render(<SparkBars values={[10, -10]} color="#00ff00" negativeColor="#ff00ff" />)
|
|
37
|
+
expect(screen.getByTestId('spark-bars-bar-0')).toHaveStyle({
|
|
38
|
+
backgroundColor: 'rgb(0, 255, 0)',
|
|
39
|
+
})
|
|
40
|
+
expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({
|
|
41
|
+
backgroundColor: 'rgb(255, 0, 255)',
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('scales bars on magnitude, so equal-magnitude values are equally tall', () => {
|
|
46
|
+
render(<SparkBars values={[100, -100, 50]} height={40} />)
|
|
47
|
+
const [a, b, c] = ['0', '1', '2'].map((i) => screen.getByTestId(`spark-bars-bar-${i}`))
|
|
48
|
+
expect(a).toHaveStyle({ height: '40px' })
|
|
49
|
+
expect(b).toHaveStyle({ height: '40px' })
|
|
50
|
+
expect(c).toHaveStyle({ height: '20px' })
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('gives a zero value the minimum bar height rather than collapsing it', () => {
|
|
54
|
+
render(<SparkBars values={[100, 0]} height={40} />)
|
|
55
|
+
expect(screen.getByTestId('spark-bars-bar-1')).toHaveStyle({ height: '2px' })
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('exposes a default accessible label and accepts an override', () => {
|
|
59
|
+
const { rerender } = render(<SparkBars values={[1, 2]} />)
|
|
60
|
+
expect(screen.getByLabelText('Bar sparkline with 2 values')).toBeInTheDocument()
|
|
61
|
+
rerender(<SparkBars values={[1, 2]} label="Growth for open.ts" />)
|
|
62
|
+
expect(screen.getByLabelText('Growth for open.ts')).toBeInTheDocument()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('has no a11y violations', async () => {
|
|
66
|
+
const { container } = render(<SparkBars values={[3, -1, 4]} />)
|
|
67
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
|
+
import { View, type ViewProps } from 'react-native'
|
|
3
|
+
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
5
|
+
|
|
6
|
+
/** Shortest bar drawn, so an all-but-empty series still reads as a series. */
|
|
7
|
+
const MIN_BAR_HEIGHT = 2
|
|
8
|
+
|
|
9
|
+
export interface SparkBarsProps extends Omit<ViewProps, 'accessibilityLabel'> {
|
|
10
|
+
/** The series, oldest first. Negative values draw in `negativeColor`. */
|
|
11
|
+
values: number[]
|
|
12
|
+
/** Overall bar-field height in px. */
|
|
13
|
+
height?: number
|
|
14
|
+
/** Width of a single bar in px. */
|
|
15
|
+
barWidth?: number
|
|
16
|
+
/** Gap between bars in px. */
|
|
17
|
+
gap?: number
|
|
18
|
+
/** Keep only the last N values — a sparkline is a recent-history glance, not an archive. */
|
|
19
|
+
maxBars?: number
|
|
20
|
+
/** Fill for non-negative bars. Defaults to `result-improve`. */
|
|
21
|
+
color?: string
|
|
22
|
+
/** Fill for negative bars. Defaults to `result-degrade`. */
|
|
23
|
+
negativeColor?: string
|
|
24
|
+
/** Screen-reader description. Defaults to a bar count. */
|
|
25
|
+
label?: string
|
|
26
|
+
className?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* SparkBars — a tiny bar-mark sparkline for a signed series.
|
|
31
|
+
*
|
|
32
|
+
* The bar-mark counterpart to {@link Sparkline}: where a line reads a
|
|
33
|
+
* *trajectory*, bars read *discrete per-period magnitude*, which is what
|
|
34
|
+
* per-session activity and per-session net growth actually are. Bars are scaled
|
|
35
|
+
* by absolute value so a negative period is as tall as an equally large
|
|
36
|
+
* positive one, and tinted with `negativeColor` to carry the sign.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <SparkBars values={[3, 8, -2, 14]} height={22} />
|
|
40
|
+
*/
|
|
41
|
+
export function SparkBars({
|
|
42
|
+
values,
|
|
43
|
+
height = 22,
|
|
44
|
+
barWidth = 3,
|
|
45
|
+
gap = 2,
|
|
46
|
+
maxBars = 24,
|
|
47
|
+
color,
|
|
48
|
+
negativeColor,
|
|
49
|
+
label,
|
|
50
|
+
className,
|
|
51
|
+
...props
|
|
52
|
+
}: SparkBarsProps) {
|
|
53
|
+
const shown = values.slice(-maxBars)
|
|
54
|
+
// A per-period delta going up or down is `result-*` (a change in a measurement),
|
|
55
|
+
// not `status-*` (a thing being broken). See TOKENS.md §1.
|
|
56
|
+
const positiveFill = color ?? resolveColor('result-improve')
|
|
57
|
+
const negativeFill = negativeColor ?? resolveColor('result-degrade')
|
|
58
|
+
// Scaling on magnitude keeps a -100 as tall as a +100; sign is carried by fill.
|
|
59
|
+
const peak = Math.max(1, ...shown.map((v) => Math.abs(v)))
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<View
|
|
63
|
+
style={{ height, gap }}
|
|
64
|
+
className={cn('flex-row items-end', className)}
|
|
65
|
+
accessibilityRole="image"
|
|
66
|
+
accessibilityLabel={label ?? `Bar sparkline with ${shown.length} values`}
|
|
67
|
+
testID="spark-bars"
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
{shown.map((v, i) => (
|
|
71
|
+
<View
|
|
72
|
+
key={i}
|
|
73
|
+
style={{
|
|
74
|
+
height: Math.max(MIN_BAR_HEIGHT, Math.round((Math.abs(v) / peak) * height)),
|
|
75
|
+
width: barWidth,
|
|
76
|
+
backgroundColor: v < 0 ? negativeFill : positiveFill,
|
|
77
|
+
}}
|
|
78
|
+
className="rounded-t-[1px]"
|
|
79
|
+
accessibilityElementsHidden
|
|
80
|
+
testID={`spark-bars-bar-${i}`}
|
|
81
|
+
/>
|
|
82
|
+
))}
|
|
83
|
+
</View>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import { SET_LEVEL_FLAT_BAR, REP_LEVEL_FLAT_BAR } from './flatBarGeometry'
|
|
6
|
+
|
|
7
|
+
const DIR = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const segmentedBarSource = readFileSync(path.join(DIR, '../Workout/SegmentedBar.tsx'), 'utf8')
|
|
9
|
+
const setBarChartSource = readFileSync(path.join(DIR, 'SetBarChart.tsx'), 'utf8')
|
|
10
|
+
|
|
11
|
+
describe('flat-bar geometry (VW-86)', () => {
|
|
12
|
+
it('documents intentionally different set-level and rep-level sizes', () => {
|
|
13
|
+
expect(SET_LEVEL_FLAT_BAR).toEqual({ height: 8, gap: 5, radius: 2 })
|
|
14
|
+
expect(REP_LEVEL_FLAT_BAR).toEqual({ height: null, gapFloor: 2, radius: 5 })
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('SegmentedBar imports its geometry from the shared module rather than its own literals', () => {
|
|
18
|
+
expect(segmentedBarSource).toMatch(
|
|
19
|
+
/import\s*\{\s*SET_LEVEL_FLAT_BAR\s*\}\s*from\s*'\.\.\/charts\/flatBarGeometry'/
|
|
20
|
+
)
|
|
21
|
+
// The old hardcoded defaults must be gone from the component's own prop destructuring.
|
|
22
|
+
expect(segmentedBarSource).not.toMatch(/height\s*=\s*8\b/)
|
|
23
|
+
expect(segmentedBarSource).not.toMatch(/radius\s*=\s*2\b/)
|
|
24
|
+
expect(segmentedBarSource).toMatch(/height\s*=\s*SET_LEVEL_FLAT_BAR\.height/)
|
|
25
|
+
expect(segmentedBarSource).toMatch(/radius\s*=\s*SET_LEVEL_FLAT_BAR\.radius/)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('SetBarChart imports its geometry from the shared module rather than its own literals', () => {
|
|
29
|
+
expect(setBarChartSource).toMatch(
|
|
30
|
+
/import\s*\{\s*REP_LEVEL_FLAT_BAR\s*\}\s*from\s*'\.\/flatBarGeometry'/
|
|
31
|
+
)
|
|
32
|
+
expect(setBarChartSource).not.toMatch(/const MIN_BAR_GAP = 2\b/)
|
|
33
|
+
expect(setBarChartSource).not.toMatch(/const DEFAULT_BAR_RADIUS = 5\b/)
|
|
34
|
+
expect(setBarChartSource).toMatch(/const MIN_BAR_GAP = REP_LEVEL_FLAT_BAR\.gapFloor/)
|
|
35
|
+
expect(setBarChartSource).toMatch(/const DEFAULT_BAR_RADIUS = REP_LEVEL_FLAT_BAR\.radius/)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('SegmentedBar keeps SEGMENTED_BAR_GAP derived from the shared set-level gap', () => {
|
|
39
|
+
expect(segmentedBarSource).toMatch(/const SEGMENTED_BAR_GAP = SET_LEVEL_FLAT_BAR\.gap/)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flat-bar geometry `SegmentedBar` (set-level: one row per SET, e.g. SetStrip/SessionRail)
|
|
3
|
+
* and `SetBarChart` (rep-level: one bar per REP within a set) each declare as their own component
|
|
4
|
+
* defaults. VW-86 named the fact that these lived in two files with no shared source as the drift
|
|
5
|
+
* risk: a future edit to one could silently diverge from the other without anyone noticing they
|
|
6
|
+
* were ever meant to be compared.
|
|
7
|
+
*
|
|
8
|
+
* They are NOT unified into one set of numbers — a strip of SETS across a session and a chart of
|
|
9
|
+
* REPS within one set are genuinely different sizes by design. This module exists so that
|
|
10
|
+
* difference is a documented, single-sourced choice instead of two numbers that happen to match
|
|
11
|
+
* or drift by accident.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** `SegmentedBar`'s own default geometry (set-level: one row per SET). */
|
|
15
|
+
export const SET_LEVEL_FLAT_BAR = {
|
|
16
|
+
/** Track height (px). */
|
|
17
|
+
height: 8,
|
|
18
|
+
/** Gap between segment slots (px) — also SetStrip's between-set gap, see `SEGMENTED_BAR_GAP`. */
|
|
19
|
+
gap: 5,
|
|
20
|
+
/** Corner radius (px). */
|
|
21
|
+
radius: 2,
|
|
22
|
+
} as const
|
|
23
|
+
|
|
24
|
+
/** `SetBarChart`'s own default geometry (rep-level: one bar per REP within a set). */
|
|
25
|
+
export const REP_LEVEL_FLAT_BAR = {
|
|
26
|
+
/** No fixed height default — SetBarChart's `height` is a required prop set by the caller. */
|
|
27
|
+
height: null,
|
|
28
|
+
/** Inter-bar gap is proportional (`gapRatio · barWidth`), floored at this many px. */
|
|
29
|
+
gapFloor: 2,
|
|
30
|
+
/** Corner radius (px) default. */
|
|
31
|
+
radius: 5,
|
|
32
|
+
} as const
|
|
@@ -5,7 +5,16 @@ import { Stepper, Step, StepIndicator, StepLabel, StepContent } from './Stepper'
|
|
|
5
5
|
const meta: Meta<typeof Stepper> = {
|
|
6
6
|
title: 'Components/Molecules/Stepper',
|
|
7
7
|
component: Stepper,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'Composes RN primitives only. The five parts share step index and orientation through ' +
|
|
14
|
+
'a context, the same shape as **Tabs**.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
9
18
|
argTypes: {
|
|
10
19
|
activeStep: {
|
|
11
20
|
control: { type: 'number', min: 0, max: 4 },
|
|
@@ -124,9 +133,7 @@ export const VerticalWithContent: Story = {
|
|
|
124
133
|
<StepIndicator />
|
|
125
134
|
<StepLabel>Create Account</StepLabel>
|
|
126
135
|
<StepContent>
|
|
127
|
-
<Text className="text-text-secondary text-sm">
|
|
128
|
-
Account creation is complete.
|
|
129
|
-
</Text>
|
|
136
|
+
<Text className="text-text-secondary text-sm">Account creation is complete.</Text>
|
|
130
137
|
</StepContent>
|
|
131
138
|
</Step>
|
|
132
139
|
<Step>
|
|
@@ -147,9 +154,7 @@ export const VerticalWithContent: Story = {
|
|
|
147
154
|
<StepIndicator />
|
|
148
155
|
<StepLabel>Configure Settings</StepLabel>
|
|
149
156
|
<StepContent>
|
|
150
|
-
<Text className="text-text-secondary text-sm">
|
|
151
|
-
Adjust your preferences.
|
|
152
|
-
</Text>
|
|
157
|
+
<Text className="text-text-secondary text-sm">Adjust your preferences.</Text>
|
|
153
158
|
</StepContent>
|
|
154
159
|
</Step>
|
|
155
160
|
</Stepper>
|
|
@@ -221,9 +226,7 @@ export const ActiveStepProgression: Story = {
|
|
|
221
226
|
<View style={{ gap: 24 }}>
|
|
222
227
|
{[0, 1, 2, 3].map((activeStep) => (
|
|
223
228
|
<View key={activeStep}>
|
|
224
|
-
<Text className="text-text-secondary text-xs mb-2">
|
|
225
|
-
Active step: {activeStep}
|
|
226
|
-
</Text>
|
|
229
|
+
<Text className="text-text-secondary text-xs mb-2">Active step: {activeStep}</Text>
|
|
227
230
|
<Stepper activeStep={activeStep} orientation="horizontal">
|
|
228
231
|
<Step>
|
|
229
232
|
<StepIndicator />
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { render, screen } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
|
-
import {
|
|
5
|
-
Stepper,
|
|
6
|
-
Step,
|
|
7
|
-
StepIndicator,
|
|
8
|
-
StepLabel,
|
|
9
|
-
StepContent,
|
|
10
|
-
} from './Stepper'
|
|
4
|
+
import { Stepper, Step, StepIndicator, StepLabel, StepContent } from './Stepper'
|
|
11
5
|
|
|
12
6
|
function renderStepper(activeStep = 1) {
|
|
13
7
|
return render(
|
|
@@ -65,9 +65,7 @@ export function Stepper({
|
|
|
65
65
|
return (
|
|
66
66
|
<>
|
|
67
67
|
{React.cloneElement(child as React.ReactElement<any>, { index })}
|
|
68
|
-
{index < React.Children.count(children) - 1 &&
|
|
69
|
-
<StepConnector index={index} />
|
|
70
|
-
)}
|
|
68
|
+
{index < React.Children.count(children) - 1 && <StepConnector index={index} />}
|
|
71
69
|
</>
|
|
72
70
|
)
|
|
73
71
|
}
|
|
@@ -88,22 +86,12 @@ function StepConnector({ index }: StepConnectorProps) {
|
|
|
88
86
|
|
|
89
87
|
if (orientation === 'horizontal') {
|
|
90
88
|
return (
|
|
91
|
-
<View
|
|
92
|
-
className={cn(
|
|
93
|
-
'flex-1 h-0.5 mx-2',
|
|
94
|
-
isCompleted ? 'bg-brand-primary' : 'bg-hairline'
|
|
95
|
-
)}
|
|
96
|
-
/>
|
|
89
|
+
<View className={cn('flex-1 h-0.5 mx-2', isCompleted ? 'bg-brand-primary' : 'bg-hairline')} />
|
|
97
90
|
)
|
|
98
91
|
}
|
|
99
92
|
|
|
100
93
|
return (
|
|
101
|
-
<View
|
|
102
|
-
className={cn(
|
|
103
|
-
'w-0.5 h-8 ml-4 my-1',
|
|
104
|
-
isCompleted ? 'bg-brand-primary' : 'bg-hairline'
|
|
105
|
-
)}
|
|
106
|
-
/>
|
|
94
|
+
<View className={cn('w-0.5 h-8 ml-4 my-1', isCompleted ? 'bg-brand-primary' : 'bg-hairline')} />
|
|
107
95
|
)
|
|
108
96
|
}
|
|
109
97
|
|
|
@@ -123,10 +111,8 @@ export interface StepProps {
|
|
|
123
111
|
export function Step({ index = 0, status, className, children }: StepProps) {
|
|
124
112
|
const { activeStep, orientation } = useContext(StepperContext)
|
|
125
113
|
|
|
126
|
-
const derivedStatus: StepStatus =
|
|
127
|
-
index < activeStep ? 'completed' :
|
|
128
|
-
index === activeStep ? 'active' : 'upcoming'
|
|
129
|
-
)
|
|
114
|
+
const derivedStatus: StepStatus =
|
|
115
|
+
status || (index < activeStep ? 'completed' : index === activeStep ? 'active' : 'upcoming')
|
|
130
116
|
|
|
131
117
|
return (
|
|
132
118
|
<View
|
|
@@ -175,6 +161,13 @@ export function StepIndicator({
|
|
|
175
161
|
error: 'bg-status-error border-status-error',
|
|
176
162
|
}
|
|
177
163
|
|
|
164
|
+
const glyphStyles: Record<StepStatus, string> = {
|
|
165
|
+
completed: 'text-on-brand-primary',
|
|
166
|
+
active: 'text-on-brand-primary',
|
|
167
|
+
upcoming: 'text-text-secondary',
|
|
168
|
+
error: 'text-on-status-error',
|
|
169
|
+
}
|
|
170
|
+
|
|
178
171
|
return (
|
|
179
172
|
<View
|
|
180
173
|
className={cn(
|
|
@@ -184,12 +177,7 @@ export function StepIndicator({
|
|
|
184
177
|
)}
|
|
185
178
|
>
|
|
186
179
|
{icon || (
|
|
187
|
-
<Text
|
|
188
|
-
className={cn(
|
|
189
|
-
'text-sm font-semibold',
|
|
190
|
-
status === 'upcoming' ? 'text-text-secondary' : 'text-white'
|
|
191
|
-
)}
|
|
192
|
-
>
|
|
180
|
+
<Text className={cn('text-sm font-semibold', glyphStyles[status])}>
|
|
193
181
|
{status === 'completed' ? '✓' : index + 1}
|
|
194
182
|
</Text>
|
|
195
183
|
)}
|
|
@@ -216,10 +204,13 @@ export function StepLabel({ status = 'upcoming', className, children }: StepLabe
|
|
|
216
204
|
className={cn(
|
|
217
205
|
'text-sm font-medium',
|
|
218
206
|
orientation === 'horizontal' ? 'mt-2' : 'ml-3',
|
|
219
|
-
status === 'active'
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
207
|
+
status === 'active'
|
|
208
|
+
? 'text-text-primary'
|
|
209
|
+
: status === 'completed'
|
|
210
|
+
? 'text-brand-primary'
|
|
211
|
+
: status === 'error'
|
|
212
|
+
? 'text-status-error'
|
|
213
|
+
: 'text-text-secondary',
|
|
223
214
|
className
|
|
224
215
|
)}
|
|
225
216
|
>
|
|
@@ -242,9 +233,5 @@ export interface StepContentProps {
|
|
|
242
233
|
export function StepContent({ status = 'upcoming', className, children }: StepContentProps) {
|
|
243
234
|
if (status !== 'active') return null
|
|
244
235
|
|
|
245
|
-
return (
|
|
246
|
-
<View className={cn('ml-11 mt-2 pb-4', className)}>
|
|
247
|
-
{children}
|
|
248
|
-
</View>
|
|
249
|
-
)
|
|
236
|
+
return <View className={cn('ml-11 mt-2 pb-4', className)}>{children}</View>
|
|
250
237
|
}
|
|
@@ -151,3 +151,54 @@ export function InfoIcon(props: IconProps) {
|
|
|
151
151
|
</SvgIcon>
|
|
152
152
|
)
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// AW-132 · App brand marks — the mark half of a `BrandLockup` for each app that
|
|
157
|
+
// is likely to mount the shell. Sized 14 by default, like `VoltrasMark`.
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
/** Headphones glyph (mirrors lucide-react `Headphones`). Audiobook brand mark. */
|
|
161
|
+
export function HeadphonesIcon({ size = 14, ...props }: IconProps) {
|
|
162
|
+
return (
|
|
163
|
+
<SvgIcon size={size} {...props}>
|
|
164
|
+
<path d="M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5a9 9 0 0 1 18 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3" />
|
|
165
|
+
</SvgIcon>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Kanban board glyph (mirrors lucide-react `SquareKanban`). Active-work brand mark. */
|
|
170
|
+
export function KanbanIcon({ size = 14, ...props }: IconProps) {
|
|
171
|
+
return (
|
|
172
|
+
<SvgIcon size={size} {...props}>
|
|
173
|
+
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
174
|
+
<path d="M8 7v7" />
|
|
175
|
+
<path d="M12 7v4" />
|
|
176
|
+
<path d="M16 7v9" />
|
|
177
|
+
</SvgIcon>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Robot glyph (mirrors lucide-react `Bot`). Agent-dashboard brand mark. */
|
|
182
|
+
export function BotIcon({ size = 14, ...props }: IconProps) {
|
|
183
|
+
return (
|
|
184
|
+
<SvgIcon size={size} {...props}>
|
|
185
|
+
<path d="M12 8V4H8" />
|
|
186
|
+
<rect width="16" height="12" x="4" y="8" rx="2" />
|
|
187
|
+
<path d="M2 14h2" />
|
|
188
|
+
<path d="M20 14h2" />
|
|
189
|
+
<path d="M15 13v2" />
|
|
190
|
+
<path d="M9 13v2" />
|
|
191
|
+
</SvgIcon>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Brain glyph (mirrors lucide-react `Brain`). Brain-app brand mark. */
|
|
196
|
+
export function BrainIcon({ size = 14, ...props }: IconProps) {
|
|
197
|
+
return (
|
|
198
|
+
<SvgIcon size={size} {...props}>
|
|
199
|
+
<path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" />
|
|
200
|
+
<path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" />
|
|
201
|
+
<path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" />
|
|
202
|
+
</SvgIcon>
|
|
203
|
+
)
|
|
204
|
+
}
|