@titan-design/react-ui 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -47
- package/dist/bodymap.js +856 -736
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +858 -738
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1431 -237
- package/dist/index.d.ts +1431 -237
- package/dist/index.js +6506 -4781
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6280 -4642
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
- package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1919 -1937
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1927 -1945
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +225 -140
- package/dist/theme/index.d.ts +225 -140
- package/dist/theme/index.js +298 -319
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +283 -315
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +145 -24
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +145 -24
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +128 -11
- package/dist/theme/tokens.d.ts +128 -11
- package/dist/theme/tokens.js +126 -26
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +124 -27
- package/dist/theme/tokens.mjs.map +1 -1
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/docs/render-testing-pattern.md +130 -0
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +3 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +4989 -1583
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +7 -2
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +122 -18
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +99 -16
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +11 -3
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
- package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +6 -2
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +8 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
- package/src/components/custom/Workout/DeviationBar.tsx +24 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
- package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
- package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/InputBar.tsx +4 -2
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +8 -3
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +14 -10
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +68 -17
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
- package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
- package/src/components/custom/Workout/RestTimer.tsx +4 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
- package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
- package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/exerciseRowState.ts +29 -0
- package/src/components/custom/Workout/index.ts +17 -2
- package/src/components/custom/Workout/metricText.stories.tsx +15 -13
- package/src/components/custom/Workout/metricText.tsx +8 -2
- package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/README.md +66 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
- package/src/components/custom/charts/SetBarChart.tsx +56 -9
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
- package/src/components/custom/charts/flatBarGeometry.ts +32 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +21 -34
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +89 -26
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +15 -5
- package/src/components/ui/alert/Alert.tsx +24 -3
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +44 -37
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +7 -27
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -27
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +10 -18
- package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +31 -19
- package/src/components/ui/pill/Pill.stories.tsx +111 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +168 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +6 -8
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/progress/Progress.tsx +9 -6
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +12 -21
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +16 -15
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +4 -5
- package/src/components/ui/stack/Stack.stories.tsx +8 -8
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +92 -33
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +8 -21
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +49 -57
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +101 -48
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/test/no-raw-color.test.ts +39 -0
- package/src/theme/Alpha.stories.tsx +103 -0
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +23 -21
- package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +40 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +45 -5
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/subtle-tone-weight.test.ts +163 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/tailwind-var-opacity.test.ts +163 -0
- package/src/theme/token-export-guard.test.ts +1 -3
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +98 -33
- package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
- package/src/theme/tokens/semantic.ts +124 -54
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.alpha-adoption.test.ts +408 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +55 -9
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback, createContext, useContext } from 'react'
|
|
2
2
|
import { View, Pressable, Modal, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { Surface } from '../surface'
|
|
5
|
+
import { TriggerSurface } from '../trigger'
|
|
4
6
|
|
|
5
7
|
export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right'
|
|
6
8
|
|
|
@@ -68,12 +70,15 @@ export function Popover({
|
|
|
68
70
|
const isOpen = controlledIsOpen ?? internalIsOpen
|
|
69
71
|
const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
70
72
|
|
|
71
|
-
const setIsOpen = useCallback(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
const setIsOpen = useCallback(
|
|
74
|
+
(open: boolean) => {
|
|
75
|
+
if (controlledIsOpen === undefined) {
|
|
76
|
+
setInternalIsOpen(open)
|
|
77
|
+
}
|
|
78
|
+
onOpenChange?.(open)
|
|
79
|
+
},
|
|
80
|
+
[controlledIsOpen, onOpenChange]
|
|
81
|
+
)
|
|
77
82
|
|
|
78
83
|
const handleHoverIn = useCallback(() => {
|
|
79
84
|
if (triggerMode !== 'hover') return
|
|
@@ -126,15 +131,14 @@ export function PopoverTrigger({ children, className }: PopoverTriggerProps) {
|
|
|
126
131
|
: {}
|
|
127
132
|
|
|
128
133
|
return (
|
|
129
|
-
<
|
|
130
|
-
|
|
134
|
+
<TriggerSurface
|
|
135
|
+
handlers={{ onPress: () => setIsOpen(!isOpen), ...hoverProps }}
|
|
131
136
|
accessibilityRole="button"
|
|
132
137
|
accessibilityState={{ expanded: isOpen }}
|
|
133
138
|
className={className}
|
|
134
|
-
{...hoverProps}
|
|
135
139
|
>
|
|
136
140
|
{children}
|
|
137
|
-
</
|
|
141
|
+
</TriggerSurface>
|
|
138
142
|
)
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -184,12 +188,13 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
|
|
|
184
188
|
className="fixed inset-0 z-40"
|
|
185
189
|
style={{ position: 'absolute' }}
|
|
186
190
|
/>
|
|
187
|
-
{/* Content */}
|
|
188
|
-
<
|
|
191
|
+
{/* Content — floating: overlay plane + lift, no ring. */}
|
|
192
|
+
<Surface
|
|
193
|
+
elevation={4}
|
|
194
|
+
rounded={false}
|
|
189
195
|
className={cn(
|
|
190
196
|
'absolute z-50 min-w-[200px]',
|
|
191
|
-
'
|
|
192
|
-
'p-4',
|
|
197
|
+
'rounded-lg p-4',
|
|
193
198
|
placementStyles[placement],
|
|
194
199
|
className
|
|
195
200
|
)}
|
|
@@ -208,7 +213,7 @@ export function PopoverContent({ children, className }: PopoverContentProps) {
|
|
|
208
213
|
/>
|
|
209
214
|
)}
|
|
210
215
|
{children}
|
|
211
|
-
</
|
|
216
|
+
</Surface>
|
|
212
217
|
</>
|
|
213
218
|
)
|
|
214
219
|
}
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export { Popover, PopoverTrigger, PopoverContent, PopoverCloseButton } from './Popover'
|
|
2
|
-
export type {
|
|
2
|
+
export type {
|
|
3
|
+
PopoverProps,
|
|
4
|
+
PopoverTriggerProps,
|
|
5
|
+
PopoverContentProps,
|
|
6
|
+
PopoverCloseButtonProps,
|
|
7
|
+
PopoverPlacement,
|
|
8
|
+
} from './Popover'
|
|
@@ -5,7 +5,7 @@ import { Progress, CircularProgress, ProgressSteps } from './Progress'
|
|
|
5
5
|
const meta: Meta<typeof Progress> = {
|
|
6
6
|
title: 'Components/Molecules/Progress',
|
|
7
7
|
component: Progress,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
value: {
|
|
11
11
|
control: { type: 'range', min: 0, max: 100, step: 1 },
|
|
@@ -131,11 +131,7 @@ export const Steps: Story = {
|
|
|
131
131
|
color="success"
|
|
132
132
|
labels={['Step 1', 'Step 2', 'Step 3', 'Step 4']}
|
|
133
133
|
/>
|
|
134
|
-
<ProgressSteps
|
|
135
|
-
currentStep={0}
|
|
136
|
-
totalSteps={5}
|
|
137
|
-
size="lg"
|
|
138
|
-
/>
|
|
134
|
+
<ProgressSteps currentStep={0} totalSteps={5} size="lg" />
|
|
139
135
|
</View>
|
|
140
136
|
),
|
|
141
137
|
}
|
|
@@ -152,12 +148,7 @@ export const UsageExamples: Story = {
|
|
|
152
148
|
{/* Storage quota */}
|
|
153
149
|
<View className="p-4 bg-surface-elevated rounded-lg">
|
|
154
150
|
<Text className="text-text-primary font-medium mb-3">Storage</Text>
|
|
155
|
-
<Progress
|
|
156
|
-
value={8.5}
|
|
157
|
-
max={10}
|
|
158
|
-
color="warning"
|
|
159
|
-
label="8.5 GB of 10 GB used"
|
|
160
|
-
/>
|
|
151
|
+
<Progress value={8.5} max={10} color="warning" label="8.5 GB of 10 GB used" />
|
|
161
152
|
</View>
|
|
162
153
|
|
|
163
154
|
{/* Checkout steps */}
|
|
@@ -154,11 +154,7 @@ describe('Progress', () => {
|
|
|
154
154
|
|
|
155
155
|
it('renders labels', () => {
|
|
156
156
|
render(
|
|
157
|
-
<ProgressSteps
|
|
158
|
-
currentStep={1}
|
|
159
|
-
totalSteps={3}
|
|
160
|
-
labels={['Step 1', 'Step 2', 'Step 3']}
|
|
161
|
-
/>
|
|
157
|
+
<ProgressSteps currentStep={1} totalSteps={3} labels={['Step 1', 'Step 2', 'Step 3']} />
|
|
162
158
|
)
|
|
163
159
|
expect(screen.getByText('Step 1')).toBeInTheDocument()
|
|
164
160
|
expect(screen.getByText('Step 2')).toBeInTheDocument()
|
|
@@ -56,13 +56,16 @@ const colorStyles: Record<ProgressColor, string> = {
|
|
|
56
56
|
info: 'bg-status-info',
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// `-muted` rather than `-subtle`: the track is structural — it has to show the
|
|
60
|
+
// bar's full extent behind the fill — and the lightest rung disappears on the
|
|
61
|
+
// dark base. Replaces a `/20` modifier that emitted no rule (VW-308).
|
|
59
62
|
const trackColorStyles: Record<ProgressColor, string> = {
|
|
60
|
-
primary: 'bg-brand-primary
|
|
61
|
-
secondary: 'bg-brand-secondary
|
|
62
|
-
success: 'bg-status-success
|
|
63
|
-
error: 'bg-status-error
|
|
64
|
-
warning: 'bg-status-warning
|
|
65
|
-
info: 'bg-status-info
|
|
63
|
+
primary: 'bg-brand-primary-muted',
|
|
64
|
+
secondary: 'bg-brand-secondary-muted',
|
|
65
|
+
success: 'bg-status-success-muted',
|
|
66
|
+
error: 'bg-status-error-muted',
|
|
67
|
+
warning: 'bg-status-warning-muted',
|
|
68
|
+
info: 'bg-status-info-muted',
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
/**
|
|
@@ -6,7 +6,7 @@ import { Radio, RadioGroup } from './Radio'
|
|
|
6
6
|
const meta: Meta<typeof RadioGroup> = {
|
|
7
7
|
title: 'Components/Molecules/Radio',
|
|
8
8
|
component: RadioGroup,
|
|
9
|
-
tags: ['autodocs'],
|
|
9
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
10
10
|
argTypes: {
|
|
11
11
|
size: {
|
|
12
12
|
control: 'select',
|
|
@@ -60,12 +60,7 @@ export const Horizontal: Story = {
|
|
|
60
60
|
render: function Render() {
|
|
61
61
|
const [value, setValue] = useState<string | null>('monthly')
|
|
62
62
|
return (
|
|
63
|
-
<RadioGroup
|
|
64
|
-
value={value}
|
|
65
|
-
onChange={setValue}
|
|
66
|
-
orientation="horizontal"
|
|
67
|
-
label="Billing Cycle"
|
|
68
|
-
>
|
|
63
|
+
<RadioGroup value={value} onChange={setValue} orientation="horizontal" label="Billing Cycle">
|
|
69
64
|
<Radio value="monthly">Monthly</Radio>
|
|
70
65
|
<Radio value="quarterly">Quarterly</Radio>
|
|
71
66
|
<Radio value="yearly">Yearly</Radio>
|
|
@@ -79,7 +74,7 @@ export const AllSizes: Story = {
|
|
|
79
74
|
const [small, setSmall] = useState<string | null>('a')
|
|
80
75
|
const [medium, setMedium] = useState<string | null>('a')
|
|
81
76
|
const [large, setLarge] = useState<string | null>('a')
|
|
82
|
-
|
|
77
|
+
|
|
83
78
|
return (
|
|
84
79
|
<View className="gap-6">
|
|
85
80
|
<View>
|
|
@@ -114,22 +109,46 @@ export const AllColors: Story = {
|
|
|
114
109
|
const [secondary, setSecondary] = useState<string | null>('a')
|
|
115
110
|
const [success, setSuccess] = useState<string | null>('a')
|
|
116
111
|
const [error, setError] = useState<string | null>('a')
|
|
117
|
-
|
|
112
|
+
|
|
118
113
|
return (
|
|
119
114
|
<View className="gap-6">
|
|
120
|
-
<RadioGroup
|
|
115
|
+
<RadioGroup
|
|
116
|
+
value={primary}
|
|
117
|
+
onChange={setPrimary}
|
|
118
|
+
color="primary"
|
|
119
|
+
orientation="horizontal"
|
|
120
|
+
label="Primary"
|
|
121
|
+
>
|
|
121
122
|
<Radio value="a">Option A</Radio>
|
|
122
123
|
<Radio value="b">Option B</Radio>
|
|
123
124
|
</RadioGroup>
|
|
124
|
-
<RadioGroup
|
|
125
|
+
<RadioGroup
|
|
126
|
+
value={secondary}
|
|
127
|
+
onChange={setSecondary}
|
|
128
|
+
color="secondary"
|
|
129
|
+
orientation="horizontal"
|
|
130
|
+
label="Secondary"
|
|
131
|
+
>
|
|
125
132
|
<Radio value="a">Option A</Radio>
|
|
126
133
|
<Radio value="b">Option B</Radio>
|
|
127
134
|
</RadioGroup>
|
|
128
|
-
<RadioGroup
|
|
135
|
+
<RadioGroup
|
|
136
|
+
value={success}
|
|
137
|
+
onChange={setSuccess}
|
|
138
|
+
color="success"
|
|
139
|
+
orientation="horizontal"
|
|
140
|
+
label="Success"
|
|
141
|
+
>
|
|
129
142
|
<Radio value="a">Option A</Radio>
|
|
130
143
|
<Radio value="b">Option B</Radio>
|
|
131
144
|
</RadioGroup>
|
|
132
|
-
<RadioGroup
|
|
145
|
+
<RadioGroup
|
|
146
|
+
value={error}
|
|
147
|
+
onChange={setError}
|
|
148
|
+
color="error"
|
|
149
|
+
orientation="horizontal"
|
|
150
|
+
label="Error"
|
|
151
|
+
>
|
|
133
152
|
<Radio value="a">Option A</Radio>
|
|
134
153
|
<Radio value="b">Option B</Radio>
|
|
135
154
|
</RadioGroup>
|
|
@@ -154,7 +173,9 @@ export const Disabled: Story = {
|
|
|
154
173
|
<Text className="text-text-secondary text-sm mb-2">Individual option disabled</Text>
|
|
155
174
|
<RadioGroup value={value} onChange={setValue}>
|
|
156
175
|
<Radio value="option1">Option 1 (enabled)</Radio>
|
|
157
|
-
<Radio value="option2" isDisabled>
|
|
176
|
+
<Radio value="option2" isDisabled>
|
|
177
|
+
Option 2 (disabled)
|
|
178
|
+
</Radio>
|
|
158
179
|
<Radio value="option3">Option 3 (enabled)</Radio>
|
|
159
180
|
</RadioGroup>
|
|
160
181
|
</View>
|
|
@@ -167,27 +188,27 @@ export const FormExample: Story = {
|
|
|
167
188
|
render: function Render() {
|
|
168
189
|
const [plan, setPlan] = useState<string | null>('pro')
|
|
169
190
|
const [billing, setBilling] = useState<string | null>('monthly')
|
|
170
|
-
|
|
191
|
+
|
|
171
192
|
return (
|
|
172
193
|
<View className="gap-6 p-4 bg-surface-base rounded-lg max-w-md">
|
|
173
194
|
<Text className="text-lg font-semibold text-text-primary">Subscription Settings</Text>
|
|
174
|
-
|
|
195
|
+
|
|
175
196
|
<RadioGroup value={plan} onChange={setPlan} label="Select Plan">
|
|
176
197
|
<Radio value="free">Free - Basic features</Radio>
|
|
177
198
|
<Radio value="pro">Pro - Advanced features</Radio>
|
|
178
199
|
<Radio value="enterprise">Enterprise - Custom solutions</Radio>
|
|
179
200
|
</RadioGroup>
|
|
180
|
-
|
|
181
|
-
<RadioGroup
|
|
182
|
-
value={billing}
|
|
183
|
-
onChange={setBilling}
|
|
201
|
+
|
|
202
|
+
<RadioGroup
|
|
203
|
+
value={billing}
|
|
204
|
+
onChange={setBilling}
|
|
184
205
|
orientation="horizontal"
|
|
185
206
|
label="Billing Frequency"
|
|
186
207
|
>
|
|
187
208
|
<Radio value="monthly">Monthly</Radio>
|
|
188
209
|
<Radio value="yearly">Yearly (save 20%)</Radio>
|
|
189
210
|
</RadioGroup>
|
|
190
|
-
|
|
211
|
+
|
|
191
212
|
<View className="pt-4 border-t border-hairline">
|
|
192
213
|
<Text className="text-sm text-text-secondary">
|
|
193
214
|
Selected: {plan} plan, billed {billing}
|
|
@@ -68,7 +68,9 @@ describe('Radio', () => {
|
|
|
68
68
|
render(
|
|
69
69
|
<RadioGroup value="a" onChange={onChange}>
|
|
70
70
|
<Radio value="a">A</Radio>
|
|
71
|
-
<Radio value="b" isDisabled>
|
|
71
|
+
<Radio value="b" isDisabled>
|
|
72
|
+
B
|
|
73
|
+
</Radio>
|
|
72
74
|
</RadioGroup>
|
|
73
75
|
)
|
|
74
76
|
const radios = screen.getAllByRole('radio')
|
|
@@ -134,7 +136,9 @@ describe('Radio', () => {
|
|
|
134
136
|
it('allows Radio to override group size and color', () => {
|
|
135
137
|
render(
|
|
136
138
|
<RadioGroup value="a" onChange={() => {}} size="sm" color="primary">
|
|
137
|
-
<Radio value="a" size="lg" color="error">
|
|
139
|
+
<Radio value="a" size="lg" color="error">
|
|
140
|
+
A
|
|
141
|
+
</Radio>
|
|
138
142
|
</RadioGroup>
|
|
139
143
|
)
|
|
140
144
|
expect(screen.getByRole('radio')).toBeInTheDocument()
|
|
@@ -78,11 +78,7 @@ export function RadioGroup({
|
|
|
78
78
|
accessibilityLabel={label}
|
|
79
79
|
{...props}
|
|
80
80
|
>
|
|
81
|
-
{label &&
|
|
82
|
-
<Text className="text-sm font-medium text-text-primary mb-2">
|
|
83
|
-
{label}
|
|
84
|
-
</Text>
|
|
85
|
-
)}
|
|
81
|
+
{label && <Text className="text-sm font-medium text-text-primary mb-2">{label}</Text>}
|
|
86
82
|
<View
|
|
87
83
|
className={cn(
|
|
88
84
|
orientation === 'horizontal' ? 'flex-row flex-wrap' : 'flex-col',
|
|
@@ -117,9 +113,18 @@ const sizeConfig: Record<RadioSize, { outer: string; inner: string; text: string
|
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
const colorStyles: Record<RadioColor, { checked: string; unchecked: string }> = {
|
|
120
|
-
primary: {
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
primary: {
|
|
117
|
+
checked: 'border-brand-primary bg-brand-primary',
|
|
118
|
+
unchecked: 'border-hairline-strong',
|
|
119
|
+
},
|
|
120
|
+
secondary: {
|
|
121
|
+
checked: 'border-brand-secondary bg-brand-secondary',
|
|
122
|
+
unchecked: 'border-hairline-strong',
|
|
123
|
+
},
|
|
124
|
+
success: {
|
|
125
|
+
checked: 'border-status-success bg-status-success',
|
|
126
|
+
unchecked: 'border-hairline-strong',
|
|
127
|
+
},
|
|
123
128
|
error: { checked: 'border-status-error bg-status-error', unchecked: 'border-hairline-strong' },
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -144,7 +149,13 @@ export function Radio({
|
|
|
144
149
|
throw new Error('Radio must be used within a RadioGroup')
|
|
145
150
|
}
|
|
146
151
|
|
|
147
|
-
const {
|
|
152
|
+
const {
|
|
153
|
+
value: selectedValue,
|
|
154
|
+
onChange,
|
|
155
|
+
isDisabled: groupDisabled,
|
|
156
|
+
size: groupSize,
|
|
157
|
+
color: groupColor,
|
|
158
|
+
} = context
|
|
148
159
|
|
|
149
160
|
const isDisabled = radioDisabled ?? groupDisabled ?? false
|
|
150
161
|
const size = radioSize ?? groupSize ?? 'md'
|
|
@@ -166,11 +177,7 @@ export function Radio({
|
|
|
166
177
|
disabled={isDisabled}
|
|
167
178
|
accessibilityRole="radio"
|
|
168
179
|
accessibilityState={{ checked: isChecked, disabled: isDisabled }}
|
|
169
|
-
className={cn(
|
|
170
|
-
'flex-row items-center',
|
|
171
|
-
isDisabled && 'opacity-50',
|
|
172
|
-
className
|
|
173
|
-
)}
|
|
180
|
+
className={cn('flex-row items-center', isDisabled && 'opacity-50', className)}
|
|
174
181
|
{...props}
|
|
175
182
|
>
|
|
176
183
|
{/* Radio circle */}
|
|
@@ -184,17 +191,11 @@ export function Radio({
|
|
|
184
191
|
)}
|
|
185
192
|
>
|
|
186
193
|
{/* Inner dot */}
|
|
187
|
-
{isChecked && (
|
|
188
|
-
<View className={cn('rounded-full bg-white', inner)} />
|
|
189
|
-
)}
|
|
194
|
+
{isChecked && <View className={cn('rounded-full bg-on-brand-primary', inner)} />}
|
|
190
195
|
</View>
|
|
191
196
|
|
|
192
197
|
{/* Label */}
|
|
193
|
-
{children && (
|
|
194
|
-
<Text className={cn('ml-2 text-text-primary', text)}>
|
|
195
|
-
{children}
|
|
196
|
-
</Text>
|
|
197
|
-
)}
|
|
198
|
+
{children && <Text className={cn('ml-2 text-text-primary', text)}>{children}</Text>}
|
|
198
199
|
</Pressable>
|
|
199
200
|
)
|
|
200
201
|
}
|
|
@@ -5,7 +5,7 @@ import { Section, SectionHeader, SectionContent } from './Section'
|
|
|
5
5
|
const meta: Meta<typeof Section> = {
|
|
6
6
|
title: 'Components/Atoms/Section',
|
|
7
7
|
component: Section,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:stable', '!status:review'],
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export default meta
|
|
@@ -16,7 +16,7 @@ export const Default: Story = {
|
|
|
16
16
|
<Section>
|
|
17
17
|
<SectionHeader title="Recent Workouts" />
|
|
18
18
|
<SectionContent>
|
|
19
|
-
<Text style={{ color: '
|
|
19
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Workout items would go here</Text>
|
|
20
20
|
</SectionContent>
|
|
21
21
|
</Section>
|
|
22
22
|
),
|
|
@@ -25,12 +25,9 @@ export const Default: Story = {
|
|
|
25
25
|
export const WithSubtitle: Story = {
|
|
26
26
|
render: () => (
|
|
27
27
|
<Section>
|
|
28
|
-
<SectionHeader
|
|
29
|
-
title="Workout Stats"
|
|
30
|
-
subtitle="Last 7 days"
|
|
31
|
-
/>
|
|
28
|
+
<SectionHeader title="Workout Stats" subtitle="Last 7 days" />
|
|
32
29
|
<SectionContent>
|
|
33
|
-
<Text style={{ color: '
|
|
30
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Stats content</Text>
|
|
34
31
|
</SectionContent>
|
|
35
32
|
</Section>
|
|
36
33
|
),
|
|
@@ -41,12 +38,10 @@ export const WithTrailingAction: Story = {
|
|
|
41
38
|
<Section>
|
|
42
39
|
<SectionHeader
|
|
43
40
|
title="Exercises"
|
|
44
|
-
trailing={
|
|
45
|
-
<Text style={{ color: '#6366f1', fontSize: 13 }}>View All</Text>
|
|
46
|
-
}
|
|
41
|
+
trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>View All</Text>}
|
|
47
42
|
/>
|
|
48
43
|
<SectionContent>
|
|
49
|
-
<Text style={{ color: '
|
|
44
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Exercise list</Text>
|
|
50
45
|
</SectionContent>
|
|
51
46
|
</Section>
|
|
52
47
|
),
|
|
@@ -58,12 +53,10 @@ export const FullExample: Story = {
|
|
|
58
53
|
<SectionHeader
|
|
59
54
|
title="Performance"
|
|
60
55
|
subtitle="Average velocity by set"
|
|
61
|
-
trailing={
|
|
62
|
-
<Text style={{ color: '#6366f1', fontSize: 13 }}>Details</Text>
|
|
63
|
-
}
|
|
56
|
+
trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>Details</Text>}
|
|
64
57
|
/>
|
|
65
58
|
<SectionContent className="rounded-lg bg-surface-elevated p-4">
|
|
66
|
-
<Text style={{ color: '
|
|
59
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Chart or data visualization</Text>
|
|
67
60
|
</SectionContent>
|
|
68
61
|
</Section>
|
|
69
62
|
),
|
|
@@ -75,7 +68,7 @@ export const MultipleSections: Story = {
|
|
|
75
68
|
<Section>
|
|
76
69
|
<SectionHeader title="Today" subtitle="3 exercises" />
|
|
77
70
|
<SectionContent className="rounded-lg bg-surface-elevated p-4">
|
|
78
|
-
<Text style={{ color: '
|
|
71
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Today's workout data</Text>
|
|
79
72
|
</SectionContent>
|
|
80
73
|
</Section>
|
|
81
74
|
|
|
@@ -83,19 +76,17 @@ export const MultipleSections: Story = {
|
|
|
83
76
|
<SectionHeader
|
|
84
77
|
title="This Week"
|
|
85
78
|
subtitle="12 sets completed"
|
|
86
|
-
trailing={
|
|
87
|
-
<Text style={{ color: '#6366f1', fontSize: 13 }}>See All</Text>
|
|
88
|
-
}
|
|
79
|
+
trailing={<Text style={{ color: 'var(--color-text-link)', fontSize: 13 }}>See All</Text>}
|
|
89
80
|
/>
|
|
90
81
|
<SectionContent className="rounded-lg bg-surface-elevated p-4">
|
|
91
|
-
<Text style={{ color: '
|
|
82
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>Weekly summary</Text>
|
|
92
83
|
</SectionContent>
|
|
93
84
|
</Section>
|
|
94
85
|
|
|
95
86
|
<Section>
|
|
96
87
|
<SectionHeader title="Personal Records" />
|
|
97
88
|
<SectionContent className="rounded-lg bg-surface-elevated p-4">
|
|
98
|
-
<Text style={{ color: '
|
|
89
|
+
<Text style={{ color: 'var(--color-text-secondary)' }}>PR list</Text>
|
|
99
90
|
</SectionContent>
|
|
100
91
|
</Section>
|
|
101
92
|
</View>
|
|
@@ -42,12 +42,7 @@ describe('SectionHeader', () => {
|
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
it('renders trailing action when provided', () => {
|
|
45
|
-
render(
|
|
46
|
-
<SectionHeader
|
|
47
|
-
title="Title"
|
|
48
|
-
trailing={<Text>View All</Text>}
|
|
49
|
-
/>
|
|
50
|
-
)
|
|
45
|
+
render(<SectionHeader title="Title" trailing={<Text>View All</Text>} />)
|
|
51
46
|
expect(screen.getByText('View All')).toBeInTheDocument()
|
|
52
47
|
})
|
|
53
48
|
|
|
@@ -29,9 +29,7 @@ export function SectionHeader({ title, subtitle, trailing, className }: SectionH
|
|
|
29
29
|
<Text className="text-sm font-semibold text-text-secondary uppercase tracking-wider">
|
|
30
30
|
{title}
|
|
31
31
|
</Text>
|
|
32
|
-
{subtitle &&
|
|
33
|
-
<Text className="text-xs text-text-tertiary mt-0.5">{subtitle}</Text>
|
|
34
|
-
)}
|
|
32
|
+
{subtitle && <Text className="text-xs text-text-tertiary mt-0.5">{subtitle}</Text>}
|
|
35
33
|
</View>
|
|
36
34
|
{trailing && <View>{trailing}</View>}
|
|
37
35
|
</View>
|
|
@@ -101,12 +101,7 @@ export const Disabled: Story = {
|
|
|
101
101
|
</View>
|
|
102
102
|
<View style={{ gap: 4 }}>
|
|
103
103
|
<Text className="text-sm text-text-secondary">Disabled with value</Text>
|
|
104
|
-
<Select
|
|
105
|
-
value="banana"
|
|
106
|
-
onChange={() => {}}
|
|
107
|
-
options={basicOptions}
|
|
108
|
-
isDisabled
|
|
109
|
-
/>
|
|
104
|
+
<Select value="banana" onChange={() => {}} options={basicOptions} isDisabled />
|
|
110
105
|
</View>
|
|
111
106
|
</View>
|
|
112
107
|
),
|
|
@@ -235,16 +230,11 @@ export const Controlled: Story = {
|
|
|
235
230
|
</Text>
|
|
236
231
|
</View>
|
|
237
232
|
))}
|
|
238
|
-
<Text
|
|
239
|
-
className="text-sm text-status-error underline"
|
|
240
|
-
onPress={() => setValue(null)}
|
|
241
|
-
>
|
|
233
|
+
<Text className="text-sm text-status-error underline" onPress={() => setValue(null)}>
|
|
242
234
|
Clear
|
|
243
235
|
</Text>
|
|
244
236
|
</View>
|
|
245
|
-
<Text className="text-sm text-text-secondary">
|
|
246
|
-
Current value: {value ?? 'null'}
|
|
247
|
-
</Text>
|
|
237
|
+
<Text className="text-sm text-text-secondary">Current value: {value ?? 'null'}</Text>
|
|
248
238
|
</View>
|
|
249
239
|
)
|
|
250
240
|
},
|
|
@@ -94,14 +94,7 @@ describe('Select', () => {
|
|
|
94
94
|
|
|
95
95
|
it('calls onChangeMulti when toggling options', () => {
|
|
96
96
|
const onChangeMulti = vi.fn()
|
|
97
|
-
render(
|
|
98
|
-
<Select
|
|
99
|
-
options={defaultOptions}
|
|
100
|
-
isMulti
|
|
101
|
-
values={[]}
|
|
102
|
-
onChangeMulti={onChangeMulti}
|
|
103
|
-
/>
|
|
104
|
-
)
|
|
97
|
+
render(<Select options={defaultOptions} isMulti values={[]} onChangeMulti={onChangeMulti} />)
|
|
105
98
|
|
|
106
99
|
fireEvent.click(screen.getByRole('combobox'))
|
|
107
100
|
fireEvent.click(screen.getByText('Option 1'))
|
|
@@ -163,9 +156,7 @@ describe('Select', () => {
|
|
|
163
156
|
|
|
164
157
|
describe('accessibility', () => {
|
|
165
158
|
it('has no accessibility violations', async () => {
|
|
166
|
-
const { container } = render(
|
|
167
|
-
<Select options={defaultOptions} value="1" />
|
|
168
|
-
)
|
|
159
|
+
const { container } = render(<Select options={defaultOptions} value="1" />)
|
|
169
160
|
const results = await axe(container, {
|
|
170
161
|
rules: {
|
|
171
162
|
'aria-input-field-name': { enabled: false },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState, createContext, useContext } from 'react'
|
|
2
2
|
import { View, Text, Pressable, ScrollView, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { Surface } from '../surface'
|
|
4
5
|
|
|
5
6
|
export interface SelectOption<T = string> {
|
|
6
7
|
value: T
|
|
@@ -91,9 +92,7 @@ export function Select<T extends string = string>({
|
|
|
91
92
|
|
|
92
93
|
const selectValue = (val: T) => {
|
|
93
94
|
if (isMulti) {
|
|
94
|
-
const newValues = values.includes(val)
|
|
95
|
-
? values.filter((v) => v !== val)
|
|
96
|
-
: [...values, val]
|
|
95
|
+
const newValues = values.includes(val) ? values.filter((v) => v !== val) : [...values, val]
|
|
97
96
|
onChangeMulti?.(newValues)
|
|
98
97
|
} else {
|
|
99
98
|
onChange?.(val)
|
|
@@ -141,6 +140,7 @@ export function Select<T extends string = string>({
|
|
|
141
140
|
accessibilityState={{ expanded: isOpen, disabled: isDisabled }}
|
|
142
141
|
className={cn(
|
|
143
142
|
'flex-row items-center justify-between px-4 py-2.5 rounded-md border',
|
|
143
|
+
// VW-82: scrim-style fill, left raw (see Modal.tsx).
|
|
144
144
|
variant === 'filled' ? 'bg-black/30' : 'bg-surface-base',
|
|
145
145
|
isInvalid
|
|
146
146
|
? 'border-border-input-error'
|
|
@@ -152,12 +152,7 @@ export function Select<T extends string = string>({
|
|
|
152
152
|
isDisabled && 'opacity-50 cursor-not-allowed'
|
|
153
153
|
)}
|
|
154
154
|
>
|
|
155
|
-
<Text
|
|
156
|
-
className={cn(
|
|
157
|
-
'flex-1',
|
|
158
|
-
hasValue ? 'text-text-primary' : 'text-text-tertiary'
|
|
159
|
-
)}
|
|
160
|
-
>
|
|
155
|
+
<Text className={cn('flex-1', hasValue ? 'text-text-primary' : 'text-text-tertiary')}>
|
|
161
156
|
{getDisplayValue()}
|
|
162
157
|
</Text>
|
|
163
158
|
<View className="flex-row items-center gap-2">
|
|
@@ -184,11 +179,12 @@ export function Select<T extends string = string>({
|
|
|
184
179
|
className="fixed inset-0 z-40"
|
|
185
180
|
style={{ position: 'absolute' }}
|
|
186
181
|
/>
|
|
187
|
-
<
|
|
182
|
+
<Surface
|
|
183
|
+
elevation={4}
|
|
184
|
+
rounded={false}
|
|
188
185
|
className={cn(
|
|
189
186
|
'absolute z-50 top-full left-0 right-0 mt-1',
|
|
190
|
-
'
|
|
191
|
-
'max-h-60 overflow-hidden'
|
|
187
|
+
'rounded-md max-h-60 overflow-hidden'
|
|
192
188
|
)}
|
|
193
189
|
>
|
|
194
190
|
<ScrollView className="py-1">
|
|
@@ -196,7 +192,7 @@ export function Select<T extends string = string>({
|
|
|
196
192
|
<SelectOption key={option.value} option={option} />
|
|
197
193
|
))}
|
|
198
194
|
</ScrollView>
|
|
199
|
-
</
|
|
195
|
+
</Surface>
|
|
200
196
|
</>
|
|
201
197
|
)}
|
|
202
198
|
</View>
|
|
@@ -232,10 +228,15 @@ function SelectOption<T>({ option }: SelectOptionComponentProps<T>) {
|
|
|
232
228
|
selected ? 'bg-brand-primary border-brand-primary' : 'border-hairline-strong'
|
|
233
229
|
)}
|
|
234
230
|
>
|
|
235
|
-
{selected && <Text className="text-
|
|
231
|
+
{selected && <Text className="text-on-brand-primary text-xs text-center">✓</Text>}
|
|
236
232
|
</View>
|
|
237
233
|
)}
|
|
238
|
-
<Text
|
|
234
|
+
<Text
|
|
235
|
+
className={cn(
|
|
236
|
+
'text-sm',
|
|
237
|
+
selected && !isMulti ? 'text-brand-primary font-medium' : 'text-text-primary'
|
|
238
|
+
)}
|
|
239
|
+
>
|
|
239
240
|
{option.label}
|
|
240
241
|
</Text>
|
|
241
242
|
</Pressable>
|