@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
2
|
import { View, Text } from 'react-native'
|
|
3
|
-
import { primitiveColors, discreteRainbow } from './tokens/primitives'
|
|
3
|
+
import { primitiveColors, discreteRainbow, primitiveRamps, categoricalPalette } from './tokens/primitives'
|
|
4
4
|
import { semanticColorsLight, semanticColorsDark } from './tokens/semantic'
|
|
5
5
|
|
|
6
6
|
const meta: Meta = {
|
|
7
|
-
title: '
|
|
7
|
+
title: 'Foundations/Color/Palette',
|
|
8
8
|
tags: ['autodocs'],
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -79,16 +79,13 @@ export const PrimitiveColors: StoryObj = {
|
|
|
79
79
|
Primitive Colors
|
|
80
80
|
</Text>
|
|
81
81
|
<Text className="text-text-secondary mb-6">
|
|
82
|
-
Raw color values.
|
|
82
|
+
Raw color values. Chromatic hues live as OKLCH tonal ramps (see the Tonal Ramps story);
|
|
83
|
+
these are the achromatic and support scales. Use semantic tokens when building components.
|
|
83
84
|
</Text>
|
|
84
85
|
|
|
85
|
-
<ColorScale name="Orange (Primary Brand)" colors={primitiveColors.accent} />
|
|
86
|
-
<ColorScale name="Steel (Secondary Brand)" colors={primitiveColors.steel} />
|
|
87
86
|
<ColorScale name="Blue" colors={primitiveColors.blue} />
|
|
88
|
-
<ColorScale name="
|
|
89
|
-
<ColorScale name="
|
|
90
|
-
<ColorScale name="Red (Error)" colors={primitiveColors.red} />
|
|
91
|
-
<ColorScale name="Sky (Info)" colors={primitiveColors.sky} />
|
|
87
|
+
<ColorScale name="Red" colors={primitiveColors.red} />
|
|
88
|
+
<ColorScale name="Red Vivid" colors={primitiveColors.redVivid} />
|
|
92
89
|
<ColorScale name="Neutral" colors={primitiveColors.neutral} />
|
|
93
90
|
<ColorScale name="Charcoal (Dark Backgrounds)" colors={primitiveColors.charcoal} />
|
|
94
91
|
</View>
|
|
@@ -236,6 +233,74 @@ export const DataVisualizationColors: StoryObj = {
|
|
|
236
233
|
),
|
|
237
234
|
}
|
|
238
235
|
|
|
236
|
+
function CategoricalRow({ name, colors }: { name: string; colors: readonly string[] }) {
|
|
237
|
+
return (
|
|
238
|
+
<View style={{ marginBottom: 24 }}>
|
|
239
|
+
<Text className="text-lg font-bold text-text-primary mb-3">
|
|
240
|
+
{name} <Text className="text-text-secondary text-sm">({colors.length})</Text>
|
|
241
|
+
</Text>
|
|
242
|
+
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
|
|
243
|
+
{colors.map((color, index) => (
|
|
244
|
+
<View key={index} style={{ alignItems: 'center' }}>
|
|
245
|
+
<View
|
|
246
|
+
style={{
|
|
247
|
+
width: 56,
|
|
248
|
+
height: 56,
|
|
249
|
+
borderRadius: 8,
|
|
250
|
+
backgroundColor: color,
|
|
251
|
+
borderWidth: 1,
|
|
252
|
+
borderColor: '#374151',
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
<Text className="text-text-secondary text-xs mt-1">{color.toUpperCase()}</Text>
|
|
256
|
+
</View>
|
|
257
|
+
))}
|
|
258
|
+
</View>
|
|
259
|
+
</View>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export const TonalRamps: StoryObj = {
|
|
264
|
+
render: () => (
|
|
265
|
+
<View style={{ padding: 24 }}>
|
|
266
|
+
<Text className="text-2xl font-bold text-text-primary mb-6">
|
|
267
|
+
Tonal Ramps (Foundations)
|
|
268
|
+
</Text>
|
|
269
|
+
<Text className="text-text-secondary mb-6">
|
|
270
|
+
Seven OKLCH-generated hue ramps, 11 perceptual steps each (50 → 950). Built with hue-torsion and a
|
|
271
|
+
chroma arc; amber absorbs the former yellow (lemon → warm body) and cyan absorbs the former steel.
|
|
272
|
+
</Text>
|
|
273
|
+
|
|
274
|
+
<ColorScale name="Red" colors={primitiveRamps.red} />
|
|
275
|
+
<ColorScale name="Orange" colors={primitiveRamps.orange} />
|
|
276
|
+
<ColorScale name="Amber" colors={primitiveRamps.amber} />
|
|
277
|
+
<ColorScale name="Green" colors={primitiveRamps.green} />
|
|
278
|
+
<ColorScale name="Cyan" colors={primitiveRamps.cyan} />
|
|
279
|
+
<ColorScale name="Blue" colors={primitiveRamps.blue} />
|
|
280
|
+
<ColorScale name="Magenta" colors={primitiveRamps.magenta} />
|
|
281
|
+
</View>
|
|
282
|
+
),
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export const CategoricalPalette: StoryObj = {
|
|
286
|
+
render: () => (
|
|
287
|
+
<View style={{ padding: 24 }}>
|
|
288
|
+
<Text className="text-2xl font-bold text-text-primary mb-6">
|
|
289
|
+
Categorical Palette
|
|
290
|
+
</Text>
|
|
291
|
+
<Text className="text-text-secondary mb-6">
|
|
292
|
+
Ordered, colorblind-safe qualitative series (worst-case deut/protanopia floor 8 through the first
|
|
293
|
+
six colors; the 7th is extended — pair it with a legend). Series index is stable. Use{' '}
|
|
294
|
+
<Text className="font-semibold">default</Text> on neutral/light surfaces (also legible under black
|
|
295
|
+
text) and <Text className="font-semibold">dark</Text> where white text sits on the swatch.
|
|
296
|
+
</Text>
|
|
297
|
+
|
|
298
|
+
<CategoricalRow name="Default" colors={categoricalPalette.default} />
|
|
299
|
+
<CategoricalRow name="Dark (white text)" colors={categoricalPalette.dark} />
|
|
300
|
+
</View>
|
|
301
|
+
),
|
|
302
|
+
}
|
|
303
|
+
|
|
239
304
|
export const BorderColors: StoryObj = {
|
|
240
305
|
render: () => (
|
|
241
306
|
<View style={{ padding: 24 }}>
|
package/src/theme/barrel.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './shadows'
|
|
|
12
12
|
export * from './elevation'
|
|
13
13
|
export * from './manifest'
|
|
14
14
|
export { resolveColor } from './resolve-color'
|
|
15
|
+
export { linearGradient, surfaceGradient, type GradientStyle } from './gradients'
|
|
15
16
|
|
|
16
17
|
// ThemeProvider TYPES may stay on the root (erased at build — no nativewind
|
|
17
18
|
// pull). Only the ThemeProvider VALUE moves to the `/theme` subpath.
|
package/src/theme/config.ts
CHANGED
|
@@ -14,10 +14,11 @@ import { semanticColorsLight, semanticColorsDark, type ThemeMode } from './token
|
|
|
14
14
|
const themeIndependentCSSVars = {
|
|
15
15
|
// RGB decomposed values for glow shadows
|
|
16
16
|
'--color-brand-primary-rgb': '255, 121, 0',
|
|
17
|
-
'--color-brand-secondary-rgb': '
|
|
18
|
-
'--color-status-success-rgb': '
|
|
17
|
+
'--color-brand-secondary-rgb': '48, 123, 155',
|
|
18
|
+
'--color-status-success-rgb': '46, 213, 115',
|
|
19
19
|
'--color-status-error-rgb': '209, 67, 67',
|
|
20
|
-
'--color-status-
|
|
20
|
+
'--color-status-error-vivid-rgb': '255, 71, 87',
|
|
21
|
+
'--color-status-warning-rgb': '249, 180, 21',
|
|
21
22
|
'--color-status-info-rgb': '33, 150, 243',
|
|
22
23
|
'--color-background-base-rgb': '16, 16, 16',
|
|
23
24
|
|
|
@@ -52,6 +53,8 @@ export const lightThemeCSSVars = {
|
|
|
52
53
|
|
|
53
54
|
'--color-status-success': semanticColorsLight['status-success'],
|
|
54
55
|
'--color-status-success-subtle': semanticColorsLight['status-success-subtle'],
|
|
56
|
+
'--color-status-live': semanticColorsLight['status-live'],
|
|
57
|
+
'--color-status-live-muted': semanticColorsLight['status-live-muted'],
|
|
55
58
|
'--color-status-error': semanticColorsLight['status-error'],
|
|
56
59
|
'--color-status-error-subtle': semanticColorsLight['status-error-subtle'],
|
|
57
60
|
'--color-status-warning': semanticColorsLight['status-warning'],
|
|
@@ -59,6 +62,11 @@ export const lightThemeCSSVars = {
|
|
|
59
62
|
'--color-status-info': semanticColorsLight['status-info'],
|
|
60
63
|
'--color-status-info-subtle': semanticColorsLight['status-info-subtle'],
|
|
61
64
|
|
|
65
|
+
'--color-status-error-vivid': semanticColorsLight['status-error-vivid'],
|
|
66
|
+
'--color-status-error-vivid-light': semanticColorsLight['status-error-vivid-light'],
|
|
67
|
+
'--color-status-error-vivid-dark': semanticColorsLight['status-error-vivid-dark'],
|
|
68
|
+
'--color-status-error-vivid-subtle': semanticColorsLight['status-error-vivid-subtle'],
|
|
69
|
+
|
|
62
70
|
'--color-text-primary': semanticColorsLight['text-primary'],
|
|
63
71
|
'--color-text-secondary': semanticColorsLight['text-secondary'],
|
|
64
72
|
'--color-text-tertiary': semanticColorsLight['text-tertiary'],
|
|
@@ -77,6 +85,7 @@ export const lightThemeCSSVars = {
|
|
|
77
85
|
'--color-border-default': semanticColorsLight['border-default'],
|
|
78
86
|
'--color-border-subtle': semanticColorsLight['border-subtle'],
|
|
79
87
|
'--color-border-strong': semanticColorsLight['border-strong'],
|
|
88
|
+
'--color-border-prominent': semanticColorsLight['border-prominent'],
|
|
80
89
|
'--color-border-focus': semanticColorsLight['border-focus'],
|
|
81
90
|
|
|
82
91
|
'--color-interactive-hover': semanticColorsLight['interactive-hover'],
|
|
@@ -165,6 +174,8 @@ export const darkThemeCSSVars = {
|
|
|
165
174
|
|
|
166
175
|
'--color-status-success': semanticColorsDark['status-success'],
|
|
167
176
|
'--color-status-success-subtle': semanticColorsDark['status-success-subtle'],
|
|
177
|
+
'--color-status-live': semanticColorsDark['status-live'],
|
|
178
|
+
'--color-status-live-muted': semanticColorsDark['status-live-muted'],
|
|
168
179
|
'--color-status-error': semanticColorsDark['status-error'],
|
|
169
180
|
'--color-status-error-subtle': semanticColorsDark['status-error-subtle'],
|
|
170
181
|
'--color-status-warning': semanticColorsDark['status-warning'],
|
|
@@ -172,6 +183,11 @@ export const darkThemeCSSVars = {
|
|
|
172
183
|
'--color-status-info': semanticColorsDark['status-info'],
|
|
173
184
|
'--color-status-info-subtle': semanticColorsDark['status-info-subtle'],
|
|
174
185
|
|
|
186
|
+
'--color-status-error-vivid': semanticColorsDark['status-error-vivid'],
|
|
187
|
+
'--color-status-error-vivid-light': semanticColorsDark['status-error-vivid-light'],
|
|
188
|
+
'--color-status-error-vivid-dark': semanticColorsDark['status-error-vivid-dark'],
|
|
189
|
+
'--color-status-error-vivid-subtle': semanticColorsDark['status-error-vivid-subtle'],
|
|
190
|
+
|
|
175
191
|
'--color-text-primary': semanticColorsDark['text-primary'],
|
|
176
192
|
'--color-text-secondary': semanticColorsDark['text-secondary'],
|
|
177
193
|
'--color-text-tertiary': semanticColorsDark['text-tertiary'],
|
|
@@ -190,6 +206,7 @@ export const darkThemeCSSVars = {
|
|
|
190
206
|
'--color-border-default': semanticColorsDark['border-default'],
|
|
191
207
|
'--color-border-subtle': semanticColorsDark['border-subtle'],
|
|
192
208
|
'--color-border-strong': semanticColorsDark['border-strong'],
|
|
209
|
+
'--color-border-prominent': semanticColorsDark['border-prominent'],
|
|
193
210
|
'--color-border-focus': semanticColorsDark['border-focus'],
|
|
194
211
|
|
|
195
212
|
'--color-interactive-hover': semanticColorsDark['interactive-hover'],
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-viz / status / brand fills, sourced from the color foundations.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { categoricalPalette, primitiveRamps as ramp } from './tokens/primitives'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Titan categorical fallback palette shared by Treemap and Scatter — the
|
|
9
|
+
* canonical {@link categoricalPalette} (ordered, nested-stable, CVD-safe).
|
|
10
|
+
* Components index into it modulo length, so the 7-color series is sufficient.
|
|
11
|
+
*/
|
|
12
|
+
export const DATAVIZ_CATEGORICAL_PALETTE = categoricalPalette.default
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* MesoCard / MesoStatusCard 3px top-accent gradient stops (dark → primary →
|
|
16
|
+
* light), on the orange ramp that brand-primary (orange-400) lives in.
|
|
17
|
+
*/
|
|
18
|
+
export const MESO_ACCENT_GRADIENT_DARK = ramp.orange[500]
|
|
19
|
+
export const MESO_ACCENT_GRADIENT_LIGHT = ramp.orange[300]
|
|
20
|
+
|
|
21
|
+
export const WORKOUT_PILL_DELOAD = ramp.magenta[600]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI-atom fills, sourced from the color foundations.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { categoricalPalette, primitiveRamps as ramp } from './tokens/primitives'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Spinner `color="primary"` fill — keeps the spinner a cool, on-palette
|
|
9
|
+
* loading accent.
|
|
10
|
+
*/
|
|
11
|
+
export const SPINNER_PRIMARY = ramp.cyan[600]
|
|
12
|
+
|
|
13
|
+
export const SPINNER_SECONDARY = ramp.green[400]
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Categorical avatar palette — deterministic per-name fill, the canonical
|
|
17
|
+
* ordered {@link categoricalPalette} (CVD-safe). Order is preserved for stable
|
|
18
|
+
* hashing.
|
|
19
|
+
*/
|
|
20
|
+
export const AVATAR_CATEGORICAL_COLORS = categoricalPalette.default
|
package/src/theme/global.css
CHANGED
|
@@ -16,36 +16,44 @@
|
|
|
16
16
|
/* Dark mode (default) */
|
|
17
17
|
:root {
|
|
18
18
|
--color-brand-primary: #FF7900;
|
|
19
|
-
--color-brand-primary-light: #
|
|
20
|
-
--color-brand-primary-dark: #
|
|
19
|
+
--color-brand-primary-light: #FFA063;
|
|
20
|
+
--color-brand-primary-dark: #DA5F00;
|
|
21
21
|
--color-brand-primary-subtle: rgba(255, 121, 0, 0.12);
|
|
22
|
-
--color-brand-secondary: #
|
|
23
|
-
--color-brand-secondary-light: #
|
|
24
|
-
--color-brand-secondary-dark: #
|
|
25
|
-
--color-brand-secondary-subtle: rgba(
|
|
26
|
-
--color-brand-primary-hover: #
|
|
27
|
-
--color-brand-primary-active: #
|
|
28
|
-
--color-brand-secondary-hover: #
|
|
29
|
-
--color-brand-secondary-active: #
|
|
22
|
+
--color-brand-secondary: #307B9B;
|
|
23
|
+
--color-brand-secondary-light: #2697B7;
|
|
24
|
+
--color-brand-secondary-dark: #2A617F;
|
|
25
|
+
--color-brand-secondary-subtle: rgba(48, 123, 155, 0.12);
|
|
26
|
+
--color-brand-primary-hover: #FFA063;
|
|
27
|
+
--color-brand-primary-active: #FFC7A2;
|
|
28
|
+
--color-brand-secondary-hover: #2697B7;
|
|
29
|
+
--color-brand-secondary-active: #01B5D1;
|
|
30
30
|
|
|
31
31
|
--color-on-brand-primary: #FFFFFF;
|
|
32
32
|
--color-on-brand-secondary: #FFFFFF;
|
|
33
33
|
|
|
34
|
-
--color-status-success: #
|
|
35
|
-
--color-status-success-light: #
|
|
36
|
-
--color-status-success-dark: #
|
|
37
|
-
--color-status-success-subtle: rgba(
|
|
34
|
+
--color-status-success: #2ED573;
|
|
35
|
+
--color-status-success-light: #58F69E;
|
|
36
|
+
--color-status-success-dark: #298732;
|
|
37
|
+
--color-status-success-subtle: rgba(46, 213, 115, 0.12);
|
|
38
|
+
--color-status-live: #2ED573;
|
|
39
|
+
--color-status-live-muted: #22A444;
|
|
38
40
|
--color-status-error: #D14343;
|
|
39
|
-
--color-status-error-light: #
|
|
40
|
-
--color-status-error-dark: #
|
|
41
|
+
--color-status-error-light: #E05254;
|
|
42
|
+
--color-status-error-dark: #A4221C;
|
|
41
43
|
--color-status-error-subtle: rgba(209, 67, 67, 0.12);
|
|
42
|
-
--color-status-
|
|
43
|
-
--color-status-
|
|
44
|
-
--color-status-
|
|
45
|
-
--color-status-
|
|
44
|
+
--color-status-error-vivid: #FF4757;
|
|
45
|
+
--color-status-error-vivid-light: #FF6070;
|
|
46
|
+
--color-status-error-vivid-dark: #C42539;
|
|
47
|
+
--color-status-error-vivid-subtle: rgba(255, 71, 87, 0.12);
|
|
48
|
+
--color-status-error-vivid-rgb: 255, 71, 87;
|
|
49
|
+
--color-border-prominent: #3C3C3C;
|
|
50
|
+
--color-status-warning: #F9B415;
|
|
51
|
+
--color-status-warning-light: #FFD352;
|
|
52
|
+
--color-status-warning-dark: #C27400;
|
|
53
|
+
--color-status-warning-subtle: rgba(249, 180, 21, 0.12);
|
|
46
54
|
--color-status-info: #2196F3;
|
|
47
|
-
--color-status-info-light: #
|
|
48
|
-
--color-status-info-dark: #
|
|
55
|
+
--color-status-info-light: #78C2FF;
|
|
56
|
+
--color-status-info-dark: #1072CB;
|
|
49
57
|
--color-status-info-subtle: rgba(33, 150, 243, 0.12);
|
|
50
58
|
|
|
51
59
|
--color-on-status-success: #FFFFFF;
|
|
@@ -119,10 +127,10 @@
|
|
|
119
127
|
|
|
120
128
|
/* RGB decomposed values for glow shadows */
|
|
121
129
|
--color-brand-primary-rgb: 255, 121, 0;
|
|
122
|
-
--color-brand-secondary-rgb:
|
|
123
|
-
--color-status-success-rgb:
|
|
130
|
+
--color-brand-secondary-rgb: 48, 123, 155;
|
|
131
|
+
--color-status-success-rgb: 46, 213, 115;
|
|
124
132
|
--color-status-error-rgb: 209, 67, 67;
|
|
125
|
-
--color-status-warning-rgb:
|
|
133
|
+
--color-status-warning-rgb: 249, 180, 21;
|
|
126
134
|
--color-status-info-rgb: 33, 150, 243;
|
|
127
135
|
--color-background-base-rgb: 16, 16, 16;
|
|
128
136
|
|
|
@@ -145,37 +153,45 @@
|
|
|
145
153
|
.light,
|
|
146
154
|
:root.light {
|
|
147
155
|
--color-brand-primary: #FF7900;
|
|
148
|
-
--color-brand-primary-light: #
|
|
149
|
-
--color-brand-primary-dark: #
|
|
156
|
+
--color-brand-primary-light: #FFA063;
|
|
157
|
+
--color-brand-primary-dark: #DA5F00;
|
|
150
158
|
--color-brand-primary-subtle: rgba(255, 121, 0, 0.08);
|
|
151
|
-
--color-brand-secondary: #
|
|
152
|
-
--color-brand-secondary-light: #
|
|
153
|
-
--color-brand-secondary-dark: #
|
|
154
|
-
--color-brand-secondary-subtle: rgba(
|
|
155
|
-
--color-brand-primary-hover: #
|
|
156
|
-
--color-brand-primary-active: #
|
|
157
|
-
--color-brand-secondary-hover: #
|
|
158
|
-
--color-brand-secondary-active: #
|
|
159
|
+
--color-brand-secondary: #307B9B;
|
|
160
|
+
--color-brand-secondary-light: #2697B7;
|
|
161
|
+
--color-brand-secondary-dark: #2A617F;
|
|
162
|
+
--color-brand-secondary-subtle: rgba(48, 123, 155, 0.08);
|
|
163
|
+
--color-brand-primary-hover: #DA5F00;
|
|
164
|
+
--color-brand-primary-active: #B94A00;
|
|
165
|
+
--color-brand-secondary-hover: #2A617F;
|
|
166
|
+
--color-brand-secondary-active: #22465F;
|
|
159
167
|
|
|
160
168
|
--color-on-brand-primary: #FFFFFF;
|
|
161
169
|
--color-on-brand-secondary: #FFFFFF;
|
|
162
170
|
|
|
163
|
-
--color-status-success: #
|
|
164
|
-
--color-status-success-light: #
|
|
165
|
-
--color-status-success-dark: #
|
|
166
|
-
--color-status-success-subtle: #
|
|
171
|
+
--color-status-success: #2ED573;
|
|
172
|
+
--color-status-success-light: #58F69E;
|
|
173
|
+
--color-status-success-dark: #298732;
|
|
174
|
+
--color-status-success-subtle: #E3FFEE;
|
|
175
|
+
--color-status-live: #2ED573;
|
|
176
|
+
--color-status-live-muted: #22A444;
|
|
167
177
|
--color-status-error: #D14343;
|
|
168
|
-
--color-status-error-light: #
|
|
169
|
-
--color-status-error-dark: #
|
|
170
|
-
--color-status-error-subtle: #
|
|
171
|
-
--color-status-
|
|
172
|
-
--color-status-
|
|
173
|
-
--color-status-
|
|
174
|
-
--color-status-
|
|
178
|
+
--color-status-error-light: #E05254;
|
|
179
|
+
--color-status-error-dark: #A4221C;
|
|
180
|
+
--color-status-error-subtle: #FFF4F4;
|
|
181
|
+
--color-status-error-vivid: #FF4757;
|
|
182
|
+
--color-status-error-vivid-light: #FF6070;
|
|
183
|
+
--color-status-error-vivid-dark: #C42539;
|
|
184
|
+
--color-status-error-vivid-subtle: rgba(255, 71, 87, 0.12);
|
|
185
|
+
--color-status-error-vivid-rgb: 255, 71, 87;
|
|
186
|
+
--color-border-prominent: #9CA3AF;
|
|
187
|
+
--color-status-warning: #F9B415;
|
|
188
|
+
--color-status-warning-light: #FFD352;
|
|
189
|
+
--color-status-warning-dark: #C27400;
|
|
190
|
+
--color-status-warning-subtle: #FFF7DD;
|
|
175
191
|
--color-status-info: #2196F3;
|
|
176
|
-
--color-status-info-light: #
|
|
177
|
-
--color-status-info-dark: #
|
|
178
|
-
--color-status-info-subtle: #
|
|
192
|
+
--color-status-info-light: #78C2FF;
|
|
193
|
+
--color-status-info-dark: #1072CB;
|
|
194
|
+
--color-status-info-subtle: #EFF8FF;
|
|
179
195
|
|
|
180
196
|
--color-on-status-success: #FFFFFF;
|
|
181
197
|
--color-on-status-error: #FFFFFF;
|
|
@@ -248,10 +264,10 @@
|
|
|
248
264
|
|
|
249
265
|
/* RGB decomposed values for glow shadows */
|
|
250
266
|
--color-brand-primary-rgb: 255, 121, 0;
|
|
251
|
-
--color-brand-secondary-rgb:
|
|
252
|
-
--color-status-success-rgb:
|
|
267
|
+
--color-brand-secondary-rgb: 48, 123, 155;
|
|
268
|
+
--color-status-success-rgb: 46, 213, 115;
|
|
253
269
|
--color-status-error-rgb: 209, 67, 67;
|
|
254
|
-
--color-status-warning-rgb:
|
|
270
|
+
--color-status-warning-rgb: 249, 180, 21;
|
|
255
271
|
--color-status-info-rgb: 33, 150, 243;
|
|
256
272
|
--color-background-base-rgb: 16, 16, 16;
|
|
257
273
|
|
|
@@ -357,7 +373,7 @@
|
|
|
357
373
|
z-index: 0;
|
|
358
374
|
background:
|
|
359
375
|
radial-gradient(ellipse 140% 100% at 15% 5%, rgba(var(--color-brand-primary-rgb, 255, 121, 0), 0.06) 0%, transparent 45%),
|
|
360
|
-
radial-gradient(ellipse 120% 80% at 85% 95%, rgba(var(--color-brand-secondary-rgb,
|
|
376
|
+
radial-gradient(ellipse 120% 80% at 85% 95%, rgba(var(--color-brand-secondary-rgb, 48, 123, 155), 0.04) 0%, transparent 45%);
|
|
361
377
|
}
|
|
362
378
|
|
|
363
379
|
/* Film grain overlay for vintage texture */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { linearGradient, surfaceGradient } from './gradients'
|
|
3
|
+
|
|
4
|
+
describe('gradients', () => {
|
|
5
|
+
it('builds a linear-gradient backgroundImage from two tokens (web CSS vars)', () => {
|
|
6
|
+
const style = linearGradient('surface-elevated', 'background-base', 180)
|
|
7
|
+
expect(style.backgroundImage).toBe(
|
|
8
|
+
'linear-gradient(180deg, var(--color-surface-elevated), var(--color-background-base))'
|
|
9
|
+
)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('respects a custom angle', () => {
|
|
13
|
+
expect(linearGradient('surface-base', 'background-base', 90).backgroundImage).toContain('90deg')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('defaults to a 180deg angle', () => {
|
|
17
|
+
expect(linearGradient('surface-base', 'background-base').backgroundImage).toContain('180deg')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('surfaceGradient.chrome is the elevated → base chrome wash', () => {
|
|
21
|
+
expect(surfaceGradient.chrome().backgroundImage).toBe(
|
|
22
|
+
'linear-gradient(180deg, var(--color-surface-elevated), var(--color-background-base))'
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolveColor } from './resolve-color'
|
|
2
|
+
import { getSemanticColors, type ThemeMode } from './tokens/semantic'
|
|
3
|
+
|
|
4
|
+
type ColorToken = keyof ReturnType<typeof getSemanticColors>
|
|
5
|
+
|
|
6
|
+
/** A `backgroundImage` style — web-only (RN ignores it); type it loosely for RN style arrays. */
|
|
7
|
+
export type GradientStyle = { backgroundImage: string }
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A linear-gradient `backgroundImage` built from two semantic color tokens.
|
|
11
|
+
*
|
|
12
|
+
* Themeable + native-safe via {@link resolveColor}: on web the stops are CSS
|
|
13
|
+
* variables (light/dark switching keeps working); on native it resolves to hex.
|
|
14
|
+
* `backgroundImage` is a **web-only** paint, so pair this with a solid
|
|
15
|
+
* `bg-*` className fallback for native (see the shell TopBar).
|
|
16
|
+
*/
|
|
17
|
+
export function linearGradient(
|
|
18
|
+
from: ColorToken,
|
|
19
|
+
to: ColorToken,
|
|
20
|
+
angle = 180,
|
|
21
|
+
mode: ThemeMode = 'dark'
|
|
22
|
+
): GradientStyle {
|
|
23
|
+
return {
|
|
24
|
+
backgroundImage: `linear-gradient(${angle}deg, ${resolveColor(from, mode)}, ${resolveColor(to, mode)})`,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Named surface gradients — the shared substrate for gradient fills. Replaces
|
|
30
|
+
* per-component inline `linear-gradient` strings.
|
|
31
|
+
*/
|
|
32
|
+
export const surfaceGradient = {
|
|
33
|
+
/** Chrome bands (top bar, headers): elevated → base, a subtle dark wash. */
|
|
34
|
+
chrome: (mode: ThemeMode = 'dark'): GradientStyle =>
|
|
35
|
+
linearGradient('surface-elevated', 'background-base', 180, mode),
|
|
36
|
+
}
|