@titan-design/react-ui 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -47
- package/dist/bodymap.js +768 -701
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +770 -703
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1320 -215
- package/dist/index.d.ts +1320 -215
- package/dist/index.js +5996 -4498
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5773 -4357
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
- package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1435 -1428
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1443 -1436
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +202 -1042
- package/dist/theme/index.d.ts +202 -1042
- package/dist/theme/index.js +215 -300
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +202 -296
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +62 -5
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +62 -5
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +972 -0
- package/dist/theme/tokens.d.ts +972 -0
- package/dist/theme/tokens.js +904 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/tokens.mjs +880 -0
- package/dist/theme/tokens.mjs.map +1 -0
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/package.json +7 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +5021 -1617
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +4 -1
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +116 -14
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +98 -15
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +7 -2
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +3 -0
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +3 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +21 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
- package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +4 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +12 -9
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +12 -7
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/index.ts +5 -0
- package/src/components/custom/Workout/metricText.stories.tsx +6 -5
- package/src/components/custom/Workout/metricText.tsx +4 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
- package/src/components/custom/charts/README.md +61 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
- package/src/components/custom/charts/SetBarChart.tsx +42 -4
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +13 -28
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +90 -27
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +32 -25
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +6 -26
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -30
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +2 -12
- package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +29 -19
- package/src/components/ui/pill/Pill.stories.tsx +58 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +164 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +5 -7
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +5 -14
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +14 -14
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +1 -4
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +17 -5
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +7 -22
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +43 -53
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +100 -47
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +24 -22
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +28 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +30 -2
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/token-export-guard.test.ts +102 -0
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +67 -35
- package/src/theme/tokens/semantic.ts +71 -37
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +5 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
package/dist/bodymap.js
CHANGED
|
@@ -19,6 +19,7 @@ function cn(...inputs) {
|
|
|
19
19
|
// src/theme/tokens/primitives.ts
|
|
20
20
|
var primitiveColors = {
|
|
21
21
|
white: "#FFFFFF"};
|
|
22
|
+
var alertRedVivid = "#FF4757";
|
|
22
23
|
var greyRamp = {
|
|
23
24
|
50: "#F9F6F3",
|
|
24
25
|
// L*97.0 W6
|
|
@@ -141,12 +142,16 @@ var semanticColorsLight = {
|
|
|
141
142
|
"brand-primary-light": primitiveRamps.orange[300],
|
|
142
143
|
"brand-primary-dark": primitiveRamps.orange[500],
|
|
143
144
|
"brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
|
|
145
|
+
"brand-primary-muted": "rgba(255, 121, 0, 0.30)",
|
|
146
|
+
"brand-primary-strong": "rgba(255, 121, 0, 0.50)",
|
|
144
147
|
"brand-primary-hover": primitiveRamps.orange[500],
|
|
145
148
|
"brand-primary-active": primitiveRamps.orange[600],
|
|
146
149
|
"brand-secondary": primitiveRamps.cyan[600],
|
|
147
150
|
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
148
151
|
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
149
152
|
"brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
|
|
153
|
+
"brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
|
|
154
|
+
"brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
|
|
150
155
|
"brand-secondary-hover": primitiveRamps.cyan[700],
|
|
151
156
|
"brand-secondary-active": primitiveRamps.cyan[800],
|
|
152
157
|
// Text on brand backgrounds (on-*)
|
|
@@ -157,6 +162,8 @@ var semanticColorsLight = {
|
|
|
157
162
|
"status-success-light": primitiveRamps.green[200],
|
|
158
163
|
"status-success-dark": primitiveRamps.green[600],
|
|
159
164
|
"status-success-subtle": primitiveRamps.green[50],
|
|
165
|
+
"status-success-muted": "rgba(46, 213, 115, 0.30)",
|
|
166
|
+
"status-success-strong": "rgba(46, 213, 115, 0.50)",
|
|
160
167
|
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
161
168
|
"status-live": primitiveRamps.green[300],
|
|
162
169
|
"status-live-muted": primitiveRamps.green[500],
|
|
@@ -164,19 +171,27 @@ var semanticColorsLight = {
|
|
|
164
171
|
"status-error-light": primitiveRamps.red[500],
|
|
165
172
|
"status-error-dark": primitiveRamps.red[700],
|
|
166
173
|
"status-error-subtle": primitiveRamps.red[50],
|
|
167
|
-
"status-error-
|
|
168
|
-
|
|
174
|
+
"status-error-muted": "rgba(209, 67, 67, 0.30)",
|
|
175
|
+
"status-error-strong": "rgba(209, 67, 67, 0.50)",
|
|
176
|
+
"status-error-vivid": alertRedVivid,
|
|
177
|
+
// NOT red[600], that is status-error
|
|
169
178
|
"status-error-vivid-light": primitiveRamps.red[500],
|
|
170
179
|
"status-error-vivid-dark": primitiveRamps.red[700],
|
|
171
180
|
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
181
|
+
"status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
|
|
182
|
+
"status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
|
|
172
183
|
"status-warning": primitiveRamps.amber[300],
|
|
173
184
|
"status-warning-light": primitiveRamps.amber[200],
|
|
174
185
|
"status-warning-dark": primitiveRamps.amber[500],
|
|
175
186
|
"status-warning-subtle": primitiveRamps.amber[50],
|
|
187
|
+
"status-warning-muted": "rgba(249, 180, 21, 0.30)",
|
|
188
|
+
"status-warning-strong": "rgba(249, 180, 21, 0.50)",
|
|
176
189
|
"status-info": primitiveRamps.blue[500],
|
|
177
190
|
"status-info-light": primitiveRamps.blue[300],
|
|
178
191
|
"status-info-dark": primitiveRamps.blue[600],
|
|
179
192
|
"status-info-subtle": primitiveRamps.blue[50],
|
|
193
|
+
"status-info-muted": "rgba(33, 150, 243, 0.30)",
|
|
194
|
+
"status-info-strong": "rgba(33, 150, 243, 0.50)",
|
|
180
195
|
// Text on status backgrounds (on-status-*)
|
|
181
196
|
"on-status-success": primitiveColors.white,
|
|
182
197
|
"on-status-error": primitiveColors.white,
|
|
@@ -271,7 +286,7 @@ var semanticColorsLight = {
|
|
|
271
286
|
"interactive-disabled": "rgba(55, 65, 81, 0.12)",
|
|
272
287
|
"interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
|
|
273
288
|
// Divider
|
|
274
|
-
|
|
289
|
+
divider: "#E8E9EB",
|
|
275
290
|
// Avatar default
|
|
276
291
|
"avatar-background": greyRamp[600],
|
|
277
292
|
"avatar-text": primitiveColors.white
|
|
@@ -282,12 +297,16 @@ var semanticColorsDark = {
|
|
|
282
297
|
"brand-primary-light": primitiveRamps.orange[300],
|
|
283
298
|
"brand-primary-dark": primitiveRamps.orange[500],
|
|
284
299
|
"brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
|
|
300
|
+
"brand-primary-muted": "rgba(255, 121, 0, 0.30)",
|
|
301
|
+
"brand-primary-strong": "rgba(255, 121, 0, 0.50)",
|
|
285
302
|
"brand-primary-hover": primitiveRamps.orange[300],
|
|
286
303
|
"brand-primary-active": primitiveRamps.orange[200],
|
|
287
304
|
"brand-secondary": primitiveRamps.cyan[600],
|
|
288
305
|
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
289
306
|
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
290
307
|
"brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
|
|
308
|
+
"brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
|
|
309
|
+
"brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
|
|
291
310
|
"brand-secondary-hover": primitiveRamps.cyan[500],
|
|
292
311
|
"brand-secondary-active": primitiveRamps.cyan[400],
|
|
293
312
|
// Text on brand backgrounds
|
|
@@ -298,6 +317,8 @@ var semanticColorsDark = {
|
|
|
298
317
|
"status-success-light": primitiveRamps.green[200],
|
|
299
318
|
"status-success-dark": primitiveRamps.green[600],
|
|
300
319
|
"status-success-subtle": "rgba(46, 213, 115, 0.12)",
|
|
320
|
+
"status-success-muted": "rgba(46, 213, 115, 0.30)",
|
|
321
|
+
"status-success-strong": "rgba(46, 213, 115, 0.50)",
|
|
301
322
|
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
302
323
|
"status-live": primitiveRamps.green[300],
|
|
303
324
|
"status-live-muted": primitiveRamps.green[500],
|
|
@@ -305,18 +326,26 @@ var semanticColorsDark = {
|
|
|
305
326
|
"status-error-light": primitiveRamps.red[500],
|
|
306
327
|
"status-error-dark": primitiveRamps.red[700],
|
|
307
328
|
"status-error-subtle": "rgba(209, 67, 67, 0.12)",
|
|
308
|
-
"status-error-
|
|
329
|
+
"status-error-muted": "rgba(209, 67, 67, 0.30)",
|
|
330
|
+
"status-error-strong": "rgba(209, 67, 67, 0.50)",
|
|
331
|
+
"status-error-vivid": alertRedVivid,
|
|
309
332
|
"status-error-vivid-light": primitiveRamps.red[500],
|
|
310
333
|
"status-error-vivid-dark": primitiveRamps.red[700],
|
|
311
334
|
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
335
|
+
"status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
|
|
336
|
+
"status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
|
|
312
337
|
"status-warning": primitiveRamps.amber[300],
|
|
313
338
|
"status-warning-light": primitiveRamps.amber[200],
|
|
314
339
|
"status-warning-dark": primitiveRamps.amber[500],
|
|
315
340
|
"status-warning-subtle": "rgba(249, 180, 21, 0.12)",
|
|
341
|
+
"status-warning-muted": "rgba(249, 180, 21, 0.30)",
|
|
342
|
+
"status-warning-strong": "rgba(249, 180, 21, 0.50)",
|
|
316
343
|
"status-info": primitiveRamps.blue[500],
|
|
317
344
|
"status-info-light": primitiveRamps.blue[300],
|
|
318
345
|
"status-info-dark": primitiveRamps.blue[600],
|
|
319
346
|
"status-info-subtle": "rgba(33, 150, 243, 0.12)",
|
|
347
|
+
"status-info-muted": "rgba(33, 150, 243, 0.30)",
|
|
348
|
+
"status-info-strong": "rgba(33, 150, 243, 0.50)",
|
|
320
349
|
// Text on status backgrounds
|
|
321
350
|
"on-status-success": primitiveColors.white,
|
|
322
351
|
"on-status-error": primitiveColors.white,
|
|
@@ -456,7 +485,7 @@ var semanticColorsDark = {
|
|
|
456
485
|
"interactive-disabled": "rgba(255, 255, 255, 0.12)",
|
|
457
486
|
"interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
|
|
458
487
|
// Divider
|
|
459
|
-
|
|
488
|
+
divider: "rgba(255, 255, 255, 0.09)",
|
|
460
489
|
// Avatar default
|
|
461
490
|
"avatar-background": greyRamp[700],
|
|
462
491
|
"avatar-text": primitiveColors.white
|
|
@@ -470,6 +499,150 @@ function resolveColor(token, mode = "dark") {
|
|
|
470
499
|
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
471
500
|
}
|
|
472
501
|
|
|
502
|
+
// src/theme/color-utils.ts
|
|
503
|
+
function hexToRgb(hex) {
|
|
504
|
+
const cleaned = hex.replace("#", "");
|
|
505
|
+
let r, g, b;
|
|
506
|
+
if (cleaned.length === 3) {
|
|
507
|
+
r = parseInt(cleaned[0] + cleaned[0], 16);
|
|
508
|
+
g = parseInt(cleaned[1] + cleaned[1], 16);
|
|
509
|
+
b = parseInt(cleaned[2] + cleaned[2], 16);
|
|
510
|
+
} else if (cleaned.length === 6) {
|
|
511
|
+
r = parseInt(cleaned.slice(0, 2), 16);
|
|
512
|
+
g = parseInt(cleaned.slice(2, 4), 16);
|
|
513
|
+
b = parseInt(cleaned.slice(4, 6), 16);
|
|
514
|
+
} else {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
return { r, g, b };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// src/theme/materials.ts
|
|
521
|
+
var c = getSemanticColors("dark");
|
|
522
|
+
function insetWell(tone = c["surface-input"]) {
|
|
523
|
+
return {
|
|
524
|
+
backgroundColor: tone,
|
|
525
|
+
boxShadow: "inset 0 2px 6px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.12)"
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
var FLOATING_LIFT_MIN = 4;
|
|
529
|
+
var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
|
|
530
|
+
var AMBIENT = {
|
|
531
|
+
1: [
|
|
532
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
533
|
+
{ y: 2, blur: 6, alpha: 0.3 }
|
|
534
|
+
],
|
|
535
|
+
2: [
|
|
536
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
537
|
+
{ y: 4, blur: 12, alpha: 0.32 }
|
|
538
|
+
],
|
|
539
|
+
3: [
|
|
540
|
+
{ y: 2, blur: 4, alpha: 0.35 },
|
|
541
|
+
{ y: 8, blur: 22, alpha: 0.35 }
|
|
542
|
+
],
|
|
543
|
+
4: [
|
|
544
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
545
|
+
{ y: 10, blur: 24, alpha: 0.3 },
|
|
546
|
+
{ y: 24, blur: 48, alpha: 0.2 }
|
|
547
|
+
],
|
|
548
|
+
5: [
|
|
549
|
+
{ y: 2, blur: 4, alpha: 0.4 },
|
|
550
|
+
{ y: 16, blur: 32, alpha: 0.35 },
|
|
551
|
+
{ y: 32, blur: 64, alpha: 0.25 }
|
|
552
|
+
]
|
|
553
|
+
};
|
|
554
|
+
var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
|
|
555
|
+
function ambientLayers(step, mode) {
|
|
556
|
+
const scale = AMBIENT_ALPHA_SCALE[mode];
|
|
557
|
+
return AMBIENT[step].map(
|
|
558
|
+
({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
function liftShadow(step, mode = "dark", opts = {}) {
|
|
562
|
+
const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
|
|
563
|
+
const layers = ambientLayers(step, mode);
|
|
564
|
+
if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
|
|
565
|
+
return layers.join(", ");
|
|
566
|
+
}
|
|
567
|
+
function liftStyle(step, mode = "dark", opts = {}) {
|
|
568
|
+
const deepest = AMBIENT[step][AMBIENT[step].length - 1];
|
|
569
|
+
return reactNative.Platform.select({
|
|
570
|
+
web: { boxShadow: liftShadow(step, mode, opts) },
|
|
571
|
+
default: {
|
|
572
|
+
shadowColor: "#000",
|
|
573
|
+
shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
|
|
574
|
+
shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
|
|
575
|
+
shadowRadius: deepest.blur / 2,
|
|
576
|
+
elevation: step
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/theme/surface-planes.ts
|
|
582
|
+
var SURFACE_LEVEL_TOKEN = {
|
|
583
|
+
frame: "background-frame",
|
|
584
|
+
background: "background-base",
|
|
585
|
+
base: "surface-base",
|
|
586
|
+
elevated: "surface-elevated",
|
|
587
|
+
raised: "surface-raised",
|
|
588
|
+
overlay: "surface-overlay"
|
|
589
|
+
};
|
|
590
|
+
var PLANE_ORDER = [
|
|
591
|
+
"frame",
|
|
592
|
+
"background",
|
|
593
|
+
"base",
|
|
594
|
+
"elevated",
|
|
595
|
+
"raised",
|
|
596
|
+
"overlay"
|
|
597
|
+
];
|
|
598
|
+
function surfaceBackground(level, mode) {
|
|
599
|
+
return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
|
|
600
|
+
}
|
|
601
|
+
function stepPlane(from, delta) {
|
|
602
|
+
const index = PLANE_ORDER.indexOf(from);
|
|
603
|
+
const clamped = Math.min(PLANE_ORDER.length - 1, Math.max(0, index + delta));
|
|
604
|
+
return PLANE_ORDER[clamped];
|
|
605
|
+
}
|
|
606
|
+
function pressedLevel(parent) {
|
|
607
|
+
return stepPlane(parent, -1);
|
|
608
|
+
}
|
|
609
|
+
function raisedLevel(parent, steps) {
|
|
610
|
+
return stepPlane(parent, Math.max(0, steps));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/theme/elevation.ts
|
|
614
|
+
var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
|
|
615
|
+
function getPressedRecessShadow(fillColor, _mode = "dark") {
|
|
616
|
+
const { boxShadow } = insetWell(fillColor);
|
|
617
|
+
return reactNative.Platform.select({
|
|
618
|
+
web: { boxShadow },
|
|
619
|
+
default: {}
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
var glowConfig = {
|
|
623
|
+
tight: { blur: 4, spread: 0, opacity: 0.4 },
|
|
624
|
+
subtle: { blur: 12, spread: 0, opacity: 0.25 },
|
|
625
|
+
medium: { blur: 20, spread: 2, opacity: 0.4 },
|
|
626
|
+
strong: { blur: 30, spread: 4, opacity: 0.55 }
|
|
627
|
+
};
|
|
628
|
+
function getGlowShadow(color, intensity = "medium") {
|
|
629
|
+
const config = glowConfig[intensity];
|
|
630
|
+
const rgb = hexToRgb(color);
|
|
631
|
+
if (!rgb) return {};
|
|
632
|
+
return reactNative.Platform.select({
|
|
633
|
+
web: {
|
|
634
|
+
boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
|
|
635
|
+
},
|
|
636
|
+
default: {
|
|
637
|
+
shadowColor: color,
|
|
638
|
+
shadowOffset: { width: 0, height: 0 },
|
|
639
|
+
shadowOpacity: config.opacity,
|
|
640
|
+
shadowRadius: config.blur / 2,
|
|
641
|
+
elevation: 0
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
473
646
|
// src/theme/workout-tokens.ts
|
|
474
647
|
var WORKOUT_TOKENS = {
|
|
475
648
|
// BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
|
|
@@ -797,7 +970,8 @@ function BodyMap({
|
|
|
797
970
|
alignSelf: "center",
|
|
798
971
|
transform: [{ scale }]
|
|
799
972
|
},
|
|
800
|
-
|
|
973
|
+
// The highlight halo is emphasis, not depth.
|
|
974
|
+
glowColor ? getGlowShadow(glowColor, "medium") : void 0
|
|
801
975
|
],
|
|
802
976
|
"aria-hidden": true,
|
|
803
977
|
accessibilityElementsHidden: true,
|
|
@@ -959,6 +1133,17 @@ var colorStyles = {
|
|
|
959
1133
|
info: "bg-status-info",
|
|
960
1134
|
"error-vivid": "bg-status-error-vivid"
|
|
961
1135
|
};
|
|
1136
|
+
var t = getSemanticColors("dark");
|
|
1137
|
+
var glowColors = {
|
|
1138
|
+
default: greyRamp[500],
|
|
1139
|
+
primary: t["brand-primary"],
|
|
1140
|
+
success: t["status-success"],
|
|
1141
|
+
live: t["status-live"],
|
|
1142
|
+
error: t["status-error"],
|
|
1143
|
+
warning: t["status-warning"],
|
|
1144
|
+
info: t["status-info"],
|
|
1145
|
+
"error-vivid": t["status-error-vivid"]
|
|
1146
|
+
};
|
|
962
1147
|
function Indicator({
|
|
963
1148
|
size = "sm",
|
|
964
1149
|
color = "default",
|
|
@@ -996,11 +1181,7 @@ function Indicator({
|
|
|
996
1181
|
)
|
|
997
1182
|
] });
|
|
998
1183
|
}
|
|
999
|
-
const
|
|
1000
|
-
...typeof style === "object" ? style : {},
|
|
1001
|
-
...colorStyle ?? {},
|
|
1002
|
-
...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
|
|
1003
|
-
};
|
|
1184
|
+
const glowStyle = glow ? getGlowShadow(customColor ?? glowColors[color], "subtle") : null;
|
|
1004
1185
|
return /* @__PURE__ */ jsx(
|
|
1005
1186
|
reactNative.View,
|
|
1006
1187
|
{
|
|
@@ -1010,54 +1191,165 @@ function Indicator({
|
|
|
1010
1191
|
colorClass,
|
|
1011
1192
|
pulseMode === "opacity" && "animate-pulse",
|
|
1012
1193
|
ring && "border-2 border-background-base",
|
|
1013
|
-
glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
1014
|
-
glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
|
|
1015
|
-
glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
|
|
1016
|
-
glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
|
|
1017
|
-
glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
|
|
1018
1194
|
className
|
|
1019
1195
|
),
|
|
1020
|
-
style:
|
|
1196
|
+
style: [style, colorStyle, glowStyle],
|
|
1021
1197
|
...props
|
|
1022
1198
|
}
|
|
1023
1199
|
);
|
|
1024
1200
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1201
|
+
var colorToTone = {
|
|
1202
|
+
default: "neutral",
|
|
1203
|
+
primary: "brand",
|
|
1204
|
+
secondary: "brand-secondary",
|
|
1205
|
+
success: "success",
|
|
1206
|
+
error: "error",
|
|
1207
|
+
warning: "warning",
|
|
1208
|
+
info: "info"
|
|
1209
|
+
};
|
|
1210
|
+
var toneStyles = {
|
|
1028
1211
|
solid: {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
secondary: "bg-brand-secondary text-text-inverse",
|
|
1032
|
-
success: "bg-status-success text-text-inverse",
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
info: "bg-status-info text-text-inverse"
|
|
1212
|
+
neutral: "bg-hairline-strong border-transparent text-text-inverse",
|
|
1213
|
+
brand: "bg-brand-primary border-transparent text-text-inverse",
|
|
1214
|
+
"brand-secondary": "bg-brand-secondary border-transparent text-text-inverse",
|
|
1215
|
+
success: "bg-status-success border-transparent text-text-inverse",
|
|
1216
|
+
warning: "bg-status-warning border-transparent text-text-inverse",
|
|
1217
|
+
error: "bg-status-error border-transparent text-text-inverse",
|
|
1218
|
+
info: "bg-status-info border-transparent text-text-inverse"
|
|
1036
1219
|
},
|
|
1037
1220
|
subtle: {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1221
|
+
// Alpha-white rather than a ramp step: a pill sits on whatever plane its
|
|
1222
|
+
// host is, and an alpha fill composites by the same amount on all of them.
|
|
1223
|
+
// A `surface-*` fill would vanish on the plane it names. Borderless like the
|
|
1224
|
+
// six coloured tones — the fill carries the capsule, not a ring.
|
|
1225
|
+
neutral: "bg-hairline-subtle border-transparent text-text-secondary",
|
|
1226
|
+
brand: "bg-brand-primary-subtle border-transparent text-brand-primary",
|
|
1227
|
+
"brand-secondary": "bg-brand-secondary-subtle border-transparent text-brand-secondary",
|
|
1228
|
+
success: "bg-status-success-subtle border-transparent text-status-success",
|
|
1229
|
+
warning: "bg-status-warning-subtle border-transparent text-status-warning",
|
|
1230
|
+
error: "bg-status-error-subtle border-transparent text-status-error",
|
|
1231
|
+
info: "bg-status-info-subtle border-transparent text-status-info"
|
|
1045
1232
|
},
|
|
1046
1233
|
outline: {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
secondary: "border
|
|
1050
|
-
success: "border
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
info: "border
|
|
1234
|
+
neutral: "border-hairline text-text-secondary",
|
|
1235
|
+
brand: "border-brand-primary text-brand-primary",
|
|
1236
|
+
"brand-secondary": "border-brand-secondary text-brand-secondary",
|
|
1237
|
+
success: "border-status-success text-status-success",
|
|
1238
|
+
warning: "border-status-warning text-status-warning",
|
|
1239
|
+
error: "border-status-error text-status-error",
|
|
1240
|
+
info: "border-status-info text-status-info"
|
|
1054
1241
|
}
|
|
1055
1242
|
};
|
|
1243
|
+
var dotToneStyles = {
|
|
1244
|
+
neutral: "bg-text-tertiary",
|
|
1245
|
+
brand: "bg-brand-primary",
|
|
1246
|
+
"brand-secondary": "bg-brand-secondary",
|
|
1247
|
+
success: "bg-status-success",
|
|
1248
|
+
warning: "bg-status-warning",
|
|
1249
|
+
error: "bg-status-error",
|
|
1250
|
+
info: "bg-status-info"
|
|
1251
|
+
};
|
|
1056
1252
|
var sizeStyles2 = {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1253
|
+
xs: { container: "px-1 py-px", text: "text-3xs" },
|
|
1254
|
+
sm: { container: "px-2 py-0.5", text: "text-2xs" },
|
|
1255
|
+
md: { container: "px-2.5 py-1", text: "text-xs" },
|
|
1256
|
+
lg: { container: "px-3 py-1.5", text: "text-sm" },
|
|
1257
|
+
xl: { container: "px-4 py-2", text: "text-base" }
|
|
1258
|
+
};
|
|
1259
|
+
function PillDot({ tone, testID }) {
|
|
1260
|
+
return /* @__PURE__ */ jsx(
|
|
1261
|
+
reactNative.View,
|
|
1262
|
+
{
|
|
1263
|
+
className: cn("w-1.5 h-1.5 rounded-full shrink-0", dotToneStyles[tone]),
|
|
1264
|
+
accessibilityElementsHidden: true,
|
|
1265
|
+
testID: testID ? `${testID}-dot` : "pill-dot"
|
|
1266
|
+
}
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
function containerClasses(p, tone) {
|
|
1270
|
+
return cn(
|
|
1271
|
+
"flex-row items-center gap-1 border self-start shrink-0",
|
|
1272
|
+
p.rounded === false ? "rounded" : "rounded-full",
|
|
1273
|
+
toneStyles[p.variant ?? "subtle"][tone],
|
|
1274
|
+
sizeStyles2[p.size ?? "sm"].container,
|
|
1275
|
+
p.isDisabled && "opacity-50",
|
|
1276
|
+
p.className
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
function PillContent({ tone, ...p }) {
|
|
1280
|
+
const textClasses = cn(
|
|
1281
|
+
"font-heading font-semibold text-inherit",
|
|
1282
|
+
sizeStyles2[p.size ?? "sm"].text,
|
|
1283
|
+
p.textClassName
|
|
1284
|
+
);
|
|
1285
|
+
const slot = p.leading ?? p.leftElement;
|
|
1286
|
+
return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
1287
|
+
slot === "dot" ? /* @__PURE__ */ jsx(PillDot, { tone: p.dotTone ?? tone, testID: p.testID }) : slot,
|
|
1288
|
+
typeof p.children === "string" ? /* @__PURE__ */ jsx(reactNative.Text, { className: textClasses, children: p.children }) : p.children,
|
|
1289
|
+
p.trailing
|
|
1290
|
+
] });
|
|
1291
|
+
}
|
|
1292
|
+
function Pill(props) {
|
|
1293
|
+
const {
|
|
1294
|
+
variant,
|
|
1295
|
+
tone,
|
|
1296
|
+
color,
|
|
1297
|
+
size,
|
|
1298
|
+
rounded,
|
|
1299
|
+
leading,
|
|
1300
|
+
dotTone,
|
|
1301
|
+
leftElement,
|
|
1302
|
+
trailing,
|
|
1303
|
+
onPress,
|
|
1304
|
+
isDisabled,
|
|
1305
|
+
className,
|
|
1306
|
+
textClassName,
|
|
1307
|
+
children,
|
|
1308
|
+
...viewProps
|
|
1309
|
+
} = props;
|
|
1310
|
+
const resolvedTone = tone ?? (color ? colorToTone[color] : "neutral");
|
|
1311
|
+
const classes = containerClasses(props, resolvedTone);
|
|
1312
|
+
const content = /* @__PURE__ */ jsx(PillContent, { ...props, tone: resolvedTone });
|
|
1313
|
+
if (onPress) {
|
|
1314
|
+
return /* @__PURE__ */ jsx(
|
|
1315
|
+
reactNative.Pressable,
|
|
1316
|
+
{
|
|
1317
|
+
onPress,
|
|
1318
|
+
disabled: isDisabled,
|
|
1319
|
+
accessibilityRole: "button",
|
|
1320
|
+
className: classes,
|
|
1321
|
+
...viewProps,
|
|
1322
|
+
children: content
|
|
1323
|
+
}
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
return /* @__PURE__ */ jsx(reactNative.View, { className: classes, ...viewProps, children: content });
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// src/components/ui/badge/Badge.tsx
|
|
1330
|
+
var colorToTone2 = {
|
|
1331
|
+
default: "neutral",
|
|
1332
|
+
primary: "brand",
|
|
1333
|
+
secondary: "brand-secondary",
|
|
1334
|
+
success: "success",
|
|
1335
|
+
error: "error",
|
|
1336
|
+
warning: "warning",
|
|
1337
|
+
info: "info"
|
|
1338
|
+
};
|
|
1339
|
+
var sizeStyles3 = {
|
|
1340
|
+
sm: "px-1.5 py-0.5",
|
|
1341
|
+
md: "px-2 py-0.5",
|
|
1342
|
+
lg: "px-2.5 py-1"
|
|
1060
1343
|
};
|
|
1344
|
+
var textSizeStyles = {
|
|
1345
|
+
sm: "text-xs",
|
|
1346
|
+
md: "text-xs",
|
|
1347
|
+
lg: "text-sm"
|
|
1348
|
+
};
|
|
1349
|
+
function dotIndicatorColor(color, dotColor) {
|
|
1350
|
+
if (dotColor) return dotColor;
|
|
1351
|
+
return color === "default" || color === "secondary" ? "default" : color;
|
|
1352
|
+
}
|
|
1061
1353
|
function Badge({
|
|
1062
1354
|
variant = "subtle",
|
|
1063
1355
|
color = "default",
|
|
@@ -1068,31 +1360,116 @@ function Badge({
|
|
|
1068
1360
|
children,
|
|
1069
1361
|
...props
|
|
1070
1362
|
}) {
|
|
1071
|
-
return /* @__PURE__ */
|
|
1072
|
-
|
|
1363
|
+
return /* @__PURE__ */ jsx(
|
|
1364
|
+
Pill,
|
|
1073
1365
|
{
|
|
1366
|
+
variant,
|
|
1367
|
+
tone: colorToTone2[color],
|
|
1368
|
+
leading: dot ? /* @__PURE__ */ jsx(Indicator, { size: "xs", color: dotIndicatorColor(color, dotColor), className: "mr-0.5" }) : void 0,
|
|
1074
1369
|
className: cn(
|
|
1075
|
-
"
|
|
1076
|
-
|
|
1077
|
-
|
|
1370
|
+
"justify-center self-auto gap-0",
|
|
1371
|
+
variant === "outline" ? "border" : "border-0",
|
|
1372
|
+
sizeStyles3[size],
|
|
1078
1373
|
className
|
|
1079
1374
|
),
|
|
1375
|
+
textClassName: cn("font-sans font-medium", textSizeStyles[size]),
|
|
1080
1376
|
...props,
|
|
1081
|
-
children
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1377
|
+
children
|
|
1378
|
+
}
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
var variantStyles = {
|
|
1382
|
+
h1: "font-heading text-5xl font-bold leading-tight",
|
|
1383
|
+
h2: "font-heading text-4xl font-bold leading-tight",
|
|
1384
|
+
h3: "font-heading text-3xl font-bold leading-tight",
|
|
1385
|
+
h4: "font-heading text-2xl font-bold leading-tight",
|
|
1386
|
+
h5: "font-heading text-xl font-semibold leading-tight",
|
|
1387
|
+
h6: "font-heading text-lg font-semibold leading-tight",
|
|
1388
|
+
body1: "font-body text-base font-normal leading-normal",
|
|
1389
|
+
body2: "font-body text-sm font-normal leading-normal",
|
|
1390
|
+
subtitle1: "font-body text-base font-medium leading-relaxed",
|
|
1391
|
+
subtitle2: "font-body text-sm font-medium leading-normal",
|
|
1392
|
+
caption: "font-body text-xs font-normal leading-loose",
|
|
1393
|
+
overline: "font-body text-xs font-semibold uppercase tracking-widest leading-relaxed",
|
|
1394
|
+
button: "font-sans text-sm font-semibold leading-relaxed",
|
|
1395
|
+
// Monospace technical readouts (clocks, ids, metrics) and their all-caps label form.
|
|
1396
|
+
mono: "font-mono text-xs font-normal leading-normal",
|
|
1397
|
+
monoLabel: "font-mono text-xs font-bold uppercase tracking-wide leading-normal",
|
|
1398
|
+
// The sans (Inter) label pair: 10px for dense table/column headers, 12px bold for
|
|
1399
|
+
// badge and row labels. `overline` is the 12px font-body form of the same idea.
|
|
1400
|
+
microLabel: "font-sans text-2xs font-semibold uppercase tracking-widest leading-normal",
|
|
1401
|
+
boldLabel: "font-sans text-xs font-bold leading-normal"
|
|
1402
|
+
};
|
|
1403
|
+
var colorStyles2 = {
|
|
1404
|
+
primary: "text-text-primary",
|
|
1405
|
+
secondary: "text-text-secondary",
|
|
1406
|
+
tertiary: "text-text-tertiary",
|
|
1407
|
+
disabled: "text-text-disabled",
|
|
1408
|
+
inverse: "text-text-inverse",
|
|
1409
|
+
success: "text-status-success",
|
|
1410
|
+
error: "text-status-error",
|
|
1411
|
+
warning: "text-status-warning",
|
|
1412
|
+
info: "text-status-info",
|
|
1413
|
+
inherit: ""
|
|
1414
|
+
// No color class, inherit from parent
|
|
1415
|
+
};
|
|
1416
|
+
var alignStyles = {
|
|
1417
|
+
left: "text-left",
|
|
1418
|
+
center: "text-center",
|
|
1419
|
+
right: "text-right",
|
|
1420
|
+
justify: "text-justify"
|
|
1421
|
+
};
|
|
1422
|
+
var headingVariants = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
1423
|
+
var marginBottomStyles = {
|
|
1424
|
+
none: "",
|
|
1425
|
+
sm: "mb-1",
|
|
1426
|
+
md: "mb-2",
|
|
1427
|
+
lg: "mb-4"
|
|
1428
|
+
};
|
|
1429
|
+
function Typography({
|
|
1430
|
+
variant = "body1",
|
|
1431
|
+
color = "primary",
|
|
1432
|
+
align,
|
|
1433
|
+
truncate = false,
|
|
1434
|
+
noWrap = false,
|
|
1435
|
+
// deprecated, kept for backward compatibility
|
|
1436
|
+
marginBottom,
|
|
1437
|
+
gutterBottom = false,
|
|
1438
|
+
// deprecated, kept for backward compatibility
|
|
1439
|
+
maxLines,
|
|
1440
|
+
className,
|
|
1441
|
+
children,
|
|
1442
|
+
...props
|
|
1443
|
+
}) {
|
|
1444
|
+
const isHeading = headingVariants.includes(variant);
|
|
1445
|
+
const shouldTruncate = truncate || noWrap;
|
|
1446
|
+
const mb = marginBottom || (gutterBottom ? "md" : "none");
|
|
1447
|
+
let numLines;
|
|
1448
|
+
if (maxLines) {
|
|
1449
|
+
numLines = maxLines;
|
|
1450
|
+
} else if (shouldTruncate) {
|
|
1451
|
+
numLines = 1;
|
|
1452
|
+
}
|
|
1453
|
+
return /* @__PURE__ */ jsx(
|
|
1454
|
+
reactNative.Text,
|
|
1455
|
+
{
|
|
1456
|
+
accessibilityRole: isHeading ? "header" : "text",
|
|
1457
|
+
numberOfLines: numLines,
|
|
1458
|
+
className: cn(
|
|
1459
|
+
variantStyles[variant],
|
|
1460
|
+
color !== "inherit" && colorStyles2[color],
|
|
1461
|
+
align && alignStyles[align],
|
|
1462
|
+
shouldTruncate && "truncate",
|
|
1463
|
+
marginBottomStyles[mb],
|
|
1464
|
+
className
|
|
1465
|
+
),
|
|
1466
|
+
...props,
|
|
1467
|
+
children
|
|
1092
1468
|
}
|
|
1093
1469
|
);
|
|
1094
1470
|
}
|
|
1095
|
-
|
|
1471
|
+
|
|
1472
|
+
// src/components/custom/Workout/Sparkline.tsx
|
|
1096
1473
|
function normalizeData(data, height) {
|
|
1097
1474
|
if (data.length === 0) return [];
|
|
1098
1475
|
const min = Math.min(...data);
|
|
@@ -1129,7 +1506,7 @@ function Sparkline({
|
|
|
1129
1506
|
}
|
|
1130
1507
|
);
|
|
1131
1508
|
}
|
|
1132
|
-
const resolvedColor = color ??
|
|
1509
|
+
const resolvedColor = color ?? resolveColor("brand-primary");
|
|
1133
1510
|
const normalized = normalizeData(data, height);
|
|
1134
1511
|
const stepX = data.length > 1 ? width / (data.length - 1) : 0;
|
|
1135
1512
|
const dotSize = 3;
|
|
@@ -1169,14 +1546,19 @@ function Sparkline({
|
|
|
1169
1546
|
],
|
|
1170
1547
|
accessibilityElementsHidden: true,
|
|
1171
1548
|
testID: `sparkline-reference-${i}`,
|
|
1172
|
-
children: line.label &&
|
|
1173
|
-
|
|
1549
|
+
children: line.label && // `3xs` (9px) is the scale floor; the label was 7px, which is off it
|
|
1550
|
+
// entirely (TOKENS.md §4). The line box stays unpinned, as the raw
|
|
1551
|
+
// <Text> this replaced was, so the absolute offset still lands.
|
|
1552
|
+
/* @__PURE__ */ jsx(
|
|
1553
|
+
Typography,
|
|
1174
1554
|
{
|
|
1555
|
+
variant: "caption",
|
|
1556
|
+
color: "inherit",
|
|
1557
|
+
className: "text-3xs leading-[normal]",
|
|
1175
1558
|
style: {
|
|
1176
1559
|
position: "absolute",
|
|
1177
1560
|
right: 0,
|
|
1178
1561
|
top: -10,
|
|
1179
|
-
fontSize: 7,
|
|
1180
1562
|
color: line.color,
|
|
1181
1563
|
opacity: 1
|
|
1182
1564
|
},
|
|
@@ -1245,9 +1627,9 @@ function Sparkline({
|
|
|
1245
1627
|
}
|
|
1246
1628
|
|
|
1247
1629
|
// src/components/custom/Workout/BodyMapDetailPanel.tsx
|
|
1248
|
-
var
|
|
1249
|
-
var
|
|
1250
|
-
var VOLUME_GRADIENT = `linear-gradient(90deg, ${
|
|
1630
|
+
var t2 = getSemanticColors("dark");
|
|
1631
|
+
var BRAND_PRIMARY2 = t2["brand-primary"];
|
|
1632
|
+
var VOLUME_GRADIENT = `linear-gradient(90deg, ${t2["status-info"]} 0%, ${t2["status-success"]} 50%, ${t2["status-error"]} 100%)`;
|
|
1251
1633
|
var SLIDE_OFFSET = 400;
|
|
1252
1634
|
var BACKDROP_OPACITY = 0.4;
|
|
1253
1635
|
var STATUS_BADGE_COLOR = {
|
|
@@ -1312,7 +1694,14 @@ function BodyMapDetailPanel({
|
|
|
1312
1694
|
return /* @__PURE__ */ jsxs(
|
|
1313
1695
|
reactNative.View,
|
|
1314
1696
|
{
|
|
1315
|
-
style: {
|
|
1697
|
+
style: {
|
|
1698
|
+
position: "absolute",
|
|
1699
|
+
top: 0,
|
|
1700
|
+
left: 0,
|
|
1701
|
+
right: 0,
|
|
1702
|
+
bottom: 0,
|
|
1703
|
+
justifyContent: "flex-end"
|
|
1704
|
+
},
|
|
1316
1705
|
testID: "body-map-detail-panel-root",
|
|
1317
1706
|
children: [
|
|
1318
1707
|
/* @__PURE__ */ jsx(
|
|
@@ -1447,8 +1836,22 @@ function BodyMapDetailPanel({
|
|
|
1447
1836
|
style: { marginBottom: 6 },
|
|
1448
1837
|
accessibilityElementsHidden: true,
|
|
1449
1838
|
children: [
|
|
1450
|
-
/* @__PURE__ */ jsx(
|
|
1451
|
-
|
|
1839
|
+
/* @__PURE__ */ jsx(
|
|
1840
|
+
reactNative.Text,
|
|
1841
|
+
{
|
|
1842
|
+
className: "text-text-tertiary",
|
|
1843
|
+
style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
|
|
1844
|
+
children: `MEV ${landmarks.mev}`
|
|
1845
|
+
}
|
|
1846
|
+
),
|
|
1847
|
+
/* @__PURE__ */ jsx(
|
|
1848
|
+
reactNative.Text,
|
|
1849
|
+
{
|
|
1850
|
+
className: "text-text-tertiary",
|
|
1851
|
+
style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
|
|
1852
|
+
children: `MRV ${landmarks.mrv}`
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1452
1855
|
]
|
|
1453
1856
|
}
|
|
1454
1857
|
),
|
|
@@ -1483,7 +1886,8 @@ function BodyMapDetailPanel({
|
|
|
1483
1886
|
height: 14,
|
|
1484
1887
|
borderRadius: 7,
|
|
1485
1888
|
borderWidth: 2,
|
|
1486
|
-
|
|
1889
|
+
// A knob resting on the volume bar: lift, with the ring as its edge.
|
|
1890
|
+
...liftStyle(1, "dark", { rim: 0 })
|
|
1487
1891
|
},
|
|
1488
1892
|
accessibilityElementsHidden: true,
|
|
1489
1893
|
testID: "body-map-detail-panel-volume-marker"
|
|
@@ -1566,7 +1970,12 @@ function BodyMapDetailPanel({
|
|
|
1566
1970
|
reactNative.Text,
|
|
1567
1971
|
{
|
|
1568
1972
|
className: "text-text-primary",
|
|
1569
|
-
style: {
|
|
1973
|
+
style: {
|
|
1974
|
+
flex: 1,
|
|
1975
|
+
fontSize: 13,
|
|
1976
|
+
fontFamily: "Inter, sans-serif",
|
|
1977
|
+
fontWeight: "600"
|
|
1978
|
+
},
|
|
1570
1979
|
testID: `body-map-detail-panel-contributing-${index}-name`,
|
|
1571
1980
|
children: exercise.name
|
|
1572
1981
|
}
|
|
@@ -1610,7 +2019,12 @@ function BodyMapDetailPanel({
|
|
|
1610
2019
|
reactNative.Text,
|
|
1611
2020
|
{
|
|
1612
2021
|
className: "text-text-primary",
|
|
1613
|
-
style: {
|
|
2022
|
+
style: {
|
|
2023
|
+
flex: 1,
|
|
2024
|
+
fontSize: 13,
|
|
2025
|
+
fontFamily: "Inter, sans-serif",
|
|
2026
|
+
fontWeight: "600"
|
|
2027
|
+
},
|
|
1614
2028
|
testID: `body-map-detail-panel-upcoming-${index}-name`,
|
|
1615
2029
|
children: exercise.name
|
|
1616
2030
|
}
|
|
@@ -1645,7 +2059,18 @@ function BodyMapDetailPanel({
|
|
|
1645
2059
|
borderColor: "rgba(255,121,0,0.3)"
|
|
1646
2060
|
},
|
|
1647
2061
|
testID: "body-map-detail-panel-view-exercises",
|
|
1648
|
-
children: /* @__PURE__ */ jsx(
|
|
2062
|
+
children: /* @__PURE__ */ jsx(
|
|
2063
|
+
reactNative.Text,
|
|
2064
|
+
{
|
|
2065
|
+
style: {
|
|
2066
|
+
fontSize: 13,
|
|
2067
|
+
fontFamily: "Inter, sans-serif",
|
|
2068
|
+
fontWeight: "700",
|
|
2069
|
+
color: BRAND_PRIMARY2
|
|
2070
|
+
},
|
|
2071
|
+
children: "View exercises"
|
|
2072
|
+
}
|
|
2073
|
+
)
|
|
1649
2074
|
}
|
|
1650
2075
|
)
|
|
1651
2076
|
]
|
|
@@ -1658,439 +2083,81 @@ function BodyMapDetailPanel({
|
|
|
1658
2083
|
}
|
|
1659
2084
|
);
|
|
1660
2085
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
function
|
|
1664
|
-
|
|
1665
|
-
let r, g, b;
|
|
1666
|
-
if (cleaned.length === 3) {
|
|
1667
|
-
r = parseInt(cleaned[0] + cleaned[0], 16);
|
|
1668
|
-
g = parseInt(cleaned[1] + cleaned[1], 16);
|
|
1669
|
-
b = parseInt(cleaned[2] + cleaned[2], 16);
|
|
1670
|
-
} else if (cleaned.length === 6) {
|
|
1671
|
-
r = parseInt(cleaned.slice(0, 2), 16);
|
|
1672
|
-
g = parseInt(cleaned.slice(2, 4), 16);
|
|
1673
|
-
b = parseInt(cleaned.slice(4, 6), 16);
|
|
1674
|
-
} else {
|
|
1675
|
-
return null;
|
|
1676
|
-
}
|
|
1677
|
-
return { r, g, b };
|
|
1678
|
-
}
|
|
1679
|
-
function rgbToHsv(r, g, b) {
|
|
1680
|
-
const rNorm = r / 255;
|
|
1681
|
-
const gNorm = g / 255;
|
|
1682
|
-
const bNorm = b / 255;
|
|
1683
|
-
const max = Math.max(rNorm, gNorm, bNorm);
|
|
1684
|
-
const min = Math.min(rNorm, gNorm, bNorm);
|
|
1685
|
-
const delta = max - min;
|
|
1686
|
-
const v = max;
|
|
1687
|
-
const s = max === 0 ? 0 : delta / max;
|
|
1688
|
-
let h = 0;
|
|
1689
|
-
if (delta !== 0) {
|
|
1690
|
-
if (max === rNorm) {
|
|
1691
|
-
h = 60 * ((gNorm - bNorm) / delta % 6);
|
|
1692
|
-
} else if (max === gNorm) {
|
|
1693
|
-
h = 60 * ((bNorm - rNorm) / delta + 2);
|
|
1694
|
-
} else {
|
|
1695
|
-
h = 60 * ((rNorm - gNorm) / delta + 4);
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
if (h < 0) h += 360;
|
|
1699
|
-
return { h, s, v };
|
|
1700
|
-
}
|
|
1701
|
-
function hsvToRgb(h, s, v) {
|
|
1702
|
-
const c = v * s;
|
|
1703
|
-
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
1704
|
-
const m = v - c;
|
|
1705
|
-
let rPrime, gPrime, bPrime;
|
|
1706
|
-
if (h >= 0 && h < 60) {
|
|
1707
|
-
rPrime = c;
|
|
1708
|
-
gPrime = x;
|
|
1709
|
-
bPrime = 0;
|
|
1710
|
-
} else if (h >= 60 && h < 120) {
|
|
1711
|
-
rPrime = x;
|
|
1712
|
-
gPrime = c;
|
|
1713
|
-
bPrime = 0;
|
|
1714
|
-
} else if (h >= 120 && h < 180) {
|
|
1715
|
-
rPrime = 0;
|
|
1716
|
-
gPrime = c;
|
|
1717
|
-
bPrime = x;
|
|
1718
|
-
} else if (h >= 180 && h < 240) {
|
|
1719
|
-
rPrime = 0;
|
|
1720
|
-
gPrime = x;
|
|
1721
|
-
bPrime = c;
|
|
1722
|
-
} else if (h >= 240 && h < 300) {
|
|
1723
|
-
rPrime = x;
|
|
1724
|
-
gPrime = 0;
|
|
1725
|
-
bPrime = c;
|
|
1726
|
-
} else {
|
|
1727
|
-
rPrime = c;
|
|
1728
|
-
gPrime = 0;
|
|
1729
|
-
bPrime = x;
|
|
1730
|
-
}
|
|
1731
|
-
return {
|
|
1732
|
-
r: Math.round((rPrime + m) * 255),
|
|
1733
|
-
g: Math.round((gPrime + m) * 255),
|
|
1734
|
-
b: Math.round((bPrime + m) * 255)
|
|
1735
|
-
};
|
|
2086
|
+
var DEFAULT_CONTEXT = { mode: "dark", level: "base" };
|
|
2087
|
+
var SurfaceContext = react.createContext(DEFAULT_CONTEXT);
|
|
2088
|
+
function useSurface() {
|
|
2089
|
+
return react.useContext(SurfaceContext);
|
|
1736
2090
|
}
|
|
1737
|
-
function
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
};
|
|
1742
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1743
|
-
}
|
|
1744
|
-
function lighten(hex, amount = 0.1) {
|
|
1745
|
-
const rgb = hexToRgb(hex);
|
|
1746
|
-
if (!rgb) return hex;
|
|
1747
|
-
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
1748
|
-
const newV = Math.min(1, hsv.v + amount);
|
|
1749
|
-
const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
|
|
1750
|
-
return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
|
|
1751
|
-
}
|
|
1752
|
-
var elevationSystem = {
|
|
1753
|
-
// Deep inset (recessed input fields, deeply pressed buttons)
|
|
1754
|
-
[-2]: {
|
|
1755
|
-
name: "deep-inset",
|
|
1756
|
-
colorAdjustment: 0,
|
|
1757
|
-
shadowIntensity: "strong",
|
|
1758
|
-
shadowStyle: "pressed",
|
|
1759
|
-
description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
|
|
1760
|
-
},
|
|
1761
|
-
// Shallow inset (pressed buttons, sunken panels)
|
|
1762
|
-
[-1]: {
|
|
1763
|
-
name: "inset",
|
|
1764
|
-
colorAdjustment: 0,
|
|
1765
|
-
shadowIntensity: "medium",
|
|
1766
|
-
shadowStyle: "pressed",
|
|
1767
|
-
description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
|
|
1768
|
-
},
|
|
1769
|
-
// Base level (page background, default surface)
|
|
1770
|
-
[0]: {
|
|
1771
|
-
name: "base",
|
|
1772
|
-
colorAdjustment: 0,
|
|
1773
|
-
shadowIntensity: "subtle",
|
|
1774
|
-
shadowStyle: "raised",
|
|
1775
|
-
description: "Base surface level (page background, default containers)"
|
|
1776
|
-
},
|
|
1777
|
-
// Level 1: Subtle elevation (outline cards, subtle containers)
|
|
1778
|
-
[1]: {
|
|
1779
|
-
name: "subtle",
|
|
1780
|
-
// The whole ladder was re-spaced in TD-07.16. It used to run
|
|
1781
|
-
// 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
|
|
1782
|
-
// the perceptual floor, so level 1 existed in the type system and nowhere on
|
|
1783
|
-
// screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
|
|
1784
|
-
// is the only thing separating 0-3, so every step has to actually land.
|
|
1785
|
-
// Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
|
|
1786
|
-
colorAdjustment: 0.025,
|
|
1787
|
-
shadowIntensity: "subtle",
|
|
1788
|
-
shadowStyle: "raised",
|
|
1789
|
-
description: "Subtle elevation (outline cards, subtle containers)"
|
|
1790
|
-
},
|
|
1791
|
-
// Level 2: Standard elevation (default cards, buttons)
|
|
1792
|
-
[2]: {
|
|
1793
|
-
name: "standard",
|
|
1794
|
-
colorAdjustment: 0.05,
|
|
1795
|
-
shadowIntensity: "medium",
|
|
1796
|
-
shadowStyle: "raised",
|
|
1797
|
-
description: "Standard elevation (default cards, raised buttons)"
|
|
1798
|
-
},
|
|
1799
|
-
// Level 3: Prominent elevation (important cards, modals)
|
|
1800
|
-
[3]: {
|
|
1801
|
-
name: "prominent",
|
|
1802
|
-
colorAdjustment: 0.075,
|
|
1803
|
-
shadowIntensity: "strong",
|
|
1804
|
-
shadowStyle: "raised",
|
|
1805
|
-
description: "Prominent elevation (important cards, modals, dropdowns)"
|
|
1806
|
-
},
|
|
1807
|
-
// Level 4: High elevation (overlays, popovers)
|
|
1808
|
-
[4]: {
|
|
1809
|
-
name: "high",
|
|
1810
|
-
colorAdjustment: 0.1,
|
|
1811
|
-
shadowIntensity: "strong",
|
|
1812
|
-
shadowStyle: "raised",
|
|
1813
|
-
description: "High elevation (overlays, popovers, tooltips)"
|
|
1814
|
-
},
|
|
1815
|
-
// Level 5: Floating (toasts, floating action buttons)
|
|
1816
|
-
[5]: {
|
|
1817
|
-
name: "floating",
|
|
1818
|
-
colorAdjustment: 0.13,
|
|
1819
|
-
shadowIntensity: "strong",
|
|
1820
|
-
shadowStyle: "raised",
|
|
1821
|
-
description: "Floating elevation (toasts, floating action buttons, highest z-index)"
|
|
1822
|
-
}
|
|
1823
|
-
};
|
|
1824
|
-
function calculateRimLightColor(baseColor, level) {
|
|
1825
|
-
const rgb = hexToRgb(baseColor);
|
|
1826
|
-
if (!rgb) {
|
|
1827
|
-
return "rgba(255, 255, 255, 0.5)";
|
|
1828
|
-
}
|
|
1829
|
-
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
1830
|
-
const isLight = hsv.v > 0.6;
|
|
1831
|
-
const isSaturated = hsv.s > 0.3;
|
|
1832
|
-
const absLevel = Math.abs(level);
|
|
1833
|
-
const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
|
|
1834
|
-
if (isSaturated) {
|
|
1835
|
-
const rimLightValue = 0.95;
|
|
1836
|
-
const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
|
|
1837
|
-
const baseOpacity = isLight ? 0.9 : 0.5;
|
|
1838
|
-
const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
|
|
1839
|
-
return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
|
|
1840
|
-
} else {
|
|
1841
|
-
const baseOpacity = isLight ? 0.9 : 0.12;
|
|
1842
|
-
const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
|
|
1843
|
-
return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
|
|
1844
|
-
}
|
|
2091
|
+
function recessDepth(inherited, planesDown, mode) {
|
|
2092
|
+
let plane = inherited.level;
|
|
2093
|
+
for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
|
|
2094
|
+
const backgroundColor = surfaceBackground(plane, mode);
|
|
2095
|
+
return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
|
|
1845
2096
|
}
|
|
1846
|
-
function
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
};
|
|
2097
|
+
function resolveSurfaceDepth(inherited, props) {
|
|
2098
|
+
const mode = props.theme ?? inherited.mode;
|
|
2099
|
+
const elevation = props.elevation ?? 0;
|
|
2100
|
+
if (props.pressed || elevation < 0) {
|
|
2101
|
+
const down = props.pressed ? 1 : -elevation;
|
|
2102
|
+
return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
|
|
1853
2103
|
}
|
|
1854
|
-
const
|
|
1855
|
-
const
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
return {
|
|
1862
|
-
dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
|
|
1863
|
-
darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
|
|
1864
|
-
};
|
|
1865
|
-
} else {
|
|
1866
|
-
return {
|
|
1867
|
-
dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
|
|
1868
|
-
darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
|
|
1869
|
-
};
|
|
1870
|
-
}
|
|
1871
|
-
} else {
|
|
1872
|
-
if (isLight) {
|
|
1873
|
-
return {
|
|
1874
|
-
dark: "rgba(0, 0, 0, 0.2)",
|
|
1875
|
-
darker: "rgba(0, 0, 0, 0.3)"
|
|
1876
|
-
};
|
|
1877
|
-
} else {
|
|
1878
|
-
return {
|
|
1879
|
-
dark: "rgba(0, 0, 0, 0.5)",
|
|
1880
|
-
darker: "rgba(0, 0, 0, 0.6)"
|
|
1881
|
-
};
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
function getRimLightConfig() {
|
|
1886
|
-
return {
|
|
1887
|
-
offset: 1,
|
|
1888
|
-
// Fixed 1px for crisp rim
|
|
1889
|
-
blur: 1
|
|
1890
|
-
// Tight blur for crisp edge
|
|
1891
|
-
};
|
|
1892
|
-
}
|
|
1893
|
-
var elevationSurfaceCache = /* @__PURE__ */ new Map();
|
|
1894
|
-
var MAX_CACHE_SIZE = 100;
|
|
1895
|
-
function getCacheKey(baseColor, level, theme) {
|
|
1896
|
-
return `${baseColor}-${level}-${theme}`;
|
|
2104
|
+
const step = props.level != null ? 0 : props.raise ?? elevation;
|
|
2105
|
+
const floating = step >= FLOATING_ELEVATION_MIN;
|
|
2106
|
+
const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
|
|
2107
|
+
const lifted = props.lift ?? step > 0;
|
|
2108
|
+
const liftStep = Math.max(1, Math.min(5, step));
|
|
2109
|
+
const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
|
|
2110
|
+
return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
|
|
1897
2111
|
}
|
|
1898
|
-
function
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
}
|
|
1913
|
-
const result = calculateElevationSurface(baseColor, level);
|
|
1914
|
-
if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
|
|
1915
|
-
const firstKey = elevationSurfaceCache.keys().next().value;
|
|
1916
|
-
elevationSurfaceCache.delete(firstKey);
|
|
1917
|
-
}
|
|
1918
|
-
elevationSurfaceCache.set(cacheKey, result);
|
|
1919
|
-
return result;
|
|
1920
|
-
}
|
|
1921
|
-
var elevationShadowCache = /* @__PURE__ */ new Map();
|
|
1922
|
-
var MAX_SHADOW_CACHE_SIZE = 50;
|
|
1923
|
-
function getShadowCacheKey(baseColor, level, theme, isHovered) {
|
|
1924
|
-
return `${baseColor}-${level}-${theme}-${isHovered}`;
|
|
1925
|
-
}
|
|
1926
|
-
function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
|
|
1927
|
-
const config = elevationSystem[level];
|
|
1928
|
-
if (level === 0) {
|
|
1929
|
-
return {};
|
|
1930
|
-
}
|
|
1931
|
-
const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
|
|
1932
|
-
const rimLightColor = calculateRimLightColor(baseColor, level);
|
|
1933
|
-
const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
|
|
1934
|
-
const intensityConfig = {
|
|
1935
|
-
subtle: { offset: 1, blur: 2 },
|
|
1936
|
-
medium: { offset: 2, blur: 4 },
|
|
1937
|
-
strong: { offset: 2, blur: 5 }
|
|
1938
|
-
};
|
|
1939
|
-
const { offset, blur } = intensityConfig[config.shadowIntensity];
|
|
1940
|
-
const rimConfig = getRimLightConfig();
|
|
1941
|
-
if (config.shadowStyle === "pressed") {
|
|
1942
|
-
if (isHovered) {
|
|
1943
|
-
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
1944
|
-
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
1945
|
-
return reactNative.Platform.select({
|
|
1946
|
-
web: {
|
|
1947
|
-
boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
1948
|
-
},
|
|
1949
|
-
default: {
|
|
1950
|
-
shadowOpacity: 0,
|
|
1951
|
-
elevation: 0
|
|
1952
|
-
}
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
return reactNative.Platform.select({
|
|
1956
|
-
web: {
|
|
1957
|
-
boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
1958
|
-
},
|
|
1959
|
-
default: {
|
|
1960
|
-
shadowOpacity: 0,
|
|
1961
|
-
elevation: 0
|
|
1962
|
-
}
|
|
1963
|
-
});
|
|
1964
|
-
} else {
|
|
1965
|
-
if (isHovered) {
|
|
1966
|
-
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
1967
|
-
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
1968
|
-
return reactNative.Platform.select({
|
|
1969
|
-
web: {
|
|
1970
|
-
boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
1971
|
-
},
|
|
1972
|
-
default: {
|
|
1973
|
-
shadowColor: "#000",
|
|
1974
|
-
shadowOffset: { width: hoverOffset, height: hoverOffset },
|
|
1975
|
-
shadowOpacity: 0.2,
|
|
1976
|
-
shadowRadius: hoverBlur / 2,
|
|
1977
|
-
elevation: hoverOffset
|
|
1978
|
-
}
|
|
1979
|
-
});
|
|
1980
|
-
}
|
|
1981
|
-
return reactNative.Platform.select({
|
|
1982
|
-
web: {
|
|
1983
|
-
boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
1984
|
-
},
|
|
1985
|
-
default: {
|
|
1986
|
-
shadowColor: "#000",
|
|
1987
|
-
shadowOffset: { width: offset, height: offset },
|
|
1988
|
-
shadowOpacity: 0.3,
|
|
1989
|
-
shadowRadius: blur / 2,
|
|
1990
|
-
elevation: offset
|
|
1991
|
-
}
|
|
1992
|
-
});
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
var FLOATING_ELEVATION_MIN = 4;
|
|
1996
|
-
function getElevationShadow(baseColor, level, theme, isHovered = false) {
|
|
1997
|
-
const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
|
|
1998
|
-
if (elevationShadowCache.has(cacheKey)) {
|
|
1999
|
-
return elevationShadowCache.get(cacheKey);
|
|
2000
|
-
}
|
|
2001
|
-
const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
|
|
2002
|
-
if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
|
|
2003
|
-
const firstKey = elevationShadowCache.keys().next().value;
|
|
2004
|
-
elevationShadowCache.delete(firstKey);
|
|
2005
|
-
}
|
|
2006
|
-
elevationShadowCache.set(cacheKey, result);
|
|
2007
|
-
return result;
|
|
2008
|
-
}
|
|
2009
|
-
function getBaseSurfaceColor(theme) {
|
|
2010
|
-
return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
|
|
2011
|
-
}
|
|
2012
|
-
var componentElevationRanges = {
|
|
2013
|
-
button: {
|
|
2014
|
-
allowed: [2],
|
|
2015
|
-
default: 2,
|
|
2016
|
-
hover: 3
|
|
2017
|
-
},
|
|
2018
|
-
card: {
|
|
2019
|
-
allowed: [1, 2, 3],
|
|
2020
|
-
default: 2,
|
|
2021
|
-
hover: 3
|
|
2022
|
-
},
|
|
2023
|
-
input: {
|
|
2024
|
-
allowed: [-2, -1, 0],
|
|
2025
|
-
default: -1
|
|
2026
|
-
},
|
|
2027
|
-
overlay: {
|
|
2028
|
-
allowed: [4, 5],
|
|
2029
|
-
default: 4
|
|
2030
|
-
}
|
|
2031
|
-
};
|
|
2032
|
-
function getValidatedElevation(component, requested) {
|
|
2033
|
-
const range = componentElevationRanges[component];
|
|
2034
|
-
if (range.allowed.includes(requested)) {
|
|
2035
|
-
return requested;
|
|
2036
|
-
}
|
|
2037
|
-
const sorted = [...range.allowed].sort((a, b) => a - b);
|
|
2038
|
-
if (requested < sorted[0]) return sorted[0];
|
|
2039
|
-
if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
|
|
2040
|
-
return sorted.reduce(
|
|
2041
|
-
(prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
|
|
2112
|
+
function useResolvedSurface(props) {
|
|
2113
|
+
const inherited = useSurface();
|
|
2114
|
+
const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
|
|
2115
|
+
return react.useMemo(
|
|
2116
|
+
() => resolveSurfaceDepth(inherited, {
|
|
2117
|
+
level,
|
|
2118
|
+
raise,
|
|
2119
|
+
elevation,
|
|
2120
|
+
pressed,
|
|
2121
|
+
lift,
|
|
2122
|
+
liftOptions,
|
|
2123
|
+
theme
|
|
2124
|
+
}),
|
|
2125
|
+
[inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
|
|
2042
2126
|
);
|
|
2043
2127
|
}
|
|
2044
|
-
function getTheme() {
|
|
2045
|
-
if (typeof document === "undefined") return "dark";
|
|
2046
|
-
return document.documentElement.classList.contains("light") ? "light" : "dark";
|
|
2047
|
-
}
|
|
2048
|
-
var listeners = [];
|
|
2049
|
-
function subscribe(listener) {
|
|
2050
|
-
listeners = [...listeners, listener];
|
|
2051
|
-
if (typeof document !== "undefined" && listeners.length === 1) {
|
|
2052
|
-
const observer = new MutationObserver((mutations) => {
|
|
2053
|
-
for (const mutation of mutations) {
|
|
2054
|
-
if (mutation.type === "attributes" && mutation.attributeName === "class") {
|
|
2055
|
-
listeners.forEach((l) => l());
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
observer.observe(document.documentElement, {
|
|
2060
|
-
attributes: true,
|
|
2061
|
-
attributeFilter: ["class"]
|
|
2062
|
-
});
|
|
2063
|
-
subscribe._observer = observer;
|
|
2064
|
-
}
|
|
2065
|
-
return () => {
|
|
2066
|
-
listeners = listeners.filter((l) => l !== listener);
|
|
2067
|
-
if (listeners.length === 0 && subscribe._observer) {
|
|
2068
|
-
subscribe._observer.disconnect();
|
|
2069
|
-
subscribe._observer = null;
|
|
2070
|
-
}
|
|
2071
|
-
};
|
|
2072
|
-
}
|
|
2073
|
-
function getSnapshot() {
|
|
2074
|
-
return getTheme();
|
|
2075
|
-
}
|
|
2076
|
-
function getServerSnapshot() {
|
|
2077
|
-
return "dark";
|
|
2078
|
-
}
|
|
2079
|
-
function useTheme() {
|
|
2080
|
-
return react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
2081
|
-
}
|
|
2082
2128
|
|
|
2083
2129
|
// src/components/ui/card/Card.tsx
|
|
2084
|
-
var
|
|
2130
|
+
var EDGE_CLASS = {
|
|
2085
2131
|
elevated: "",
|
|
2086
|
-
|
|
2087
|
-
outline: "border-2 border-hairline-strong",
|
|
2088
|
-
// Thicker border with stronger contrast
|
|
2132
|
+
accent: "",
|
|
2089
2133
|
filled: "",
|
|
2090
|
-
|
|
2091
|
-
accent: "border border-hairline",
|
|
2134
|
+
outline: "border border-hairline-strong",
|
|
2092
2135
|
subtle: "border border-hairline-subtle"
|
|
2093
2136
|
};
|
|
2137
|
+
var LIFTED = {
|
|
2138
|
+
elevated: true,
|
|
2139
|
+
accent: true,
|
|
2140
|
+
filled: false,
|
|
2141
|
+
outline: false,
|
|
2142
|
+
subtle: false
|
|
2143
|
+
};
|
|
2144
|
+
var STAYS_ON_HOST = {
|
|
2145
|
+
elevated: false,
|
|
2146
|
+
accent: false,
|
|
2147
|
+
filled: false,
|
|
2148
|
+
outline: true,
|
|
2149
|
+
subtle: true
|
|
2150
|
+
};
|
|
2151
|
+
function useCardDepth(variant, elevation, hovered) {
|
|
2152
|
+
const raise = STAYS_ON_HOST[variant] ? void 0 : elevation;
|
|
2153
|
+
const resolved = useResolvedSurface({ raise, lift: LIFTED[variant] });
|
|
2154
|
+
const depthStyle = react.useMemo(() => {
|
|
2155
|
+
if (!hovered || !LIFTED[variant]) return resolved.depthStyle;
|
|
2156
|
+
const hoverStep = Math.min(3, resolved.step + 1);
|
|
2157
|
+
return liftStyle(hoverStep, resolved.mode);
|
|
2158
|
+
}, [hovered, variant, resolved]);
|
|
2159
|
+
return { ...resolved, depthStyle };
|
|
2160
|
+
}
|
|
2094
2161
|
function Card({
|
|
2095
2162
|
variant = "elevated",
|
|
2096
2163
|
elevation = 2,
|
|
@@ -2111,89 +2178,54 @@ function Card({
|
|
|
2111
2178
|
}) {
|
|
2112
2179
|
const isClickable = isInteractive || !!onPress;
|
|
2113
2180
|
const [isHovered, setIsHovered] = react.useState(false);
|
|
2114
|
-
const
|
|
2115
|
-
const elevationLevel = react.useMemo(() => {
|
|
2116
|
-
const validated = getValidatedElevation("card", elevation);
|
|
2117
|
-
if (variant === "outline" || variant === "accent" || variant === "subtle") {
|
|
2118
|
-
return 1;
|
|
2119
|
-
}
|
|
2120
|
-
return validated;
|
|
2121
|
-
}, [variant, elevation]);
|
|
2122
|
-
const baseColor = react.useMemo(() => getBaseSurfaceColor(theme), [theme]);
|
|
2123
|
-
const surfaceColor = react.useMemo(() => {
|
|
2124
|
-
if ((variant === "outline" || variant === "accent") && theme === "light") {
|
|
2125
|
-
return "#FAFAFA";
|
|
2126
|
-
}
|
|
2127
|
-
if (variant === "subtle") {
|
|
2128
|
-
return getElevationSurface(baseColor, 0, theme);
|
|
2129
|
-
}
|
|
2130
|
-
return getElevationSurface(baseColor, elevationLevel, theme);
|
|
2131
|
-
}, [baseColor, elevationLevel, theme, variant]);
|
|
2132
|
-
const shadowStyle = react.useMemo(() => {
|
|
2133
|
-
const shouldHover = isHovered && isClickable;
|
|
2134
|
-
return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
|
|
2135
|
-
}, [baseColor, elevationLevel, theme, isHovered, isClickable]);
|
|
2136
|
-
const cardContent = isLoading ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
2137
|
-
skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
2138
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
|
|
2139
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
|
|
2140
|
-
] }),
|
|
2141
|
-
/* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
|
|
2142
|
-
reactNative.View,
|
|
2143
|
-
{
|
|
2144
|
-
className: cn(
|
|
2145
|
-
"h-4 bg-interactive-disabled rounded",
|
|
2146
|
-
i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
|
|
2147
|
-
)
|
|
2148
|
-
},
|
|
2149
|
-
i
|
|
2150
|
-
)) }),
|
|
2151
|
-
skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
|
|
2152
|
-
] }) : children;
|
|
2181
|
+
const depth = useCardDepth(variant, elevation, isHovered && isClickable);
|
|
2153
2182
|
const baseClassName = cn(
|
|
2154
2183
|
"rounded-lg overflow-hidden relative",
|
|
2155
|
-
|
|
2156
|
-
variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
|
|
2157
|
-
// Remove Tailwind shadow classes - we're using elevation shadows via style prop
|
|
2184
|
+
borderColor ? "border" : EDGE_CLASS[variant],
|
|
2158
2185
|
isClickable && "web:cursor-pointer web:transition-all web:duration-150",
|
|
2159
2186
|
isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
|
|
2160
2187
|
isLoading && "pointer-events-none animate-pulse",
|
|
2161
2188
|
className
|
|
2162
2189
|
);
|
|
2163
|
-
const accentStyle = react.useMemo(() => variant === "accent" ? {
|
|
2164
|
-
borderLeftWidth: accentWidth ?? 3,
|
|
2165
|
-
borderLeftColor: accentColor ?? "var(--color-brand-primary)"
|
|
2166
|
-
} : {}, [variant, accentWidth, accentColor]);
|
|
2167
2190
|
const mergedStyle = react.useMemo(() => {
|
|
2168
|
-
const
|
|
2169
|
-
backgroundColor: bgColor ||
|
|
2191
|
+
const own = {
|
|
2192
|
+
backgroundColor: bgColor || depth.backgroundColor,
|
|
2170
2193
|
borderRadius: 8,
|
|
2171
2194
|
overflow: "hidden",
|
|
2172
|
-
...
|
|
2173
|
-
...accentStyle
|
|
2195
|
+
...depth.depthStyle
|
|
2174
2196
|
};
|
|
2175
|
-
if (
|
|
2176
|
-
|
|
2197
|
+
if (variant === "accent") {
|
|
2198
|
+
own.borderLeftWidth = accentWidth ?? 3;
|
|
2199
|
+
own.borderLeftColor = accentColor ?? "var(--color-brand-primary)";
|
|
2177
2200
|
}
|
|
2178
|
-
if (
|
|
2179
|
-
return [
|
|
2180
|
-
}, [style,
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2201
|
+
if (borderColor) own.borderColor = borderColor;
|
|
2202
|
+
return style ? [own, style] : own;
|
|
2203
|
+
}, [style, depth, bgColor, borderColor, variant, accentWidth, accentColor]);
|
|
2204
|
+
const context = react.useMemo(
|
|
2205
|
+
() => ({ mode: depth.mode, level: depth.plane }),
|
|
2206
|
+
[depth.mode, depth.plane]
|
|
2207
|
+
);
|
|
2208
|
+
const content = isLoading ? /* @__PURE__ */ jsx(
|
|
2209
|
+
SkeletonBody,
|
|
2210
|
+
{
|
|
2211
|
+
hasHeader: skeletonHasHeader,
|
|
2212
|
+
hasFooter: skeletonHasFooter,
|
|
2213
|
+
contentLines: skeletonContentLines
|
|
2214
|
+
}
|
|
2215
|
+
) : children;
|
|
2216
|
+
return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: context, children: isClickable ? /* @__PURE__ */ jsx(
|
|
2217
|
+
reactNative.Pressable,
|
|
2218
|
+
{
|
|
2219
|
+
onPress,
|
|
2220
|
+
onHoverIn: () => setIsHovered(true),
|
|
2221
|
+
onHoverOut: () => setIsHovered(false),
|
|
2222
|
+
accessibilityRole: "button",
|
|
2223
|
+
className: baseClassName,
|
|
2224
|
+
style: mergedStyle,
|
|
2225
|
+
...props,
|
|
2226
|
+
children: content
|
|
2227
|
+
}
|
|
2228
|
+
) : /* @__PURE__ */ jsx(reactNative.View, { className: baseClassName, style: mergedStyle, ...props, children: content }) });
|
|
2197
2229
|
}
|
|
2198
2230
|
function CardHeader({ children, className }) {
|
|
2199
2231
|
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-6", className), children });
|
|
@@ -2204,60 +2236,122 @@ function CardContent({ children, className }) {
|
|
|
2204
2236
|
function CardFooter({ children, className }) {
|
|
2205
2237
|
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
|
|
2206
2238
|
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2239
|
+
function SkeletonBody({ hasHeader, hasFooter, contentLines }) {
|
|
2240
|
+
return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
2241
|
+
hasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
2242
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
|
|
2243
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
|
|
2244
|
+
] }),
|
|
2245
|
+
/* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: contentLines }).map((_, i) => /* @__PURE__ */ jsx(
|
|
2246
|
+
reactNative.View,
|
|
2247
|
+
{
|
|
2248
|
+
className: cn(
|
|
2249
|
+
"h-4 bg-interactive-disabled rounded",
|
|
2250
|
+
i < contentLines - 1 ? "mb-2 w-full" : "w-4/5"
|
|
2251
|
+
)
|
|
2252
|
+
},
|
|
2253
|
+
i
|
|
2254
|
+
)) }),
|
|
2255
|
+
hasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
|
|
2256
|
+
] });
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
// src/utils/colors.ts
|
|
2260
|
+
function alpha(color, opacity) {
|
|
2261
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
2262
|
+
if (color.startsWith("#")) {
|
|
2263
|
+
const hex = color.slice(1);
|
|
2264
|
+
let r, g, b;
|
|
2265
|
+
if (hex.length === 3) {
|
|
2266
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
2267
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
2268
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
2269
|
+
} else if (hex.length === 6) {
|
|
2270
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
2271
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
2272
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
2273
|
+
} else {
|
|
2274
|
+
return color;
|
|
2275
|
+
}
|
|
2276
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
2277
|
+
}
|
|
2278
|
+
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
2279
|
+
if (rgbMatch) {
|
|
2280
|
+
const [, r, g, b] = rgbMatch;
|
|
2281
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
2230
2282
|
}
|
|
2283
|
+
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
|
|
2284
|
+
if (rgbaMatch) {
|
|
2285
|
+
const [, r, g, b] = rgbaMatch;
|
|
2286
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
2287
|
+
}
|
|
2288
|
+
return color;
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
// src/components/custom/Workout/StatusDot.tsx
|
|
2292
|
+
var solidFillToken = {
|
|
2293
|
+
success: "status-success",
|
|
2294
|
+
warning: "status-warning",
|
|
2295
|
+
error: "status-error",
|
|
2296
|
+
neutral: "text-tertiary"
|
|
2231
2297
|
};
|
|
2232
|
-
var
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
|
|
2236
|
-
neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
|
|
2237
|
-
"on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
2238
|
-
deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
2239
|
-
future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
|
|
2298
|
+
var ringWashToken = {
|
|
2299
|
+
"on-track": { fill: "status-success-subtle", border: "status-success-muted" },
|
|
2300
|
+
deviation: { fill: "status-warning-subtle", border: "status-warning-muted" }
|
|
2240
2301
|
};
|
|
2302
|
+
var FUTURE_FILL = alpha(greyRamp[500], 0.1);
|
|
2303
|
+
var FUTURE_BORDER = alpha(greyRamp[500], 0.2);
|
|
2304
|
+
var glyphToken = {
|
|
2305
|
+
success: "text-inverse",
|
|
2306
|
+
warning: "text-inverse",
|
|
2307
|
+
error: "text-inverse",
|
|
2308
|
+
neutral: "text-inverse",
|
|
2309
|
+
"on-track": "status-success",
|
|
2310
|
+
deviation: "status-warning",
|
|
2311
|
+
future: "text-tertiary"
|
|
2312
|
+
};
|
|
2313
|
+
var glowColors2 = {
|
|
2314
|
+
success: semanticColorsDark["status-success"],
|
|
2315
|
+
warning: semanticColorsDark["status-warning"],
|
|
2316
|
+
error: semanticColorsDark["status-error"],
|
|
2317
|
+
neutral: greyRamp[500],
|
|
2318
|
+
"on-track": semanticColorsDark["status-success"],
|
|
2319
|
+
deviation: semanticColorsDark["status-warning"],
|
|
2320
|
+
future: greyRamp[500]
|
|
2321
|
+
};
|
|
2322
|
+
var glowStyles = Object.fromEntries(
|
|
2323
|
+
Object.entries(glowColors2).map(([variant, color]) => [variant, getGlowShadow(color, "subtle")])
|
|
2324
|
+
);
|
|
2241
2325
|
var iconChars = {
|
|
2242
2326
|
check: "\u2713",
|
|
2243
2327
|
exclamation: "!",
|
|
2244
2328
|
dash: "\u2014"
|
|
2245
2329
|
};
|
|
2246
|
-
var iconColors = {
|
|
2247
|
-
success: "#0A5C52",
|
|
2248
|
-
warning: "#6B4000",
|
|
2249
|
-
error: "#5C1A1A",
|
|
2250
|
-
neutral: greyRamp[200],
|
|
2251
|
-
"on-track": t2["status-success"],
|
|
2252
|
-
deviation: t2["status-warning"],
|
|
2253
|
-
future: greyRamp[500]
|
|
2254
|
-
};
|
|
2255
2330
|
var sizeDimensions = {
|
|
2256
2331
|
sm: { size: 8, showIcon: false },
|
|
2257
2332
|
md: { size: 18, showIcon: true }
|
|
2258
2333
|
};
|
|
2259
2334
|
function isSolidVariant(variant) {
|
|
2260
|
-
return variant in
|
|
2335
|
+
return variant in solidFillToken;
|
|
2336
|
+
}
|
|
2337
|
+
function ringStyle(variant) {
|
|
2338
|
+
if (variant === "future") {
|
|
2339
|
+
return {
|
|
2340
|
+
backgroundColor: FUTURE_FILL,
|
|
2341
|
+
borderWidth: 1,
|
|
2342
|
+
borderStyle: "dashed",
|
|
2343
|
+
borderColor: FUTURE_BORDER
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
if (variant === "on-track" || variant === "deviation") {
|
|
2347
|
+
const tokens = ringWashToken[variant];
|
|
2348
|
+
return {
|
|
2349
|
+
backgroundColor: resolveColor(tokens.fill),
|
|
2350
|
+
borderWidth: 1,
|
|
2351
|
+
borderColor: resolveColor(tokens.border)
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
return void 0;
|
|
2261
2355
|
}
|
|
2262
2356
|
function StatusDot({
|
|
2263
2357
|
variant,
|
|
@@ -2270,7 +2364,7 @@ function StatusDot({
|
|
|
2270
2364
|
}) {
|
|
2271
2365
|
const config = sizeDimensions[size];
|
|
2272
2366
|
const solid = isSolidVariant(variant);
|
|
2273
|
-
const ring =
|
|
2367
|
+
const ring = ringStyle(variant);
|
|
2274
2368
|
const glowStyle = glow ? glowStyles[variant] : null;
|
|
2275
2369
|
const dot = /* @__PURE__ */ jsx(
|
|
2276
2370
|
reactNative.View,
|
|
@@ -2284,22 +2378,22 @@ function StatusDot({
|
|
|
2284
2378
|
justifyContent: "center",
|
|
2285
2379
|
flexShrink: 0
|
|
2286
2380
|
},
|
|
2287
|
-
solid ? { backgroundColor:
|
|
2288
|
-
ring
|
|
2381
|
+
solid ? { backgroundColor: resolveColor(solidFillToken[variant]) } : void 0,
|
|
2382
|
+
ring,
|
|
2289
2383
|
glowStyle ? glowStyle : void 0
|
|
2290
2384
|
],
|
|
2291
2385
|
accessibilityRole: "image",
|
|
2292
2386
|
accessibilityLabel: `${variant} status`,
|
|
2293
2387
|
testID: "status-dot",
|
|
2294
|
-
children: config.showIcon && icon &&
|
|
2295
|
-
|
|
2388
|
+
children: config.showIcon && icon && // The glyph was 11px/900, off the type scale (TOKENS.md §4); `boldLabel` is
|
|
2389
|
+
// the 12px sans label step and `font-black` keeps the original weight.
|
|
2390
|
+
/* @__PURE__ */ jsx(
|
|
2391
|
+
Typography,
|
|
2296
2392
|
{
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
color: iconColors[variant]
|
|
2302
|
-
},
|
|
2393
|
+
variant: "boldLabel",
|
|
2394
|
+
color: "inherit",
|
|
2395
|
+
className: "font-black leading-none",
|
|
2396
|
+
style: { color: resolveColor(glyphToken[variant]) },
|
|
2303
2397
|
accessibilityElementsHidden: true,
|
|
2304
2398
|
children: iconChars[icon]
|
|
2305
2399
|
}
|
|
@@ -2317,9 +2411,11 @@ function StatusDot({
|
|
|
2317
2411
|
children: [
|
|
2318
2412
|
/* @__PURE__ */ jsx(reactNative.View, { accessibilityElementsHidden: true, children: dot }),
|
|
2319
2413
|
/* @__PURE__ */ jsx(
|
|
2320
|
-
|
|
2414
|
+
Typography,
|
|
2321
2415
|
{
|
|
2322
|
-
|
|
2416
|
+
variant: "caption",
|
|
2417
|
+
color: "secondary",
|
|
2418
|
+
className: "leading-4",
|
|
2323
2419
|
accessibilityElementsHidden: true,
|
|
2324
2420
|
children: label
|
|
2325
2421
|
}
|
|
@@ -2335,13 +2431,13 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
|
|
|
2335
2431
|
|
|
2336
2432
|
// src/components/custom/Workout/MesoStatusCard.tsx
|
|
2337
2433
|
var t3 = getSemanticColors("dark");
|
|
2338
|
-
var
|
|
2434
|
+
var BRAND_PRIMARY3 = t3["brand-primary"];
|
|
2339
2435
|
var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
|
|
2340
2436
|
var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
|
|
2341
2437
|
var SUCCESS = t3["status-success"];
|
|
2342
2438
|
var WARNING = t3["status-warning"];
|
|
2343
2439
|
var ERROR = t3["status-error"];
|
|
2344
|
-
var ACCENT_STOPS = [BRAND_PRIMARY_DARK,
|
|
2440
|
+
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY3, BRAND_PRIMARY_LIGHT];
|
|
2345
2441
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
2346
2442
|
var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(46,213,115,0.25) 0%, rgba(249,180,21,0.25) 50%, rgba(209,67,67,0.25) 100%)";
|
|
2347
2443
|
var STATUS_VARIANTS = {
|
|
@@ -2366,15 +2462,7 @@ function renderCoachingText(text, highlights) {
|
|
|
2366
2462
|
if (escaped.length === 0) return text;
|
|
2367
2463
|
const regex = new RegExp(`(${escaped.join("|")})`, "g");
|
|
2368
2464
|
return text.split(regex).map(
|
|
2369
|
-
(part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
|
|
2370
|
-
reactNative.Text,
|
|
2371
|
-
{
|
|
2372
|
-
className: "text-text-primary",
|
|
2373
|
-
style: { fontWeight: "700" },
|
|
2374
|
-
children: part
|
|
2375
|
-
},
|
|
2376
|
-
`${part}-${index}`
|
|
2377
|
-
) : /* @__PURE__ */ jsx(react.Fragment, { children: part }, `t-${index}`)
|
|
2465
|
+
(part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-primary", style: { fontWeight: "700" }, children: part }, `${part}-${index}`) : /* @__PURE__ */ jsx(react.Fragment, { children: part }, `t-${index}`)
|
|
2378
2466
|
);
|
|
2379
2467
|
}
|
|
2380
2468
|
function StatusPill({ badge }) {
|
|
@@ -2459,41 +2547,34 @@ function Gauge({ gauge }) {
|
|
|
2459
2547
|
"aria-valuemax": 100,
|
|
2460
2548
|
testID: "meso-status-card-gauge",
|
|
2461
2549
|
children: [
|
|
2462
|
-
/* @__PURE__ */ jsxs(
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
},
|
|
2491
|
-
children: gauge.sublabel
|
|
2492
|
-
}
|
|
2493
|
-
)
|
|
2494
|
-
]
|
|
2495
|
-
}
|
|
2496
|
-
),
|
|
2550
|
+
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", accessibilityElementsHidden: true, children: [
|
|
2551
|
+
/* @__PURE__ */ jsx(
|
|
2552
|
+
reactNative.Text,
|
|
2553
|
+
{
|
|
2554
|
+
className: "text-text-secondary",
|
|
2555
|
+
style: {
|
|
2556
|
+
fontSize: 10,
|
|
2557
|
+
fontFamily: "Inter, sans-serif",
|
|
2558
|
+
fontWeight: "500",
|
|
2559
|
+
letterSpacing: 0.5,
|
|
2560
|
+
textTransform: "uppercase"
|
|
2561
|
+
},
|
|
2562
|
+
children: gauge.label
|
|
2563
|
+
}
|
|
2564
|
+
),
|
|
2565
|
+
gauge.sublabel != null && /* @__PURE__ */ jsx(
|
|
2566
|
+
reactNative.Text,
|
|
2567
|
+
{
|
|
2568
|
+
className: "text-text-tertiary",
|
|
2569
|
+
style: {
|
|
2570
|
+
fontSize: 10,
|
|
2571
|
+
fontFamily: "Inter, sans-serif",
|
|
2572
|
+
fontWeight: "500"
|
|
2573
|
+
},
|
|
2574
|
+
children: gauge.sublabel
|
|
2575
|
+
}
|
|
2576
|
+
)
|
|
2577
|
+
] }),
|
|
2497
2578
|
/* @__PURE__ */ jsxs(
|
|
2498
2579
|
reactNative.View,
|
|
2499
2580
|
{
|
|
@@ -2534,7 +2615,8 @@ function Gauge({ gauge }) {
|
|
|
2534
2615
|
borderRadius: 9999,
|
|
2535
2616
|
borderWidth: 2,
|
|
2536
2617
|
backgroundColor: markerColor,
|
|
2537
|
-
|
|
2618
|
+
// A knob resting on the gauge: lift, with the ring as its edge.
|
|
2619
|
+
...liftStyle(1, "dark", { rim: 0 })
|
|
2538
2620
|
},
|
|
2539
2621
|
testID: "meso-status-card-gauge-marker"
|
|
2540
2622
|
}
|
|
@@ -2586,30 +2668,23 @@ function MesoStatusCard({
|
|
|
2586
2668
|
),
|
|
2587
2669
|
/* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
|
|
2588
2670
|
/* @__PURE__ */ jsxs(reactNative.View, { testID: "meso-status-card-header", children: [
|
|
2589
|
-
/* @__PURE__ */ jsxs(
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
children: mesoName
|
|
2607
|
-
}
|
|
2608
|
-
),
|
|
2609
|
-
/* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
|
|
2610
|
-
]
|
|
2611
|
-
}
|
|
2612
|
-
),
|
|
2671
|
+
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", style: { gap: 8 }, children: [
|
|
2672
|
+
/* @__PURE__ */ jsx(
|
|
2673
|
+
reactNative.Text,
|
|
2674
|
+
{
|
|
2675
|
+
className: "text-text-primary",
|
|
2676
|
+
style: {
|
|
2677
|
+
flexShrink: 1,
|
|
2678
|
+
fontSize: 15,
|
|
2679
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
2680
|
+
fontWeight: "700"
|
|
2681
|
+
},
|
|
2682
|
+
testID: "meso-status-card-name",
|
|
2683
|
+
children: mesoName
|
|
2684
|
+
}
|
|
2685
|
+
),
|
|
2686
|
+
/* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
|
|
2687
|
+
] }),
|
|
2613
2688
|
/* @__PURE__ */ jsx(
|
|
2614
2689
|
reactNative.Text,
|
|
2615
2690
|
{
|
|
@@ -2624,15 +2699,7 @@ function MesoStatusCard({
|
|
|
2624
2699
|
}
|
|
2625
2700
|
)
|
|
2626
2701
|
] }),
|
|
2627
|
-
metrics.length > 0 && /* @__PURE__ */ jsx(
|
|
2628
|
-
reactNative.View,
|
|
2629
|
-
{
|
|
2630
|
-
className: "flex-row flex-wrap",
|
|
2631
|
-
style: { gap: 8 },
|
|
2632
|
-
testID: "meso-status-card-metrics",
|
|
2633
|
-
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`))
|
|
2634
|
-
}
|
|
2635
|
-
),
|
|
2702
|
+
metrics.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row flex-wrap", style: { gap: 8 }, testID: "meso-status-card-metrics", children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`)) }),
|
|
2636
2703
|
gauges.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 12 }, testID: "meso-status-card-gauges", children: gauges.map((gauge, index) => /* @__PURE__ */ jsx(Gauge, { gauge }, `${gauge.label}-${index}`)) }),
|
|
2637
2704
|
coaching != null && /* @__PURE__ */ jsx(
|
|
2638
2705
|
reactNative.View,
|