@titan-design/react-ui 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -47
- package/dist/bodymap.js +768 -701
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +770 -703
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1320 -215
- package/dist/index.d.ts +1320 -215
- package/dist/index.js +5996 -4498
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5773 -4357
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
- package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1435 -1428
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1443 -1436
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +202 -1042
- package/dist/theme/index.d.ts +202 -1042
- package/dist/theme/index.js +215 -300
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +202 -296
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +62 -5
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +62 -5
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +972 -0
- package/dist/theme/tokens.d.ts +972 -0
- package/dist/theme/tokens.js +904 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/tokens.mjs +880 -0
- package/dist/theme/tokens.mjs.map +1 -0
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/package.json +7 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +5021 -1617
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +4 -1
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +116 -14
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +98 -15
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +7 -2
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +3 -0
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +3 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +21 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
- package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +4 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +12 -9
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +12 -7
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/index.ts +5 -0
- package/src/components/custom/Workout/metricText.stories.tsx +6 -5
- package/src/components/custom/Workout/metricText.tsx +4 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
- package/src/components/custom/charts/README.md +61 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
- package/src/components/custom/charts/SetBarChart.tsx +42 -4
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +13 -28
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +90 -27
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +32 -25
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +6 -26
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -30
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +2 -12
- package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +29 -19
- package/src/components/ui/pill/Pill.stories.tsx +58 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +164 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +5 -7
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +5 -14
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +14 -14
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +1 -4
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +17 -5
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +7 -22
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +43 -53
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +100 -47
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +24 -22
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +28 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +30 -2
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/token-export-guard.test.ts +102 -0
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +67 -35
- package/src/theme/tokens/semantic.ts +71 -37
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +5 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -10,7 +10,7 @@ describe('Pill', () => {
|
|
|
10
10
|
})
|
|
11
11
|
|
|
12
12
|
it('renders with all variants', () => {
|
|
13
|
-
const variants = ['subtle', 'outline'] as const
|
|
13
|
+
const variants = ['solid', 'subtle', 'outline'] as const
|
|
14
14
|
variants.forEach((variant) => {
|
|
15
15
|
const { unmount } = render(<Pill variant={variant}>Test</Pill>)
|
|
16
16
|
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
@@ -19,7 +19,15 @@ describe('Pill', () => {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
it('renders with all colors', () => {
|
|
22
|
-
const colors = [
|
|
22
|
+
const colors = [
|
|
23
|
+
'default',
|
|
24
|
+
'primary',
|
|
25
|
+
'secondary',
|
|
26
|
+
'success',
|
|
27
|
+
'error',
|
|
28
|
+
'warning',
|
|
29
|
+
'info',
|
|
30
|
+
] as const
|
|
23
31
|
colors.forEach((color) => {
|
|
24
32
|
const { unmount } = render(<Pill color={color}>Test</Pill>)
|
|
25
33
|
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
@@ -27,8 +35,25 @@ describe('Pill', () => {
|
|
|
27
35
|
})
|
|
28
36
|
})
|
|
29
37
|
|
|
38
|
+
it('renders with all tones', () => {
|
|
39
|
+
const tones = [
|
|
40
|
+
'neutral',
|
|
41
|
+
'brand',
|
|
42
|
+
'brand-secondary',
|
|
43
|
+
'success',
|
|
44
|
+
'warning',
|
|
45
|
+
'error',
|
|
46
|
+
'info',
|
|
47
|
+
] as const
|
|
48
|
+
tones.forEach((tone) => {
|
|
49
|
+
const { unmount } = render(<Pill tone={tone}>Test</Pill>)
|
|
50
|
+
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
51
|
+
unmount()
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
30
55
|
it('renders with all sizes', () => {
|
|
31
|
-
const sizes = ['xs', 'sm', 'md'] as const
|
|
56
|
+
const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
|
|
32
57
|
sizes.forEach((size) => {
|
|
33
58
|
const { unmount } = render(<Pill size={size}>Test</Pill>)
|
|
34
59
|
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
@@ -36,6 +61,60 @@ describe('Pill', () => {
|
|
|
36
61
|
})
|
|
37
62
|
})
|
|
38
63
|
|
|
64
|
+
it('renders a tone-matched dot for leading="dot"', () => {
|
|
65
|
+
render(
|
|
66
|
+
<Pill tone="success" leading="dot">
|
|
67
|
+
Active
|
|
68
|
+
</Pill>
|
|
69
|
+
)
|
|
70
|
+
expect(screen.getByTestId('pill-dot')).toBeInTheDocument()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('renders each tone with a leading dot', () => {
|
|
74
|
+
const tones = ['neutral', 'brand', 'brand-secondary', 'error'] as const
|
|
75
|
+
tones.forEach((tone) => {
|
|
76
|
+
const { unmount } = render(
|
|
77
|
+
<Pill tone={tone} leading="dot">
|
|
78
|
+
Test
|
|
79
|
+
</Pill>
|
|
80
|
+
)
|
|
81
|
+
expect(screen.getByTestId('pill-dot')).toBeInTheDocument()
|
|
82
|
+
unmount()
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('renders a leading icon node', () => {
|
|
87
|
+
render(<Pill leading={<span data-testid="icon" />}>Label</Pill>)
|
|
88
|
+
expect(screen.getByTestId('icon')).toBeInTheDocument()
|
|
89
|
+
expect(screen.queryByTestId('pill-dot')).not.toBeInTheDocument()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('renders a trailing slot', () => {
|
|
93
|
+
render(<Pill trailing={<span data-testid="dismiss" />}>Label</Pill>)
|
|
94
|
+
expect(screen.getByTestId('dismiss')).toBeInTheDocument()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('does not fire onPress when disabled', () => {
|
|
98
|
+
const handler = vi.fn()
|
|
99
|
+
render(
|
|
100
|
+
<Pill onPress={handler} isDisabled>
|
|
101
|
+
Click
|
|
102
|
+
</Pill>
|
|
103
|
+
)
|
|
104
|
+
fireEvent.click(screen.getByRole('button'))
|
|
105
|
+
expect(handler).not.toHaveBeenCalled()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('maps the legacy color prop onto a tone', () => {
|
|
109
|
+
render(
|
|
110
|
+
<Pill color="primary" leading="dot">
|
|
111
|
+
Legacy
|
|
112
|
+
</Pill>
|
|
113
|
+
)
|
|
114
|
+
expect(screen.getByText('Legacy')).toBeInTheDocument()
|
|
115
|
+
expect(screen.getByTestId('pill-dot')).toBeInTheDocument()
|
|
116
|
+
})
|
|
117
|
+
|
|
39
118
|
it('applies rounded-full by default', () => {
|
|
40
119
|
const { container } = render(<Pill>Test</Pill>)
|
|
41
120
|
expect(container.firstChild).toBeInTheDocument()
|
|
@@ -65,5 +144,24 @@ describe('Pill', () => {
|
|
|
65
144
|
const results = await axe(container)
|
|
66
145
|
expect(results).toHaveNoViolations()
|
|
67
146
|
})
|
|
147
|
+
|
|
148
|
+
it('has no accessibility violations with a leading dot', async () => {
|
|
149
|
+
const { container } = render(
|
|
150
|
+
<Pill tone="success" leading="dot">
|
|
151
|
+
Active
|
|
152
|
+
</Pill>
|
|
153
|
+
)
|
|
154
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('has no accessibility violations when interactive', async () => {
|
|
158
|
+
const { container } = render(<Pill onPress={() => {}}>Filter</Pill>)
|
|
159
|
+
expect(await axe(container)).toHaveNoViolations()
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('exposes a button role when interactive', () => {
|
|
163
|
+
render(<Pill onPress={() => {}}>Filter</Pill>)
|
|
164
|
+
expect(screen.getByRole('button')).toBeInTheDocument()
|
|
165
|
+
})
|
|
68
166
|
})
|
|
69
167
|
})
|
|
@@ -2,102 +2,217 @@ import React from 'react'
|
|
|
2
2
|
import { View, Text, Pressable, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
4
|
|
|
5
|
-
export type PillVariant = 'subtle' | 'outline'
|
|
6
|
-
|
|
7
|
-
export type
|
|
5
|
+
export type PillVariant = 'solid' | 'subtle' | 'outline'
|
|
6
|
+
/** Semantic tone. `brand-secondary` is the accent, not a second brand. */
|
|
7
|
+
export type PillTone =
|
|
8
|
+
| 'neutral'
|
|
9
|
+
| 'brand'
|
|
10
|
+
| 'brand-secondary'
|
|
11
|
+
| 'success'
|
|
12
|
+
| 'warning'
|
|
13
|
+
| 'error'
|
|
14
|
+
| 'info'
|
|
15
|
+
/** Legacy palette names, kept so existing `color=` call sites keep working. */
|
|
16
|
+
export type PillColor =
|
|
17
|
+
| 'default'
|
|
18
|
+
| 'primary'
|
|
19
|
+
| 'secondary'
|
|
20
|
+
| 'success'
|
|
21
|
+
| 'error'
|
|
22
|
+
| 'warning'
|
|
23
|
+
| 'info'
|
|
24
|
+
export type PillSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
8
25
|
|
|
9
26
|
export interface PillProps extends ViewProps {
|
|
10
27
|
/** Pill content */
|
|
11
|
-
children
|
|
28
|
+
children?: React.ReactNode
|
|
12
29
|
/** Visual variant */
|
|
13
30
|
variant?: PillVariant
|
|
14
|
-
/**
|
|
31
|
+
/** Semantic tone */
|
|
32
|
+
tone?: PillTone
|
|
33
|
+
/** @deprecated Use `tone` — `color` maps onto it and is kept for call-site compatibility. */
|
|
15
34
|
color?: PillColor
|
|
16
35
|
/** Size */
|
|
17
36
|
size?: PillSize
|
|
18
37
|
/** Fully rounded (default true) or slight radius */
|
|
19
38
|
rounded?: boolean
|
|
20
|
-
/**
|
|
39
|
+
/** Leading slot: `'dot'` renders a tone-matched dot, any node renders as-is. */
|
|
40
|
+
leading?: React.ReactNode | 'dot'
|
|
41
|
+
/**
|
|
42
|
+
* Colour the leading dot independently of the capsule. For the pattern where
|
|
43
|
+
* the label is neutral and only the dot carries status, so a row of chips
|
|
44
|
+
* stays quiet and the dots are the signal.
|
|
45
|
+
*/
|
|
46
|
+
dotTone?: PillTone
|
|
47
|
+
/** @deprecated Use `leading`. */
|
|
21
48
|
leftElement?: React.ReactNode
|
|
49
|
+
/** Trailing slot (dismiss affordance, counter) */
|
|
50
|
+
trailing?: React.ReactNode
|
|
22
51
|
/** Press handler (makes pill interactive) */
|
|
23
52
|
onPress?: () => void
|
|
24
|
-
/**
|
|
53
|
+
/** Non-interactive and dimmed */
|
|
54
|
+
isDisabled?: boolean
|
|
55
|
+
/** Additional className on the container */
|
|
25
56
|
className?: string
|
|
57
|
+
/** Additional className on the label, for presets that own their typography */
|
|
58
|
+
textClassName?: string
|
|
26
59
|
}
|
|
27
60
|
|
|
28
|
-
const
|
|
61
|
+
const colorToTone: Record<PillColor, PillTone> = {
|
|
62
|
+
default: 'neutral',
|
|
63
|
+
primary: 'brand',
|
|
64
|
+
secondary: 'brand-secondary',
|
|
65
|
+
success: 'success',
|
|
66
|
+
error: 'error',
|
|
67
|
+
warning: 'warning',
|
|
68
|
+
info: 'info',
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const toneStyles: Record<PillVariant, Record<PillTone, string>> = {
|
|
72
|
+
solid: {
|
|
73
|
+
neutral: 'bg-hairline-strong border-transparent text-text-inverse',
|
|
74
|
+
brand: 'bg-brand-primary border-transparent text-text-inverse',
|
|
75
|
+
'brand-secondary': 'bg-brand-secondary border-transparent text-text-inverse',
|
|
76
|
+
success: 'bg-status-success border-transparent text-text-inverse',
|
|
77
|
+
warning: 'bg-status-warning border-transparent text-text-inverse',
|
|
78
|
+
error: 'bg-status-error border-transparent text-text-inverse',
|
|
79
|
+
info: 'bg-status-info border-transparent text-text-inverse',
|
|
80
|
+
},
|
|
29
81
|
subtle: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
82
|
+
// Alpha-white rather than a ramp step: a pill sits on whatever plane its
|
|
83
|
+
// host is, and an alpha fill composites by the same amount on all of them.
|
|
84
|
+
// A `surface-*` fill would vanish on the plane it names. Borderless like the
|
|
85
|
+
// six coloured tones — the fill carries the capsule, not a ring.
|
|
86
|
+
neutral: 'bg-hairline-subtle border-transparent text-text-secondary',
|
|
87
|
+
brand: 'bg-brand-primary-subtle border-transparent text-brand-primary',
|
|
88
|
+
'brand-secondary': 'bg-brand-secondary-subtle border-transparent text-brand-secondary',
|
|
89
|
+
success: 'bg-status-success-subtle border-transparent text-status-success',
|
|
90
|
+
warning: 'bg-status-warning-subtle border-transparent text-status-warning',
|
|
91
|
+
error: 'bg-status-error-subtle border-transparent text-status-error',
|
|
92
|
+
info: 'bg-status-info-subtle border-transparent text-status-info',
|
|
37
93
|
},
|
|
38
94
|
outline: {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
secondary: 'border-brand-secondary text-brand-secondary',
|
|
95
|
+
neutral: 'border-hairline text-text-secondary',
|
|
96
|
+
brand: 'border-brand-primary text-brand-primary',
|
|
97
|
+
'brand-secondary': 'border-brand-secondary text-brand-secondary',
|
|
42
98
|
success: 'border-status-success text-status-success',
|
|
43
|
-
error: 'border-status-error text-status-error',
|
|
44
99
|
warning: 'border-status-warning text-status-warning',
|
|
100
|
+
error: 'border-status-error text-status-error',
|
|
45
101
|
info: 'border-status-info text-status-info',
|
|
46
102
|
},
|
|
47
103
|
}
|
|
48
104
|
|
|
105
|
+
const dotToneStyles: Record<PillTone, string> = {
|
|
106
|
+
neutral: 'bg-text-tertiary',
|
|
107
|
+
brand: 'bg-brand-primary',
|
|
108
|
+
'brand-secondary': 'bg-brand-secondary',
|
|
109
|
+
success: 'bg-status-success',
|
|
110
|
+
warning: 'bg-status-warning',
|
|
111
|
+
error: 'bg-status-error',
|
|
112
|
+
info: 'bg-status-info',
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// One text step per rung. `md` used to repeat `sm`'s 10px, which left no 12px
|
|
116
|
+
// capsule at all and pushed anything between the two down to 10px — that is how
|
|
117
|
+
// MuscleGroupChip lost 7px of height. `md` is the 12px rung now.
|
|
49
118
|
const sizeStyles: Record<PillSize, { container: string; text: string }> = {
|
|
50
|
-
xs: { container: 'px-1 py-px', text: 'text-
|
|
51
|
-
sm: { container: 'px-2 py-0.5', text: 'text-
|
|
52
|
-
md: { container: 'px-2 py-1', text: 'text-
|
|
119
|
+
xs: { container: 'px-1 py-px', text: 'text-3xs' },
|
|
120
|
+
sm: { container: 'px-2 py-0.5', text: 'text-2xs' },
|
|
121
|
+
md: { container: 'px-2.5 py-1', text: 'text-xs' },
|
|
122
|
+
lg: { container: 'px-3 py-1.5', text: 'text-sm' },
|
|
123
|
+
xl: { container: 'px-4 py-2', text: 'text-base' },
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The dot derives its testID from the pill's, so a preset's dot stays
|
|
127
|
+
// addressable under the preset's own name (`muscle-group-chip-dot`) instead of
|
|
128
|
+
// collapsing to a generic one — the visual parity layer targets it by name.
|
|
129
|
+
function PillDot({ tone, testID }: { tone: PillTone; testID?: string }) {
|
|
130
|
+
return (
|
|
131
|
+
<View
|
|
132
|
+
className={cn('w-1.5 h-1.5 rounded-full shrink-0', dotToneStyles[tone])}
|
|
133
|
+
accessibilityElementsHidden
|
|
134
|
+
testID={testID ? `${testID}-dot` : 'pill-dot'}
|
|
135
|
+
/>
|
|
136
|
+
)
|
|
53
137
|
}
|
|
54
138
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
variant = 'subtle',
|
|
58
|
-
color = 'default',
|
|
59
|
-
size = 'sm',
|
|
60
|
-
rounded = true,
|
|
61
|
-
leftElement,
|
|
62
|
-
onPress,
|
|
63
|
-
className,
|
|
64
|
-
...props
|
|
65
|
-
}: PillProps) {
|
|
66
|
-
const containerClasses = cn(
|
|
139
|
+
function containerClasses(p: PillProps, tone: PillTone) {
|
|
140
|
+
return cn(
|
|
67
141
|
'flex-row items-center gap-1 border self-start shrink-0',
|
|
68
|
-
rounded ? 'rounded
|
|
69
|
-
|
|
70
|
-
sizeStyles[size].container,
|
|
71
|
-
|
|
142
|
+
p.rounded === false ? 'rounded' : 'rounded-full',
|
|
143
|
+
toneStyles[p.variant ?? 'subtle'][tone],
|
|
144
|
+
sizeStyles[p.size ?? 'sm'].container,
|
|
145
|
+
p.isDisabled && 'opacity-50',
|
|
146
|
+
p.className
|
|
72
147
|
)
|
|
148
|
+
}
|
|
73
149
|
|
|
150
|
+
function PillContent({ tone, ...p }: PillProps & { tone: PillTone }) {
|
|
74
151
|
const textClasses = cn(
|
|
75
|
-
'font-heading font-semibold',
|
|
76
|
-
sizeStyles[size].text,
|
|
77
|
-
|
|
152
|
+
'font-heading font-semibold text-inherit',
|
|
153
|
+
sizeStyles[p.size ?? 'sm'].text,
|
|
154
|
+
p.textClassName
|
|
78
155
|
)
|
|
79
|
-
|
|
80
|
-
|
|
156
|
+
const slot = p.leading ?? p.leftElement
|
|
157
|
+
return (
|
|
81
158
|
<>
|
|
82
|
-
{
|
|
83
|
-
{typeof children === 'string' ? (
|
|
84
|
-
<Text className={textClasses}>{children}</Text>
|
|
159
|
+
{slot === 'dot' ? <PillDot tone={p.dotTone ?? tone} testID={p.testID} /> : slot}
|
|
160
|
+
{typeof p.children === 'string' ? (
|
|
161
|
+
<Text className={textClasses}>{p.children}</Text>
|
|
85
162
|
) : (
|
|
86
|
-
children
|
|
163
|
+
p.children
|
|
87
164
|
)}
|
|
165
|
+
{p.trailing}
|
|
88
166
|
</>
|
|
89
167
|
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The single pill primitive: a capsule of tone-coloured label with optional
|
|
172
|
+
* leading and trailing slots. `Badge`, `Chip`, `StatusPill` and
|
|
173
|
+
* `MuscleGroupChip` are presets over it.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* <Pill tone="success" leading="dot">Active</Pill>
|
|
177
|
+
*/
|
|
178
|
+
export function Pill(props: PillProps) {
|
|
179
|
+
const {
|
|
180
|
+
variant,
|
|
181
|
+
tone,
|
|
182
|
+
color,
|
|
183
|
+
size,
|
|
184
|
+
rounded,
|
|
185
|
+
leading,
|
|
186
|
+
dotTone,
|
|
187
|
+
leftElement,
|
|
188
|
+
trailing,
|
|
189
|
+
onPress,
|
|
190
|
+
isDisabled,
|
|
191
|
+
className,
|
|
192
|
+
textClassName,
|
|
193
|
+
children,
|
|
194
|
+
...viewProps
|
|
195
|
+
} = props
|
|
196
|
+
const resolvedTone = tone ?? (color ? colorToTone[color] : 'neutral')
|
|
197
|
+
const classes = containerClasses(props, resolvedTone)
|
|
198
|
+
const content = <PillContent {...props} tone={resolvedTone} />
|
|
90
199
|
|
|
91
200
|
if (onPress) {
|
|
92
201
|
return (
|
|
93
|
-
<Pressable
|
|
202
|
+
<Pressable
|
|
203
|
+
onPress={onPress}
|
|
204
|
+
disabled={isDisabled}
|
|
205
|
+
accessibilityRole="button"
|
|
206
|
+
className={classes}
|
|
207
|
+
{...viewProps}
|
|
208
|
+
>
|
|
94
209
|
{content}
|
|
95
210
|
</Pressable>
|
|
96
211
|
)
|
|
97
212
|
}
|
|
98
213
|
|
|
99
214
|
return (
|
|
100
|
-
<View className={
|
|
215
|
+
<View className={classes} {...viewProps}>
|
|
101
216
|
{content}
|
|
102
217
|
</View>
|
|
103
218
|
)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Pill } from './Pill'
|
|
2
|
-
export type { PillProps, PillVariant, PillColor, PillSize } from './Pill'
|
|
2
|
+
export type { PillProps, PillVariant, PillTone, PillColor, PillSize } from './Pill'
|
|
@@ -124,15 +124,15 @@ export const WithCloseButton: Story = {
|
|
|
124
124
|
</Button>
|
|
125
125
|
</PopoverTrigger>
|
|
126
126
|
<PopoverContent>
|
|
127
|
-
<View
|
|
127
|
+
<View
|
|
128
|
+
style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}
|
|
129
|
+
>
|
|
128
130
|
<Text className="text-text-primary text-sm font-semibold">Settings</Text>
|
|
129
131
|
<PopoverCloseButton>
|
|
130
132
|
<Text className="text-text-secondary text-lg">✕</Text>
|
|
131
133
|
</PopoverCloseButton>
|
|
132
134
|
</View>
|
|
133
|
-
<Text className="text-text-secondary text-sm mt-2">
|
|
134
|
-
Configure your preferences here.
|
|
135
|
-
</Text>
|
|
135
|
+
<Text className="text-text-secondary text-sm mt-2">Configure your preferences here.</Text>
|
|
136
136
|
</PopoverContent>
|
|
137
137
|
</Popover>
|
|
138
138
|
),
|
|
@@ -149,9 +149,7 @@ export const WithFormContent: Story = {
|
|
|
149
149
|
<PopoverContent>
|
|
150
150
|
<View style={{ gap: 12 }}>
|
|
151
151
|
<Text className="text-text-primary text-sm font-semibold">Edit Display Name</Text>
|
|
152
|
-
<Text className="text-text-secondary text-xs">
|
|
153
|
-
Enter your new display name below.
|
|
154
|
-
</Text>
|
|
152
|
+
<Text className="text-text-secondary text-xs">Enter your new display name below.</Text>
|
|
155
153
|
<View className="bg-surface-input border border-hairline rounded-md px-3 py-2">
|
|
156
154
|
<Text className="text-text-secondary text-sm">John Doe</Text>
|
|
157
155
|
</View>
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
2
|
import { render, screen, fireEvent, act } from '@testing-library/react'
|
|
3
3
|
import { axe } from 'jest-axe'
|
|
4
|
-
import {
|
|
5
|
-
Popover,
|
|
6
|
-
PopoverTrigger,
|
|
7
|
-
PopoverContent,
|
|
8
|
-
PopoverCloseButton,
|
|
9
|
-
} from './Popover'
|
|
4
|
+
import { Popover, PopoverTrigger, PopoverContent, PopoverCloseButton } from './Popover'
|
|
10
5
|
|
|
11
6
|
describe('Popover', () => {
|
|
12
7
|
it('renders trigger element', () => {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback, createContext, useContext } from 'react'
|
|
2
2
|
import { View, Pressable, Modal, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { Surface } from '../surface'
|
|
5
|
+
import { TriggerSurface } from '../trigger'
|
|
4
6
|
|
|
5
7
|
export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right'
|
|
6
8
|
|
|
@@ -68,12 +70,15 @@ export function Popover({
|
|
|
68
70
|
const isOpen = controlledIsOpen ?? internalIsOpen
|
|
69
71
|
const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
70
72
|
|
|
71
|
-
const setIsOpen = useCallback(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
const setIsOpen = useCallback(
|
|
74
|
+
(open: boolean) => {
|
|
75
|
+
if (controlledIsOpen === undefined) {
|
|
76
|
+
setInternalIsOpen(open)
|
|
77
|
+
}
|
|
78
|
+
onOpenChange?.(open)
|
|
79
|
+
},
|
|
80
|
+
[controlledIsOpen, onOpenChange]
|
|
81
|
+
)
|
|
77
82
|
|
|
78
83
|
const handleHoverIn = useCallback(() => {
|
|
79
84
|
if (triggerMode !== 'hover') return
|
|
@@ -126,15 +131,14 @@ export function PopoverTrigger({ children, className }: PopoverTriggerProps) {
|
|
|
126
131
|
: {}
|
|
127
132
|
|
|
128
133
|
return (
|
|
129
|
-
<
|
|
130
|
-
|
|
134
|
+
<TriggerSurface
|
|
135
|
+
handlers={{ onPress: () => setIsOpen(!isOpen), ...hoverProps }}
|
|
131
136
|
accessibilityRole="button"
|
|
132
137
|
accessibilityState={{ expanded: isOpen }}
|
|
133
138
|
className={className}
|
|
134
|
-
{...hoverProps}
|
|
135
139
|
>
|
|
136
140
|
{children}
|
|
137
|
-
</
|
|
141
|
+
</TriggerSurface>
|
|
138
142
|
)
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -184,12 +188,13 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
|
|
|
184
188
|
className="fixed inset-0 z-40"
|
|
185
189
|
style={{ position: 'absolute' }}
|
|
186
190
|
/>
|
|
187
|
-
{/* Content */}
|
|
188
|
-
<
|
|
191
|
+
{/* Content — floating: overlay plane + lift, no ring. */}
|
|
192
|
+
<Surface
|
|
193
|
+
elevation={4}
|
|
194
|
+
rounded={false}
|
|
189
195
|
className={cn(
|
|
190
196
|
'absolute z-50 min-w-[200px]',
|
|
191
|
-
'
|
|
192
|
-
'p-4',
|
|
197
|
+
'rounded-lg p-4',
|
|
193
198
|
placementStyles[placement],
|
|
194
199
|
className
|
|
195
200
|
)}
|
|
@@ -208,7 +213,7 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
|
|
|
208
213
|
/>
|
|
209
214
|
)}
|
|
210
215
|
{children}
|
|
211
|
-
</
|
|
216
|
+
</Surface>
|
|
212
217
|
</>
|
|
213
218
|
)
|
|
214
219
|
}
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export { Popover, PopoverTrigger, PopoverContent, PopoverCloseButton } from './Popover'
|
|
2
|
-
export type {
|
|
2
|
+
export type {
|
|
3
|
+
PopoverProps,
|
|
4
|
+
PopoverTriggerProps,
|
|
5
|
+
PopoverContentProps,
|
|
6
|
+
PopoverCloseButtonProps,
|
|
7
|
+
PopoverPlacement,
|
|
8
|
+
} from './Popover'
|
|
@@ -5,7 +5,7 @@ import { Progress, CircularProgress, ProgressSteps } from './Progress'
|
|
|
5
5
|
const meta: Meta<typeof Progress> = {
|
|
6
6
|
title: 'Components/Molecules/Progress',
|
|
7
7
|
component: Progress,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
value: {
|
|
11
11
|
control: { type: 'range', min: 0, max: 100, step: 1 },
|
|
@@ -131,11 +131,7 @@ export const Steps: Story = {
|
|
|
131
131
|
color="success"
|
|
132
132
|
labels={['Step 1', 'Step 2', 'Step 3', 'Step 4']}
|
|
133
133
|
/>
|
|
134
|
-
<ProgressSteps
|
|
135
|
-
currentStep={0}
|
|
136
|
-
totalSteps={5}
|
|
137
|
-
size="lg"
|
|
138
|
-
/>
|
|
134
|
+
<ProgressSteps currentStep={0} totalSteps={5} size="lg" />
|
|
139
135
|
</View>
|
|
140
136
|
),
|
|
141
137
|
}
|
|
@@ -152,12 +148,7 @@ export const UsageExamples: Story = {
|
|
|
152
148
|
{/* Storage quota */}
|
|
153
149
|
<View className="p-4 bg-surface-elevated rounded-lg">
|
|
154
150
|
<Text className="text-text-primary font-medium mb-3">Storage</Text>
|
|
155
|
-
<Progress
|
|
156
|
-
value={8.5}
|
|
157
|
-
max={10}
|
|
158
|
-
color="warning"
|
|
159
|
-
label="8.5 GB of 10 GB used"
|
|
160
|
-
/>
|
|
151
|
+
<Progress value={8.5} max={10} color="warning" label="8.5 GB of 10 GB used" />
|
|
161
152
|
</View>
|
|
162
153
|
|
|
163
154
|
{/* Checkout steps */}
|
|
@@ -154,11 +154,7 @@ describe('Progress', () => {
|
|
|
154
154
|
|
|
155
155
|
it('renders labels', () => {
|
|
156
156
|
render(
|
|
157
|
-
<ProgressSteps
|
|
158
|
-
currentStep={1}
|
|
159
|
-
totalSteps={3}
|
|
160
|
-
labels={['Step 1', 'Step 2', 'Step 3']}
|
|
161
|
-
/>
|
|
157
|
+
<ProgressSteps currentStep={1} totalSteps={3} labels={['Step 1', 'Step 2', 'Step 3']} />
|
|
162
158
|
)
|
|
163
159
|
expect(screen.getByText('Step 1')).toBeInTheDocument()
|
|
164
160
|
expect(screen.getByText('Step 2')).toBeInTheDocument()
|