@titan-design/react-ui 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -47
- package/dist/bodymap.js +856 -736
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +858 -738
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1431 -237
- package/dist/index.d.ts +1431 -237
- package/dist/index.js +6506 -4781
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6280 -4642
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
- package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1919 -1937
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1927 -1945
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +225 -140
- package/dist/theme/index.d.ts +225 -140
- package/dist/theme/index.js +298 -319
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +283 -315
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +145 -24
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +145 -24
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +128 -11
- package/dist/theme/tokens.d.ts +128 -11
- package/dist/theme/tokens.js +126 -26
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +124 -27
- package/dist/theme/tokens.mjs.map +1 -1
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/docs/render-testing-pattern.md +130 -0
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +3 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +4989 -1583
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +7 -2
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +122 -18
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +99 -16
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +11 -3
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
- package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +6 -2
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +8 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
- package/src/components/custom/Workout/DeviationBar.tsx +24 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
- package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
- package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/InputBar.tsx +4 -2
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +8 -3
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +14 -10
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +68 -17
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
- package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
- package/src/components/custom/Workout/RestTimer.tsx +4 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
- package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
- package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/exerciseRowState.ts +29 -0
- package/src/components/custom/Workout/index.ts +17 -2
- package/src/components/custom/Workout/metricText.stories.tsx +15 -13
- package/src/components/custom/Workout/metricText.tsx +8 -2
- package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/README.md +66 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
- package/src/components/custom/charts/SetBarChart.tsx +56 -9
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
- package/src/components/custom/charts/flatBarGeometry.ts +32 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +21 -34
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +89 -26
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +15 -5
- package/src/components/ui/alert/Alert.tsx +24 -3
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +44 -37
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +7 -27
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -27
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +10 -18
- package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +31 -19
- package/src/components/ui/pill/Pill.stories.tsx +111 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +168 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +6 -8
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/progress/Progress.tsx +9 -6
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +12 -21
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +16 -15
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +4 -5
- package/src/components/ui/stack/Stack.stories.tsx +8 -8
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +92 -33
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +8 -21
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +49 -57
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +101 -48
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/test/no-raw-color.test.ts +39 -0
- package/src/theme/Alpha.stories.tsx +103 -0
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +23 -21
- package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +40 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +45 -5
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/subtle-tone-weight.test.ts +163 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/tailwind-var-opacity.test.ts +163 -0
- package/src/theme/token-export-guard.test.ts +1 -3
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +98 -33
- package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
- package/src/theme/tokens/semantic.ts +124 -54
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.alpha-adoption.test.ts +408 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +55 -9
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TopBar } from '../TopBar'
|
|
2
|
+
import { SessionStatePill, type SessionState } from './SessionStatePill'
|
|
3
|
+
import { DeviceMenu } from './DeviceMenu'
|
|
4
|
+
import { type Device } from './DeviceRow'
|
|
5
|
+
|
|
6
|
+
export interface WorkoutTopBarProps {
|
|
7
|
+
/** Global session state → the status pill. */
|
|
8
|
+
state: SessionState
|
|
9
|
+
/** Devices for the connection glyph + dropdown. */
|
|
10
|
+
devices: Device[]
|
|
11
|
+
/** The moment to display in the clock (Date/timestamp). Omit for a live ticking clock. */
|
|
12
|
+
time?: number | Date
|
|
13
|
+
/** Brand subtitle. Default "wall dashboard". */
|
|
14
|
+
subtitle?: string
|
|
15
|
+
/** Force the subtitle on/off; defaults to container-responsive. */
|
|
16
|
+
showSubtitle?: boolean
|
|
17
|
+
/** Force the clock on/off; defaults to container-responsive. */
|
|
18
|
+
showClock?: boolean
|
|
19
|
+
onSelectDevice?: (device: Device) => void
|
|
20
|
+
className?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The workout app's top bar — the generic {@link TopBar} with the workout's own
|
|
25
|
+
* chrome in its `trailing` slot: session state, then the device menu. The bar
|
|
26
|
+
* adds its dividers and the clock; this component only supplies the items.
|
|
27
|
+
*/
|
|
28
|
+
export function WorkoutTopBar({
|
|
29
|
+
state,
|
|
30
|
+
devices,
|
|
31
|
+
time,
|
|
32
|
+
subtitle,
|
|
33
|
+
showSubtitle,
|
|
34
|
+
showClock,
|
|
35
|
+
onSelectDevice,
|
|
36
|
+
className,
|
|
37
|
+
}: WorkoutTopBarProps) {
|
|
38
|
+
return (
|
|
39
|
+
<TopBar
|
|
40
|
+
brand="voltras"
|
|
41
|
+
subtitle={subtitle}
|
|
42
|
+
showSubtitle={showSubtitle}
|
|
43
|
+
showClock={showClock}
|
|
44
|
+
time={time}
|
|
45
|
+
className={className}
|
|
46
|
+
trailing={[
|
|
47
|
+
<SessionStatePill key="state" state={state} />,
|
|
48
|
+
<DeviceMenu key="devices" devices={devices} onSelectDevice={onSelectDevice} />,
|
|
49
|
+
]}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Workout-app shell chrome — composes the generic shell family one directory up.
|
|
2
|
+
// Nothing here is reusable by another app; nothing generic may import from here.
|
|
3
|
+
export * from './SessionStatePill'
|
|
4
|
+
export * from './DeviceIndicator'
|
|
5
|
+
export * from './DeviceRow'
|
|
6
|
+
export * from './DeviceMenu'
|
|
7
|
+
export * from './workoutNavItems'
|
|
8
|
+
export * from './WorkoutTopBar'
|
|
9
|
+
export * from './WorkoutShell'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ActivityIcon, HistoryIcon, LayersIcon, PersonStandingIcon } from '../../icons'
|
|
2
|
+
import { type SideNavItem } from '../SideNav'
|
|
3
|
+
|
|
4
|
+
/** The four workout-dashboard categories with their locked S2 glyphs (activity · history · layers · figure). */
|
|
5
|
+
export const workoutNavItems: SideNavItem[] = [
|
|
6
|
+
{ key: 'live', label: 'Live', icon: <ActivityIcon size={20} color="currentColor" /> },
|
|
7
|
+
{ key: 'review', label: 'Review', icon: <HistoryIcon size={20} color="currentColor" /> },
|
|
8
|
+
{ key: 'program', label: 'Plan', icon: <LayersIcon size={20} color="currentColor" /> },
|
|
9
|
+
{ key: 'body', label: 'Body', icon: <PersonStandingIcon size={20} color="currentColor" /> },
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use `workoutNavItems` — these are the workout app's categories,
|
|
14
|
+
* not a generic shell default. `SideNav.items` is required now (AW-132).
|
|
15
|
+
*/
|
|
16
|
+
export const defaultNavItems = workoutNavItems
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# `ui/*` — the generic primitive family
|
|
2
|
+
|
|
3
|
+
The domain-free foundation tier: 38 primitives that know nothing about workouts,
|
|
4
|
+
sessions or initiatives. Everything in `custom/*` and `shell/*` is built on this
|
|
5
|
+
layer, and `ui/*` may not import from either of them — the tier order is
|
|
6
|
+
`theme → icons → ui → custom → shell → pages`.
|
|
7
|
+
|
|
8
|
+
This README is the **index**. It maps each primitive's dependencies
|
|
9
|
+
(**composes ↓**) and its consumers (**used-by ↑**) so the tree navigates in both
|
|
10
|
+
directions and a hand-rolled element that should have reached for an existing
|
|
11
|
+
primitive is visible. Storybook mirrors it under
|
|
12
|
+
`Components/Atoms|Molecules|Organisms/…`; each primitive's autodocs page repeats
|
|
13
|
+
its Composes links.
|
|
14
|
+
|
|
15
|
+
Counts below are generated, not hand-kept: they come from
|
|
16
|
+
[`src/arch/arch-graph.json`](../../arch/arch-graph.json) (regenerate with
|
|
17
|
+
`pnpm arch:graph`, which `arch-graph.freshness.test.ts` keeps honest). **In-repo**
|
|
18
|
+
is in-library consumers; **external** is import sites in the three checkouts the
|
|
19
|
+
graph scans (voltras mobile, voltras-mcp, codewatch dashboard). It is a floor,
|
|
20
|
+
not a census: `docs/audits/2026-09-08-critique-addenda.md` §D1 found seven
|
|
21
|
+
downstream checkouts, and audiobook/frontend — the one that tracks HEAD — is not
|
|
22
|
+
among the three.
|
|
23
|
+
|
|
24
|
+
## The one rule this family exists to enforce
|
|
25
|
+
|
|
26
|
+
A primitive here is the _only_ implementation of its shape. When a family needs
|
|
27
|
+
a rule, a pill, a dot or a plane, it composes `ui/*` — it does not draw one. The
|
|
28
|
+
audit that produced this file found four container primitives competing and
|
|
29
|
+
twelve pill-shaped components; roadmap decisions 1, 3, 4, 5, 10 and 11 collapsed
|
|
30
|
+
them, and the survivors are marked as presets below.
|
|
31
|
+
|
|
32
|
+
## Dependency map
|
|
33
|
+
|
|
34
|
+
| Component | Tier | Composes ↓ | Used-by ↑ (in-repo) | In-repo | External |
|
|
35
|
+
| ---------------- | -------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- |
|
|
36
|
+
| `alert` | atom | — | — (app-facing leaf) | 0 | 6 |
|
|
37
|
+
| `autocomplete` | molecule | Surface | — | 0 | 0 |
|
|
38
|
+
| `avatar` | atom | — | — | 0 | 0 |
|
|
39
|
+
| `badge` | molecule | Pill, Indicator | BodyMapDetailPanel, MesoCard, ReadinessCheck | 3 | 3 |
|
|
40
|
+
| `breadcrumbs` | atom | — | — | 0 | 0 |
|
|
41
|
+
| `button` | atom | — | examples | 1 | 17 |
|
|
42
|
+
| `card` | molecule | Surface | CoChangeChip, FileActivityDetail, FileHistoryExplorer, InitiativeCard, MesoCard, MesoStatusCard, PortfolioOverview, ReadinessCheck, SessionDetail, WorkoutCard | 10 | 74 |
|
|
43
|
+
| `checkbox` | atom | — | examples | 1 | 0 |
|
|
44
|
+
| `chip` | molecule | Pill | — (external-only preset) | 0 | 0 |
|
|
45
|
+
| `collapse` | atom | — | SessionDetail | 1 | 0 |
|
|
46
|
+
| `data-row` | atom | — | FileActivityDetail, VolumeLandmarkBar | 2 | 2 |
|
|
47
|
+
| `divider` | atom | — | FileHistoryExplorer, OpenLoops, SessionDetail, SessionList, TopBar | 5 | 2 |
|
|
48
|
+
| `drawer` | molecule | Surface | PrHistoryModal | 1 | 6 |
|
|
49
|
+
| `form-field` | atom | — | examples | 1 | 0 |
|
|
50
|
+
| `help-tip` | molecule | Surface | — **deprecated**, use Tooltip | 0 | 0 |
|
|
51
|
+
| `icon-box` | atom | — | — | 0 | 0 |
|
|
52
|
+
| `indicator` | atom | — | Badge, DeviceRow, SessionStatePill, SeverityLabel | 6 | 0 |
|
|
53
|
+
| `input` | atom | — | examples | 1 | 1 |
|
|
54
|
+
| `link` | atom | — | — | 0 | 0 |
|
|
55
|
+
| `list-item` | atom | — | — (app-facing leaf) | 0 | 9 |
|
|
56
|
+
| `menu` | molecule | Surface | — | 0 | 0 |
|
|
57
|
+
| `modal` | molecule | Surface | — | 0 | 0 |
|
|
58
|
+
| `pill` | atom | — | Badge, Chip, CoChangeChip, FileActivityDetail, InitiativeCard, InitiativeHeader, MuscleGroupChip, OpenLoops, SessionDetail, StatusPill, TaskRow | 11 | 1 |
|
|
59
|
+
| `popover` | molecule | Surface | DeviceMenu | 1 | 0 |
|
|
60
|
+
| `progress` | atom | — | CircularTimer | 1 | 2 |
|
|
61
|
+
| `radio` | atom | — | examples | 1 | 2 |
|
|
62
|
+
| `section` | atom | — | — (app-facing leaf) | 0 | 10 |
|
|
63
|
+
| `select` | molecule | Surface | examples | 2 | 1 |
|
|
64
|
+
| `skeleton` | atom | — | — | 0 | 0 |
|
|
65
|
+
| `spinner` | atom | — | — (app-facing leaf) | 0 | 2 |
|
|
66
|
+
| `stack` | atom | — | MetricTiles, ScheduleTiles | 2 | 27 |
|
|
67
|
+
| `surface` | atom | — | Autocomplete, Card, DashboardShell, Drawer, HelpTip, LiveFatigueCard, Menu, Modal, Popover, Select, SessionHeader, SessionRail, Toast, ToolbarButton, Tooltip | 15 | 29 |
|
|
68
|
+
| `switch` | atom | — | — | 0 | 0 |
|
|
69
|
+
| `tabs` | atom | — | — | 0 | 0 |
|
|
70
|
+
| `tile` | atom | — | FileActivityDetail, FileHistoryExplorer, MetricTiles, ScheduleTiles — **deprecated**, use a Card stat preset | 4 | 0 |
|
|
71
|
+
| `toast` | molecule | Surface | — | 0 | 0 |
|
|
72
|
+
| `toolbar-button` | molecule | Surface | — | 0 | 0 |
|
|
73
|
+
| `tooltip` | molecule | Surface | FatigueLights, SessionDetail, SessionListItem, Table, TaskRow, ZoneTrack | 8 | 1 |
|
|
74
|
+
|
|
75
|
+
Two roots carry the family: **`surface`** (15 in-repo consumers — every floating
|
|
76
|
+
and raised plane) and **`pill`** (11 — every pill-shaped label since decision 3).
|
|
77
|
+
Nothing else in `ui/*` is composed by more than six.
|
|
78
|
+
|
|
79
|
+
## Reuse audit — where `ui/*` still hand-rolls
|
|
80
|
+
|
|
81
|
+
| Leaf | Should compose | Status |
|
|
82
|
+
| -------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
+
| Text runs (79 raw `<Text>` in 27 files) | `Typography` | **Open.** `Typography` is in `custom/`, which `ui/*` may not import. Roadmap decision 9 moves it into `ui/`; until then every heading and label here is hand-styled. |
|
|
84
|
+
| Pill-shaped labels | `Pill` | **Closed** (#172). `Badge` and `Chip` now render `<Pill>`; the six folded-in variants are in `DEPRECATIONS.md`. |
|
|
85
|
+
| Status dots | `Indicator` | **Closed** for `ui/*`. `StatusDot` (Workout) is deprecated toward `Indicator` (decision 10). |
|
|
86
|
+
| Raised / floating planes | `Surface` (`raise` / `elevation`) | **Closed** (#166, #173). Eleven molecules compose `Surface` rather than setting `bg-surface-*` themselves. |
|
|
87
|
+
| Rules and separators (20 `border-hairline*` in 12 files) | `Divider` | **Partly open.** Decision 4 allows `border-hairline` only on Card `outline`/`subtle`, Table rules and input borders — `Select`, `Radio`, `Drawer` and `Tabs` still draw their own. |
|
|
88
|
+
| Tooltip-with-a-label lockup | `Tooltip` + your own label | **Closed** by deprecation. `HelpTip` and `LabelWithHelp` are retired (decision 5). |
|
|
89
|
+
|
|
90
|
+
## Watch list
|
|
91
|
+
|
|
92
|
+
- **`Typography` cannot be composed here.** The tier order forbids the import, so
|
|
93
|
+
the 79 raw `<Text>` runs above cannot be fixed inside this family. Blocked on
|
|
94
|
+
roadmap E3 moving `Typography` and `Eyebrow` into `ui/`.
|
|
95
|
+
- **Fourteen primitives read as dead** — `autocomplete`, `avatar`, `breadcrumbs`,
|
|
96
|
+
`chip`, `help-tip`, `icon-box`, `link`, `menu`, `modal`, `skeleton`, `switch`,
|
|
97
|
+
`tabs`, `toast`, `toolbar-button`. That is not automatically a delete: the graph
|
|
98
|
+
sees three of seven downstream checkouts, and `Chip` in particular has a known
|
|
99
|
+
consumer (audiobook/frontend, §D1) the graph cannot see. Settle per component
|
|
100
|
+
under roadmap E6.4, not by reading this table.
|
|
101
|
+
- **`modal` and `menu` read dead while `drawer` and `popover` do not.** The
|
|
102
|
+
overlay set is mid-migration onto the floating lift (E1); recheck after the
|
|
103
|
+
trigger work lands rather than treating the split as a decision.
|
|
104
|
+
|
|
105
|
+
## Maturity
|
|
106
|
+
|
|
107
|
+
Status tags on these stories are derived, not chosen — the rule is in
|
|
108
|
+
[`MATURITY.md`](../../../MATURITY.md). Membership in the dependency map above is
|
|
109
|
+
one of its three inputs, so **adding a primitive here without adding its row
|
|
110
|
+
leaves it `status:candidate`**.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Decorator, Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View, Text } from 'react-native'
|
|
3
3
|
import { Alert, AlertTitle, AlertDescription } from './Alert'
|
|
4
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
4
5
|
|
|
5
6
|
const meta: Meta<typeof Alert> = {
|
|
6
7
|
title: 'Components/Molecules/Alert',
|
|
7
8
|
component: Alert,
|
|
8
|
-
tags: ['autodocs'],
|
|
9
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
10
|
parameters: {
|
|
10
11
|
docs: {
|
|
11
12
|
description: {
|
|
@@ -178,7 +179,7 @@ export const DescriptionOnly: Story = {
|
|
|
178
179
|
|
|
179
180
|
/** Wall-background frame for the compact cue stories. */
|
|
180
181
|
const wall: Decorator = (Story) => (
|
|
181
|
-
<View style={{ width: 460, padding: 28, backgroundColor: '
|
|
182
|
+
<View style={{ width: 460, padding: 28, backgroundColor: 'var(--color-background-frame)' }}>
|
|
182
183
|
<Story />
|
|
183
184
|
</View>
|
|
184
185
|
)
|
|
@@ -219,13 +220,22 @@ export const CompactLiveCue: Story = {
|
|
|
219
220
|
/** Default vs compact, side by side, for the density comparison. */
|
|
220
221
|
export const DefaultVsCompact: Story = {
|
|
221
222
|
render: () => (
|
|
222
|
-
<View
|
|
223
|
-
|
|
223
|
+
<View
|
|
224
|
+
style={{
|
|
225
|
+
gap: 16,
|
|
226
|
+
width: 460,
|
|
227
|
+
padding: 28,
|
|
228
|
+
backgroundColor: 'var(--color-background-frame)',
|
|
229
|
+
}}
|
|
230
|
+
>
|
|
231
|
+
<Text style={{ color: greyRamp[700], fontSize: 10, fontWeight: '700' }}>DEFAULT</Text>
|
|
224
232
|
<Alert status="warning" variant="subtle">
|
|
225
233
|
<AlertTitle>Approaching threshold</AlertTitle>
|
|
226
234
|
<AlertDescription>18% velocity loss — one or two reps left in the band.</AlertDescription>
|
|
227
235
|
</Alert>
|
|
228
|
-
<Text style={{ color:
|
|
236
|
+
<Text style={{ color: greyRamp[700], fontSize: 10, fontWeight: '700' }}>
|
|
237
|
+
COMPACT (cue pill)
|
|
238
|
+
</Text>
|
|
229
239
|
<Alert
|
|
230
240
|
status="warning"
|
|
231
241
|
variant="subtle"
|
|
@@ -44,42 +44,54 @@ const statusColors: Record<
|
|
|
44
44
|
subtle: string
|
|
45
45
|
outline: string
|
|
46
46
|
solid: string
|
|
47
|
+
/** Text/glyph colour on the `solid` fill — the status's on-colour. */
|
|
48
|
+
onSolid: string
|
|
47
49
|
border: string
|
|
48
50
|
icon: string
|
|
49
51
|
text: string
|
|
52
|
+
/** Label ON the `subtle` fill — see AW-133; the base token is too deep to read there. */
|
|
53
|
+
subtleText: string
|
|
50
54
|
}
|
|
51
55
|
> = {
|
|
52
56
|
success: {
|
|
53
57
|
subtle: 'bg-status-success-subtle',
|
|
54
58
|
outline: 'border-2 border-status-success bg-transparent',
|
|
55
59
|
solid: 'bg-status-success',
|
|
60
|
+
onSolid: 'text-on-status-success',
|
|
56
61
|
border: 'border-status-success',
|
|
57
62
|
icon: 'text-status-success',
|
|
58
63
|
text: 'text-status-success',
|
|
64
|
+
subtleText: 'text-on-status-success-subtle',
|
|
59
65
|
},
|
|
60
66
|
info: {
|
|
61
67
|
subtle: 'bg-status-info-subtle',
|
|
62
68
|
outline: 'border-2 border-status-info bg-transparent',
|
|
63
69
|
solid: 'bg-status-info',
|
|
70
|
+
onSolid: 'text-on-status-info',
|
|
64
71
|
border: 'border-status-info',
|
|
65
72
|
icon: 'text-status-info',
|
|
66
73
|
text: 'text-status-info',
|
|
74
|
+
subtleText: 'text-on-status-info-subtle',
|
|
67
75
|
},
|
|
68
76
|
warning: {
|
|
69
77
|
subtle: 'bg-status-warning-subtle',
|
|
70
78
|
outline: 'border-2 border-status-warning bg-transparent',
|
|
71
79
|
solid: 'bg-status-warning',
|
|
80
|
+
onSolid: 'text-on-status-warning',
|
|
72
81
|
border: 'border-status-warning',
|
|
73
82
|
icon: 'text-status-warning',
|
|
74
83
|
text: 'text-status-warning',
|
|
84
|
+
subtleText: 'text-on-status-warning-subtle',
|
|
75
85
|
},
|
|
76
86
|
error: {
|
|
77
87
|
subtle: 'bg-status-error-subtle',
|
|
78
88
|
outline: 'border-2 border-status-error bg-transparent',
|
|
79
89
|
solid: 'bg-status-error',
|
|
90
|
+
onSolid: 'text-on-status-error',
|
|
80
91
|
border: 'border-status-error',
|
|
81
92
|
icon: 'text-status-error',
|
|
82
93
|
text: 'text-status-error',
|
|
94
|
+
subtleText: 'text-on-status-error-subtle',
|
|
83
95
|
},
|
|
84
96
|
}
|
|
85
97
|
|
|
@@ -142,7 +154,7 @@ export function Alert({
|
|
|
142
154
|
className={cn(
|
|
143
155
|
'font-bold',
|
|
144
156
|
isCompact ? 'text-base' : 'text-lg',
|
|
145
|
-
isSolid ? '
|
|
157
|
+
isSolid ? colors.onSolid : variant === 'subtle' ? colors.subtleText : colors.icon
|
|
146
158
|
)}
|
|
147
159
|
>
|
|
148
160
|
{defaultIcons[status]}
|
|
@@ -154,7 +166,10 @@ export function Alert({
|
|
|
154
166
|
<View className="flex-1">
|
|
155
167
|
{message != null && (
|
|
156
168
|
<Text
|
|
157
|
-
className={cn(
|
|
169
|
+
className={cn(
|
|
170
|
+
'text-sm font-semibold',
|
|
171
|
+
isSolid ? colors.onSolid : variant === 'subtle' ? colors.subtleText : colors.text
|
|
172
|
+
)}
|
|
158
173
|
testID="alert-message"
|
|
159
174
|
>
|
|
160
175
|
{message}
|
|
@@ -168,9 +183,15 @@ export function Alert({
|
|
|
168
183
|
onPress={onClose}
|
|
169
184
|
accessibilityRole="button"
|
|
170
185
|
accessibilityLabel="Close alert"
|
|
186
|
+
/* VW-82: press-state scrims stay raw (see Modal.tsx). */
|
|
171
187
|
className="ml-2 p-1 rounded web:hover:bg-black/10 active:bg-black/20"
|
|
172
188
|
>
|
|
173
|
-
<Text
|
|
189
|
+
<Text
|
|
190
|
+
className={cn(
|
|
191
|
+
'text-lg',
|
|
192
|
+
isSolid ? cn(colors.onSolid, 'opacity-70') : 'text-text-secondary'
|
|
193
|
+
)}
|
|
194
|
+
>
|
|
174
195
|
×
|
|
175
196
|
</Text>
|
|
176
197
|
</Pressable>
|
|
@@ -6,7 +6,7 @@ import { Autocomplete, AutocompleteOption } from './Autocomplete'
|
|
|
6
6
|
const meta: Meta<typeof Autocomplete> = {
|
|
7
7
|
title: 'Components/Molecules/Autocomplete',
|
|
8
8
|
component: Autocomplete,
|
|
9
|
-
tags: ['autodocs'],
|
|
9
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
10
10
|
argTypes: {
|
|
11
11
|
isDisabled: {
|
|
12
12
|
control: 'boolean',
|
|
@@ -48,9 +48,7 @@ export const Default: Story = {
|
|
|
48
48
|
onChange={setValue}
|
|
49
49
|
placeholder="Search fruits..."
|
|
50
50
|
/>
|
|
51
|
-
<Text className="text-sm text-text-secondary mt-2">
|
|
52
|
-
Selected: {value || 'None'}
|
|
53
|
-
</Text>
|
|
51
|
+
<Text className="text-sm text-text-secondary mt-2">Selected: {value || 'None'}</Text>
|
|
54
52
|
</View>
|
|
55
53
|
)
|
|
56
54
|
},
|
|
@@ -140,12 +138,7 @@ export const Disabled: Story = {
|
|
|
140
138
|
render: function Render() {
|
|
141
139
|
return (
|
|
142
140
|
<View className="w-64">
|
|
143
|
-
<Autocomplete
|
|
144
|
-
options={fruitOptions}
|
|
145
|
-
value="apple"
|
|
146
|
-
label="Disabled field"
|
|
147
|
-
isDisabled
|
|
148
|
-
/>
|
|
141
|
+
<Autocomplete options={fruitOptions} value="apple" label="Disabled field" isDisabled />
|
|
149
142
|
</View>
|
|
150
143
|
)
|
|
151
144
|
},
|
|
@@ -175,7 +168,12 @@ export const DisabledOptions: Story = {
|
|
|
175
168
|
const optionsWithDisabled: AutocompleteOption[] = [
|
|
176
169
|
{ value: 'free', label: 'Free Plan' },
|
|
177
170
|
{ value: 'pro', label: 'Pro Plan' },
|
|
178
|
-
{
|
|
171
|
+
{
|
|
172
|
+
value: 'enterprise',
|
|
173
|
+
label: 'Enterprise Plan',
|
|
174
|
+
isDisabled: true,
|
|
175
|
+
description: 'Contact sales',
|
|
176
|
+
},
|
|
179
177
|
]
|
|
180
178
|
return (
|
|
181
179
|
<View className="w-64">
|
|
@@ -289,8 +287,8 @@ export const FormExample: Story = {
|
|
|
289
287
|
|
|
290
288
|
<View className="pt-2 border-t border-hairline">
|
|
291
289
|
<Text className="text-sm text-text-secondary">
|
|
292
|
-
Selected: {country ? `${countryOptions.find(c => c.value === country)?.label}` : '-'}
|
|
293
|
-
{city ? `, ${cityOptions[country!]?.find(c => c.value === city)?.label}` : ''}
|
|
290
|
+
Selected: {country ? `${countryOptions.find((c) => c.value === country)?.label}` : '-'}
|
|
291
|
+
{city ? `, ${cityOptions[country!]?.find((c) => c.value === city)?.label}` : ''}
|
|
294
292
|
</Text>
|
|
295
293
|
</View>
|
|
296
294
|
</View>
|
|
@@ -102,26 +102,20 @@ describe('Autocomplete', () => {
|
|
|
102
102
|
})
|
|
103
103
|
|
|
104
104
|
it('shows clear button when value is selected', () => {
|
|
105
|
-
render(
|
|
106
|
-
<Autocomplete options={defaultOptions} value="1" isClearable />
|
|
107
|
-
)
|
|
105
|
+
render(<Autocomplete options={defaultOptions} value="1" isClearable />)
|
|
108
106
|
expect(screen.getByLabelText('Clear selection')).toBeInTheDocument()
|
|
109
107
|
})
|
|
110
108
|
|
|
111
109
|
it('calls onChange with null when clear is pressed', () => {
|
|
112
110
|
const onChange = vi.fn()
|
|
113
|
-
render(
|
|
114
|
-
<Autocomplete options={defaultOptions} value="1" onChange={onChange} isClearable />
|
|
115
|
-
)
|
|
111
|
+
render(<Autocomplete options={defaultOptions} value="1" onChange={onChange} isClearable />)
|
|
116
112
|
|
|
117
113
|
fireEvent.click(screen.getByLabelText('Clear selection'))
|
|
118
114
|
expect(onChange).toHaveBeenCalledWith(null)
|
|
119
115
|
})
|
|
120
116
|
|
|
121
117
|
it('does not show clear button when isClearable is false', () => {
|
|
122
|
-
render(
|
|
123
|
-
<Autocomplete options={defaultOptions} value="1" isClearable={false} />
|
|
124
|
-
)
|
|
118
|
+
render(<Autocomplete options={defaultOptions} value="1" isClearable={false} />)
|
|
125
119
|
expect(screen.queryByLabelText('Clear selection')).not.toBeInTheDocument()
|
|
126
120
|
})
|
|
127
121
|
|
|
@@ -144,13 +138,7 @@ describe('Autocomplete', () => {
|
|
|
144
138
|
})
|
|
145
139
|
|
|
146
140
|
it('shows custom minCharsText', () => {
|
|
147
|
-
render(
|
|
148
|
-
<Autocomplete
|
|
149
|
-
options={defaultOptions}
|
|
150
|
-
minChars={3}
|
|
151
|
-
minCharsText="Keep typing..."
|
|
152
|
-
/>
|
|
153
|
-
)
|
|
141
|
+
render(<Autocomplete options={defaultOptions} minChars={3} minCharsText="Keep typing..." />)
|
|
154
142
|
const input = screen.getByPlaceholderText('Search...')
|
|
155
143
|
|
|
156
144
|
typeInInput(input, 'A')
|
|
@@ -185,9 +173,7 @@ describe('Autocomplete', () => {
|
|
|
185
173
|
})
|
|
186
174
|
|
|
187
175
|
it('does not show clear button when disabled', () => {
|
|
188
|
-
render(
|
|
189
|
-
<Autocomplete options={defaultOptions} value="1" isDisabled isClearable />
|
|
190
|
-
)
|
|
176
|
+
render(<Autocomplete options={defaultOptions} value="1" isDisabled isClearable />)
|
|
191
177
|
expect(screen.queryByLabelText('Clear selection')).not.toBeInTheDocument()
|
|
192
178
|
})
|
|
193
179
|
})
|
|
@@ -225,9 +211,7 @@ describe('Autocomplete', () => {
|
|
|
225
211
|
|
|
226
212
|
describe('accessibility', () => {
|
|
227
213
|
it('has no accessibility violations', async () => {
|
|
228
|
-
const { container } = render(
|
|
229
|
-
<Autocomplete options={defaultOptions} label="Search" />
|
|
230
|
-
)
|
|
214
|
+
const { container } = render(<Autocomplete options={defaultOptions} label="Search" />)
|
|
231
215
|
const results = await axe(container)
|
|
232
216
|
expect(results).toHaveNoViolations()
|
|
233
217
|
})
|
|
@@ -238,9 +222,7 @@ describe('Autocomplete', () => {
|
|
|
238
222
|
})
|
|
239
223
|
|
|
240
224
|
it('clear button has accessible label', () => {
|
|
241
|
-
render(
|
|
242
|
-
<Autocomplete options={defaultOptions} value="1" isClearable />
|
|
243
|
-
)
|
|
225
|
+
render(<Autocomplete options={defaultOptions} value="1" isClearable />)
|
|
244
226
|
expect(screen.getByLabelText('Clear selection')).toBeInTheDocument()
|
|
245
227
|
})
|
|
246
228
|
})
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import React, { useState, useCallback, useMemo } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
TextInput,
|
|
6
|
+
Pressable,
|
|
7
|
+
ScrollView,
|
|
8
|
+
type ViewProps,
|
|
9
|
+
type TextInputProps,
|
|
10
|
+
} from 'react-native'
|
|
3
11
|
import { cn } from '../../../utils/cn'
|
|
12
|
+
import { Surface } from '../surface'
|
|
4
13
|
|
|
5
14
|
export interface AutocompleteOption<T = string> {
|
|
6
15
|
value: T
|
|
@@ -115,10 +124,7 @@ export function Autocomplete<T extends string = string>({
|
|
|
115
124
|
const [highlightedIndex, setHighlightedIndex] = useState(-1)
|
|
116
125
|
|
|
117
126
|
// Get the label for the selected value
|
|
118
|
-
const selectedOption = useMemo(
|
|
119
|
-
() => options.find((o) => o.value === value),
|
|
120
|
-
[options, value]
|
|
121
|
-
)
|
|
127
|
+
const selectedOption = useMemo(() => options.find((o) => o.value === value), [options, value])
|
|
122
128
|
|
|
123
129
|
// Filter options based on input
|
|
124
130
|
const filteredOptions = useMemo(() => {
|
|
@@ -206,21 +212,14 @@ export function Autocomplete<T extends string = string>({
|
|
|
206
212
|
onBlur={handleBlur}
|
|
207
213
|
placeholder={placeholder}
|
|
208
214
|
editable={!isDisabled}
|
|
209
|
-
className={cn(
|
|
210
|
-
'flex-1 px-3 py-2 text-text-primary',
|
|
211
|
-
'placeholder:text-text-tertiary'
|
|
212
|
-
)}
|
|
215
|
+
className={cn('flex-1 px-3 py-2 text-text-primary', 'placeholder:text-text-tertiary')}
|
|
213
216
|
accessibilityLabel={label}
|
|
214
217
|
{...inputProps}
|
|
215
218
|
/>
|
|
216
219
|
|
|
217
220
|
{/* Clear button */}
|
|
218
221
|
{isClearable && value && !isDisabled && (
|
|
219
|
-
<Pressable
|
|
220
|
-
onPress={handleClear}
|
|
221
|
-
className="p-2"
|
|
222
|
-
accessibilityLabel="Clear selection"
|
|
223
|
-
>
|
|
222
|
+
<Pressable onPress={handleClear} className="p-2" accessibilityLabel="Clear selection">
|
|
224
223
|
<Text className="text-text-tertiary">×</Text>
|
|
225
224
|
</Pressable>
|
|
226
225
|
)}
|
|
@@ -235,11 +234,12 @@ export function Autocomplete<T extends string = string>({
|
|
|
235
234
|
|
|
236
235
|
{/* Dropdown */}
|
|
237
236
|
{isOpen && (
|
|
238
|
-
<
|
|
237
|
+
<Surface
|
|
238
|
+
elevation={4}
|
|
239
|
+
rounded={false}
|
|
239
240
|
className={cn(
|
|
240
241
|
'absolute z-50 top-full left-0 right-0 mt-1',
|
|
241
|
-
'
|
|
242
|
-
'max-h-60 overflow-hidden'
|
|
242
|
+
'rounded-md max-h-60 overflow-hidden'
|
|
243
243
|
)}
|
|
244
244
|
>
|
|
245
245
|
<ScrollView className="py-1">
|
|
@@ -252,16 +252,12 @@ export function Autocomplete<T extends string = string>({
|
|
|
252
252
|
|
|
253
253
|
{/* Loading message */}
|
|
254
254
|
{isLoading && (
|
|
255
|
-
<Text className="px-3 py-2 text-sm text-text-tertiary">
|
|
256
|
-
{loadingText}
|
|
257
|
-
</Text>
|
|
255
|
+
<Text className="px-3 py-2 text-sm text-text-tertiary">{loadingText}</Text>
|
|
258
256
|
)}
|
|
259
257
|
|
|
260
258
|
{/* No results */}
|
|
261
259
|
{showNoResults && (
|
|
262
|
-
<Text className="px-3 py-2 text-sm text-text-tertiary">
|
|
263
|
-
{noOptionsText}
|
|
264
|
-
</Text>
|
|
260
|
+
<Text className="px-3 py-2 text-sm text-text-tertiary">{noOptionsText}</Text>
|
|
265
261
|
)}
|
|
266
262
|
|
|
267
263
|
{/* Options */}
|
|
@@ -312,17 +308,14 @@ export function Autocomplete<T extends string = string>({
|
|
|
312
308
|
)
|
|
313
309
|
})}
|
|
314
310
|
</ScrollView>
|
|
315
|
-
</
|
|
311
|
+
</Surface>
|
|
316
312
|
)}
|
|
317
313
|
</View>
|
|
318
314
|
|
|
319
315
|
{/* Helper/Error text */}
|
|
320
316
|
{(helperText || errorMessage) && (
|
|
321
317
|
<Text
|
|
322
|
-
className={cn(
|
|
323
|
-
'text-xs mt-1',
|
|
324
|
-
isInvalid ? 'text-status-error' : 'text-text-tertiary'
|
|
325
|
-
)}
|
|
318
|
+
className={cn('text-xs mt-1', isInvalid ? 'text-status-error' : 'text-text-tertiary')}
|
|
326
319
|
>
|
|
327
320
|
{errorMessage || helperText}
|
|
328
321
|
</Text>
|
|
@@ -5,7 +5,7 @@ import { Avatar, AvatarBadge, AvatarGroup } from './Avatar'
|
|
|
5
5
|
const meta: Meta<typeof Avatar> = {
|
|
6
6
|
title: 'Components/Atoms/Avatar',
|
|
7
7
|
component: Avatar,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
size: {
|
|
11
11
|
control: 'select',
|
|
@@ -133,12 +133,7 @@ export interface AvatarGroupProps {
|
|
|
133
133
|
/**
|
|
134
134
|
* Group of avatars with stacking effect.
|
|
135
135
|
*/
|
|
136
|
-
export function AvatarGroup({
|
|
137
|
-
children,
|
|
138
|
-
max,
|
|
139
|
-
size = 'md',
|
|
140
|
-
className,
|
|
141
|
-
}: AvatarGroupProps) {
|
|
136
|
+
export function AvatarGroup({ children, max, size = 'md', className }: AvatarGroupProps) {
|
|
142
137
|
const childArray = React.Children.toArray(children)
|
|
143
138
|
const visibleChildren = max ? childArray.slice(0, max) : childArray
|
|
144
139
|
const remainingCount = max ? Math.max(0, childArray.length - max) : 0
|
|
@@ -148,10 +143,7 @@ export function AvatarGroup({
|
|
|
148
143
|
{visibleChildren.map((child, index) => (
|
|
149
144
|
<View
|
|
150
145
|
key={index}
|
|
151
|
-
className={cn(
|
|
152
|
-
'border-2 border-surface-base rounded-full',
|
|
153
|
-
index > 0 && '-ml-2'
|
|
154
|
-
)}
|
|
146
|
+
className={cn('border-2 border-surface-base rounded-full', index > 0 && '-ml-2')}
|
|
155
147
|
>
|
|
156
148
|
{React.isValidElement(child)
|
|
157
149
|
? React.cloneElement(child as React.ReactElement<any>, { size })
|