@titan-design/react-ui 0.1.0 → 0.2.5

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.
Files changed (236) hide show
  1. package/README.md +47 -1
  2. package/dist/{chunk-MGW37MPO.mjs → chunk-UXVRPOME.mjs} +173 -3
  3. package/dist/chunk-UXVRPOME.mjs.map +1 -0
  4. package/dist/index.d.mts +101 -12
  5. package/dist/index.d.ts +101 -12
  6. package/dist/index.js +1267 -468
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +734 -112
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/theme/index.d.mts +86 -1
  11. package/dist/theme/index.d.ts +86 -1
  12. package/dist/theme/index.js +166 -0
  13. package/dist/theme/index.js.map +1 -1
  14. package/dist/theme/index.mjs +1 -1
  15. package/package.json +22 -6
  16. package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
  17. package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
  18. package/src/components/custom/DateTime/DateTime.tsx +235 -0
  19. package/src/components/custom/DateTime/index.ts +2 -0
  20. package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
  21. package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
  22. package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
  23. package/src/components/custom/EmptyState/index.ts +2 -0
  24. package/src/components/custom/Metric/Metric.stories.tsx +133 -0
  25. package/src/components/custom/Metric/Metric.test.tsx +120 -0
  26. package/src/components/custom/Metric/Metric.tsx +92 -0
  27. package/src/components/custom/Metric/index.ts +2 -0
  28. package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
  29. package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
  30. package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
  31. package/src/components/custom/Sidebar/index.ts +18 -0
  32. package/src/components/custom/Table/Table.stories.tsx +481 -0
  33. package/src/components/custom/Table/Table.test.tsx +531 -0
  34. package/src/components/custom/Table/Table.tsx +696 -0
  35. package/src/components/custom/Table/index.ts +22 -0
  36. package/src/components/custom/Typography/Typography.stories.tsx +153 -0
  37. package/src/components/custom/Typography/Typography.test.tsx +107 -0
  38. package/src/components/custom/Typography/Typography.tsx +218 -0
  39. package/src/components/custom/Typography/index.ts +19 -0
  40. package/src/components/custom/Workout/RestTimer.stories.tsx +71 -0
  41. package/src/components/custom/Workout/RestTimer.test.tsx +145 -0
  42. package/src/components/custom/Workout/RestTimer.tsx +172 -0
  43. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +144 -0
  44. package/src/components/custom/Workout/SupersetWrapper.test.tsx +130 -0
  45. package/src/components/custom/Workout/SupersetWrapper.tsx +63 -0
  46. package/src/components/custom/Workout/index.ts +2 -0
  47. package/src/components/custom/index.ts +9 -0
  48. package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
  49. package/src/components/custom/stepper/Stepper.test.tsx +230 -0
  50. package/src/components/custom/stepper/Stepper.tsx +250 -0
  51. package/src/components/custom/stepper/index.ts +10 -0
  52. package/src/components/index.ts +5 -0
  53. package/src/components/ui/alert/Alert.stories.tsx +154 -0
  54. package/src/components/ui/alert/Alert.test.tsx +202 -0
  55. package/src/components/ui/alert/Alert.tsx +170 -0
  56. package/src/components/ui/alert/index.ts +8 -0
  57. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
  58. package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
  59. package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
  60. package/src/components/ui/autocomplete/index.ts +2 -0
  61. package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
  62. package/src/components/ui/avatar/Avatar.test.tsx +152 -0
  63. package/src/components/ui/avatar/Avatar.tsx +176 -0
  64. package/src/components/ui/avatar/index.ts +2 -0
  65. package/src/components/ui/badge/Badge.stories.tsx +100 -0
  66. package/src/components/ui/badge/Badge.test.tsx +103 -0
  67. package/src/components/ui/badge/Badge.tsx +119 -0
  68. package/src/components/ui/badge/index.ts +3 -0
  69. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
  70. package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
  71. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
  72. package/src/components/ui/breadcrumbs/index.ts +2 -0
  73. package/src/components/ui/button/Button.stories.tsx +216 -0
  74. package/src/components/ui/button/Button.test.tsx +132 -0
  75. package/src/components/ui/button/Button.tsx +297 -0
  76. package/src/components/ui/button/index.ts +10 -0
  77. package/src/components/ui/card/Card.stories.tsx +443 -0
  78. package/src/components/ui/card/Card.test.tsx +294 -0
  79. package/src/components/ui/card/Card.tsx +401 -0
  80. package/src/components/ui/card/index.ts +20 -0
  81. package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
  82. package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
  83. package/src/components/ui/checkbox/Checkbox.tsx +163 -0
  84. package/src/components/ui/checkbox/index.ts +2 -0
  85. package/src/components/ui/chip/Chip.stories.tsx +112 -0
  86. package/src/components/ui/chip/Chip.test.tsx +119 -0
  87. package/src/components/ui/chip/Chip.tsx +151 -0
  88. package/src/components/ui/chip/index.ts +2 -0
  89. package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
  90. package/src/components/ui/collapse/Collapse.test.tsx +298 -0
  91. package/src/components/ui/collapse/Collapse.tsx +275 -0
  92. package/src/components/ui/collapse/index.ts +18 -0
  93. package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
  94. package/src/components/ui/data-row/DataRow.test.tsx +78 -0
  95. package/src/components/ui/data-row/DataRow.tsx +29 -0
  96. package/src/components/ui/data-row/index.ts +2 -0
  97. package/src/components/ui/divider/Divider.stories.tsx +71 -0
  98. package/src/components/ui/divider/Divider.test.tsx +55 -0
  99. package/src/components/ui/divider/Divider.tsx +37 -0
  100. package/src/components/ui/divider/index.ts +2 -0
  101. package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
  102. package/src/components/ui/drawer/Drawer.test.tsx +142 -0
  103. package/src/components/ui/drawer/Drawer.tsx +228 -0
  104. package/src/components/ui/drawer/index.ts +9 -0
  105. package/src/components/ui/form-field/FormField.stories.tsx +260 -0
  106. package/src/components/ui/form-field/FormField.test.tsx +280 -0
  107. package/src/components/ui/form-field/FormField.tsx +308 -0
  108. package/src/components/ui/form-field/index.ts +2 -0
  109. package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
  110. package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
  111. package/src/components/ui/help-tip/HelpTip.tsx +229 -0
  112. package/src/components/ui/help-tip/index.ts +2 -0
  113. package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
  114. package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
  115. package/src/components/ui/icon-box/IconBox.tsx +57 -0
  116. package/src/components/ui/icon-box/index.ts +1 -0
  117. package/src/components/ui/index.ts +38 -0
  118. package/src/components/ui/indicator/Indicator.stories.tsx +74 -0
  119. package/src/components/ui/indicator/Indicator.test.tsx +55 -0
  120. package/src/components/ui/indicator/Indicator.tsx +73 -0
  121. package/src/components/ui/indicator/index.ts +2 -0
  122. package/src/components/ui/input/Input.stories.tsx +192 -0
  123. package/src/components/ui/input/Input.test.tsx +86 -0
  124. package/src/components/ui/input/Input.tsx +273 -0
  125. package/src/components/ui/input/index.ts +2 -0
  126. package/src/components/ui/link/Link.stories.tsx +78 -0
  127. package/src/components/ui/link/Link.test.tsx +94 -0
  128. package/src/components/ui/link/Link.tsx +86 -0
  129. package/src/components/ui/link/index.ts +2 -0
  130. package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
  131. package/src/components/ui/list-item/ListItem.test.tsx +128 -0
  132. package/src/components/ui/list-item/ListItem.tsx +89 -0
  133. package/src/components/ui/list-item/index.ts +14 -0
  134. package/src/components/ui/menu/Menu.stories.tsx +180 -0
  135. package/src/components/ui/menu/Menu.test.tsx +353 -0
  136. package/src/components/ui/menu/Menu.tsx +222 -0
  137. package/src/components/ui/menu/index.ts +2 -0
  138. package/src/components/ui/modal/Modal.stories.tsx +350 -0
  139. package/src/components/ui/modal/Modal.test.tsx +159 -0
  140. package/src/components/ui/modal/Modal.tsx +254 -0
  141. package/src/components/ui/modal/index.ts +19 -0
  142. package/src/components/ui/pill/Pill.stories.tsx +71 -0
  143. package/src/components/ui/pill/Pill.test.tsx +69 -0
  144. package/src/components/ui/pill/Pill.tsx +104 -0
  145. package/src/components/ui/pill/index.ts +2 -0
  146. package/src/components/ui/popover/Popover.stories.tsx +190 -0
  147. package/src/components/ui/popover/Popover.test.tsx +419 -0
  148. package/src/components/ui/popover/Popover.tsx +237 -0
  149. package/src/components/ui/popover/index.ts +2 -0
  150. package/src/components/ui/progress/Progress.stories.tsx +190 -0
  151. package/src/components/ui/progress/Progress.test.tsx +210 -0
  152. package/src/components/ui/progress/Progress.tsx +339 -0
  153. package/src/components/ui/progress/index.ts +9 -0
  154. package/src/components/ui/radio/Radio.stories.tsx +199 -0
  155. package/src/components/ui/radio/Radio.test.tsx +166 -0
  156. package/src/components/ui/radio/Radio.tsx +200 -0
  157. package/src/components/ui/radio/index.ts +2 -0
  158. package/src/components/ui/section/Section.stories.tsx +111 -0
  159. package/src/components/ui/section/Section.test.tsx +121 -0
  160. package/src/components/ui/section/Section.tsx +52 -0
  161. package/src/components/ui/section/index.ts +6 -0
  162. package/src/components/ui/select/Select.stories.tsx +286 -0
  163. package/src/components/ui/select/Select.test.tsx +200 -0
  164. package/src/components/ui/select/Select.tsx +243 -0
  165. package/src/components/ui/select/index.ts +2 -0
  166. package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
  167. package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
  168. package/src/components/ui/skeleton/Skeleton.tsx +229 -0
  169. package/src/components/ui/skeleton/index.ts +16 -0
  170. package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
  171. package/src/components/ui/spinner/Spinner.test.tsx +67 -0
  172. package/src/components/ui/spinner/Spinner.tsx +72 -0
  173. package/src/components/ui/spinner/index.ts +2 -0
  174. package/src/components/ui/stack/Stack.stories.tsx +127 -0
  175. package/src/components/ui/stack/Stack.test.tsx +184 -0
  176. package/src/components/ui/stack/Stack.tsx +76 -0
  177. package/src/components/ui/stack/index.ts +2 -0
  178. package/src/components/ui/surface/Surface.stories.tsx +91 -0
  179. package/src/components/ui/surface/Surface.test.tsx +63 -0
  180. package/src/components/ui/surface/Surface.tsx +51 -0
  181. package/src/components/ui/surface/index.ts +1 -0
  182. package/src/components/ui/switch/Switch.stories.tsx +111 -0
  183. package/src/components/ui/switch/Switch.test.tsx +112 -0
  184. package/src/components/ui/switch/Switch.tsx +103 -0
  185. package/src/components/ui/switch/index.ts +2 -0
  186. package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
  187. package/src/components/ui/tabs/Tabs.test.tsx +192 -0
  188. package/src/components/ui/tabs/Tabs.tsx +253 -0
  189. package/src/components/ui/tabs/index.ts +16 -0
  190. package/src/components/ui/toast/Toast.stories.tsx +255 -0
  191. package/src/components/ui/toast/Toast.test.tsx +207 -0
  192. package/src/components/ui/toast/Toast.tsx +327 -0
  193. package/src/components/ui/toast/index.ts +9 -0
  194. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
  195. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
  196. package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
  197. package/src/components/ui/toolbar-button/index.ts +7 -0
  198. package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
  199. package/src/components/ui/tooltip/Tooltip.test.tsx +262 -0
  200. package/src/components/ui/tooltip/Tooltip.tsx +234 -0
  201. package/src/components/ui/tooltip/index.ts +2 -0
  202. package/src/index.ts +10 -0
  203. package/src/stories/PresetShowcase.stories.tsx +462 -0
  204. package/src/stories/ThemePresets.stories.tsx +85 -0
  205. package/src/test/setup.ts +19 -0
  206. package/src/theme/Colors.stories.tsx +258 -0
  207. package/src/theme/config.ts +193 -0
  208. package/src/theme/elevation.stories.tsx +346 -0
  209. package/src/theme/elevation.test.ts +27 -0
  210. package/src/theme/elevation.ts +567 -0
  211. package/src/theme/global.css +129 -1
  212. package/src/theme/index.ts +40 -0
  213. package/src/theme/presets/apply.ts +97 -0
  214. package/src/theme/presets/audiobook.ts +93 -0
  215. package/src/theme/presets/default.ts +6 -0
  216. package/src/theme/presets/index.ts +4 -0
  217. package/src/theme/presets/presets.test.ts +51 -0
  218. package/src/theme/presets/types.ts +76 -0
  219. package/src/theme/shadows.stories.tsx +523 -0
  220. package/src/theme/shadows.ts +439 -0
  221. package/src/theme/tokens/index.ts +2 -0
  222. package/src/theme/tokens/primitives.ts +354 -0
  223. package/src/theme/tokens/semantic.ts +381 -0
  224. package/src/types/jest-axe.d.ts +16 -0
  225. package/src/types/nativewind.d.ts +54 -0
  226. package/src/utils/avatar-color.test.ts +30 -0
  227. package/src/utils/avatar-color.ts +20 -0
  228. package/src/utils/cn.ts +14 -0
  229. package/src/utils/colors.ts +140 -0
  230. package/src/utils/form.ts +188 -0
  231. package/src/utils/index.ts +29 -0
  232. package/src/utils/useTheme.ts +72 -0
  233. package/src/web-jsx/jsx-dev-runtime.ts +28 -0
  234. package/src/web-jsx/jsx-runtime.ts +41 -0
  235. package/tailwind.config.js +53 -3
  236. package/dist/chunk-MGW37MPO.mjs.map +0 -1
