@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,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The {@link LiveFatiguePanel}'s responsive layout, as one pure function (TD-03.58).
|
|
3
|
+
*
|
|
4
|
+
* The panel is container-responsive, not prop-sized (SIZE-D01): it measures its own width
|
|
5
|
+
* in `onLayout` and feeds it here. Everything the two columns need — whether they stack,
|
|
6
|
+
* the padding, the gap, the card's width, and the split of the ONE body height — comes out
|
|
7
|
+
* of this one call, so the hero and the card cannot disagree about any of it.
|
|
8
|
+
*
|
|
9
|
+
* Pure, with no `react-native` import, so the breakpoint behaviour is unit-testable
|
|
10
|
+
* without `onLayout` (which never fires under jsdom).
|
|
11
|
+
*
|
|
12
|
+
* SOURCED vs CHOSEN. The breakpoint edges are titan's own `primitiveBreakpoints` — not
|
|
13
|
+
* invented here. The per-tier padding/gap/card numbers below the `md` edge, the `xl`
|
|
14
|
+
* card-width ratio and its cap, and the stacked height share ARE chosen; each is a single
|
|
15
|
+
* named constant and each is called out in the PR body.
|
|
16
|
+
*/
|
|
17
|
+
import { primitiveBreakpoints } from '../../../theme/tokens/primitives'
|
|
18
|
+
|
|
19
|
+
/** titan's breakpoint scale, re-exported as the panel's tier edges. Sourced, not chosen. */
|
|
20
|
+
export const PANEL_BREAKPOINTS = primitiveBreakpoints
|
|
21
|
+
|
|
22
|
+
export type PanelTier = keyof typeof PANEL_BREAKPOINTS
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The `md` edge (1000) is where the two columns fit side by side: the card's own default
|
|
26
|
+
* 318 plus the hero's usable minimum plus the padding and gap. Below it they stack.
|
|
27
|
+
*/
|
|
28
|
+
const ROW_TIER_MIN = PANEL_BREAKPOINTS.md
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The tier for a measured container width. An unmeasured container (0, before the first
|
|
32
|
+
* `onLayout`) resolves to `md` — today's side-by-side geometry — so the first paint matches
|
|
33
|
+
* what the panel has always rendered rather than flashing a stacked layout.
|
|
34
|
+
*/
|
|
35
|
+
export function panelTier(width: number): PanelTier {
|
|
36
|
+
if (width <= 0) return 'md'
|
|
37
|
+
if (width >= PANEL_BREAKPOINTS.xl) return 'xl'
|
|
38
|
+
if (width >= PANEL_BREAKPOINTS.lg) return 'lg'
|
|
39
|
+
if (width >= PANEL_BREAKPOINTS.md) return 'md'
|
|
40
|
+
if (width >= PANEL_BREAKPOINTS.sm) return 'sm'
|
|
41
|
+
return 'xs'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** titan's long-standing card column width, and the floor every wider tier clamps to. */
|
|
45
|
+
export const CARD_WIDTH_BASE = 318
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* CHOSEN. At wall width a 318px card is ~17% of the content row against ~34% at the `md`
|
|
49
|
+
* edge, so it reads as a sliver beside the hero. 0.22 pulls it back toward the `md`
|
|
50
|
+
* proportion without letting the hero lose its lead.
|
|
51
|
+
*/
|
|
52
|
+
export const CARD_WIDTH_XL_RATIO = 0.22
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* CHOSEN. The cap. The card's internal charts (`RomProgressionChart`, `GhostSpark`) were
|
|
56
|
+
* drawn around ~318 and go sparse rather than richer past roughly 1.5x that, so the
|
|
57
|
+
* expansion stops at 460 (reached at 2091px) instead of tracking the container forever.
|
|
58
|
+
*/
|
|
59
|
+
export const CARD_WIDTH_MAX = 460
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* CHOSEN. Stacked, the CARD takes the larger share of the one body height. Its sections
|
|
63
|
+
* have hard floors — the verdict hero, the three lights, the ROM chart and the ghost spark —
|
|
64
|
+
* while the velocity hero is a bar plot that scales continuously, so squeezing the hero
|
|
65
|
+
* degrades gracefully and squeezing the card overflows it.
|
|
66
|
+
*/
|
|
67
|
+
export const CARD_HEIGHT_SHARE_STACKED = 0.55
|
|
68
|
+
|
|
69
|
+
/** What the hero reserves above its plot for the `VELOCITY · this set` eyebrow, px. */
|
|
70
|
+
export const HERO_EYEBROW_ALLOWANCE = 26
|
|
71
|
+
|
|
72
|
+
// --- the card's own height arithmetic ------------------------------------------------
|
|
73
|
+
// It lives here rather than inside LiveFatigueCard so the panel can reason about the card's
|
|
74
|
+
// floor without importing a component (this module stays react-native-free and testable).
|
|
75
|
+
|
|
76
|
+
/** Floor for the ghost-spark plot inside the card, px. */
|
|
77
|
+
export const CARD_MIN_CHART_HEIGHT = 168
|
|
78
|
+
/** Ceiling for the ghost-spark plot inside the card, px. */
|
|
79
|
+
export const CARD_MAX_CHART_HEIGHT = 240
|
|
80
|
+
/** Share of a pinned card height the ghost-spark plot takes, before the clamp. */
|
|
81
|
+
export const CARD_CHART_HEIGHT_RATIO = 0.4
|
|
82
|
+
/** What an unpinned card gives the ghost-spark plot, px. */
|
|
83
|
+
export const CARD_NATURAL_CHART_HEIGHT = 172
|
|
84
|
+
|
|
85
|
+
/** The ghost-spark plot height for a card height, or the natural height when unpinned. */
|
|
86
|
+
export function cardChartHeight(cardHeight?: number): number {
|
|
87
|
+
if (cardHeight == null) return CARD_NATURAL_CHART_HEIGHT
|
|
88
|
+
const scaled = cardHeight * CARD_CHART_HEIGHT_RATIO
|
|
89
|
+
return Math.round(Math.min(CARD_MAX_CHART_HEIGHT, Math.max(CARD_MIN_CHART_HEIGHT, scaled)))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* MEASURED, not chosen: everything in the card that is not the ghost-spark plot — the 18px
|
|
94
|
+
* padding top and bottom, the verdict hero, the three lights, the two 16px minimum spacers
|
|
95
|
+
* and the ROM chart. Taken from the rendered card in Storybook (`scrollHeight` 384 at the
|
|
96
|
+
* {@link CARD_MIN_CHART_HEIGHT} floor), so a change to those sections needs re-measuring.
|
|
97
|
+
*/
|
|
98
|
+
export const CARD_CHROME_HEIGHT = 216
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The shortest a stacked card can be drawn without its content spilling past the rounded
|
|
102
|
+
* edge. Before this floor existed, an `xs` panel at `bodyHeight` 560 gave the card 301px
|
|
103
|
+
* against a 384px content height and the ghost spark rendered outside the card.
|
|
104
|
+
*/
|
|
105
|
+
export const CARD_MIN_HEIGHT_STACKED = CARD_CHROME_HEIGHT + CARD_MIN_CHART_HEIGHT
|
|
106
|
+
|
|
107
|
+
/** Padding and column gap per tier. `md` and up hold today's values exactly. */
|
|
108
|
+
const TIER_SPACING: Record<PanelTier, { padding: number; gap: number }> = {
|
|
109
|
+
xs: { padding: 16, gap: 12 },
|
|
110
|
+
sm: { padding: 20, gap: 14 },
|
|
111
|
+
md: { padding: 24, gap: 18 },
|
|
112
|
+
lg: { padding: 24, gap: 18 },
|
|
113
|
+
xl: { padding: 24, gap: 18 },
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface PanelLayout {
|
|
117
|
+
tier: PanelTier
|
|
118
|
+
/** Card below the hero rather than beside it. */
|
|
119
|
+
stacked: boolean
|
|
120
|
+
/** Uniform padding around the body row, px. */
|
|
121
|
+
padding: number
|
|
122
|
+
/** Gap between the hero and the card, px — column gap when row, row gap when stacked. */
|
|
123
|
+
gap: number
|
|
124
|
+
/**
|
|
125
|
+
* Card width, px. Stacked, this is the full content width, so the card takes a real
|
|
126
|
+
* number rather than needing a second `onLayout` of its own to size its charts.
|
|
127
|
+
*/
|
|
128
|
+
cardWidth: number
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The card column width for a row tier, before any explicit `cardWidth` override. */
|
|
132
|
+
function rowCardWidth(tier: PanelTier, width: number): number {
|
|
133
|
+
if (tier !== 'xl') return CARD_WIDTH_BASE
|
|
134
|
+
const fluid = Math.round(width * CARD_WIDTH_XL_RATIO)
|
|
135
|
+
return Math.min(CARD_WIDTH_MAX, Math.max(CARD_WIDTH_BASE, fluid))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** The whole layout for a measured container width. */
|
|
139
|
+
export function panelLayout(width: number): PanelLayout {
|
|
140
|
+
const tier = panelTier(width)
|
|
141
|
+
const { padding, gap } = TIER_SPACING[tier]
|
|
142
|
+
const stacked = width > 0 && width < ROW_TIER_MIN
|
|
143
|
+
const cardWidth = stacked
|
|
144
|
+
? Math.max(0, Math.round(width - padding * 2))
|
|
145
|
+
: rowCardWidth(tier, width)
|
|
146
|
+
return { tier, stacked, padding, gap, cardWidth }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface PanelBodySplit {
|
|
150
|
+
/** Height handed to the velocity hero's plot, px. */
|
|
151
|
+
heroHeight: number
|
|
152
|
+
/** Height handed to the fatigue card, px. */
|
|
153
|
+
cardHeight: number
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* CHOSEN. The shortest the velocity plot is still worth drawing. Below this the bars stop
|
|
158
|
+
* being readable across a room, so the stacked panel grows past `bodyHeight` rather than
|
|
159
|
+
* flattening the hero any further.
|
|
160
|
+
*/
|
|
161
|
+
export const HERO_MIN_PLOT_HEIGHT = 140
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The ONE body height split across the hero and the card (TD-03.60). Side by side both
|
|
165
|
+
* take the full height; stacked they share it by {@link CARD_HEIGHT_SHARE_STACKED} with the
|
|
166
|
+
* gap taken out first, and neither drops below its floor. Either way both numbers come from
|
|
167
|
+
* this one call, so changing `bodyHeight` moves both or neither.
|
|
168
|
+
*/
|
|
169
|
+
export function panelBodySplit(bodyHeight: number, layout: PanelLayout): PanelBodySplit {
|
|
170
|
+
if (!layout.stacked) {
|
|
171
|
+
return {
|
|
172
|
+
heroHeight: Math.max(0, bodyHeight - HERO_EYEBROW_ALLOWANCE),
|
|
173
|
+
cardHeight: Math.max(0, bodyHeight),
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const usable = Math.max(0, bodyHeight - layout.gap)
|
|
177
|
+
const cardHeight = Math.max(
|
|
178
|
+
CARD_MIN_HEIGHT_STACKED,
|
|
179
|
+
Math.round(usable * CARD_HEIGHT_SHARE_STACKED)
|
|
180
|
+
)
|
|
181
|
+
return {
|
|
182
|
+
heroHeight: Math.max(HERO_MIN_PLOT_HEIGHT, usable - cardHeight - HERO_EYEBROW_ALLOWANCE),
|
|
183
|
+
cardHeight,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { Gauge } from './Gauge'
|
|
3
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
4
|
+
|
|
5
|
+
const t = getSemanticColors('dark')
|
|
3
6
|
|
|
4
7
|
const meta: Meta<typeof Gauge> = {
|
|
5
|
-
title: '
|
|
8
|
+
title: 'Custom/Charts/Gauge',
|
|
6
9
|
component: Gauge,
|
|
7
|
-
tags: ['autodocs'],
|
|
10
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
8
11
|
argTypes: {
|
|
9
12
|
value: { control: { type: 'range', min: 0, max: 100, step: 1 } },
|
|
10
13
|
size: { control: { type: 'range', min: 100, max: 320, step: 10 } },
|
|
@@ -32,7 +35,7 @@ export const ArbitraryDomain: Story = {
|
|
|
32
35
|
|
|
33
36
|
/** Single-color override ignores the threshold bands. */
|
|
34
37
|
export const OverrideColor: Story = {
|
|
35
|
-
args: { value: 55, unit: '%', label: 'Coverage', color: '
|
|
38
|
+
args: { value: 55, unit: '%', label: 'Coverage', color: t['data-7'], size: 180 },
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
/** Value above max is clamped for the fill but shown verbatim. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { View, Text, type ViewProps } from 'react-native'
|
|
2
2
|
import { cn } from '../../../utils/cn'
|
|
3
3
|
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
4
|
+
import { primitiveColors } from '../../../theme/tokens/primitives'
|
|
5
|
+
import { alpha } from '../../../utils/colors'
|
|
4
6
|
|
|
5
7
|
const sem = getSemanticColors('dark')
|
|
6
8
|
|
|
@@ -36,7 +38,7 @@ export interface GaugeProps extends Omit<ViewProps, 'children'> {
|
|
|
36
38
|
const STATUS_SUCCESS = sem['status-success']
|
|
37
39
|
const STATUS_WARNING = sem['status-warning']
|
|
38
40
|
const STATUS_ERROR = sem['status-error']
|
|
39
|
-
const TRACK =
|
|
41
|
+
const TRACK = alpha(primitiveColors.white, 0.08)
|
|
40
42
|
|
|
41
43
|
/** Titan status-token bands for a 0–100 score. */
|
|
42
44
|
const DEFAULT_THRESHOLDS: GaugeThreshold[] = [
|
|
@@ -152,7 +154,10 @@ export function Gauge({
|
|
|
152
154
|
))}
|
|
153
155
|
|
|
154
156
|
{/* Center readout — Metric visual language. */}
|
|
155
|
-
<View
|
|
157
|
+
<View
|
|
158
|
+
style={{ position: 'absolute', top: 0, left: 0, width: size, height: size }}
|
|
159
|
+
className="items-center justify-center"
|
|
160
|
+
>
|
|
156
161
|
<View className="flex-row items-baseline gap-0.5">
|
|
157
162
|
<Text testID="gauge-value" className="text-3xl font-bold" style={{ color: displayColor }}>
|
|
158
163
|
{formatValue(value)}
|
|
@@ -5,7 +5,16 @@ import { Metric, MetricGroup } from './Metric'
|
|
|
5
5
|
const meta: Meta<typeof Metric> = {
|
|
6
6
|
title: 'Components/Molecules/Metric',
|
|
7
7
|
component: Metric,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'Composes RN primitives only. `MetricGroup` arranges several with a divider rule ' +
|
|
14
|
+
'between them.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
9
18
|
argTypes: {
|
|
10
19
|
value: {
|
|
11
20
|
control: 'text',
|
|
@@ -60,9 +60,7 @@ describe('Metric', () => {
|
|
|
60
60
|
|
|
61
61
|
describe('accessibility', () => {
|
|
62
62
|
it('has no accessibility violations', async () => {
|
|
63
|
-
const { container } = render(
|
|
64
|
-
<Metric value="42" label="Reps" unit="reps" trend="up" />
|
|
65
|
-
)
|
|
63
|
+
const { container } = render(<Metric value="42" label="Reps" unit="reps" trend="up" />)
|
|
66
64
|
const results = await axe(container)
|
|
67
65
|
expect(results).toHaveNoViolations()
|
|
68
66
|
})
|
|
@@ -46,18 +46,10 @@ export function Metric({
|
|
|
46
46
|
<View className={cn('items-center', className)} {...props}>
|
|
47
47
|
<View className="flex-row items-baseline gap-1">
|
|
48
48
|
<Text className={cn(styles.value, 'text-text-primary')}>{value}</Text>
|
|
49
|
-
{unit && (
|
|
50
|
-
|
|
51
|
-
)}
|
|
52
|
-
{trend && (
|
|
53
|
-
<Text className={cn(styles.unit, trendColors[trend])}>
|
|
54
|
-
{trendArrows[trend]}
|
|
55
|
-
</Text>
|
|
56
|
-
)}
|
|
49
|
+
{unit && <Text className={cn(styles.unit, 'text-text-tertiary')}>{unit}</Text>}
|
|
50
|
+
{trend && <Text className={cn(styles.unit, trendColors[trend])}>{trendArrows[trend]}</Text>}
|
|
57
51
|
</View>
|
|
58
|
-
<Text className={cn(styles.label, 'text-text-secondary mt-1')}>
|
|
59
|
-
{label}
|
|
60
|
-
</Text>
|
|
52
|
+
<Text className={cn(styles.label, 'text-text-secondary mt-1')}>{label}</Text>
|
|
61
53
|
</View>
|
|
62
54
|
)
|
|
63
55
|
}
|
|
@@ -67,11 +59,7 @@ export interface MetricGroupProps extends ViewProps {
|
|
|
67
59
|
children: React.ReactNode
|
|
68
60
|
}
|
|
69
61
|
|
|
70
|
-
export function MetricGroup({
|
|
71
|
-
className,
|
|
72
|
-
children,
|
|
73
|
-
...props
|
|
74
|
-
}: MetricGroupProps) {
|
|
62
|
+
export function MetricGroup({ className, children, ...props }: MetricGroupProps) {
|
|
75
63
|
const items = React.Children.toArray(children)
|
|
76
64
|
|
|
77
65
|
return (
|
|
@@ -80,10 +68,7 @@ export function MetricGroup({
|
|
|
80
68
|
<React.Fragment key={i}>
|
|
81
69
|
<View className="flex-1 items-center">{child}</View>
|
|
82
70
|
{i < items.length - 1 && (
|
|
83
|
-
<View
|
|
84
|
-
className="w-px h-8 bg-divider mx-2"
|
|
85
|
-
testID="metric-divider"
|
|
86
|
-
/>
|
|
71
|
+
<View className="w-px h-8 bg-divider mx-2" testID="metric-divider" />
|
|
87
72
|
)}
|
|
88
73
|
</React.Fragment>
|
|
89
74
|
))}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { View } from 'react-native'
|
|
3
|
+
import { MarkdownProse, type ProseLinker } from './MarkdownProse'
|
|
4
|
+
|
|
5
|
+
const SAMPLE = `# Shipped AW-17 and AW-18
|
|
6
|
+
|
|
7
|
+
Resolved the cwd to an initiative via the registered worktree, then folded the
|
|
8
|
+
result into [[bootstrap-prompt]]. See #42 for the file-history explorer.
|
|
9
|
+
|
|
10
|
+
## What changed
|
|
11
|
+
|
|
12
|
+
- \`active-work open\` now resolves **worktree-registered** cwds first
|
|
13
|
+
- A missing worktree no longer aborts the launch; AW-116 tracks the prune
|
|
14
|
+
- TD-07.14 unified the greys, so the shell planes moved with it
|
|
15
|
+
|
|
16
|
+
### Follow-ups
|
|
17
|
+
|
|
18
|
+
Nothing blocks AW-22; the reader is next.`
|
|
19
|
+
|
|
20
|
+
const TASK_LINKER: ProseLinker = {
|
|
21
|
+
id: 'task',
|
|
22
|
+
pattern: /\b[A-Z]{2,}-\d+(?:\.\d+)?\b/,
|
|
23
|
+
tone: 'brand',
|
|
24
|
+
}
|
|
25
|
+
const WIKI_LINKER: ProseLinker = {
|
|
26
|
+
id: 'wiki',
|
|
27
|
+
pattern: /\[\[[^\]]+\]\]/,
|
|
28
|
+
tone: 'link',
|
|
29
|
+
label: (ref) => ref.slice(2, -2),
|
|
30
|
+
}
|
|
31
|
+
const PR_LINKER: ProseLinker = { id: 'pr', pattern: /#\d+\b/, tone: 'muted' }
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* **MarkdownProse** — a small markdown subset (headings, bullets, paragraphs,
|
|
35
|
+
* bold, code) rendered as themed prose, with caller-described references
|
|
36
|
+
* auto-linked in one of three tones.
|
|
37
|
+
*
|
|
38
|
+
* Composes `Typography`. Used by `SessionDetail` and the initiative reader.
|
|
39
|
+
*/
|
|
40
|
+
const meta: Meta<typeof MarkdownProse> = {
|
|
41
|
+
title: 'Custom/Prose/MarkdownProse',
|
|
42
|
+
component: MarkdownProse,
|
|
43
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
44
|
+
args: {
|
|
45
|
+
body: SAMPLE,
|
|
46
|
+
linkers: [TASK_LINKER, WIKI_LINKER, PR_LINKER],
|
|
47
|
+
},
|
|
48
|
+
argTypes: {
|
|
49
|
+
linkers: { table: { disable: true } },
|
|
50
|
+
},
|
|
51
|
+
decorators: [
|
|
52
|
+
(Story) => (
|
|
53
|
+
<View className="w-full max-w-[640px] p-4">
|
|
54
|
+
<Story />
|
|
55
|
+
</View>
|
|
56
|
+
),
|
|
57
|
+
],
|
|
58
|
+
parameters: {
|
|
59
|
+
docs: {
|
|
60
|
+
description: {
|
|
61
|
+
component:
|
|
62
|
+
'Composes **Typography**. Linkers are tried in order; a match renders in its tone and, when the linker carries `onPress`, as a pressable link.',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
export default meta
|
|
68
|
+
|
|
69
|
+
type Story = StoryObj<typeof MarkdownProse>
|
|
70
|
+
|
|
71
|
+
/** Task ids in brand, `[[links]]` as links, PR numbers muted. */
|
|
72
|
+
export const Default: Story = {}
|
|
73
|
+
|
|
74
|
+
/** The same body with no linkers: plain prose. */
|
|
75
|
+
export const NoLinkers: Story = {
|
|
76
|
+
args: { linkers: [] },
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Pressable references: each linker carries an `onPress`. */
|
|
80
|
+
export const Pressable: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
linkers: [
|
|
83
|
+
{ ...TASK_LINKER, onPress: (id) => console.log('task', id) },
|
|
84
|
+
{ ...WIKI_LINKER, onPress: (name) => console.log('link', name) },
|
|
85
|
+
{ ...PR_LINKER, onPress: (ref) => console.log('pr', ref) },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react'
|
|
3
|
+
import { axe } from 'jest-axe'
|
|
4
|
+
import { MarkdownProse, parseProseBlocks, type ProseLinker } from './MarkdownProse'
|
|
5
|
+
|
|
6
|
+
const taskLinker: ProseLinker = { id: 'task', pattern: /\b[A-Z]{2,}-\d+\b/, tone: 'brand' }
|
|
7
|
+
const wikiLinker: ProseLinker = {
|
|
8
|
+
id: 'wiki',
|
|
9
|
+
pattern: /\[\[[^\]]+\]\]/,
|
|
10
|
+
tone: 'link',
|
|
11
|
+
label: (ref) => ref.slice(2, -2),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('parseProseBlocks', () => {
|
|
15
|
+
it('joins consecutive lines into one paragraph and splits on blank lines', () => {
|
|
16
|
+
const blocks = parseProseBlocks('one\ntwo\n\nthree')
|
|
17
|
+
expect(blocks).toEqual([
|
|
18
|
+
{ type: 'p', text: 'one two' },
|
|
19
|
+
{ type: 'p', text: 'three' },
|
|
20
|
+
])
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('reads headings and bullets, flattening deep headings to h3', () => {
|
|
24
|
+
const blocks = parseProseBlocks('# Title\n## Section\n#### Deep\n- item\n* other')
|
|
25
|
+
expect(blocks.map((b) => b.type)).toEqual(['h1', 'h2', 'h3', 'li', 'li'])
|
|
26
|
+
expect(blocks[2]!.text).toBe('Deep')
|
|
27
|
+
expect(blocks[4]!.text).toBe('other')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('folds an indented continuation line into the bullet above it', () => {
|
|
31
|
+
const blocks = parseProseBlocks('- first `code\n span` continues\nnot indented')
|
|
32
|
+
expect(blocks).toEqual([
|
|
33
|
+
{ type: 'li', text: 'first `code span` continues' },
|
|
34
|
+
{ type: 'p', text: 'not indented' },
|
|
35
|
+
])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('renders nothing for an empty body', () => {
|
|
39
|
+
expect(parseProseBlocks('')).toEqual([])
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
describe('MarkdownProse', () => {
|
|
44
|
+
it('renders bold and code spans without their markers', () => {
|
|
45
|
+
render(<MarkdownProse body="a **bold** and `code` span" />)
|
|
46
|
+
expect(screen.getByText('bold')).toBeInTheDocument()
|
|
47
|
+
expect(screen.getByText('code')).toBeInTheDocument()
|
|
48
|
+
expect(screen.queryByText(/\*\*/)).not.toBeInTheDocument()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('auto-links each linker in its tone and applies the label', () => {
|
|
52
|
+
render(
|
|
53
|
+
<MarkdownProse body="See AW-22 and [[memory-note]]." linkers={[taskLinker, wikiLinker]} />
|
|
54
|
+
)
|
|
55
|
+
expect(screen.getByTestId('prose-ref-task')).toHaveTextContent('AW-22')
|
|
56
|
+
expect(screen.getByTestId('prose-ref-wiki')).toHaveTextContent('memory-note')
|
|
57
|
+
expect(screen.queryByText('[[memory-note]]')).not.toBeInTheDocument()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('makes a reference pressable only when its linker has a handler', () => {
|
|
61
|
+
const onPress = vi.fn()
|
|
62
|
+
render(
|
|
63
|
+
<MarkdownProse body="AW-1 then [[note]]" linkers={[{ ...taskLinker, onPress }, wikiLinker]} />
|
|
64
|
+
)
|
|
65
|
+
fireEvent.click(screen.getByTestId('prose-ref-task'))
|
|
66
|
+
expect(onPress).toHaveBeenCalledWith('AW-1')
|
|
67
|
+
expect(screen.getByTestId('prose-ref-task')).toHaveAttribute('role', 'link')
|
|
68
|
+
expect(screen.getByTestId('prose-ref-wiki')).not.toHaveAttribute('role')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('lets the first matching linker win when two patterns overlap', () => {
|
|
72
|
+
const broad: ProseLinker = { id: 'broad', pattern: /\b[A-Z]+-\d+\b/ }
|
|
73
|
+
render(<MarkdownProse body="AW-9" linkers={[taskLinker, broad]} />)
|
|
74
|
+
expect(screen.getByTestId('prose-ref-task')).toBeInTheDocument()
|
|
75
|
+
expect(screen.queryByTestId('prose-ref-broad')).not.toBeInTheDocument()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('has no a11y violations', async () => {
|
|
79
|
+
const { container } = render(
|
|
80
|
+
<MarkdownProse
|
|
81
|
+
body="# Head\n\nBody with AW-3.\n\n- a bullet"
|
|
82
|
+
linkers={[{ ...taskLinker, onPress: () => {} }]}
|
|
83
|
+
/>
|
|
84
|
+
)
|
|
85
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
86
|
+
})
|
|
87
|
+
})
|