@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
|
@@ -2,41 +2,107 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
2
2
|
import { View } from 'react-native'
|
|
3
3
|
import { Pill } from './Pill'
|
|
4
4
|
import { Indicator } from '../indicator'
|
|
5
|
+
import { Surface } from '../surface'
|
|
6
|
+
import { Typography } from '../../custom/Typography'
|
|
5
7
|
|
|
6
8
|
const meta: Meta<typeof Pill> = {
|
|
7
9
|
title: 'Components/Atoms/Pill',
|
|
8
10
|
component: Pill,
|
|
9
|
-
tags: ['autodocs'],
|
|
11
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
10
12
|
argTypes: {
|
|
11
|
-
variant: { control: 'select', options: ['subtle', 'outline'] },
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
variant: { control: 'select', options: ['solid', 'subtle', 'outline'] },
|
|
14
|
+
tone: {
|
|
15
|
+
control: 'select',
|
|
16
|
+
options: ['neutral', 'brand', 'brand-secondary', 'success', 'warning', 'error', 'info'],
|
|
17
|
+
},
|
|
18
|
+
size: { control: 'select', options: ['xs', 'sm', 'md', 'lg', 'xl'] },
|
|
19
|
+
leading: { control: 'select', options: [undefined, 'dot'] },
|
|
14
20
|
rounded: { control: 'boolean' },
|
|
21
|
+
isDisabled: { control: 'boolean' },
|
|
15
22
|
},
|
|
16
23
|
}
|
|
17
24
|
export default meta
|
|
18
25
|
type Story = StoryObj<typeof Pill>
|
|
19
26
|
|
|
20
|
-
export const Default: Story = { args: { children: 'Label',
|
|
27
|
+
export const Default: Story = { args: { children: 'Label', tone: 'brand' } }
|
|
21
28
|
|
|
22
29
|
export const AllVariants: Story = {
|
|
23
30
|
render: () => (
|
|
24
31
|
<View className="flex-row gap-2">
|
|
25
|
-
<Pill variant="
|
|
26
|
-
|
|
32
|
+
<Pill variant="solid" tone="brand">
|
|
33
|
+
Solid
|
|
34
|
+
</Pill>
|
|
35
|
+
<Pill variant="subtle" tone="brand">
|
|
36
|
+
Subtle
|
|
37
|
+
</Pill>
|
|
38
|
+
<Pill variant="outline" tone="brand">
|
|
39
|
+
Outline
|
|
40
|
+
</Pill>
|
|
27
41
|
</View>
|
|
28
42
|
),
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
export const
|
|
45
|
+
export const AllTones: Story = {
|
|
32
46
|
render: () => (
|
|
33
47
|
<View className="flex-row gap-2 flex-wrap">
|
|
34
|
-
<Pill
|
|
35
|
-
<Pill
|
|
36
|
-
<Pill
|
|
37
|
-
<Pill
|
|
38
|
-
<Pill
|
|
39
|
-
<Pill
|
|
48
|
+
<Pill tone="neutral">Neutral</Pill>
|
|
49
|
+
<Pill tone="brand">Brand</Pill>
|
|
50
|
+
<Pill tone="brand-secondary">Accent</Pill>
|
|
51
|
+
<Pill tone="success">Success</Pill>
|
|
52
|
+
<Pill tone="warning">Warning</Pill>
|
|
53
|
+
<Pill tone="error">Error</Pill>
|
|
54
|
+
<Pill tone="info">Info</Pill>
|
|
55
|
+
</View>
|
|
56
|
+
),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The same row on both planes a subtle pill actually lands on. A `-subtle` fill is
|
|
61
|
+
* alpha, so it composites against whatever is behind it: the raised card lifts every
|
|
62
|
+
* capsule and costs each label contrast. It is the harder case and the one AW-133 is
|
|
63
|
+
* measured against, so judge the tone weight here, not only on the page plane.
|
|
64
|
+
*/
|
|
65
|
+
export const OnBothPlanes: Story = {
|
|
66
|
+
parameters: {
|
|
67
|
+
docs: {
|
|
68
|
+
description: {
|
|
69
|
+
story:
|
|
70
|
+
'Page plane (`grey-925`) above, raised card (`grey-875`) below. Every tone loses ' +
|
|
71
|
+
'roughly 0.8-1.0 of contrast ratio on the card. `brand` is the deliberate exception ' +
|
|
72
|
+
'from AW-133 — its label stays the exact `orange[400]` brand hue rather than ' +
|
|
73
|
+
'levelling with the other five, which leaves it the one tone under AA here.',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
render: () => (
|
|
78
|
+
<View className="gap-4">
|
|
79
|
+
<View className="gap-2">
|
|
80
|
+
<Typography variant="caption" color="tertiary">
|
|
81
|
+
page plane · grey-925
|
|
82
|
+
</Typography>
|
|
83
|
+
<View className="flex-row gap-2 flex-wrap">
|
|
84
|
+
<Pill tone="brand">Brand</Pill>
|
|
85
|
+
<Pill tone="brand-secondary">Accent</Pill>
|
|
86
|
+
<Pill tone="success">Success</Pill>
|
|
87
|
+
<Pill tone="warning">Warning</Pill>
|
|
88
|
+
<Pill tone="error">Error</Pill>
|
|
89
|
+
<Pill tone="info">Info</Pill>
|
|
90
|
+
</View>
|
|
91
|
+
</View>
|
|
92
|
+
|
|
93
|
+
<Surface level="raised" className="gap-2 rounded-xl border-hairline p-4">
|
|
94
|
+
<Typography variant="caption" color="tertiary">
|
|
95
|
+
raised card · grey-875
|
|
96
|
+
</Typography>
|
|
97
|
+
<View className="flex-row gap-2 flex-wrap">
|
|
98
|
+
<Pill tone="brand">Brand</Pill>
|
|
99
|
+
<Pill tone="brand-secondary">Accent</Pill>
|
|
100
|
+
<Pill tone="success">Success</Pill>
|
|
101
|
+
<Pill tone="warning">Warning</Pill>
|
|
102
|
+
<Pill tone="error">Error</Pill>
|
|
103
|
+
<Pill tone="info">Info</Pill>
|
|
104
|
+
</View>
|
|
105
|
+
</Surface>
|
|
40
106
|
</View>
|
|
41
107
|
),
|
|
42
108
|
}
|
|
@@ -44,19 +110,37 @@ export const AllColors: Story = {
|
|
|
44
110
|
export const AllSizes: Story = {
|
|
45
111
|
render: () => (
|
|
46
112
|
<View className="flex-row gap-2 items-center">
|
|
47
|
-
<Pill size="xs"
|
|
48
|
-
|
|
49
|
-
|
|
113
|
+
<Pill size="xs" tone="brand">
|
|
114
|
+
XS
|
|
115
|
+
</Pill>
|
|
116
|
+
<Pill size="sm" tone="brand">
|
|
117
|
+
SM
|
|
118
|
+
</Pill>
|
|
119
|
+
<Pill size="md" tone="brand">
|
|
120
|
+
MD
|
|
121
|
+
</Pill>
|
|
122
|
+
<Pill size="lg" tone="brand">
|
|
123
|
+
LG
|
|
124
|
+
</Pill>
|
|
125
|
+
<Pill size="xl" tone="brand">
|
|
126
|
+
XL
|
|
127
|
+
</Pill>
|
|
50
128
|
</View>
|
|
51
129
|
),
|
|
52
130
|
}
|
|
53
131
|
|
|
54
|
-
export const
|
|
132
|
+
export const LeadingSlot: Story = {
|
|
55
133
|
render: () => (
|
|
56
134
|
<View className="flex-row gap-2">
|
|
57
|
-
<Pill
|
|
58
|
-
|
|
59
|
-
|
|
135
|
+
<Pill tone="success" leading="dot">
|
|
136
|
+
Active
|
|
137
|
+
</Pill>
|
|
138
|
+
<Pill tone="error" leading="dot">
|
|
139
|
+
Failed
|
|
140
|
+
</Pill>
|
|
141
|
+
<Pill tone="warning" leading={<Indicator size="xs" color="warning" />}>
|
|
142
|
+
Pending
|
|
143
|
+
</Pill>
|
|
60
144
|
</View>
|
|
61
145
|
),
|
|
62
146
|
}
|
|
@@ -64,8 +148,12 @@ export const WithDot: Story = {
|
|
|
64
148
|
export const SquareCorners: Story = {
|
|
65
149
|
render: () => (
|
|
66
150
|
<View className="flex-row gap-2">
|
|
67
|
-
<Pill rounded={false}
|
|
68
|
-
|
|
151
|
+
<Pill rounded={false} tone="brand">
|
|
152
|
+
Tag
|
|
153
|
+
</Pill>
|
|
154
|
+
<Pill rounded={false} tone="success">
|
|
155
|
+
Done
|
|
156
|
+
</Pill>
|
|
69
157
|
</View>
|
|
70
158
|
),
|
|
71
159
|
}
|
|
@@ -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,221 @@ 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
|
+
// Label comes from `on-*-subtle`, not the base tone token: the base is tuned to
|
|
87
|
+
// carry a white label as a solid fill, which left error and accent unreadable
|
|
88
|
+
// here (AW-133). The on-subtle tokens level the family at one weight.
|
|
89
|
+
neutral: 'bg-hairline-subtle border-transparent text-text-secondary',
|
|
90
|
+
brand: 'bg-brand-primary-subtle border-transparent text-on-brand-primary-subtle',
|
|
91
|
+
'brand-secondary':
|
|
92
|
+
'bg-brand-secondary-subtle border-transparent text-on-brand-secondary-subtle',
|
|
93
|
+
success: 'bg-status-success-subtle border-transparent text-on-status-success-subtle',
|
|
94
|
+
warning: 'bg-status-warning-subtle border-transparent text-on-status-warning-subtle',
|
|
95
|
+
error: 'bg-status-error-subtle border-transparent text-on-status-error-subtle',
|
|
96
|
+
info: 'bg-status-info-subtle border-transparent text-on-status-info-subtle',
|
|
37
97
|
},
|
|
38
98
|
outline: {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
secondary: 'border-brand-secondary text-brand-secondary',
|
|
99
|
+
neutral: 'border-hairline text-text-secondary',
|
|
100
|
+
brand: 'border-brand-primary text-brand-primary',
|
|
101
|
+
'brand-secondary': 'border-brand-secondary text-brand-secondary',
|
|
42
102
|
success: 'border-status-success text-status-success',
|
|
43
|
-
error: 'border-status-error text-status-error',
|
|
44
103
|
warning: 'border-status-warning text-status-warning',
|
|
104
|
+
error: 'border-status-error text-status-error',
|
|
45
105
|
info: 'border-status-info text-status-info',
|
|
46
106
|
},
|
|
47
107
|
}
|
|
48
108
|
|
|
109
|
+
const dotToneStyles: Record<PillTone, string> = {
|
|
110
|
+
neutral: 'bg-text-tertiary',
|
|
111
|
+
brand: 'bg-brand-primary',
|
|
112
|
+
'brand-secondary': 'bg-brand-secondary',
|
|
113
|
+
success: 'bg-status-success',
|
|
114
|
+
warning: 'bg-status-warning',
|
|
115
|
+
error: 'bg-status-error',
|
|
116
|
+
info: 'bg-status-info',
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// One text step per rung. `md` used to repeat `sm`'s 10px, which left no 12px
|
|
120
|
+
// capsule at all and pushed anything between the two down to 10px — that is how
|
|
121
|
+
// MuscleGroupChip lost 7px of height. `md` is the 12px rung now.
|
|
49
122
|
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-
|
|
123
|
+
xs: { container: 'px-1 py-px', text: 'text-3xs' },
|
|
124
|
+
sm: { container: 'px-2 py-0.5', text: 'text-2xs' },
|
|
125
|
+
md: { container: 'px-2.5 py-1', text: 'text-xs' },
|
|
126
|
+
lg: { container: 'px-3 py-1.5', text: 'text-sm' },
|
|
127
|
+
xl: { container: 'px-4 py-2', text: 'text-base' },
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// The dot derives its testID from the pill's, so a preset's dot stays
|
|
131
|
+
// addressable under the preset's own name (`muscle-group-chip-dot`) instead of
|
|
132
|
+
// collapsing to a generic one — the visual parity layer targets it by name.
|
|
133
|
+
function PillDot({ tone, testID }: { tone: PillTone; testID?: string }) {
|
|
134
|
+
return (
|
|
135
|
+
<View
|
|
136
|
+
className={cn('w-1.5 h-1.5 rounded-full shrink-0', dotToneStyles[tone])}
|
|
137
|
+
accessibilityElementsHidden
|
|
138
|
+
testID={testID ? `${testID}-dot` : 'pill-dot'}
|
|
139
|
+
/>
|
|
140
|
+
)
|
|
53
141
|
}
|
|
54
142
|
|
|
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(
|
|
143
|
+
function containerClasses(p: PillProps, tone: PillTone) {
|
|
144
|
+
return cn(
|
|
67
145
|
'flex-row items-center gap-1 border self-start shrink-0',
|
|
68
|
-
rounded ? 'rounded
|
|
69
|
-
|
|
70
|
-
sizeStyles[size].container,
|
|
71
|
-
|
|
146
|
+
p.rounded === false ? 'rounded' : 'rounded-full',
|
|
147
|
+
toneStyles[p.variant ?? 'subtle'][tone],
|
|
148
|
+
sizeStyles[p.size ?? 'sm'].container,
|
|
149
|
+
p.isDisabled && 'opacity-50',
|
|
150
|
+
p.className
|
|
72
151
|
)
|
|
152
|
+
}
|
|
73
153
|
|
|
154
|
+
function PillContent({ tone, ...p }: PillProps & { tone: PillTone }) {
|
|
74
155
|
const textClasses = cn(
|
|
75
|
-
'font-heading font-semibold',
|
|
76
|
-
sizeStyles[size].text,
|
|
77
|
-
|
|
156
|
+
'font-heading font-semibold text-inherit',
|
|
157
|
+
sizeStyles[p.size ?? 'sm'].text,
|
|
158
|
+
p.textClassName
|
|
78
159
|
)
|
|
79
|
-
|
|
80
|
-
|
|
160
|
+
const slot = p.leading ?? p.leftElement
|
|
161
|
+
return (
|
|
81
162
|
<>
|
|
82
|
-
{
|
|
83
|
-
{typeof children === 'string' ? (
|
|
84
|
-
<Text className={textClasses}>{children}</Text>
|
|
163
|
+
{slot === 'dot' ? <PillDot tone={p.dotTone ?? tone} testID={p.testID} /> : slot}
|
|
164
|
+
{typeof p.children === 'string' ? (
|
|
165
|
+
<Text className={textClasses}>{p.children}</Text>
|
|
85
166
|
) : (
|
|
86
|
-
children
|
|
167
|
+
p.children
|
|
87
168
|
)}
|
|
169
|
+
{p.trailing}
|
|
88
170
|
</>
|
|
89
171
|
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The single pill primitive: a capsule of tone-coloured label with optional
|
|
176
|
+
* leading and trailing slots. `Badge`, `Chip`, `StatusPill` and
|
|
177
|
+
* `MuscleGroupChip` are presets over it.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* <Pill tone="success" leading="dot">Active</Pill>
|
|
181
|
+
*/
|
|
182
|
+
export function Pill(props: PillProps) {
|
|
183
|
+
const {
|
|
184
|
+
variant,
|
|
185
|
+
tone,
|
|
186
|
+
color,
|
|
187
|
+
size,
|
|
188
|
+
rounded,
|
|
189
|
+
leading,
|
|
190
|
+
dotTone,
|
|
191
|
+
leftElement,
|
|
192
|
+
trailing,
|
|
193
|
+
onPress,
|
|
194
|
+
isDisabled,
|
|
195
|
+
className,
|
|
196
|
+
textClassName,
|
|
197
|
+
children,
|
|
198
|
+
...viewProps
|
|
199
|
+
} = props
|
|
200
|
+
const resolvedTone = tone ?? (color ? colorToTone[color] : 'neutral')
|
|
201
|
+
const classes = containerClasses(props, resolvedTone)
|
|
202
|
+
const content = <PillContent {...props} tone={resolvedTone} />
|
|
90
203
|
|
|
91
204
|
if (onPress) {
|
|
92
205
|
return (
|
|
93
|
-
<Pressable
|
|
206
|
+
<Pressable
|
|
207
|
+
onPress={onPress}
|
|
208
|
+
disabled={isDisabled}
|
|
209
|
+
accessibilityRole="button"
|
|
210
|
+
className={classes}
|
|
211
|
+
{...viewProps}
|
|
212
|
+
>
|
|
94
213
|
{content}
|
|
95
214
|
</Pressable>
|
|
96
215
|
)
|
|
97
216
|
}
|
|
98
217
|
|
|
99
218
|
return (
|
|
100
|
-
<View className={
|
|
219
|
+
<View className={classes} {...viewProps}>
|
|
101
220
|
{content}
|
|
102
221
|
</View>
|
|
103
222
|
)
|
|
@@ -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>
|
|
@@ -162,7 +160,7 @@ export const WithFormContent: Story = {
|
|
|
162
160
|
</View>
|
|
163
161
|
</PopoverCloseButton>
|
|
164
162
|
<View className="px-3 py-1.5 rounded-md bg-brand-primary">
|
|
165
|
-
<Text className="text-
|
|
163
|
+
<Text className="text-on-brand-primary text-sm font-medium">Save</Text>
|
|
166
164
|
</View>
|
|
167
165
|
</View>
|
|
168
166
|
</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', () => {
|