@@ -0,0 +1,346 @@
1
+ /**
2
+ * Elevation System Stories
3
+ *
4
+ * Demonstrates the elevation hierarchy system with:
5
+ * - All elevation levels (-2 to +5)
6
+ * - Light and dark mode base colors
7
+ * - Custom base colors from theme (orange, steel, etc.)
8
+ * - Stacked layers with inset elements
9
+ */
10
+
11
+ import type { Meta, StoryObj } from '@storybook/react-vite'
12
+ import { View, Text } from 'react-native'
13
+ import {
14
+ getElevationConfig,
15
+ getElevationSurface,
16
+ getElevationShadow,
17
+ getBaseSurfaceColor,
18
+ type ElevationLevel,
19
+ } from './elevation'
20
+ import { useTheme } from '../utils/useTheme'
21
+ import { Card, CardContent, CardInset } from '../components/ui/card/Card'
22
+
23
+ const meta: Meta = {
24
+ title: 'Theme/Elevation System',
25
+ tags: ['autodocs'],
26
+ }
27
+
28
+ export default meta
29
+ type Story = StoryObj<typeof meta>
30
+
31
+ // Helper component to display an elevation level
32
+ function ElevationBox({
33
+ level,
34
+ baseColor,
35
+ theme,
36
+ label,
37
+ }: {
38
+ level: ElevationLevel
39
+ baseColor: string
40
+ theme: 'light' | 'dark'
41
+ label?: string
42
+ }) {
43
+ const config = getElevationConfig(level)
44
+ const surfaceColor = getElevationSurface(baseColor, level, theme)
45
+ const shadowStyle = getElevationShadow(baseColor, level, theme)
46
+
47
+ return (
48
+ <View className="items-center gap-2">
49
+ <View
50
+ className="w-24 h-24 rounded-lg items-center justify-center"
51
+ style={[
52
+ { backgroundColor: surfaceColor },
53
+ shadowStyle,
54
+ ]}
55
+ >
56
+ <Text className="text-xs font-semibold text-text-primary">
57
+ {level}
58
+ </Text>
59
+ </View>
60
+ <View className="items-center">
61
+ <Text className="text-xs font-medium text-text-primary">
62
+ {label || config.name}
63
+ </Text>
64
+ <Text className="text-[10px] text-text-secondary mt-0.5">
65
+ {surfaceColor}
66
+ </Text>
67
+ </View>
68
+ </View>
69
+ )
70
+ }
71
+
72
+ // Helper to show all elevations for a base color
73
+ function ElevationShowcase({
74
+ baseColor,
75
+ baseColorName,
76
+ theme,
77
+ }: {
78
+ baseColor: string
79
+ baseColorName: string
80
+ theme: 'light' | 'dark'
81
+ }) {
82
+ const levels: ElevationLevel[] = [-2, -1, 0, 1, 2, 3, 4, 5]
83
+
84
+ return (
85
+ <View className="mb-8">
86
+ <View className="mb-4">
87
+ <Text className="text-lg font-semibold text-text-primary mb-1">
88
+ {baseColorName}
89
+ </Text>
90
+ <Text className="text-sm text-text-secondary">
91
+ Base: {baseColor} ({theme} mode)
92
+ </Text>
93
+ </View>
94
+ <View className="flex-row flex-wrap gap-6 justify-center">
95
+ {levels.map((level) => (
96
+ <ElevationBox
97
+ key={level}
98
+ level={level}
99
+ baseColor={baseColor}
100
+ theme={theme}
101
+ />
102
+ ))}
103
+ </View>
104
+ </View>
105
+ )
106
+ }
107
+
108
+ export const ElevationLevels: Story = {
109
+ render: function Render() {
110
+ const theme = useTheme()
111
+ const baseColor = getBaseSurfaceColor(theme)
112
+ const modeName = theme === 'light' ? 'Light' : 'Dark'
113
+
114
+ return (
115
+ <View className="p-6 min-h-screen bg-background-base">
116
+ <View className="max-w-6xl mx-auto">
117
+ <Text className="text-2xl font-bold text-text-primary mb-2">
118
+ {modeName} Mode Base Color
119
+ </Text>
120
+ <Text className="text-sm text-text-secondary mb-6">
121
+ Base color: {baseColor} ({theme} mode) — toggle the Storybook theme to see the other mode.
122
+ </Text>
123
+ <ElevationShowcase
124
+ baseColor={baseColor}
125
+ baseColorName={`${modeName} Mode Base`}
126
+ theme={theme}
127
+ />
128
+ </View>
129
+ </View>
130
+ )
131
+ },
132
+ }
133
+
134
+ export const CustomColors: Story = {
135
+ render: function Render() {
136
+ const theme = useTheme()
137
+ const customColors = [
138
+ { name: 'Orange', color: '#FF7900' },
139
+ { name: 'Steel', color: '#406D87' },
140
+ { name: 'Teal', color: '#14B8A6' },
141
+ { name: 'Neutral Gray', color: '#6B7280' },
142
+ ]
143
+
144
+ return (
145
+ <View className="p-6 min-h-screen bg-background-base">
146
+ <View className="max-w-6xl mx-auto">
147
+ <Text className="text-2xl font-bold text-text-primary mb-2">
148
+ Custom Base Colors
149
+ </Text>
150
+ <Text className="text-sm text-text-secondary mb-6">
151
+ Elevation system works with any base color. These examples show how
152
+ different colors create elevation hierarchies.
153
+ </Text>
154
+ {customColors.map(({ name, color }) => (
155
+ <ElevationShowcase
156
+ key={name}
157
+ baseColor={color}
158
+ baseColorName={name}
159
+ theme={theme}
160
+ />
161
+ ))}
162
+ </View>
163
+ </View>
164
+ )
165
+ },
166
+ }
167
+
168
+ export const StackedLayers: Story = {
169
+ render: function Render() {
170
+ const theme = useTheme()
171
+
172
+ return (
173
+ <View className="p-6 min-h-screen bg-background-base">
174
+
175
+ <View className="max-w-4xl mx-auto gap-6">
176
+ <Text className="text-2xl font-bold text-text-primary mb-2">
177
+ Stacked Layers - All Elevations
178
+ </Text>
179
+ <Text className="text-sm text-text-secondary mb-6">
180
+ Cards at all 5 positive elevations (1-5) stacked to show the full hierarchy.
181
+ </Text>
182
+
183
+ {/* Stack all 5 elevations */}
184
+ {([1, 2, 3, 4, 5] as const).map((elevation) => {
185
+ const config = getElevationConfig(elevation)
186
+ return (
187
+ <Card key={elevation} elevation={elevation} className="p-6">
188
+ <CardContent className="p-0">
189
+ <Text className="text-lg font-semibold text-text-primary mb-2">
190
+ Elevation {elevation} - {config.name}
191
+ </Text>
192
+ <Text className="text-sm text-text-secondary mb-4">
193
+ {config.description}
194
+ </Text>
195
+ {elevation >= 2 && (
196
+ <CardInset elevation={-1} className="p-4">
197
+ <Text className="text-sm text-text-secondary">
198
+ Inset element at elevation -1 (shallow inset)
199
+ </Text>
200
+ </CardInset>
201
+ )}
202
+ </CardContent>
203
+ </Card>
204
+ )
205
+ })}
206
+
207
+ {/* Example with nested insets */}
208
+ <Card elevation={3} className="p-6">
209
+ <CardContent className="p-0">
210
+ <Text className="text-lg font-semibold text-text-primary mb-4">
211
+ Nested Inset Elements
212
+ </Text>
213
+ <CardInset elevation={-1} className="p-4 mb-4">
214
+ <Text className="text-sm text-text-secondary mb-2">
215
+ Outer inset at -1
216
+ </Text>
217
+ <CardInset elevation={-2} className="p-3">
218
+ <Text className="text-xs text-text-secondary">
219
+ Inner inset at -2
220
+ </Text>
221
+ </CardInset>
222
+ </CardInset>
223
+ </CardContent>
224
+ </Card>
225
+ </View>
226
+ </View>
227
+ )
228
+ },
229
+ }
230
+
231
+ export const ElevationComparison: Story = {
232
+ render: function Render() {
233
+ const theme = useTheme()
234
+ const baseColor = getBaseSurfaceColor(theme)
235
+
236
+ return (
237
+ <View className="p-6 min-h-screen bg-background-base">
238
+
239
+ <View className="max-w-6xl mx-auto">
240
+ <Text className="text-2xl font-bold text-text-primary mb-2">
241
+ Elevation Comparison
242
+ </Text>
243
+ <Text className="text-sm text-text-secondary mb-6">
244
+ Side-by-side comparison of all elevation levels showing the visual hierarchy.
245
+ </Text>
246
+
247
+ <View className="flex-row flex-wrap gap-8 justify-center">
248
+ {([-2, -1, 0, 1, 2, 3, 4, 5] as ElevationLevel[]).map((level) => {
249
+ const config = getElevationConfig(level)
250
+ const surfaceColor = getElevationSurface(baseColor, level, theme)
251
+ const shadowStyle = getElevationShadow(baseColor, level, theme)
252
+
253
+ return (
254
+ <View key={level} className="items-center gap-3">
255
+ <View
256
+ className="w-32 h-32 rounded-xl items-center justify-center p-4"
257
+ style={[
258
+ { backgroundColor: surfaceColor },
259
+ shadowStyle,
260
+ ]}
261
+ >
262
+ <Text className="text-2xl font-bold mb-1 text-text-primary">
263
+ {level}
264
+ </Text>
265
+ <Text className="text-xs text-center text-text-secondary">
266
+ {config.name}
267
+ </Text>
268
+ </View>
269
+ <View className="items-center">
270
+ <Text className="text-xs font-medium text-text-primary text-center">
271
+ {config.description}
272
+ </Text>
273
+ <Text className="text-[10px] text-text-secondary mt-1 text-center">
274
+ {surfaceColor}
275
+ </Text>
276
+ </View>
277
+ </View>
278
+ )
279
+ })}
280
+ </View>
281
+ </View>
282
+ </View>
283
+ )
284
+ },
285
+ }
286
+
287
+ export const ComponentElevationRanges: Story = {
288
+ render: function Render() {
289
+ const theme = useTheme()
290
+ const baseColor = getBaseSurfaceColor(theme)
291
+
292
+ const componentRanges = [
293
+ { name: 'Button', elevations: [2] as const },
294
+ { name: 'Card', elevations: [1, 2, 3] as const },
295
+ { name: 'Input', elevations: [-2, -1, 0] as const },
296
+ { name: 'Overlay', elevations: [4, 5] as const },
297
+ ]
298
+
299
+ return (
300
+ <View className="p-6 min-h-screen bg-background-base">
301
+ <View className="max-w-6xl mx-auto">
302
+ <Text className="text-2xl font-bold text-text-primary mb-2">
303
+ Component Elevation Ranges
304
+ </Text>
305
+ <Text className="text-sm text-text-secondary mb-6">
306
+ Each component type has a specific range of allowed elevations for visual consistency.
307
+ </Text>
308
+
309
+ {componentRanges.map(({ name, elevations }) => (
310
+ <View key={name} className="mb-8">
311
+ <Text className="text-lg font-semibold text-text-primary mb-4">
312
+ {name}
313
+ </Text>
314
+ <View className="flex-row flex-wrap gap-6">
315
+ {elevations.map((level) => {
316
+ const config = getElevationConfig(level)
317
+ const surfaceColor = getElevationSurface(baseColor, level, theme)
318
+ const shadowStyle = getElevationShadow(baseColor, level, theme)
319
+
320
+ return (
321
+ <View key={level} className="items-center gap-2">
322
+ <View
323
+ className="w-20 h-20 rounded-lg items-center justify-center"
324
+ style={[
325
+ { backgroundColor: surfaceColor },
326
+ shadowStyle,
327
+ ]}
328
+ >
329
+ <Text className="text-lg font-bold text-text-primary">
330
+ {level}
331
+ </Text>
332
+ </View>
333
+ <Text className="text-xs text-text-secondary">
334
+ {config.name}
335
+ </Text>
336
+ </View>
337
+ )
338
+ })}
339
+ </View>
340
+ </View>
341
+ ))}
342
+ </View>
343
+ </View>
344
+ )
345
+ },
346
+ }
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { getGlowShadow } from './elevation'
3
+
4
+ describe('getGlowShadow', () => {
5
+ it('returns shadow style for valid hex color', () => {
6
+ const style = getGlowShadow('#FF7900', 'medium')
7
+ expect(style).toBeDefined()
8
+ expect(Object.keys(style).length).toBeGreaterThan(0)
9
+ })
10
+
11
+ it('returns empty object for invalid color', () => {
12
+ const style = getGlowShadow('not-a-color')
13
+ expect(style).toEqual({})
14
+ })
15
+
16
+ it('scales intensity across levels', () => {
17
+ const subtle = getGlowShadow('#FF7900', 'subtle')
18
+ const strong = getGlowShadow('#FF7900', 'strong')
19
+ expect(subtle).not.toEqual(strong)
20
+ })
21
+
22
+ it('defaults to medium intensity', () => {
23
+ const defaultStyle = getGlowShadow('#FF7900')
24
+ const mediumStyle = getGlowShadow('#FF7900', 'medium')
25
+ expect(defaultStyle).toEqual(mediumStyle)
26
+ })
27
+ })