@titan-design/react-ui 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -47
- package/dist/bodymap.js +768 -701
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +770 -703
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1319 -216
- package/dist/index.d.ts +1319 -216
- package/dist/index.js +5996 -4498
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5773 -4357
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
- package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1435 -1428
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1443 -1436
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +195 -134
- package/dist/theme/index.d.ts +195 -134
- package/dist/theme/index.js +215 -300
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +202 -296
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +62 -5
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +62 -5
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +73 -5
- package/dist/theme/tokens.d.ts +73 -5
- package/dist/theme/tokens.js +55 -7
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +55 -8
- 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/package.json +1 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +5021 -1617
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +4 -1
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +116 -14
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +98 -15
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +7 -2
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +3 -0
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +3 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +21 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
- package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +4 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +12 -9
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +11 -6
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/index.ts +5 -0
- package/src/components/custom/Workout/metricText.stories.tsx +6 -5
- package/src/components/custom/Workout/metricText.tsx +4 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
- package/src/components/custom/charts/README.md +61 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
- package/src/components/custom/charts/SetBarChart.tsx +42 -4
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +13 -28
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +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 +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +32 -25
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +6 -26
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -30
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +2 -12
- package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +29 -19
- package/src/components/ui/pill/Pill.stories.tsx +58 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +164 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +5 -7
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +5 -14
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +14 -14
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +1 -4
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +17 -5
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +7 -22
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +43 -53
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +100 -47
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +23 -21
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +28 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +30 -2
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/token-export-guard.test.ts +1 -3
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +65 -33
- package/src/theme/tokens/semantic.ts +71 -37
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +5 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// The depth contract every floating overlay owes the lift model (E1).
|
|
2
|
+
//
|
|
3
|
+
// One panel, one recipe: the overlay plane from the grey ramp, the rim-light,
|
|
4
|
+
// the three-layer ambient shadow, and NO hairline ring — a ring is an edge, not
|
|
5
|
+
// a lift, and stays the divider's job. The panels are asserted as INLINE STYLE
|
|
6
|
+
// because `<Surface>` writes background and shadow into `style`; a `bg-*` or
|
|
7
|
+
// `shadow-*` className on one would be discarded, so asserting the class would
|
|
8
|
+
// pass while the render was wrong. The plane comes from the ramp, so a re-space
|
|
9
|
+
// moves these expectations rather than breaking them.
|
|
10
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
11
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
12
|
+
import { greyRamp } from '../../theme/tokens/primitives'
|
|
13
|
+
import { Autocomplete } from './autocomplete'
|
|
14
|
+
import { Drawer, DrawerBody } from './drawer'
|
|
15
|
+
import { HelpTip } from './help-tip'
|
|
16
|
+
import { Menu, MenuTrigger, MenuList, MenuItem } from './menu'
|
|
17
|
+
import { Modal, ModalContent, ModalBody } from './modal'
|
|
18
|
+
import { Popover, PopoverTrigger, PopoverContent } from './popover'
|
|
19
|
+
import { Select } from './select'
|
|
20
|
+
import { Toast } from './toast'
|
|
21
|
+
import { Tooltip } from './tooltip'
|
|
22
|
+
|
|
23
|
+
/** The plane every floating overlay shares: past the top of the ramp. */
|
|
24
|
+
const OVERLAY = greyRamp[850]
|
|
25
|
+
|
|
26
|
+
/** The nearest ancestor that paints a plane of its own — the floating panel. */
|
|
27
|
+
function panelAround(child: HTMLElement): HTMLElement {
|
|
28
|
+
let el: HTMLElement | null = child
|
|
29
|
+
while (el && !el.style.boxShadow) el = el.parentElement
|
|
30
|
+
if (!el) throw new Error('no element with an inline boxShadow above the panel content')
|
|
31
|
+
return el
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Split a boxShadow on its layer commas, ignoring the ones inside `rgba(...)`. */
|
|
35
|
+
function shadowLayers(boxShadow: string): string[] {
|
|
36
|
+
return boxShadow.split(/,(?![^(]*\))/).filter((layer) => layer.trim())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function expectFloating(panel: HTMLElement) {
|
|
40
|
+
expect(panel).toHaveStyle({ backgroundColor: OVERLAY })
|
|
41
|
+
const layers = shadowLayers(panel.style.boxShadow)
|
|
42
|
+
expect(layers[0]).toContain('inset 0 1px 0 rgba(255,255,255,0.12)')
|
|
43
|
+
// Three ambient layers under the rim: the floating shadow, not a content lift.
|
|
44
|
+
expect(layers.slice(1)).toHaveLength(3)
|
|
45
|
+
expect(panel.style.borderTopWidth).toBe('')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Open the overlay, then assert the panel wrapping `contentText`. */
|
|
49
|
+
function expectFloatingPanelAround(contentText: string) {
|
|
50
|
+
expectFloating(panelAround(screen.getByText(contentText)))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const options = [
|
|
54
|
+
{ value: '1', label: 'Apple' },
|
|
55
|
+
{ value: '2', label: 'Banana' },
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
describe('floating overlay depth', () => {
|
|
59
|
+
it('Menu list floats on the overlay plane with no ring', () => {
|
|
60
|
+
render(
|
|
61
|
+
<Menu>
|
|
62
|
+
<MenuTrigger>
|
|
63
|
+
<button>Options</button>
|
|
64
|
+
</MenuTrigger>
|
|
65
|
+
<MenuList>
|
|
66
|
+
<MenuItem>Edit</MenuItem>
|
|
67
|
+
</MenuList>
|
|
68
|
+
</Menu>
|
|
69
|
+
)
|
|
70
|
+
fireEvent.click(screen.getByText('Options'))
|
|
71
|
+
expectFloatingPanelAround('Edit')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('Popover content floats on the overlay plane with no ring', () => {
|
|
75
|
+
render(
|
|
76
|
+
<Popover>
|
|
77
|
+
<PopoverTrigger>
|
|
78
|
+
<button>Open</button>
|
|
79
|
+
</PopoverTrigger>
|
|
80
|
+
<PopoverContent>
|
|
81
|
+
<span>Popover body</span>
|
|
82
|
+
</PopoverContent>
|
|
83
|
+
</Popover>
|
|
84
|
+
)
|
|
85
|
+
fireEvent.click(screen.getByText('Open'))
|
|
86
|
+
expectFloatingPanelAround('Popover body')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('Tooltip box floats on the overlay plane with no ring', () => {
|
|
90
|
+
render(
|
|
91
|
+
<Tooltip label="Tooltip text">
|
|
92
|
+
<button>Hover me</button>
|
|
93
|
+
</Tooltip>
|
|
94
|
+
)
|
|
95
|
+
fireEvent.mouseEnter(screen.getByText('Hover me').closest('[tabindex]')!)
|
|
96
|
+
expectFloatingPanelAround('Tooltip text')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('HelpTip bubble floats on the overlay plane with no ring', () => {
|
|
100
|
+
render(<HelpTip content="Help text" />)
|
|
101
|
+
fireEvent.click(screen.getByRole('button', { name: 'Show help information' }))
|
|
102
|
+
expectFloatingPanelAround('Help text')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('Select dropdown floats on the overlay plane with no ring', () => {
|
|
106
|
+
render(<Select options={options} />)
|
|
107
|
+
fireEvent.click(screen.getByRole('combobox'))
|
|
108
|
+
expectFloatingPanelAround('Banana')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('Autocomplete dropdown floats on the overlay plane with no ring', () => {
|
|
112
|
+
render(<Autocomplete options={options} placeholder="Search" />)
|
|
113
|
+
fireEvent.focus(screen.getByPlaceholderText('Search'))
|
|
114
|
+
expectFloatingPanelAround('Banana')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('Drawer panel floats on the overlay plane with no ring', () => {
|
|
118
|
+
render(
|
|
119
|
+
<Drawer isOpen onClose={vi.fn()} title="Test Drawer">
|
|
120
|
+
<DrawerBody>Drawer body</DrawerBody>
|
|
121
|
+
</Drawer>
|
|
122
|
+
)
|
|
123
|
+
expectFloatingPanelAround('Drawer body')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('Modal content floats on the deepest lift with no ring', () => {
|
|
127
|
+
render(
|
|
128
|
+
<Modal isOpen onClose={vi.fn()}>
|
|
129
|
+
<ModalContent>
|
|
130
|
+
<ModalBody>Modal body</ModalBody>
|
|
131
|
+
</ModalContent>
|
|
132
|
+
</Modal>
|
|
133
|
+
)
|
|
134
|
+
expectFloatingPanelAround('Modal body')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('Toast floats on the deepest lift with no ring', () => {
|
|
138
|
+
render(<Toast title="Saved" />)
|
|
139
|
+
// Its `border-l-4` status stripe is a colour accent on one edge, not a ring,
|
|
140
|
+
// and rides the className rather than the inline style asserted here.
|
|
141
|
+
expectFloatingPanelAround('Saved')
|
|
142
|
+
})
|
|
143
|
+
})
|
|
@@ -2,12 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
2
2
|
import { View, Text, TextInput } from 'react-native'
|
|
3
3
|
import { FormField, FormSection, FormActions, FormRow } from './FormField'
|
|
4
4
|
import { Button, ButtonText } from '../button'
|
|
5
|
-
import { Input } from '../input'
|
|
6
5
|
|
|
7
6
|
const meta: Meta<typeof FormField> = {
|
|
8
7
|
title: 'Components/Molecules/FormField',
|
|
9
8
|
component: FormField,
|
|
10
|
-
|
|
9
|
+
parameters: {},
|
|
10
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
11
11
|
argTypes: {
|
|
12
12
|
labelSize: {
|
|
13
13
|
control: 'select',
|
|
@@ -70,10 +70,7 @@ export const Required: Story = {
|
|
|
70
70
|
export const WithHelperText: Story = {
|
|
71
71
|
render: () => (
|
|
72
72
|
<View className="w-80">
|
|
73
|
-
<FormField
|
|
74
|
-
label="Username"
|
|
75
|
-
helperText="Choose a unique username between 3-20 characters"
|
|
76
|
-
>
|
|
73
|
+
<FormField label="Username" helperText="Choose a unique username between 3-20 characters">
|
|
77
74
|
<SimpleInput placeholder="Enter username" />
|
|
78
75
|
</FormField>
|
|
79
76
|
</View>
|
|
@@ -83,11 +80,7 @@ export const WithHelperText: Story = {
|
|
|
83
80
|
export const WithError: Story = {
|
|
84
81
|
render: () => (
|
|
85
82
|
<View className="w-80">
|
|
86
|
-
<FormField
|
|
87
|
-
label="Password"
|
|
88
|
-
isRequired
|
|
89
|
-
errorMessage="Password must be at least 8 characters"
|
|
90
|
-
>
|
|
83
|
+
<FormField label="Password" isRequired errorMessage="Password must be at least 8 characters">
|
|
91
84
|
<SimpleInput placeholder="Enter password" isInvalid />
|
|
92
85
|
</FormField>
|
|
93
86
|
</View>
|
|
@@ -159,10 +152,7 @@ export const FormRowExample: Story = {
|
|
|
159
152
|
export const FormSectionExample: Story = {
|
|
160
153
|
render: () => (
|
|
161
154
|
<View className="w-full max-w-lg">
|
|
162
|
-
<FormSection
|
|
163
|
-
title="Personal Information"
|
|
164
|
-
description="Please provide your personal details"
|
|
165
|
-
>
|
|
155
|
+
<FormSection title="Personal Information" description="Please provide your personal details">
|
|
166
156
|
<FormRow>
|
|
167
157
|
<FormField label="First Name" isRequired className="flex-1">
|
|
168
158
|
<SimpleInput placeholder="John" />
|
|
@@ -240,11 +230,7 @@ export const ValidationStates: Story = {
|
|
|
240
230
|
</View>
|
|
241
231
|
</FormField>
|
|
242
232
|
|
|
243
|
-
<FormField
|
|
244
|
-
label="Invalid Input"
|
|
245
|
-
isRequired
|
|
246
|
-
errorMessage="Please enter a valid email address"
|
|
247
|
-
>
|
|
233
|
+
<FormField label="Invalid Input" isRequired errorMessage="Please enter a valid email address">
|
|
248
234
|
<View className="border border-status-error rounded-md px-3 py-2 bg-surface-input">
|
|
249
235
|
<Text className="text-text-primary">not-an-email</Text>
|
|
250
236
|
</View>
|
|
@@ -64,11 +64,7 @@ describe('FormField', () => {
|
|
|
64
64
|
|
|
65
65
|
it('shows error message instead of helper text when both are provided', () => {
|
|
66
66
|
render(
|
|
67
|
-
<FormField
|
|
68
|
-
label="Email"
|
|
69
|
-
helperText="Enter a valid email"
|
|
70
|
-
errorMessage="Invalid email"
|
|
71
|
-
>
|
|
67
|
+
<FormField label="Email" helperText="Enter a valid email" errorMessage="Invalid email">
|
|
72
68
|
<input />
|
|
73
69
|
</FormField>
|
|
74
70
|
)
|
|
@@ -95,22 +95,12 @@ export function FormField({
|
|
|
95
95
|
{/* Label Section */}
|
|
96
96
|
{label && (
|
|
97
97
|
<View
|
|
98
|
-
className={cn(
|
|
99
|
-
'flex-row items-center',
|
|
100
|
-
isHorizontal ? 'pt-2' : 'mb-1.5'
|
|
101
|
-
)}
|
|
98
|
+
className={cn('flex-row items-center', isHorizontal ? 'pt-2' : 'mb-1.5')}
|
|
102
99
|
style={isHorizontal && labelWidth ? { width: labelWidth as number } : undefined}
|
|
103
100
|
>
|
|
104
|
-
<Text
|
|
105
|
-
className={cn(
|
|
106
|
-
'font-medium text-text-primary',
|
|
107
|
-
labelSizeStyles[labelSize]
|
|
108
|
-
)}
|
|
109
|
-
>
|
|
101
|
+
<Text className={cn('font-medium text-text-primary', labelSizeStyles[labelSize])}>
|
|
110
102
|
{label}
|
|
111
|
-
{isRequired &&
|
|
112
|
-
<Text className="text-status-error ml-0.5">*</Text>
|
|
113
|
-
)}
|
|
103
|
+
{isRequired && <Text className="text-status-error ml-0.5">*</Text>}
|
|
114
104
|
</Text>
|
|
115
105
|
|
|
116
106
|
{helpContent && (
|
|
@@ -147,10 +137,7 @@ export function FormField({
|
|
|
147
137
|
{(helperText || errorMessage) && (
|
|
148
138
|
<Text
|
|
149
139
|
id={isInvalid ? errorId : helperId}
|
|
150
|
-
className={cn(
|
|
151
|
-
'text-xs mt-1.5',
|
|
152
|
-
isInvalid ? 'text-status-error' : 'text-text-tertiary'
|
|
153
|
-
)}
|
|
140
|
+
className={cn('text-xs mt-1.5', isInvalid ? 'text-status-error' : 'text-text-tertiary')}
|
|
154
141
|
>
|
|
155
142
|
{errorMessage || helperText}
|
|
156
143
|
</Text>
|
|
@@ -199,22 +186,12 @@ export function FormSection({
|
|
|
199
186
|
>
|
|
200
187
|
{(title || description) && (
|
|
201
188
|
<View className="mb-4">
|
|
202
|
-
{title &&
|
|
203
|
-
|
|
204
|
-
{title}
|
|
205
|
-
</Text>
|
|
206
|
-
)}
|
|
207
|
-
{description && (
|
|
208
|
-
<Text className="text-sm text-text-secondary mt-1">
|
|
209
|
-
{description}
|
|
210
|
-
</Text>
|
|
211
|
-
)}
|
|
189
|
+
{title && <Text className="text-lg font-semibold text-text-primary">{title}</Text>}
|
|
190
|
+
{description && <Text className="text-sm text-text-secondary mt-1">{description}</Text>}
|
|
212
191
|
</View>
|
|
213
192
|
)}
|
|
214
193
|
|
|
215
|
-
<View className="gap-4">
|
|
216
|
-
{children}
|
|
217
|
-
</View>
|
|
194
|
+
<View className="gap-4">{children}</View>
|
|
218
195
|
</View>
|
|
219
196
|
)
|
|
220
197
|
}
|
|
@@ -243,12 +220,7 @@ const alignStyles = {
|
|
|
243
220
|
* <Button>Submit</Button>
|
|
244
221
|
* </FormActions>
|
|
245
222
|
*/
|
|
246
|
-
export function FormActions({
|
|
247
|
-
align = 'right',
|
|
248
|
-
className,
|
|
249
|
-
children,
|
|
250
|
-
...props
|
|
251
|
-
}: FormActionsProps) {
|
|
223
|
+
export function FormActions({ align = 'right', className, children, ...props }: FormActionsProps) {
|
|
252
224
|
return (
|
|
253
225
|
<View
|
|
254
226
|
className={cn(
|
|
@@ -291,17 +263,9 @@ const gapStyles = {
|
|
|
291
263
|
* </FormField>
|
|
292
264
|
* </FormRow>
|
|
293
265
|
*/
|
|
294
|
-
export function FormRow({
|
|
295
|
-
gap = 'md',
|
|
296
|
-
className,
|
|
297
|
-
children,
|
|
298
|
-
...props
|
|
299
|
-
}: FormRowProps) {
|
|
266
|
+
export function FormRow({ gap = 'md', className, children, ...props }: FormRowProps) {
|
|
300
267
|
return (
|
|
301
|
-
<View
|
|
302
|
-
className={cn('flex-row items-start', gapStyles[gap], className)}
|
|
303
|
-
{...props}
|
|
304
|
-
>
|
|
268
|
+
<View className={cn('flex-row items-start', gapStyles[gap], className)} {...props}>
|
|
305
269
|
{children}
|
|
306
270
|
</View>
|
|
307
271
|
)
|
|
@@ -5,7 +5,7 @@ import { HelpTip, LabelWithHelp } from './HelpTip'
|
|
|
5
5
|
const meta: Meta<typeof HelpTip> = {
|
|
6
6
|
title: 'Components/Molecules/HelpTip',
|
|
7
7
|
component: HelpTip,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
size: {
|
|
11
11
|
control: 'select',
|
|
@@ -115,7 +115,8 @@ export const AllPlacements: Story = {
|
|
|
115
115
|
|
|
116
116
|
export const WithLongContent: Story = {
|
|
117
117
|
args: {
|
|
118
|
-
content:
|
|
118
|
+
content:
|
|
119
|
+
'This is a longer tooltip that contains more detailed information about the feature. It will wrap to multiple lines if needed, and you can customize the max width.',
|
|
119
120
|
maxWidth: 300,
|
|
120
121
|
},
|
|
121
122
|
}
|
|
@@ -126,15 +127,9 @@ export const WithRichContent: Story = {
|
|
|
126
127
|
content={
|
|
127
128
|
<View className="gap-1">
|
|
128
129
|
<Text className="text-sm font-semibold text-text-primary">API Rate Limits</Text>
|
|
129
|
-
<Text className="text-xs text-text-secondary">
|
|
130
|
-
|
|
131
|
-
</Text>
|
|
132
|
-
<Text className="text-xs text-text-secondary">
|
|
133
|
-
• Pro tier: 1000 requests/hour
|
|
134
|
-
</Text>
|
|
135
|
-
<Text className="text-xs text-text-secondary">
|
|
136
|
-
• Enterprise: Unlimited
|
|
137
|
-
</Text>
|
|
130
|
+
<Text className="text-xs text-text-secondary">• Free tier: 100 requests/hour</Text>
|
|
131
|
+
<Text className="text-xs text-text-secondary">• Pro tier: 1000 requests/hour</Text>
|
|
132
|
+
<Text className="text-xs text-text-secondary">• Enterprise: Unlimited</Text>
|
|
138
133
|
</View>
|
|
139
134
|
}
|
|
140
135
|
icon="info"
|
|
@@ -148,10 +143,7 @@ export const InlineWithLabel: Story = {
|
|
|
148
143
|
<View className="gap-4">
|
|
149
144
|
<View className="flex-row items-center gap-1">
|
|
150
145
|
<Text className="text-sm font-medium text-text-primary">Email Address</Text>
|
|
151
|
-
<HelpTip
|
|
152
|
-
content="We'll never share your email with third parties."
|
|
153
|
-
size="sm"
|
|
154
|
-
/>
|
|
146
|
+
<HelpTip content="We'll never share your email with third parties." size="sm" />
|
|
155
147
|
</View>
|
|
156
148
|
|
|
157
149
|
<View className="flex-row items-center gap-1">
|
|
@@ -178,10 +170,7 @@ export const InlineWithLabel: Story = {
|
|
|
178
170
|
export const LabelWithHelpComponent: Story = {
|
|
179
171
|
render: () => (
|
|
180
172
|
<View className="gap-4">
|
|
181
|
-
<LabelWithHelp
|
|
182
|
-
label="Username"
|
|
183
|
-
helpContent="Choose a unique username for your account."
|
|
184
|
-
/>
|
|
173
|
+
<LabelWithHelp label="Username" helpContent="Choose a unique username for your account." />
|
|
185
174
|
|
|
186
175
|
<LabelWithHelp
|
|
187
176
|
label="Email Address"
|
|
@@ -28,9 +28,7 @@ describe('HelpTip', () => {
|
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
it('renders custom ReactNode content', () => {
|
|
31
|
-
render(
|
|
32
|
-
<HelpTip content={<span data-testid="custom-content">Rich content</span>} />
|
|
33
|
-
)
|
|
31
|
+
render(<HelpTip content={<span data-testid="custom-content">Rich content</span>} />)
|
|
34
32
|
|
|
35
33
|
fireEvent.click(screen.getByRole('button', { name: 'Show help information' }))
|
|
36
34
|
expect(screen.getByTestId('custom-content')).toBeInTheDocument()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { View, Text, Pressable, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { Surface } from '../surface'
|
|
4
5
|
|
|
5
6
|
export type HelpTipSize = 'sm' | 'md' | 'lg'
|
|
6
7
|
export type HelpTipPlacement = 'top' | 'bottom' | 'left' | 'right'
|
|
@@ -56,10 +57,12 @@ const placementStyles: Record<HelpTipPlacement, string> = {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
const arrowStyles: Record<HelpTipPlacement, string> = {
|
|
59
|
-
top: 'bottom-0 left-1/2 -translate-x-1/2 translate-y-full border-t-surface-
|
|
60
|
-
bottom:
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
top: 'bottom-0 left-1/2 -translate-x-1/2 translate-y-full border-t-surface-overlay border-x-transparent border-b-transparent',
|
|
61
|
+
bottom:
|
|
62
|
+
'top-0 left-1/2 -translate-x-1/2 -translate-y-full border-b-surface-overlay border-x-transparent border-t-transparent',
|
|
63
|
+
left: 'right-0 top-1/2 -translate-y-1/2 translate-x-full border-l-surface-overlay border-y-transparent border-r-transparent',
|
|
64
|
+
right:
|
|
65
|
+
'left-0 top-1/2 -translate-y-1/2 -translate-x-full border-r-surface-overlay border-y-transparent border-l-transparent',
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/**
|
|
@@ -87,6 +90,9 @@ const arrowStyles: Record<HelpTipPlacement, string> = {
|
|
|
87
90
|
* <Text>Email Address</Text>
|
|
88
91
|
* <HelpTip content="We'll never share your email with anyone." size="sm" />
|
|
89
92
|
* </View>
|
|
93
|
+
*
|
|
94
|
+
* @deprecated Use `Tooltip` (roadmap decision 5) — removed after AW-127
|
|
95
|
+
* consumer migration.
|
|
90
96
|
*/
|
|
91
97
|
export function HelpTip({
|
|
92
98
|
content,
|
|
@@ -144,43 +150,33 @@ export function HelpTip({
|
|
|
144
150
|
iconClassName
|
|
145
151
|
)}
|
|
146
152
|
>
|
|
147
|
-
<Text className={cn('font-semibold', iconSize, colorStyles[color])}>
|
|
148
|
-
{iconMap[icon]}
|
|
149
|
-
</Text>
|
|
153
|
+
<Text className={cn('font-semibold', iconSize, colorStyles[color])}>{iconMap[icon]}</Text>
|
|
150
154
|
</Pressable>
|
|
151
155
|
|
|
152
156
|
{/* Tooltip */}
|
|
153
157
|
{isOpen && (
|
|
154
|
-
<
|
|
158
|
+
<Surface
|
|
159
|
+
elevation={4}
|
|
160
|
+
rounded={false}
|
|
155
161
|
className={cn(
|
|
156
162
|
'absolute z-50',
|
|
157
|
-
'
|
|
158
|
-
'border border-hairline',
|
|
159
|
-
'px-3 py-2',
|
|
163
|
+
'rounded-lg px-3 py-2',
|
|
160
164
|
placementStyles[placement],
|
|
161
165
|
tooltipClassName
|
|
162
166
|
)}
|
|
163
167
|
style={{ maxWidth }}
|
|
164
168
|
>
|
|
165
169
|
{typeof content === 'string' ? (
|
|
166
|
-
<Text className={cn('text-text-primary', textSize)}>
|
|
167
|
-
{content}
|
|
168
|
-
</Text>
|
|
170
|
+
<Text className={cn('text-text-primary', textSize)}>{content}</Text>
|
|
169
171
|
) : (
|
|
170
172
|
content
|
|
171
173
|
)}
|
|
172
174
|
|
|
173
175
|
{/* Arrow */}
|
|
174
176
|
{hasArrow && (
|
|
175
|
-
<View
|
|
176
|
-
className={cn(
|
|
177
|
-
'absolute w-0 h-0',
|
|
178
|
-
'border-4',
|
|
179
|
-
arrowStyles[placement]
|
|
180
|
-
)}
|
|
181
|
-
/>
|
|
177
|
+
<View className={cn('absolute w-0 h-0', 'border-4', arrowStyles[placement])} />
|
|
182
178
|
)}
|
|
183
|
-
</
|
|
179
|
+
</Surface>
|
|
184
180
|
)}
|
|
185
181
|
</View>
|
|
186
182
|
)
|
|
@@ -208,6 +204,9 @@ export interface LabelWithHelpProps extends ViewProps {
|
|
|
208
204
|
* helpContent="Your API key can be found in the developer settings."
|
|
209
205
|
* isRequired
|
|
210
206
|
* />
|
|
207
|
+
*
|
|
208
|
+
* @deprecated Use `Tooltip` beside your own label (roadmap decision 5) —
|
|
209
|
+
* removed after AW-127 consumer migration.
|
|
211
210
|
*/
|
|
212
211
|
export function LabelWithHelp({
|
|
213
212
|
label,
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export { HelpTip, LabelWithHelp } from './HelpTip'
|
|
2
|
-
export type {
|
|
2
|
+
export type {
|
|
3
|
+
HelpTipProps,
|
|
4
|
+
LabelWithHelpProps,
|
|
5
|
+
HelpTipSize,
|
|
6
|
+
HelpTipPlacement,
|
|
7
|
+
HelpTipIcon,
|
|
8
|
+
} from './HelpTip'
|
|
@@ -55,7 +55,7 @@ function BoltIcon({ size = 20, className }: { size?: number; className?: string
|
|
|
55
55
|
const meta: Meta<typeof IconBox> = {
|
|
56
56
|
title: 'Components/Atoms/IconBox',
|
|
57
57
|
component: IconBox,
|
|
58
|
-
tags: ['autodocs'],
|
|
58
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
59
59
|
argTypes: {
|
|
60
60
|
color: {
|
|
61
61
|
control: 'select',
|
|
@@ -98,13 +98,7 @@ describe('IconBox', () => {
|
|
|
98
98
|
|
|
99
99
|
it('renders with all props combined', () => {
|
|
100
100
|
render(
|
|
101
|
-
<IconBox
|
|
102
|
-
icon={MockIcon}
|
|
103
|
-
color="success"
|
|
104
|
-
size="lg"
|
|
105
|
-
className="mt-2"
|
|
106
|
-
testID="full-icon-box"
|
|
107
|
-
/>,
|
|
101
|
+
<IconBox icon={MockIcon} color="success" size="lg" className="mt-2" testID="full-icon-box" />
|
|
108
102
|
)
|
|
109
103
|
expect(screen.getByTestId('full-icon-box')).toBeInTheDocument()
|
|
110
104
|
expect(screen.getByTestId('icon')).toHaveAttribute('data-size', '24')
|
|
@@ -2,14 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { View, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
4
|
|
|
5
|
-
type IconBoxColor =
|
|
6
|
-
| 'primary'
|
|
7
|
-
| 'secondary'
|
|
8
|
-
| 'success'
|
|
9
|
-
| 'error'
|
|
10
|
-
| 'warning'
|
|
11
|
-
| 'info'
|
|
12
|
-
| 'neutral'
|
|
5
|
+
type IconBoxColor = 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'neutral'
|
|
13
6
|
|
|
14
7
|
type IconBoxSize = 'sm' | 'md' | 'lg'
|
|
15
8
|
|
|
@@ -47,10 +40,7 @@ export function IconBox({
|
|
|
47
40
|
const sizes = sizeClasses[size]
|
|
48
41
|
|
|
49
42
|
return (
|
|
50
|
-
<View
|
|
51
|
-
className={cn('items-center justify-center', colors.bg, sizes.box, className)}
|
|
52
|
-
{...props}
|
|
53
|
-
>
|
|
43
|
+
<View className={cn('items-center justify-center', colors.bg, sizes.box, className)} {...props}>
|
|
54
44
|
<Icon size={sizes.iconSize} className={colors.icon} />
|
|
55
45
|
</View>
|
|
56
46
|
)
|
|
@@ -5,7 +5,7 @@ import { Indicator } from './Indicator'
|
|
|
5
5
|
const meta: Meta<typeof Indicator> = {
|
|
6
6
|
title: 'Components/Atoms/Indicator',
|
|
7
7
|
component: Indicator,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
size: { control: 'select', options: ['xs', 'sm', 'md', 'lg'] },
|
|
11
11
|
color: {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { View, type ViewProps } from 'react-native'
|
|
2
2
|
import { cn } from '../../../utils/cn'
|
|
3
|
+
import { getGlowShadow } from '../../../theme/elevation'
|
|
4
|
+
import { getSemanticColors } from '../../../theme/tokens/semantic'
|
|
5
|
+
import { greyRamp } from '../../../theme/tokens/primitives'
|
|
3
6
|
|
|
4
7
|
export type IndicatorSize = 'xs' | 'sm' | 'md' | 'lg'
|
|
5
8
|
export type IndicatorColor =
|
|
@@ -50,6 +53,21 @@ const colorStyles: Record<IndicatorColor, string> = {
|
|
|
50
53
|
'error-vivid': 'bg-status-error-vivid',
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
// Glow is EMPHASIS, not depth: the dot's own colour, through the shared builder.
|
|
57
|
+
// Literal hex (not `resolveColor`) because getGlowShadow does colour maths on it.
|
|
58
|
+
const t = getSemanticColors('dark')
|
|
59
|
+
|
|
60
|
+
const glowColors: Record<IndicatorColor, string> = {
|
|
61
|
+
default: greyRamp[500],
|
|
62
|
+
primary: t['brand-primary'],
|
|
63
|
+
success: t['status-success'],
|
|
64
|
+
live: t['status-live'],
|
|
65
|
+
error: t['status-error'],
|
|
66
|
+
warning: t['status-warning'],
|
|
67
|
+
info: t['status-info'],
|
|
68
|
+
'error-vivid': t['status-error-vivid'],
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
export function Indicator({
|
|
54
72
|
size = 'sm',
|
|
55
73
|
color = 'default',
|
|
@@ -86,11 +104,7 @@ export function Indicator({
|
|
|
86
104
|
)
|
|
87
105
|
}
|
|
88
106
|
|
|
89
|
-
const
|
|
90
|
-
...(typeof style === 'object' ? style : {}),
|
|
91
|
-
...(colorStyle ?? {}),
|
|
92
|
-
...(glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}),
|
|
93
|
-
}
|
|
107
|
+
const glowStyle = glow ? getGlowShadow(customColor ?? glowColors[color], 'subtle') : null
|
|
94
108
|
|
|
95
109
|
return (
|
|
96
110
|
<View
|
|
@@ -100,17 +114,9 @@ export function Indicator({
|
|
|
100
114
|
colorClass,
|
|
101
115
|
pulseMode === 'opacity' && 'animate-pulse',
|
|
102
116
|
ring && 'border-2 border-background-base',
|
|
103
|
-
glow &&
|
|
104
|
-
!customColor &&
|
|
105
|
-
(color === 'success' || color === 'live') &&
|
|
106
|
-
'shadow-[0_0_6px_rgba(46,213,115,0.6)]',
|
|
107
|
-
glow && !customColor && color === 'error' && 'shadow-[0_0_6px_rgba(239,68,68,0.6)]',
|
|
108
|
-
glow && !customColor && color === 'warning' && 'shadow-[0_0_6px_rgba(245,158,11,0.6)]',
|
|
109
|
-
glow && !customColor && color === 'primary' && 'shadow-[0_0_6px_rgba(255,121,0,0.6)]',
|
|
110
|
-
glow && !customColor && color === 'error-vivid' && 'shadow-[0_0_6px_rgba(255,71,87,0.6)]',
|
|
111
117
|
className
|
|
112
118
|
)}
|
|
113
|
-
style={
|
|
119
|
+
style={[style, colorStyle, glowStyle]}
|
|
114
120
|
{...props}
|
|
115
121
|
/>
|
|
116
122
|
)
|
|
@@ -5,7 +5,7 @@ import { Input, InputGroup, PasswordInput } from './Input'
|
|
|
5
5
|
const meta: Meta<typeof Input> = {
|
|
6
6
|
title: 'Components/Molecules/Input',
|
|
7
7
|
component: Input,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
variant: {
|
|
11
11
|
control: 'select',
|
|
@@ -161,10 +161,7 @@ function SearchIcon() {
|
|
|
161
161
|
export const WithLeftElement: Story = {
|
|
162
162
|
render: () => (
|
|
163
163
|
<View style={{ gap: 16, width: 300 }}>
|
|
164
|
-
<Input
|
|
165
|
-
placeholder="Search..."
|
|
166
|
-
leftElement={<SearchIcon />}
|
|
167
|
-
/>
|
|
164
|
+
<Input placeholder="Search..." leftElement={<SearchIcon />} />
|
|
168
165
|
</View>
|
|
169
166
|
),
|
|
170
167
|
}
|
|
@@ -181,12 +178,7 @@ export const FormExample: Story = {
|
|
|
181
178
|
helperText="Must be at least 8 characters"
|
|
182
179
|
isRequired
|
|
183
180
|
/>
|
|
184
|
-
<Input
|
|
185
|
-
label="Bio"
|
|
186
|
-
placeholder="Tell us about yourself..."
|
|
187
|
-
multiline
|
|
188
|
-
numberOfLines={3}
|
|
189
|
-
/>
|
|
181
|
+
<Input label="Bio" placeholder="Tell us about yourself..." multiline numberOfLines={3} />
|
|
190
182
|
</InputGroup>
|
|
191
183
|
),
|
|
192
184
|
}
|