@titan-design/react-ui 0.5.0 → 0.7.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/dist/bodymap.js +241 -189
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +241 -189
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1017 -130
- package/dist/index.d.ts +1017 -130
- package/dist/index.js +3058 -1090
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2992 -1091
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-MO0JCySL.d.mts → pages-8u_4WbL-.d.mts} +280 -57
- package/dist/{pages-D7Jlssvp.d.ts → pages-DaWiBOGa.d.ts} +280 -57
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1797 -1292
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1797 -1292
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +464 -268
- package/dist/theme/index.d.ts +464 -268
- package/dist/theme/index.js +303 -191
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +295 -192
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +160 -143
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +160 -143
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +3 -1
- package/src/arch/Architecture.stories.tsx +870 -0
- package/src/arch/annotations.json +48 -0
- package/src/arch/arch-graph.json +4301 -0
- package/src/components/custom/DateTime/DateTime.stories.tsx +83 -7
- package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
- package/src/components/custom/DateTime/DateTime.tsx +55 -15
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.tsx +6 -3
- package/src/components/custom/Metric/Metric.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.tsx +3 -5
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
- package/src/components/custom/Table/Table.stories.tsx +1 -1
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +62 -0
- package/src/components/custom/TimerReadout/TimerReadout.test.tsx +72 -0
- package/src/components/custom/TimerReadout/TimerReadout.tsx +75 -0
- package/src/components/custom/TimerReadout/index.ts +1 -0
- package/src/components/custom/Treemap/Treemap.stories.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +3 -5
- package/src/components/custom/Typography/Typography.stories.tsx +46 -28
- package/src/components/custom/Typography/Typography.test.tsx +13 -3
- package/src/components/custom/Typography/Typography.tsx +5 -0
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +21 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +16 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +11 -16
- package/src/components/custom/Workout/BaseBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.tsx +6 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +1 -1
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +2 -2
- package/src/components/custom/Workout/CapacityBandChart.tsx +9 -6
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.tsx +7 -4
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +51 -66
- package/src/components/custom/Workout/ExerciseCard.test.tsx +146 -143
- package/src/components/custom/Workout/ExerciseCard.tsx +176 -198
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +99 -0
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +72 -0
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +43 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +151 -0
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +5 -3
- package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +4 -4
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +6 -6
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +81 -0
- package/src/components/custom/Workout/ExerciseHeading.test.tsx +77 -0
- package/src/components/custom/Workout/ExerciseHeading.tsx +85 -0
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +110 -0
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +93 -0
- package/src/components/custom/Workout/ExerciseIndicator.tsx +120 -0
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +51 -0
- package/src/components/custom/Workout/FatigueMeter.test.tsx +73 -0
- package/src/components/custom/Workout/FatigueMeter.tsx +82 -0
- package/src/components/custom/Workout/InputBar.stories.tsx +1 -1
- package/src/components/custom/Workout/InputBar.tsx +2 -1
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +8 -8
- package/src/components/custom/Workout/IntensityBar.tsx +10 -6
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +153 -0
- package/src/components/custom/Workout/LiveAuraFrame.test.tsx +74 -0
- package/src/components/custom/Workout/LiveAuraFrame.tsx +105 -0
- package/src/components/custom/Workout/MesoCard.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoCard.tsx +8 -3
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.tsx +3 -2
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
- package/src/components/custom/Workout/MetricTiles.stories.tsx +60 -0
- package/src/components/custom/Workout/MetricTiles.test.tsx +58 -0
- package/src/components/custom/Workout/MetricTiles.tsx +48 -0
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +1 -1
- package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.tsx +5 -2
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +1 -1
- package/src/components/custom/Workout/PrHistoryModal.tsx +4 -3
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +4 -16
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +10 -7
- package/src/components/custom/Workout/README.md +146 -4
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +1 -1
- package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
- package/src/components/custom/Workout/RestTimer.stories.tsx +1 -1
- package/src/components/custom/Workout/RestTimer.tsx +17 -11
- package/src/components/custom/Workout/RowInventory.stories.tsx +405 -0
- package/src/components/custom/Workout/S3FullRail.stories.tsx +34 -0
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +95 -0
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +61 -0
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +176 -0
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +240 -0
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +40 -0
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +34 -0
- package/src/components/custom/Workout/ScheduleTiles.tsx +70 -0
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +99 -0
- package/src/components/custom/Workout/SegmentedBar.test.tsx +77 -0
- package/src/components/custom/Workout/SegmentedBar.tsx +172 -0
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +50 -0
- package/src/components/custom/Workout/SegmentedProgressBar.test.tsx +80 -0
- package/src/components/custom/Workout/SegmentedProgressBar.tsx +67 -0
- package/src/components/custom/Workout/SessionHeader.stories.tsx +121 -0
- package/src/components/custom/Workout/SessionHeader.test.tsx +122 -0
- package/src/components/custom/Workout/SessionHeader.tsx +152 -0
- package/src/components/custom/Workout/SessionRail.stories.tsx +153 -0
- package/src/components/custom/Workout/SessionRail.test.tsx +86 -0
- package/src/components/custom/Workout/SessionRail.tsx +126 -0
- package/src/components/custom/Workout/SetBar.stories.tsx +124 -0
- package/src/components/custom/Workout/SetBar.test.tsx +123 -0
- package/src/components/custom/Workout/SetBar.tsx +171 -0
- package/src/components/custom/Workout/SetRow.stories.tsx +50 -100
- package/src/components/custom/Workout/SetRow.test.tsx +94 -166
- package/src/components/custom/Workout/SetRow.tsx +170 -232
- package/src/components/custom/Workout/SetStrip.stories.tsx +154 -0
- package/src/components/custom/Workout/SetStrip.test.tsx +109 -0
- package/src/components/custom/Workout/SetStrip.tsx +71 -0
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +66 -0
- package/src/components/custom/Workout/SetTableHeader.test.tsx +47 -0
- package/src/components/custom/Workout/SetTableHeader.tsx +88 -0
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +47 -0
- package/src/components/custom/Workout/SetsRepsLoad.test.tsx +44 -0
- package/src/components/custom/Workout/SetsRepsLoad.tsx +52 -0
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.tsx +2 -1
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +2 -2
- package/src/components/custom/Workout/StatusDot.tsx +12 -9
- package/src/components/custom/Workout/StatusPill.stories.tsx +59 -0
- package/src/components/custom/Workout/StatusPill.test.tsx +63 -0
- package/src/components/custom/Workout/StatusPill.tsx +88 -0
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +1 -1
- package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +1 -1
- package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
- package/src/components/custom/Workout/TempoBar.stories.tsx +1 -1
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +12 -1
- package/src/components/custom/Workout/TempoDisplay.tsx +29 -36
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +1 -1
- package/src/components/custom/Workout/VelocityStrip.modalities.stories.tsx +254 -0
- package/src/components/custom/Workout/VelocityStrip.responsive.stories.tsx +145 -0
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +129 -66
- package/src/components/custom/Workout/VelocityStrip.test.tsx +379 -144
- package/src/components/custom/Workout/VelocityStrip.tsx +508 -120
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +73 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.test.tsx +119 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +154 -0
- package/src/components/custom/Workout/WeekRow.stories.tsx +1 -1
- package/src/components/custom/Workout/WeekRow.tsx +3 -2
- package/src/components/custom/Workout/WeightBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/WeightBadge.tsx +6 -2
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +2 -6
- package/src/components/custom/Workout/WorkoutCard.test.tsx +13 -46
- package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +1 -1
- package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +140 -0
- package/src/components/custom/Workout/ZoneTrack.test.tsx +200 -0
- package/src/components/custom/Workout/ZoneTrack.tsx +315 -0
- package/src/components/custom/Workout/icons.tsx +6 -67
- package/src/components/custom/Workout/index.ts +55 -2
- package/src/components/custom/Workout/metricText.stories.tsx +69 -0
- package/src/components/custom/Workout/metricText.tsx +34 -0
- package/src/components/custom/Workout/paceTone.test.ts +29 -0
- package/src/components/custom/Workout/paceTone.ts +27 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +177 -0
- package/src/components/custom/index.ts +1 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
- package/src/components/icons/SvgIcon.tsx +50 -0
- package/src/components/icons/icons.stories.tsx +122 -0
- package/src/components/icons/icons.test.tsx +73 -0
- package/src/components/icons/icons.tsx +153 -0
- package/src/components/icons/index.ts +4 -0
- package/src/components/index.ts +6 -0
- package/src/components/shell/BrandLockup.stories.tsx +27 -0
- package/src/components/shell/BrandLockup.test.tsx +23 -0
- package/src/components/shell/BrandLockup.tsx +47 -0
- package/src/components/shell/DashboardShell.stories.tsx +65 -0
- package/src/components/shell/DashboardShell.test.tsx +42 -0
- package/src/components/shell/DashboardShell.tsx +74 -0
- package/src/components/shell/DeviceIndicator.stories.tsx +28 -0
- package/src/components/shell/DeviceIndicator.test.tsx +26 -0
- package/src/components/shell/DeviceIndicator.tsx +52 -0
- package/src/components/shell/DeviceMenu.stories.tsx +47 -0
- package/src/components/shell/DeviceMenu.test.tsx +40 -0
- package/src/components/shell/DeviceMenu.tsx +65 -0
- package/src/components/shell/DeviceRow.stories.tsx +38 -0
- package/src/components/shell/DeviceRow.test.tsx +37 -0
- package/src/components/shell/DeviceRow.tsx +58 -0
- package/src/components/shell/NavItem.stories.tsx +52 -0
- package/src/components/shell/NavItem.test.tsx +35 -0
- package/src/components/shell/NavItem.tsx +75 -0
- package/src/components/shell/README.md +116 -0
- package/src/components/shell/SessionRailSpecimen.stories.tsx +753 -0
- package/src/components/shell/SessionStatePill.stories.tsx +27 -0
- package/src/components/shell/SessionStatePill.test.tsx +25 -0
- package/src/components/shell/SessionStatePill.tsx +46 -0
- package/src/components/shell/SideNav.stories.tsx +81 -0
- package/src/components/shell/SideNav.test.tsx +51 -0
- package/src/components/shell/SideNav.tsx +74 -0
- package/src/components/shell/TopBar.stories.tsx +49 -0
- package/src/components/shell/TopBar.test.tsx +36 -0
- package/src/components/shell/TopBar.tsx +89 -0
- package/src/components/shell/index.ts +13 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/badge/Badge.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/button/Button.stories.tsx +1 -1
- package/src/components/ui/card/Card.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/chip/Chip.stories.tsx +1 -1
- package/src/components/ui/collapse/Collapse.stories.tsx +1 -1
- package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/drawer/Drawer.stories.tsx +1 -1
- package/src/components/ui/form-field/FormField.stories.tsx +1 -1
- package/src/components/ui/help-tip/HelpTip.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/indicator/Indicator.stories.tsx +38 -2
- package/src/components/ui/indicator/Indicator.test.tsx +20 -1
- package/src/components/ui/indicator/Indicator.tsx +50 -6
- package/src/components/ui/indicator/index.ts +1 -1
- package/src/components/ui/input/Input.stories.tsx +1 -1
- package/src/components/ui/link/Link.stories.tsx +1 -1
- package/src/components/ui/list-item/ListItem.stories.tsx +1 -1
- package/src/components/ui/menu/Menu.stories.tsx +1 -1
- package/src/components/ui/modal/Modal.stories.tsx +1 -1
- package/src/components/ui/pill/Pill.stories.tsx +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +1 -1
- package/src/components/ui/progress/Progress.stories.tsx +1 -1
- package/src/components/ui/radio/Radio.stories.tsx +1 -1
- package/src/components/ui/section/Section.stories.tsx +1 -1
- package/src/components/ui/select/Select.stories.tsx +1 -1
- package/src/components/ui/skeleton/Skeleton.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -2
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.stories.tsx +79 -0
- package/src/components/ui/tile/Tile.test.tsx +48 -0
- package/src/components/ui/tile/Tile.tsx +64 -0
- package/src/components/ui/tile/index.ts +2 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
- package/src/components/ui/tooltip/Tooltip.stories.tsx +1 -1
- package/src/examples/react-hook-form/ReactHookForm.stories.tsx +1 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTimer.test.ts +150 -0
- package/src/hooks/useTimer.ts +77 -0
- package/src/index.ts +3 -0
- package/src/pages.ts +1 -1
- package/src/stories/PresetShowcase.stories.tsx +1 -1
- package/src/stories/ThemePresets.stories.tsx +1 -1
- package/src/theme/ColorSystem.stories.tsx +323 -0
- package/src/theme/Colors.stories.tsx +74 -9
- package/src/theme/barrel.ts +1 -0
- package/src/theme/config.ts +20 -3
- package/src/theme/elevation.stories.tsx +1 -1
- package/src/theme/extracted-colors-dataviz.ts +21 -0
- package/src/theme/extracted-colors-ui.ts +20 -0
- package/src/theme/global.css +69 -53
- package/src/theme/gradients.test.ts +25 -0
- package/src/theme/gradients.ts +36 -0
- package/src/theme/shadows.stories.tsx +1 -1
- package/src/theme/tokens/primitives.test.ts +232 -0
- package/src/theme/tokens/primitives.ts +238 -87
- package/src/theme/tokens/semantic.ts +101 -81
- package/src/theme/workout-tokens.ts +26 -21
- package/src/utils/avatar-color.ts +3 -3
- package/tailwind.config.js +15 -3
|
@@ -3,12 +3,15 @@ import { View } from 'react-native'
|
|
|
3
3
|
import { Indicator } from './Indicator'
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof Indicator> = {
|
|
6
|
-
title: 'Components/Indicator',
|
|
6
|
+
title: 'Components/Atoms/Indicator',
|
|
7
7
|
component: Indicator,
|
|
8
8
|
tags: ['autodocs'],
|
|
9
9
|
argTypes: {
|
|
10
10
|
size: { control: 'select', options: ['xs', 'sm', 'md', 'lg'] },
|
|
11
|
-
color: {
|
|
11
|
+
color: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['default', 'primary', 'success', 'live', 'error', 'warning', 'info'],
|
|
14
|
+
},
|
|
12
15
|
glow: { control: 'boolean' },
|
|
13
16
|
ring: { control: 'boolean' },
|
|
14
17
|
},
|
|
@@ -72,3 +75,36 @@ export const CustomColor: Story = {
|
|
|
72
75
|
</View>
|
|
73
76
|
),
|
|
74
77
|
}
|
|
78
|
+
|
|
79
|
+
export const Pulse: Story = {
|
|
80
|
+
render: () => (
|
|
81
|
+
<View className="flex-row gap-6 items-center">
|
|
82
|
+
<Indicator size="md" color="success" pulse />
|
|
83
|
+
<Indicator size="md" color="success" pulse="ping" />
|
|
84
|
+
<Indicator size="md" color="warning" />
|
|
85
|
+
<Indicator size="md" color="default" />
|
|
86
|
+
</View>
|
|
87
|
+
),
|
|
88
|
+
parameters: {
|
|
89
|
+
docs: {
|
|
90
|
+
description: {
|
|
91
|
+
story:
|
|
92
|
+
'Opacity pulse (default), expanding-ring pulse (`pulse="ping"`, green for live), solid, dim.',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const Vivid: Story = {
|
|
99
|
+
render: () => (
|
|
100
|
+
<View className="flex-row gap-4 items-center">
|
|
101
|
+
<Indicator size="md" color="success" />
|
|
102
|
+
<Indicator size="md" color="success" />
|
|
103
|
+
<Indicator size="md" color="error" />
|
|
104
|
+
<Indicator size="md" color="error-vivid" />
|
|
105
|
+
</View>
|
|
106
|
+
),
|
|
107
|
+
parameters: {
|
|
108
|
+
docs: { description: { story: 'Standard status vs the vivid palette (success/error).' } },
|
|
109
|
+
},
|
|
110
|
+
}
|
|
@@ -18,7 +18,16 @@ describe('Indicator', () => {
|
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
it('renders with all color options', () => {
|
|
21
|
-
const colors = [
|
|
21
|
+
const colors = [
|
|
22
|
+
'default',
|
|
23
|
+
'primary',
|
|
24
|
+
'success',
|
|
25
|
+
'live',
|
|
26
|
+
'error',
|
|
27
|
+
'warning',
|
|
28
|
+
'info',
|
|
29
|
+
'error-vivid',
|
|
30
|
+
] as const
|
|
22
31
|
colors.forEach((color) => {
|
|
23
32
|
const { unmount } = render(<Indicator color={color} />)
|
|
24
33
|
unmount()
|
|
@@ -45,6 +54,16 @@ describe('Indicator', () => {
|
|
|
45
54
|
expect(container.firstChild).toBeInTheDocument()
|
|
46
55
|
})
|
|
47
56
|
|
|
57
|
+
it('supports pulse prop (opacity)', () => {
|
|
58
|
+
const { container } = render(<Indicator pulse color="success" />)
|
|
59
|
+
expect(container.firstChild).toBeInTheDocument()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('supports the ping pulse variant', () => {
|
|
63
|
+
const { container } = render(<Indicator pulse="ping" color="success" />)
|
|
64
|
+
expect(container.firstChild).toBeInTheDocument()
|
|
65
|
+
})
|
|
66
|
+
|
|
48
67
|
describe('accessibility', () => {
|
|
49
68
|
it('has no accessibility violations', async () => {
|
|
50
69
|
const { container } = render(<Indicator color="success" />)
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import { View, type ViewProps } from 'react-native'
|
|
3
2
|
import { cn } from '../../../utils/cn'
|
|
4
3
|
|
|
5
4
|
export type IndicatorSize = 'xs' | 'sm' | 'md' | 'lg'
|
|
6
|
-
export type IndicatorColor =
|
|
5
|
+
export type IndicatorColor =
|
|
6
|
+
| 'default'
|
|
7
|
+
| 'primary'
|
|
8
|
+
| 'success'
|
|
9
|
+
| 'live'
|
|
10
|
+
| 'error'
|
|
11
|
+
| 'warning'
|
|
12
|
+
| 'info'
|
|
13
|
+
| 'error-vivid'
|
|
14
|
+
|
|
15
|
+
/** How a pulsing indicator animates: a subtle opacity fade, or an expanding ring. */
|
|
16
|
+
export type IndicatorPulse = 'opacity' | 'ping'
|
|
7
17
|
|
|
8
18
|
export interface IndicatorProps extends ViewProps {
|
|
9
19
|
/** Dot size */
|
|
@@ -16,6 +26,8 @@ export interface IndicatorProps extends ViewProps {
|
|
|
16
26
|
glow?: boolean
|
|
17
27
|
/** Add a ring border */
|
|
18
28
|
ring?: boolean
|
|
29
|
+
/** Animate for live/active status. `true` = opacity fade; `'ping'` = expanding ring. */
|
|
30
|
+
pulse?: boolean | IndicatorPulse
|
|
19
31
|
/** Additional className */
|
|
20
32
|
className?: string
|
|
21
33
|
}
|
|
@@ -31,9 +43,11 @@ const colorStyles: Record<IndicatorColor, string> = {
|
|
|
31
43
|
default: 'bg-text-tertiary',
|
|
32
44
|
primary: 'bg-brand-primary',
|
|
33
45
|
success: 'bg-status-success',
|
|
46
|
+
live: 'bg-status-live',
|
|
34
47
|
error: 'bg-status-error',
|
|
35
48
|
warning: 'bg-status-warning',
|
|
36
49
|
info: 'bg-status-info',
|
|
50
|
+
'error-vivid': 'bg-status-error-vivid',
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
export function Indicator({
|
|
@@ -42,14 +56,39 @@ export function Indicator({
|
|
|
42
56
|
customColor,
|
|
43
57
|
glow = false,
|
|
44
58
|
ring = false,
|
|
59
|
+
pulse = false,
|
|
45
60
|
className,
|
|
46
61
|
style,
|
|
47
62
|
...props
|
|
48
63
|
}: IndicatorProps) {
|
|
64
|
+
const pulseMode: IndicatorPulse | false = pulse === true ? 'opacity' : pulse || false
|
|
65
|
+
const colorClass = !customColor ? colorStyles[color] : undefined
|
|
66
|
+
const colorStyle = customColor ? { backgroundColor: customColor } : undefined
|
|
67
|
+
|
|
68
|
+
// Expanding-ring pulse: a ping layer behind the solid dot (for live/active status).
|
|
69
|
+
if (pulseMode === 'ping') {
|
|
70
|
+
return (
|
|
71
|
+
<View className={cn('relative', sizeStyles[size], className)} style={style} {...props}>
|
|
72
|
+
<View
|
|
73
|
+
className={cn('absolute inset-0 rounded-full animate-ping', colorClass)}
|
|
74
|
+
style={colorStyle}
|
|
75
|
+
/>
|
|
76
|
+
<View
|
|
77
|
+
className={cn(
|
|
78
|
+
'relative rounded-full',
|
|
79
|
+
sizeStyles[size],
|
|
80
|
+
colorClass,
|
|
81
|
+
ring && 'border-2 border-background-base'
|
|
82
|
+
)}
|
|
83
|
+
style={colorStyle}
|
|
84
|
+
/>
|
|
85
|
+
</View>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
49
89
|
const dynamicStyle = {
|
|
50
90
|
...(typeof style === 'object' ? style : {}),
|
|
51
|
-
...(
|
|
52
|
-
...(glow && !customColor ? {} : {}),
|
|
91
|
+
...(colorStyle ?? {}),
|
|
53
92
|
...(glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}),
|
|
54
93
|
}
|
|
55
94
|
|
|
@@ -58,12 +97,17 @@ export function Indicator({
|
|
|
58
97
|
className={cn(
|
|
59
98
|
'rounded-full shrink-0',
|
|
60
99
|
sizeStyles[size],
|
|
61
|
-
|
|
100
|
+
colorClass,
|
|
101
|
+
pulseMode === 'opacity' && 'animate-pulse',
|
|
62
102
|
ring && 'border-2 border-background-base',
|
|
63
|
-
glow &&
|
|
103
|
+
glow &&
|
|
104
|
+
!customColor &&
|
|
105
|
+
(color === 'success' || color === 'live') &&
|
|
106
|
+
'shadow-[0_0_6px_rgba(46,213,115,0.6)]',
|
|
64
107
|
glow && !customColor && color === 'error' && 'shadow-[0_0_6px_rgba(239,68,68,0.6)]',
|
|
65
108
|
glow && !customColor && color === 'warning' && 'shadow-[0_0_6px_rgba(245,158,11,0.6)]',
|
|
66
109
|
glow && !customColor && color === 'primary' && 'shadow-[0_0_6px_rgba(255,121,0,0.6)]',
|
|
110
|
+
glow && !customColor && color === 'error-vivid' && 'shadow-[0_0_6px_rgba(255,71,87,0.6)]',
|
|
67
111
|
className
|
|
68
112
|
)}
|
|
69
113
|
style={Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Indicator } from './Indicator'
|
|
2
|
-
export type { IndicatorProps, IndicatorSize, IndicatorColor } from './Indicator'
|
|
2
|
+
export type { IndicatorProps, IndicatorSize, IndicatorColor, IndicatorPulse } from './Indicator'
|
|
@@ -4,7 +4,7 @@ import { Menu, MenuTrigger, MenuList, MenuItem, MenuDivider, MenuGroup } from '.
|
|
|
4
4
|
import { Button, ButtonText } from '../button/Button'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Menu> = {
|
|
7
|
-
title: 'Components/Menu',
|
|
7
|
+
title: 'Components/Molecules/Menu',
|
|
8
8
|
component: Menu,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
argTypes: {
|
|
@@ -4,7 +4,7 @@ import { Popover, PopoverTrigger, PopoverContent, PopoverCloseButton } from './P
|
|
|
4
4
|
import { Button, ButtonText } from '../button/Button'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Popover> = {
|
|
7
|
-
title: 'Components/Popover',
|
|
7
|
+
title: 'Components/Molecules/Popover',
|
|
8
8
|
component: Popover,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
argTypes: {
|
|
@@ -3,7 +3,7 @@ import { View, Text } from 'react-native'
|
|
|
3
3
|
import { Progress, CircularProgress, ProgressSteps } from './Progress'
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof Progress> = {
|
|
6
|
-
title: 'Components/Progress',
|
|
6
|
+
title: 'Components/Molecules/Progress',
|
|
7
7
|
component: Progress,
|
|
8
8
|
tags: ['autodocs'],
|
|
9
9
|
argTypes: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { ActivityIndicator, View, type ViewProps } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
|
+
import { SPINNER_PRIMARY, SPINNER_SECONDARY } from '../../../theme/extracted-colors-ui'
|
|
4
5
|
|
|
5
6
|
export type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl'
|
|
6
7
|
export type SpinnerColor = 'primary' | 'secondary' | 'white' | 'default'
|
|
@@ -24,8 +25,8 @@ const sizeMap: Record<SpinnerSize, 'small' | 'large'> = {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const colorMap: Record<SpinnerColor, string> = {
|
|
27
|
-
primary:
|
|
28
|
-
secondary:
|
|
28
|
+
primary: SPINNER_PRIMARY,
|
|
29
|
+
secondary: SPINNER_SECONDARY,
|
|
29
30
|
white: '#FFFFFF',
|
|
30
31
|
default: '#6B7280',
|
|
31
32
|
}
|
|
@@ -4,7 +4,7 @@ import { Surface } from './Surface'
|
|
|
4
4
|
import type { ElevationLevel } from '../../../theme/elevation'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Surface> = {
|
|
7
|
-
title: 'Components/Surface',
|
|
7
|
+
title: 'Components/Atoms/Surface',
|
|
8
8
|
component: Surface,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
argTypes: {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { View } from 'react-native'
|
|
3
|
+
import { Tile } from './Tile'
|
|
4
|
+
import { getSemanticColors } from '../../../theme'
|
|
5
|
+
|
|
6
|
+
const ACCENT = getSemanticColors('dark')['status-warning']
|
|
7
|
+
const SUCCESS = getSemanticColors('dark')['status-success']
|
|
8
|
+
|
|
9
|
+
const meta: Meta<typeof Tile> = {
|
|
10
|
+
title: 'Components/Atoms/Tile',
|
|
11
|
+
component: Tile,
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
parameters: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component: '**Atom.** A compact card preset; grouped by SessionMetrics / ScheduleTiles.',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
label: { control: 'text', description: 'Uppercase micro-label' },
|
|
22
|
+
value: { control: 'text', description: 'Primary mono value' },
|
|
23
|
+
valueColor: { control: 'color', description: 'Tints the value' },
|
|
24
|
+
align: {
|
|
25
|
+
control: 'radio',
|
|
26
|
+
options: ['center', 'start'],
|
|
27
|
+
description: 'Content alignment',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default meta
|
|
33
|
+
type Story = StoryObj<typeof Tile>
|
|
34
|
+
|
|
35
|
+
export const Default: Story = {
|
|
36
|
+
args: {
|
|
37
|
+
label: 'Volume',
|
|
38
|
+
value: '76%',
|
|
39
|
+
align: 'center',
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const Row: Story = {
|
|
44
|
+
render: () => (
|
|
45
|
+
<View style={{ flexDirection: 'row', gap: 4, width: 246 }}>
|
|
46
|
+
<Tile label="Volume" value="76%" />
|
|
47
|
+
<Tile label="Load" value="7.3k" />
|
|
48
|
+
<Tile label="Fatigue" value="MOD" valueColor={ACCENT} />
|
|
49
|
+
</View>
|
|
50
|
+
),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const ScheduleTiles: Story = {
|
|
54
|
+
render: () => (
|
|
55
|
+
<View style={{ flexDirection: 'row', gap: 4, width: 246 }}>
|
|
56
|
+
<Tile label="Date" value="Jul 10" />
|
|
57
|
+
<Tile label="Time" value="6:30 PM" />
|
|
58
|
+
<Tile label="Until" value="5h" valueColor={ACCENT} />
|
|
59
|
+
</View>
|
|
60
|
+
),
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const ValueColors: Story = {
|
|
64
|
+
render: () => (
|
|
65
|
+
<View style={{ flexDirection: 'row', gap: 4, width: 246 }}>
|
|
66
|
+
<Tile label="Default" value="12" />
|
|
67
|
+
<Tile label="Success" value="OK" valueColor={SUCCESS} />
|
|
68
|
+
<Tile label="Warning" value="MOD" valueColor={ACCENT} />
|
|
69
|
+
</View>
|
|
70
|
+
),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const StartAligned: Story = {
|
|
74
|
+
args: {
|
|
75
|
+
label: 'Program',
|
|
76
|
+
value: 'Pull A',
|
|
77
|
+
align: 'start',
|
|
78
|
+
},
|
|
79
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import { axe } from 'jest-axe'
|
|
4
|
+
import { Tile } from './Tile'
|
|
5
|
+
|
|
6
|
+
describe('Tile', () => {
|
|
7
|
+
it('renders label and value', () => {
|
|
8
|
+
render(<Tile label="Volume" value="76%" />)
|
|
9
|
+
expect(screen.getByText('Volume')).toBeInTheDocument()
|
|
10
|
+
expect(screen.getByText('76%')).toBeInTheDocument()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('applies valueColor to the value text', () => {
|
|
14
|
+
render(<Tile label="Fatigue" value="MOD" valueColor="#F5A623" />)
|
|
15
|
+
const value = screen.getByText('MOD')
|
|
16
|
+
expect(value).toHaveStyle({ color: '#F5A623' })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('does not set an inline color when valueColor is omitted', () => {
|
|
20
|
+
render(<Tile label="Volume" value="76%" />)
|
|
21
|
+
const value = screen.getByText('76%')
|
|
22
|
+
expect(value.style.color).toBe('')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('renders with start alignment', () => {
|
|
26
|
+
render(<Tile label="Program" value="Pull A" align="start" />)
|
|
27
|
+
expect(screen.getByText('Program')).toBeInTheDocument()
|
|
28
|
+
expect(screen.getByText('Pull A')).toBeInTheDocument()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('applies custom className', () => {
|
|
32
|
+
const { container } = render(<Tile label="Load" value="7.3k" className="custom-class" />)
|
|
33
|
+
expect(container.firstChild).toBeInTheDocument()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('passes additional props through', () => {
|
|
37
|
+
render(<Tile label="Load" value="7.3k" testID="tile-test" />)
|
|
38
|
+
expect(screen.getByText('7.3k')).toBeInTheDocument()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('accessibility', () => {
|
|
42
|
+
it('has no accessibility violations', async () => {
|
|
43
|
+
const { container } = render(<Tile label="Volume" value="76%" />)
|
|
44
|
+
const results = await axe(container)
|
|
45
|
+
expect(results).toHaveNoViolations()
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { View, Text, type ViewProps } from 'react-native'
|
|
2
|
+
import { cn } from '../../../utils/cn'
|
|
3
|
+
|
|
4
|
+
export interface TileProps extends ViewProps {
|
|
5
|
+
/** Uppercase micro-label shown above the value */
|
|
6
|
+
label: string
|
|
7
|
+
/** Primary value, rendered in a bold mono face */
|
|
8
|
+
value: string
|
|
9
|
+
/** Tints the value (status/accent hex or CSS color); defaults to primary text */
|
|
10
|
+
valueColor?: string
|
|
11
|
+
/** Content alignment within the tile (default: 'center') */
|
|
12
|
+
align?: 'center' | 'start'
|
|
13
|
+
/** Additional className */
|
|
14
|
+
className?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tile — a compact label-over-value stat card.
|
|
19
|
+
*
|
|
20
|
+
* A rounded raised box with an uppercase micro-label stacked over a bold mono
|
|
21
|
+
* value. Fills its flex slot so a row of Tiles reads as an even HStack.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <Tile label="Volume" value="76%" />
|
|
25
|
+
* <Tile label="Fatigue" value="MOD" valueColor="#F5A623" />
|
|
26
|
+
*/
|
|
27
|
+
export function Tile({
|
|
28
|
+
label,
|
|
29
|
+
value,
|
|
30
|
+
valueColor,
|
|
31
|
+
align = 'center',
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: TileProps) {
|
|
35
|
+
const isCenter = align === 'center'
|
|
36
|
+
return (
|
|
37
|
+
<View
|
|
38
|
+
className={cn(
|
|
39
|
+
'flex-1 rounded-md bg-surface-raised px-1.5 py-2',
|
|
40
|
+
isCenter ? 'items-center' : 'items-start',
|
|
41
|
+
className
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<Text
|
|
46
|
+
className={cn(
|
|
47
|
+
'text-[10px] font-bold uppercase tracking-wider text-text-tertiary',
|
|
48
|
+
isCenter ? 'text-center' : 'text-left'
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
{label}
|
|
52
|
+
</Text>
|
|
53
|
+
<Text
|
|
54
|
+
className={cn(
|
|
55
|
+
'mt-0.5 font-mono text-sm font-bold text-text-primary',
|
|
56
|
+
isCenter ? 'text-center' : 'text-left'
|
|
57
|
+
)}
|
|
58
|
+
style={valueColor ? { color: valueColor } : undefined}
|
|
59
|
+
>
|
|
60
|
+
{value}
|
|
61
|
+
</Text>
|
|
62
|
+
</View>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
@@ -4,7 +4,7 @@ import { Toast, ToastProvider, useToast } from './Toast'
|
|
|
4
4
|
import { Button, ButtonText } from '../button'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Toast> = {
|
|
7
|
-
title: 'Components/Toast',
|
|
7
|
+
title: 'Components/Molecules/Toast',
|
|
8
8
|
component: Toast,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
argTypes: {
|
|
@@ -4,7 +4,7 @@ import { View, Text } from 'react-native'
|
|
|
4
4
|
import { ToolbarButton, ToolbarButtonGroup } from './ToolbarButton'
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof ToolbarButton> = {
|
|
7
|
-
title: 'Components/ToolbarButton',
|
|
7
|
+
title: 'Components/Molecules/ToolbarButton',
|
|
8
8
|
component: ToolbarButton,
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
argTypes: {
|
|
@@ -2,6 +2,7 @@ import React, { useState, useCallback, createContext, useContext } from 'react'
|
|
|
2
2
|
import { View, Text, Pressable, type ViewProps, StyleSheet, Platform } from 'react-native'
|
|
3
3
|
import { cn } from '../../../utils/cn'
|
|
4
4
|
import { neumorphicShadows, getHoverColors } from '../../../theme'
|
|
5
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
5
6
|
|
|
6
7
|
export type ToolbarButtonVariant = 'default' | 'neumorphic'
|
|
7
8
|
export type ToolbarButtonSize = 'sm' | 'md' | 'lg'
|
|
@@ -129,7 +130,7 @@ export function ToolbarButton({
|
|
|
129
130
|
|
|
130
131
|
// Determine icon color based on state
|
|
131
132
|
const getIconColor = () => {
|
|
132
|
-
if (isActive === true) return '
|
|
133
|
+
if (isActive === true) return resolveColor('brand-primary')
|
|
133
134
|
return showActive ? '#FFFFFF' : '#D1D1D1'
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -10,7 +10,7 @@ import { RhfContactForm, type ContactFormValues } from './RhfContactForm'
|
|
|
10
10
|
* `Controller` render-prop idiom. See `ControlledFields.tsx` for the adapters.
|
|
11
11
|
*/
|
|
12
12
|
const meta: Meta<typeof RhfContactForm> = {
|
|
13
|
-
title: '
|
|
13
|
+
title: 'Lab/Recipes/React Hook Form',
|
|
14
14
|
component: RhfContactForm,
|
|
15
15
|
tags: ['autodocs'],
|
|
16
16
|
parameters: {
|