@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,99 @@
|
|
|
1
|
+
# Library roadmap — decided 2026-09-08
|
|
2
|
+
|
|
3
|
+
The operator reviewed a deep critique of `packages/ui` (attached as
|
|
4
|
+
`docs/audits/2026-09-08-library-critique.md`) and answered its sixteen
|
|
5
|
+
competing-system questions. This file is the record. When a change touches
|
|
6
|
+
one of these areas, it follows the decision here or reopens it explicitly.
|
|
7
|
+
|
|
8
|
+
## Standing policies
|
|
9
|
+
|
|
10
|
+
**Colour.** Every colour used anywhere comes from a colour ramp (`greyRamp`,
|
|
11
|
+
the OKLCH ramps in `theme/tokens/primitives.ts`). Semantic tokens and palettes
|
|
12
|
+
reference ramp steps; components use only semantic tokens. No file declares
|
|
13
|
+
its own colour. The eslint token-purity error block extends to every family;
|
|
14
|
+
the raw-colour baseline (`titan/no-raw-color`) shrinks per PR and is deleted at
|
|
15
|
+
zero. Workout and Fatigue are not dark-only by design: they become theme-correct.
|
|
16
|
+
|
|
17
|
+
**Consumers.** We own every downstream consumer of `@titan-design/react-ui`
|
|
18
|
+
(audiobook, source-linked; voltras-mcp; agent-chat, tokens only; voltras
|
|
19
|
+
mobile; codewatch; two stale forks). Breaking changes are allowed. A component
|
|
20
|
+
being retired is marked `@deprecated` in code first so no new usage appears,
|
|
21
|
+
and each consumer gets a follow-up task to migrate.
|
|
22
|
+
|
|
23
|
+
**Depth.** See Foundations/Depth. Tone plus lift (rim 0.12, ambient shadow
|
|
24
|
+
scaled by planes crossed) on every raised plane; floating surfaces carry the
|
|
25
|
+
rim and no hairline ring; lift sparingly, inset inside cards; light mode is
|
|
26
|
+
deferred to its own pass.
|
|
27
|
+
|
|
28
|
+
## Decisions (critique §B)
|
|
29
|
+
|
|
30
|
+
| # | Question | Decision |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| 1 | Container | `Card` is the only content container. `Surface` is for shell roots (shell, page, rail). `Tile` becomes a Card stat preset. `Section`/`SectionHeader` become Card presets (voltras mobile uses them), not deleted. |
|
|
33
|
+
| 2 | numeric vs named elevation | Both public: `level` is absolute for shell roots, `raise`/`elevation` are relative. Landed in #166. |
|
|
34
|
+
| 3 | Pills | One `Pill` primitive (tone / size / leading slot). `Badge`, `Chip`, `StatusPill`, `PrBadge`, `MuscleGroupChip` survive as thin presets (external users). `BaseBadge`, `WorkoutPill`, `SessionStatePill`, `WeightBadge`, `SeverityLabel`, `CoChangeChip` fold in or are deleted. |
|
|
35
|
+
| 4 | Divider | Every rule is a `Divider`. `border-hairline*` is legal only on Card `outline`/`subtle`, Table rules, and input borders. |
|
|
36
|
+
| 5 | HelpTip | Delete `HelpTip` and `LabelWithHelp`; a Tooltip story shows the pattern. |
|
|
37
|
+
| 6 | Theme source | `SurfaceContext`/`ThemeProvider` only. `utils/useTheme.ts` is deleted (Card no longer uses it after #166). |
|
|
38
|
+
| 7 | Workout/Fatigue dark-only? | No. Full theme-correct port (E3), in the batches below. |
|
|
39
|
+
| 8 | Colour math | One `theme/color-math.ts` with CIELAB L* as the sanctioned metric; duplicate `hexToRgb` ×4, `mixHex` ×4, luminance ×3, test `lstar` ×3 deleted. |
|
|
40
|
+
| 9 | Typography | `Typography` and `Eyebrow` move into `ui/`; re-export shims stay in `custom/`. |
|
|
41
|
+
| 10 | Dot | `Indicator` survives. `StatusDot`'s consumers migrate; its inline glows route through `getGlowShadow`. Fatigue README corrected. |
|
|
42
|
+
| 11 | Metric | One `Metric` with size / align / trend. `MetricTiles` becomes a preset (one external site); `MetricCell` deleted (no consumers). |
|
|
43
|
+
| 12 | paperSheet | Stays hero-only. Cards use the lift (rim 0.12); grain is not on ordinary cards. |
|
|
44
|
+
| 13 | Formatters | `utils/format/{number,time,workout}`. No component-local `formatX` or inline `toFixed`; lint enforces after migration. |
|
|
45
|
+
| 14 | Storybook tree | Six groups: `Foundations/` · `Components/Atoms|Molecules|Organisms/` (ui/* only) · `Custom/<Family>/` · `Shell/` · `Pages/` · `Lab/<Family>/` (src/lab only). |
|
|
46
|
+
| 15 | Lint | One mechanism: the per-family token-purity error block, extended everywhere; baseline retired at zero. |
|
|
47
|
+
| 16 | Light mode | Deferred. Task filed. Not a target for any family until the dark port is done. |
|
|
48
|
+
|
|
49
|
+
## Epics, in order
|
|
50
|
+
|
|
51
|
+
**E1 · Depth follow-ups** (after #166; starts now)
|
|
52
|
+
- 13 `ui/*` overlays (autocomplete, drawer, help-tip, indicator, menu, modal, popover, select, switch, tabs, toast, toolbar-button, tooltip) move from Tailwind `shadow-*` + hairline ring to the floating lift recipe. Done when `grep -rE "shadow-(sm|md|lg|xl|2xl)" src/components/ui` is empty.
|
|
53
|
+
- Delete `utils/useTheme.ts`.
|
|
54
|
+
- Replace literal-hex pins in `Surface.test.tsx`, `surface.contract.test.ts`, `Card.test.tsx`, `elevation.test.ts` with `greyRamp[...]` references.
|
|
55
|
+
- Purge stale comments: `SessionRail.stories.tsx:40`, `utils/colors.ts:4`, `SessionRail.tsx:16-17`, the skill's `gotchas.md` "Neumorphic depth" section.
|
|
56
|
+
- Delete the `lab/north-star/surfaces.ts` fork and `DualGhostLine`'s local copies; point lab at `theme/materials`.
|
|
57
|
+
- Glow shadows (StatusDot ×7, Indicator, MesoCard, BodyMap, ZoneTrack, IntensityBar, PrHistoryModal) route through `getGlowShadow`.
|
|
58
|
+
|
|
59
|
+
**E4 · Storybook reorganisation** (can run beside E1 on non-overlapping files)
|
|
60
|
+
- Retitle onto the six-group tree; fix `Composes` links.
|
|
61
|
+
- Move the 8 `Lab/`-titled files out of `src/components` (they publish to npm today).
|
|
62
|
+
- Delete duplicate `Lab/ActiveWork/*` (6), `Lab/Components/*` (3), `Lab/Archive/Surface`, each with a REJECTED.md entry.
|
|
63
|
+
- ASCII titles; one naming convention per family.
|
|
64
|
+
- `autodocs` + a `Composes` line on every hardened story; decorators compose `<Surface level="base">`.
|
|
65
|
+
- Thin per-state stories to Default + controls (Input 15, Card 14, Alert 14, Toast 13).
|
|
66
|
+
|
|
67
|
+
**E5 · Governance refresh** (after E4 so tags land on final titles)
|
|
68
|
+
- Regenerate `arch-graph.json`; CI fails when it is older than the newest `index.ts`.
|
|
69
|
+
- REJECTED.md backfill for the ten archived directions plus retired `inset`, `tonalFill`/`ditherTile`, `data-1..10`.
|
|
70
|
+
- `status:` tags; MATURITY review for `ui/*` (38 primitives, not 52).
|
|
71
|
+
- READMEs for `ui/*`, charts, Prose; fix Fatigue README's StatusDot line.
|
|
72
|
+
- Update the workflow skill's `gotchas.md` and `06-lint-guardrails.md`.
|
|
73
|
+
|
|
74
|
+
**E2 · Consolidation** (decisions 1, 3, 4, 5, 10, 11)
|
|
75
|
+
- Card as sole container; Tile and Section as presets; loose `bg-surface-*` Views (58 sites) onto Card.
|
|
76
|
+
- Pill primitive + presets; `Chip` loses `neutral-*`/`text-white`.
|
|
77
|
+
- Divider everywhere (21 rules). Indicator over StatusDot. Metric absorbs MetricTiles; MetricCell deleted. HelpTip deleted.
|
|
78
|
+
- Each retired export: `@deprecated` first, then a consumer-update task per downstream repo.
|
|
79
|
+
|
|
80
|
+
**E3 · Port Workout and Fatigue** (decisions 7, 8, 9, 13, 15)
|
|
81
|
+
- Typography + Eyebrow into `ui/`; `theme/color-math.ts`; `utils/format/*`.
|
|
82
|
+
- Workout batches from the 2026-09-08 audit, smallest drift and most consumers first:
|
|
83
|
+
- B1 (S): MetricCell, SetStrip, SetTableHeader, SetsRepsLoad, ExerciseHeading, ExerciseIndicator, ExerciseCardHeading, PrBadge.
|
|
84
|
+
- B2 (M): SegmentedBar, MuscleGroupChip, PlaceholderStrip, ScheduleTiles, StatusPill, SupersetWrapper, MesoProgressBar, Sparkline, VolumeLandmarkBar, SessionHeader, WeekRow, WorkoutCard.
|
|
85
|
+
- B3 (M): StatusDot (6 cross-family consumers), WeightBadge (the one render-path `getSemanticColors('dark')` bug, lines 46 and 105), ExerciseCard, SetRow, SetBar, WorkoutPill.
|
|
86
|
+
- B4 (M/L): InputBar, PrHistoryModal, RestTimer, SessionRail, BodyMap (the pattern to copy: three correct `resolveColor` calls; one leftover module constant), MesoCard.
|
|
87
|
+
- B5 (L): MesoStatusCard (drift 40, highest), TempoDisplay, BodyMapDetailPanel, StrengthTrendChart, ZoneTrack, CapacityBandChart, IntensityBar, ReadinessCheck, the five page organisms, VelocityStrip (1,468 lines).
|
|
88
|
+
- Fatigue: 9 module constants, local colour math.
|
|
89
|
+
- `ui/*`: 81 raw `Text` onto Typography; Button `#ffffff`, Alert `bg-black`, Tooltip `bg-neutral-800`, Spinner hex.
|
|
90
|
+
- Lint: every family in the error block; delete `raw-color-baseline.json` at zero.
|
|
91
|
+
- Move `velocity-story-kit.tsx` and `setHeadingKit.tsx` out of `components/`.
|
|
92
|
+
|
|
93
|
+
**E6 · Code-quality floor** (independent)
|
|
94
|
+
- Split the 29 functions over 100 lines (four charts >300 lines; VelocityStrip).
|
|
95
|
+
- eslint warnings 81 → 0. `axe` in the 16 test files lacking it. Delete the 18 gitignored `tmp-*.mjs`.
|
|
96
|
+
|
|
97
|
+
## Consumer follow-ups (one task per repo when E2 lands)
|
|
98
|
+
|
|
99
|
+
audiobook/frontend (Badge, Chip, StatusPill) · voltras-mcp (Pill, Badge, PrBadge, MuscleGroupChip, MetricTiles, StatusPill type) · voltras mobile (Card, Metric, Section, SectionHeader, `getSemanticColors`/`alpha`) · codewatch (Badge, Metric) · voltras-mcp-wave0 and codewatch-wt-c76 (stale forks: retire or repoint).
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Render tests and the visual-baseline layers
|
|
2
|
+
|
|
3
|
+
What a render test proves in this library, what it doesn't, and when to reach for one of
|
|
4
|
+
the three visual layers instead.
|
|
5
|
+
|
|
6
|
+
## What a render test is
|
|
7
|
+
|
|
8
|
+
Every component ships a `Component.test.tsx` next to it — 149 of them today, one per
|
|
9
|
+
component, each importing `render`/`screen` from `@testing-library/react`
|
|
10
|
+
(`grep -l "from '@testing-library/react'" src -r --include="*.test.tsx" | wc -l`). A
|
|
11
|
+
render test mounts the component with React Testing Library and asserts against the DOM
|
|
12
|
+
it produces: text is present, a role exists, a prop toggles an attribute, `jest-axe`
|
|
13
|
+
finds no violations. `src/components/ui/button/Button.test.tsx` is the reference shape —
|
|
14
|
+
mount variants, fire events, assert on `screen`, then an `accessibility` block running
|
|
15
|
+
`axe(container)`.
|
|
16
|
+
|
|
17
|
+
Coverage thresholds are enforced by Vitest, scoped to components only
|
|
18
|
+
(`vitest.config.ts:26-31`):
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
coverage: {
|
|
22
|
+
include: ['src/components/**/*.{ts,tsx}'],
|
|
23
|
+
exclude: ['src/**/*.stories.tsx', 'src/**/*.test.tsx', 'src/**/index.ts'],
|
|
24
|
+
thresholds: { statements: 80, branches: 80, functions: 80, lines: 80 },
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What it does NOT prove
|
|
29
|
+
|
|
30
|
+
**A render test that asserts a component mounts and toggles does not prove it renders
|
|
31
|
+
correctly.** Testing Library's queries only see whatever the test environment's DOM
|
|
32
|
+
diffing actually produced — and that instrumentation can miss a real defect even when a
|
|
33
|
+
component is visibly broken. VW-100's fix for `AdvancedAccordion` hit this directly: a
|
|
34
|
+
deliberately-broken control produced **zero warnings** under the (React Native) jest-expo
|
|
35
|
+
harness, because the strict-mode instrumentation needed a real React fiber render pass
|
|
36
|
+
that harness wasn't doing. The render test only proved the component mounted and
|
|
37
|
+
toggled — not that it looked right. Titan's own render tests use a real browser DOM via
|
|
38
|
+
jsdom + RTL rather than jest-expo, which is a stronger environment, but the underlying
|
|
39
|
+
limit is the same: **DOM assertions do not check pixels.** Nothing in this suite is
|
|
40
|
+
visual proof. That's what the three layers below are for. Don't read a green render
|
|
41
|
+
suite, or green coverage numbers, as evidence a component looks correct — only that its
|
|
42
|
+
DOM/behavior contract holds.
|
|
43
|
+
|
|
44
|
+
## The three visual layers, and when to reach for each
|
|
45
|
+
|
|
46
|
+
Titan runs `@playwright/test` `^1.58.2` (`packages/ui/package.json`) against four
|
|
47
|
+
configs. Three are wired into `.github/workflows/visual.yml`; the fourth is a local-only
|
|
48
|
+
dev harness (see below).
|
|
49
|
+
|
|
50
|
+
| Layer | Config | Script | What it actually checks |
|
|
51
|
+
| ---------------------------------- | ------------------------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| 1 — component screenshot baselines | `playwright.baseline.config.ts` | `test:visual:baseline` | Boots the specimen dev server (`pnpm specimen`, port 5200) and runs `specimen/baseline/**/*.screenshot.test.ts` against committed `*-chromium-linux.png` baselines, `maxDiffPixelRatio: 0.01`. 68 baselines exist today, generated from the pinned `mcr.microsoft.com/playwright:v1.58.2-noble` container so they're byte-comparable to CI. |
|
|
53
|
+
| 2 — Storybook story baselines | `playwright.config.ts` (the default) | `test:visual:stories` | Boots Storybook (`pnpm storybook --ci`, port 6006) and runs `tests/visual/stories.spec.ts`, which enumerates `index.json` and screenshots every story matching `SCOPE = /^(shell-\|icons-\|icons--)/` — today that's the shell family plus the icon primitive, not the whole library. The clock is frozen and CSS animations disabled so control-driven/animated stories snapshot deterministically. |
|
|
54
|
+
| 3 — HTML-vs-React parity | `playwright.comparison.config.ts` | `test:visual:compare` | Boots the specimen dev server and runs `specimen/**/*.visual.test.ts`: a computed-style comparison between a hand-written HTML reference and the React/NativeWind render of the same component, to catch NativeWind/RNW output drifting from the intended CSS. |
|
|
55
|
+
| — token-resolution harness | `playwright.tokens.config.ts` | `test:visual:tokens` | Runs `specimen/token-resolution.spec.ts` against the specimen server. Not referenced anywhere in `.github/workflows/`, so it is a **local-only dev tool** — it does not gate anything today. |
|
|
56
|
+
|
|
57
|
+
Two files under `tests/visual/` — `visual.spec.ts` (a bare "storybook loads" smoke check)
|
|
58
|
+
and `validation.spec.ts` (ad hoc, assertion-free screenshot capture to
|
|
59
|
+
`tests/visual/validation/`) — exist but aren't targeted by any `package.json` script or
|
|
60
|
+
CI step. They're leftover/manual tooling, not part of the gated pattern; don't treat them
|
|
61
|
+
as covering anything.
|
|
62
|
+
|
|
63
|
+
**When to reach for which:** a render test for behavior/a11y on every component, always.
|
|
64
|
+
Layer 3 when you're worried NativeWind's web output has drifted from what the class names
|
|
65
|
+
should compute to. Layer 1 when you want a pixel-exact regression gate on a specific
|
|
66
|
+
component in isolation. Layer 2 when the thing you're worried about only shows up in a
|
|
67
|
+
real Storybook story (composition, controls, live/animated state) rather than the
|
|
68
|
+
specimen harness.
|
|
69
|
+
|
|
70
|
+
## Do the visual layers actually run on pull requests?
|
|
71
|
+
|
|
72
|
+
**Partially.** `.github/workflows/visual.yml` triggers on `push`/`pull_request` to
|
|
73
|
+
`main`, and Layers 1 and 3 run their real gating scripts (`test:visual:baseline`,
|
|
74
|
+
`test:visual:compare`) — a pixel or computed-style mismatch fails the PR. **Layer 2 does
|
|
75
|
+
not currently gate anything**: the CI step runs `test:visual:stories:update` (the
|
|
76
|
+
`--update-snapshots` seed variant), not the gate, because baselines for it aren't
|
|
77
|
+
committed yet — the workflow's own comment calls this out as a bootstrap step and
|
|
78
|
+
documents the two-line change (commit the seeded PNGs, swap the script to
|
|
79
|
+
`test:visual:stories`) that would turn it into a real gate. Until that happens, a story
|
|
80
|
+
visual regression in the shell/icons scope will not fail your PR.
|
|
81
|
+
|
|
82
|
+
## Where a new component's test goes, and its minimal shape
|
|
83
|
+
|
|
84
|
+
`Component.test.tsx` sits beside `Component.tsx` in `src/components/ui/<name>/` (or
|
|
85
|
+
`custom/<Family>/`), per the file-structure convention in the repo's `CLAUDE.md`.
|
|
86
|
+
Minimal shape, following `Button.test.tsx`:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { describe, it, expect } from 'vitest'
|
|
90
|
+
import { render, screen } from '@testing-library/react'
|
|
91
|
+
import { axe } from 'jest-axe'
|
|
92
|
+
import { Component } from './Component'
|
|
93
|
+
|
|
94
|
+
describe('Component', () => {
|
|
95
|
+
it('renders correctly', () => {
|
|
96
|
+
render(<Component />)
|
|
97
|
+
// assert on screen.getBy...
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('has no accessibility violations', async () => {
|
|
101
|
+
const { container } = render(<Component />)
|
|
102
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A new component does not automatically get a Layer 1/2/3 visual test — those are opted
|
|
108
|
+
into per-component (Layer 1) or per-story-scope (Layer 2), and per hand-written reference
|
|
109
|
+
(Layer 3). Nothing in the current config auto-enrolls a new component into any of them.
|
|
110
|
+
|
|
111
|
+
## How the visual baselines are updated, and what a moved baseline means in review
|
|
112
|
+
|
|
113
|
+
- **Layer 1** (`test:visual:baseline:update`) regenerates `*-chromium-linux.png` under
|
|
114
|
+
`specimen/baseline/**/*.screenshot.test.ts-snapshots/`. `visual.yml` always runs this
|
|
115
|
+
step (`if: always()`) in the same pinned container as the gate and uploads the result
|
|
116
|
+
as the `component-visual-baselines` artifact, so a genuinely-changed component's
|
|
117
|
+
baseline comes back different while every unchanged one is byte-identical — no local
|
|
118
|
+
rendering noise. Refreshing means: download that artifact, commit the changed PNGs.
|
|
119
|
+
- **Layer 2** (`test:visual:stories:update`) regenerates
|
|
120
|
+
`tests/visual/reference/stories.spec.ts-snapshots/` the same way, uploaded as
|
|
121
|
+
`storybook-visual-baselines`; per the previous section this currently runs
|
|
122
|
+
unconditionally (it's the seed step, not a gate).
|
|
123
|
+
- **Layer 3** has no baseline images to move — it's a computed-style comparison, not a
|
|
124
|
+
screenshot diff.
|
|
125
|
+
|
|
126
|
+
**A moved baseline in review is a rendering change, not a rubber stamp.** Because Layer 1
|
|
127
|
+
baselines are only ever regenerated in the pinned container, a diff limited to the
|
|
128
|
+
changed component's PNG(s) is a real signal that its markup or styles moved — reviewers
|
|
129
|
+
should ask what changed and why, the same as any other diff, rather than treating "CI
|
|
130
|
+
regenerated it" as self-justifying.
|
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { useEffect, useMemo, useState } from 'react'
|
|
3
3
|
import { getSemanticColors } from '../theme/tokens/semantic'
|
|
4
|
+
import { primitiveColors } from '../theme/tokens/primitives'
|
|
5
|
+
import { alpha } from '../utils/colors'
|
|
4
6
|
import graph from './arch-graph.json'
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -396,7 +398,7 @@ function RenderModal({
|
|
|
396
398
|
style={{
|
|
397
399
|
position: 'fixed',
|
|
398
400
|
inset: 0,
|
|
399
|
-
background:
|
|
401
|
+
background: alpha(primitiveColors.black, 0.66),
|
|
400
402
|
display: 'flex',
|
|
401
403
|
alignItems: 'center',
|
|
402
404
|
justifyContent: 'center',
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
// @ts-expect-error — plain-ESM build tooling, shared with scripts/arch-graph.mjs
|
|
6
|
+
import { componentBarrelHash } from '../../scripts/barrel-hash.mjs'
|
|
7
|
+
import graph from './arch-graph.json'
|
|
8
|
+
|
|
9
|
+
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
|
10
|
+
const REPO_ROOT = path.resolve(PKG_ROOT, '../..')
|
|
11
|
+
|
|
12
|
+
describe('arch-graph.json freshness', () => {
|
|
13
|
+
it('records the barrel hash it was generated from', () => {
|
|
14
|
+
expect(graph.componentBarrelHash).toMatch(/^sha256:[0-9a-f]{64}$/)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('matches the current component barrels', () => {
|
|
18
|
+
expect(
|
|
19
|
+
graph.componentBarrelHash,
|
|
20
|
+
'arch-graph.json is stale: a component barrel changed since it was generated. ' +
|
|
21
|
+
'Run `pnpm arch:graph -- --reindex` from the repo root and commit the result.'
|
|
22
|
+
).toBe(componentBarrelHash(PKG_ROOT))
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('tallies every configured consumer, so none can be silently scored as zero usage', () => {
|
|
26
|
+
const configured = graph.summary.consumers.map((c) => c.name)
|
|
27
|
+
for (const component of graph.components) {
|
|
28
|
+
expect(
|
|
29
|
+
Object.keys(component.xproj)
|
|
30
|
+
.filter((k) => k !== 'total')
|
|
31
|
+
.sort(),
|
|
32
|
+
`${component.name}.xproj is missing a configured consumer. A consumer absent from ` +
|
|
33
|
+
'the tally scores 0 usage, which lands its components on the `dead` list.'
|
|
34
|
+
).toEqual([...configured].sort())
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// The consumer list is committed precisely so every machine computes the same
|
|
39
|
+
// `dead` verdicts. Adding a consumer without regenerating leaves a graph that
|
|
40
|
+
// looks authoritative and is wrong about the repo that was just added.
|
|
41
|
+
it('was generated from the committed consumer list', () => {
|
|
42
|
+
const shared = JSON.parse(
|
|
43
|
+
readFileSync(path.join(REPO_ROOT, 'scripts/arch.config.json'), 'utf8')
|
|
44
|
+
) as { consumers: { name: string }[] }
|
|
45
|
+
|
|
46
|
+
expect(
|
|
47
|
+
graph.summary.consumers.map((c) => c.name).sort(),
|
|
48
|
+
'arch-graph.json was generated from a different consumer set than ' +
|
|
49
|
+
'scripts/arch.config.json. Run `pnpm arch:graph -- --reindex` and commit the result.'
|
|
50
|
+
).toEqual(shared.consumers.map((c) => c.name).sort())
|
|
51
|
+
})
|
|
52
|
+
})
|