@praxiis/ui 0.0.1

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 (187) hide show
  1. package/dist/index.d.mts +52556 -0
  2. package/dist/index.d.ts +52556 -0
  3. package/dist/index.js +8753 -0
  4. package/dist/index.mjs +8777 -0
  5. package/package.json +70 -0
  6. package/src/__test-utils__/index.tsx +39 -0
  7. package/src/components/CalendarStrip/CalendarStrip.helpers.ts +106 -0
  8. package/src/components/CalendarStrip/CalendarStrip.tsx +83 -0
  9. package/src/components/CalendarStrip/CalendarStrip.types.ts +133 -0
  10. package/src/components/CalendarStrip/DayCard/DayCard.helpers.ts +44 -0
  11. package/src/components/CalendarStrip/DayCard/DayCard.tsx +71 -0
  12. package/src/components/CalendarStrip/DayCard/DayCard.types.ts +134 -0
  13. package/src/components/CalendarStrip/DayCard/index.ts +2 -0
  14. package/src/components/CalendarStrip/DayCard/useDayCardLogic.ts +45 -0
  15. package/src/components/CalendarStrip/index.ts +9 -0
  16. package/src/components/CalendarStrip/useCalendarStripLogic.ts +53 -0
  17. package/src/components/EmptyState/EmptyState.helpers.ts +104 -0
  18. package/src/components/EmptyState/EmptyState.tsx +205 -0
  19. package/src/components/EmptyState/EmptyState.types.ts +213 -0
  20. package/src/components/EmptyState/index.ts +44 -0
  21. package/src/components/EmptyState/useEmptyStateLogic.ts +131 -0
  22. package/src/components/Header/Header.helpers.ts +93 -0
  23. package/src/components/Header/Header.tsx +185 -0
  24. package/src/components/Header/Header.types.ts +153 -0
  25. package/src/components/Header/index.ts +44 -0
  26. package/src/components/Header/useHeaderLogic.ts +146 -0
  27. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.helpers.ts +50 -0
  28. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.tsx +78 -0
  29. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.types.ts +99 -0
  30. package/src/components/ScheduleItem/ScheduleItem/index.ts +16 -0
  31. package/src/components/ScheduleItem/ScheduleItem/useScheduleItemLogic.ts +31 -0
  32. package/src/components/ScheduleItem/index.ts +15 -0
  33. package/src/components/index.ts +40 -0
  34. package/src/core/index.ts +34 -0
  35. package/src/core/restyle/RestyleThemeProviderWrapper.tsx +31 -0
  36. package/src/core/restyle/index.ts +38 -0
  37. package/src/core/restyle/restylePresetRegistry.ts +195 -0
  38. package/src/core/restyle/restyleTheme.ts +1352 -0
  39. package/src/core/restyle/restyleTypes.ts +8 -0
  40. package/src/core/restyle/useRestyleTheme.ts +10 -0
  41. package/src/hooks/animations/index.ts +3 -0
  42. package/src/hooks/animations/useAnimatedValue.ts +10 -0
  43. package/src/hooks/animations/useEntranceAnimation.ts +106 -0
  44. package/src/hooks/animations/usePulseAnimation.ts +63 -0
  45. package/src/hooks/index.ts +30 -0
  46. package/src/hooks/useReducedMotion.ts +60 -0
  47. package/src/i18n/index.ts +2 -0
  48. package/src/i18n/labels/en.ts +120 -0
  49. package/src/i18n/labels/es.ts +120 -0
  50. package/src/i18n/labels/index.ts +6 -0
  51. package/src/i18n/labels/types.ts +165 -0
  52. package/src/index.tsx +215 -0
  53. package/src/primitives/actions/Button/Button.helpers.ts +243 -0
  54. package/src/primitives/actions/Button/Button.tsx +198 -0
  55. package/src/primitives/actions/Button/Button.types.ts +207 -0
  56. package/src/primitives/actions/Button/index.ts +41 -0
  57. package/src/primitives/actions/Button/useButtonLogic.ts +160 -0
  58. package/src/primitives/actions/IconButton/IconButton.helpers.ts +235 -0
  59. package/src/primitives/actions/IconButton/IconButton.tsx +177 -0
  60. package/src/primitives/actions/IconButton/IconButton.types.ts +273 -0
  61. package/src/primitives/actions/IconButton/index.ts +30 -0
  62. package/src/primitives/actions/IconButton/useIconButtonLogic.ts +172 -0
  63. package/src/primitives/actions/index.ts +20 -0
  64. package/src/primitives/content/Avatar/Avatar.helpers.ts +177 -0
  65. package/src/primitives/content/Avatar/Avatar.tsx +199 -0
  66. package/src/primitives/content/Avatar/Avatar.types.ts +222 -0
  67. package/src/primitives/content/Avatar/index.ts +46 -0
  68. package/src/primitives/content/Avatar/useAvatarLogic.ts +149 -0
  69. package/src/primitives/content/Badge/Badge.helpers.ts +175 -0
  70. package/src/primitives/content/Badge/Badge.tsx +174 -0
  71. package/src/primitives/content/Badge/Badge.types.ts +223 -0
  72. package/src/primitives/content/Badge/index.ts +40 -0
  73. package/src/primitives/content/Badge/useBadgeLogic.ts +128 -0
  74. package/src/primitives/content/Card/Card.helpers.ts +27 -0
  75. package/src/primitives/content/Card/Card.tsx +123 -0
  76. package/src/primitives/content/Card/Card.types.ts +95 -0
  77. package/src/primitives/content/Card/index.ts +20 -0
  78. package/src/primitives/content/Card/useCardLogic.ts +48 -0
  79. package/src/primitives/content/Chip/Chip.helpers.ts +304 -0
  80. package/src/primitives/content/Chip/Chip.tsx +205 -0
  81. package/src/primitives/content/Chip/Chip.types.ts +234 -0
  82. package/src/primitives/content/Chip/index.ts +47 -0
  83. package/src/primitives/content/Chip/useChipLogic.ts +167 -0
  84. package/src/primitives/content/Icon/Icon.helpers.ts +54 -0
  85. package/src/primitives/content/Icon/Icon.tsx +110 -0
  86. package/src/primitives/content/Icon/Icon.types.ts +95 -0
  87. package/src/primitives/content/Icon/index.ts +20 -0
  88. package/src/primitives/content/Icon/useIconLogic.ts +73 -0
  89. package/src/primitives/content/index.ts +45 -0
  90. package/src/primitives/feedback/ProgressBar/ProgressBar.helpers.ts +122 -0
  91. package/src/primitives/feedback/ProgressBar/ProgressBar.tsx +154 -0
  92. package/src/primitives/feedback/ProgressBar/ProgressBar.types.ts +178 -0
  93. package/src/primitives/feedback/ProgressBar/index.ts +17 -0
  94. package/src/primitives/feedback/ProgressBar/useProgressBarLogic.ts +120 -0
  95. package/src/primitives/feedback/Skeleton/Skeleton.helpers.ts +145 -0
  96. package/src/primitives/feedback/Skeleton/Skeleton.tsx +155 -0
  97. package/src/primitives/feedback/Skeleton/Skeleton.types.ts +223 -0
  98. package/src/primitives/feedback/Skeleton/index.ts +44 -0
  99. package/src/primitives/feedback/Skeleton/useSkeletonLogic.ts +125 -0
  100. package/src/primitives/feedback/Spinner/Spinner.helpers.ts +40 -0
  101. package/src/primitives/feedback/Spinner/Spinner.tsx +105 -0
  102. package/src/primitives/feedback/Spinner/Spinner.types.ts +114 -0
  103. package/src/primitives/feedback/Spinner/index.ts +18 -0
  104. package/src/primitives/feedback/Spinner/useSpinnerLogic.ts +84 -0
  105. package/src/primitives/feedback/Toast/Toast.helpers.ts +163 -0
  106. package/src/primitives/feedback/Toast/Toast.tsx +190 -0
  107. package/src/primitives/feedback/Toast/Toast.types.ts +270 -0
  108. package/src/primitives/feedback/Toast/ToastContext.tsx +96 -0
  109. package/src/primitives/feedback/Toast/ToastProvider.tsx +241 -0
  110. package/src/primitives/feedback/Toast/index.ts +59 -0
  111. package/src/primitives/feedback/Toast/useToastLogic.ts +112 -0
  112. package/src/primitives/feedback/index.ts +45 -0
  113. package/src/primitives/index.ts +158 -0
  114. package/src/primitives/inputs/Checkbox/Checkbox.helpers.ts +132 -0
  115. package/src/primitives/inputs/Checkbox/Checkbox.tsx +150 -0
  116. package/src/primitives/inputs/Checkbox/Checkbox.types.ts +106 -0
  117. package/src/primitives/inputs/Checkbox/index.ts +30 -0
  118. package/src/primitives/inputs/Checkbox/useCheckboxLogic.ts +121 -0
  119. package/src/primitives/inputs/RadioButton/RadioButton.helpers.ts +123 -0
  120. package/src/primitives/inputs/RadioButton/RadioButton.tsx +159 -0
  121. package/src/primitives/inputs/RadioButton/RadioButton.types.ts +106 -0
  122. package/src/primitives/inputs/RadioButton/index.ts +25 -0
  123. package/src/primitives/inputs/RadioButton/useRadioButtonLogic.ts +117 -0
  124. package/src/primitives/inputs/SegmentedControl/SegmentedControl.helpers.ts +174 -0
  125. package/src/primitives/inputs/SegmentedControl/SegmentedControl.tsx +224 -0
  126. package/src/primitives/inputs/SegmentedControl/SegmentedControl.types.ts +187 -0
  127. package/src/primitives/inputs/SegmentedControl/index.ts +39 -0
  128. package/src/primitives/inputs/SegmentedControl/useSegmentedControlLogic.ts +151 -0
  129. package/src/primitives/inputs/SelectSheet/SelectSheet.helpers.ts +147 -0
  130. package/src/primitives/inputs/SelectSheet/SelectSheet.tsx +247 -0
  131. package/src/primitives/inputs/SelectSheet/SelectSheet.types.ts +196 -0
  132. package/src/primitives/inputs/SelectSheet/SelectSheetOption.tsx +177 -0
  133. package/src/primitives/inputs/SelectSheet/index.ts +48 -0
  134. package/src/primitives/inputs/SelectSheet/useSelectSheetLogic.ts +309 -0
  135. package/src/primitives/inputs/Switch/Switch.helpers.ts +109 -0
  136. package/src/primitives/inputs/Switch/Switch.tsx +191 -0
  137. package/src/primitives/inputs/Switch/Switch.types.ts +154 -0
  138. package/src/primitives/inputs/Switch/index.ts +40 -0
  139. package/src/primitives/inputs/Switch/useSwitchLogic.ts +192 -0
  140. package/src/primitives/inputs/TextInput/TextInput.helpers.ts +206 -0
  141. package/src/primitives/inputs/TextInput/TextInput.tsx +392 -0
  142. package/src/primitives/inputs/TextInput/TextInput.types.ts +216 -0
  143. package/src/primitives/inputs/TextInput/index.ts +37 -0
  144. package/src/primitives/inputs/TextInput/useTextInputLogic.ts +195 -0
  145. package/src/primitives/inputs/index.ts +52 -0
  146. package/src/primitives/layout/AnimatedBox.tsx +44 -0
  147. package/src/primitives/layout/Box.tsx +71 -0
  148. package/src/primitives/layout/Divider/Divider.helpers.ts +115 -0
  149. package/src/primitives/layout/Divider/Divider.tsx +139 -0
  150. package/src/primitives/layout/Divider/Divider.types.ts +178 -0
  151. package/src/primitives/layout/Divider/index.ts +24 -0
  152. package/src/primitives/layout/Divider/useDividerLogic.ts +109 -0
  153. package/src/primitives/layout/FlatList.tsx +66 -0
  154. package/src/primitives/layout/Pressable.tsx +74 -0
  155. package/src/primitives/layout/ScrollView.tsx +63 -0
  156. package/src/primitives/layout/Stack.tsx +69 -0
  157. package/src/primitives/layout/index.ts +40 -0
  158. package/src/primitives/navigation/index.ts +6 -0
  159. package/src/primitives/overlays/Modal/Modal.helpers.ts +31 -0
  160. package/src/primitives/overlays/Modal/Modal.tsx +264 -0
  161. package/src/primitives/overlays/Modal/Modal.types.ts +193 -0
  162. package/src/primitives/overlays/Modal/index.ts +43 -0
  163. package/src/primitives/overlays/Modal/useModalLogic.ts +103 -0
  164. package/src/primitives/overlays/index.ts +12 -0
  165. package/src/primitives/typography/Text.tsx +51 -0
  166. package/src/primitives/typography/index.ts +1 -0
  167. package/src/provider/DesignSystemContext.ts +22 -0
  168. package/src/provider/DesignSystemProvider.tsx +121 -0
  169. package/src/provider/index.ts +7 -0
  170. package/src/providers/ThemeProvider/createTheme.ts +304 -0
  171. package/src/providers/ThemeProvider/defaultTheme.ts +70 -0
  172. package/src/providers/ThemeProvider/index.ts +34 -0
  173. package/src/providers/ThemeProvider/types.ts +249 -0
  174. package/src/providers/index.ts +29 -0
  175. package/src/tokens/colors.ts +371 -0
  176. package/src/tokens/index.ts +145 -0
  177. package/src/tokens/motion.ts +176 -0
  178. package/src/tokens/radii.ts +82 -0
  179. package/src/tokens/scales.ts +588 -0
  180. package/src/tokens/shadows.ts +190 -0
  181. package/src/tokens/spacing.ts +140 -0
  182. package/src/tokens/tokens.json +207 -0
  183. package/src/tokens/typography.ts +251 -0
  184. package/src/types.ts +50 -0
  185. package/src/utils/accessibility.ts +169 -0
  186. package/src/utils/index.ts +25 -0
  187. package/src/utils/platform.ts +72 -0
@@ -0,0 +1,1352 @@
1
+ /**
2
+ * El Sendero Design System - Restyle Theme Configuration
3
+ *
4
+ * Maps all design system tokens to Restyle theme format.
5
+ * Restyle enables type-safe, prop-based styling for React Native components.
6
+ */
7
+
8
+ import { createTheme } from "@shopify/restyle";
9
+ import {
10
+ baseColors,
11
+ darkSemanticColors,
12
+ fontFamily,
13
+ lightSemanticColors,
14
+ radii,
15
+ spacing,
16
+ typographyPresets,
17
+ zIndex,
18
+ } from "../../tokens";
19
+
20
+ // =============================================================================
21
+ // PRESET RESTYLE THEME BUILDER
22
+ // =============================================================================
23
+
24
+ import type { ThemeColors, DeepPartial } from "../../providers/ThemeProvider/types";
25
+
26
+ export type SemanticColorsInput = {
27
+ [K in keyof typeof lightSemanticColors]: {
28
+ [P in keyof (typeof lightSemanticColors)[K]]: string;
29
+ };
30
+ };
31
+
32
+ export const flattenColors = (semanticColors: SemanticColorsInput) =>
33
+ ({
34
+ // Backgrounds
35
+ backgroundPrimary: semanticColors.background.primary,
36
+ backgroundSecondary: semanticColors.background.secondary,
37
+ backgroundTertiary: semanticColors.background.tertiary,
38
+ backgroundInverse: semanticColors.background.inverse,
39
+
40
+ // Surfaces
41
+ surfacePrimary: semanticColors.surface.primary,
42
+ surfaceSecondary: semanticColors.surface.secondary,
43
+ surfaceElevated: semanticColors.surface.elevated,
44
+ surfaceOverlay: semanticColors.surface.overlay,
45
+
46
+ // Text
47
+ textPrimary: semanticColors.text.primary,
48
+ textSecondary: semanticColors.text.secondary,
49
+ textTertiary: semanticColors.text.tertiary,
50
+ textDisabled: semanticColors.text.disabled,
51
+ textInverse: semanticColors.text.inverse,
52
+ textLink: semanticColors.text.link,
53
+
54
+ // Borders
55
+ borderDefault: semanticColors.border.default,
56
+ borderSubtle: semanticColors.border.subtle,
57
+ borderStrong: semanticColors.border.strong,
58
+ borderFocus: semanticColors.border.focus,
59
+
60
+ // Accents
61
+ accentPrimary: semanticColors.accent.primary,
62
+ accentPrimaryHover: semanticColors.accent.primaryHover,
63
+ accentPrimaryPressed: semanticColors.accent.primaryPressed,
64
+ accentSecondary: semanticColors.accent.secondary,
65
+ accentSecondaryHover: semanticColors.accent.secondaryHover,
66
+ accentSecondaryPressed: semanticColors.accent.secondaryPressed,
67
+
68
+ // Interactive
69
+ interactiveDefault: semanticColors.interactive.default,
70
+ interactiveHover: semanticColors.interactive.hover,
71
+ interactivePressed: semanticColors.interactive.pressed,
72
+ interactiveDisabled: semanticColors.interactive.disabled,
73
+
74
+ // Feedback
75
+ feedbackSuccess: semanticColors.feedback.success,
76
+ feedbackSuccessLight: semanticColors.feedback.successLight,
77
+ feedbackSuccessDark: semanticColors.feedback.successDark,
78
+ feedbackWarning: semanticColors.feedback.warning,
79
+ feedbackWarningLight: semanticColors.feedback.warningLight,
80
+ feedbackWarningDark: semanticColors.feedback.warningDark,
81
+ feedbackError: semanticColors.feedback.error,
82
+ feedbackErrorLight: semanticColors.feedback.errorLight,
83
+ feedbackErrorDark: semanticColors.feedback.errorDark,
84
+ feedbackInfo: semanticColors.feedback.info,
85
+ feedbackInfoLight: semanticColors.feedback.infoLight,
86
+ feedbackInfoDark: semanticColors.feedback.infoDark,
87
+
88
+ // Danger (for buttons)
89
+ dangerPrimary: semanticColors.feedback.error,
90
+ dangerPrimaryHover: semanticColors.feedback.errorDark,
91
+ dangerPrimaryPressed: semanticColors.feedback.errorDark,
92
+
93
+ // Special
94
+ specialSkeleton: semanticColors.special.skeleton,
95
+ specialDivider: semanticColors.special.divider,
96
+ specialScrim: semanticColors.special.scrim,
97
+
98
+ // Emotion colors
99
+ emotionHappy: semanticColors.emotion.happy,
100
+ emotionCalm: semanticColors.emotion.calm,
101
+ emotionNeutral: semanticColors.emotion.neutral,
102
+ emotionSad: semanticColors.emotion.sad,
103
+ emotionAnxious: semanticColors.emotion.anxious,
104
+ emotionAngry: semanticColors.emotion.angry,
105
+ emotionOverwhelmed: semanticColors.emotion.overwhelmed,
106
+
107
+ // Transparent
108
+ transparent: "transparent",
109
+
110
+ // Base Colors - Blue (Primary)
111
+ blue50: baseColors.blue[50],
112
+ blue100: baseColors.blue[100],
113
+ blue200: baseColors.blue[200],
114
+ blue300: baseColors.blue[300],
115
+ blue400: baseColors.blue[400],
116
+ blue500: baseColors.blue[500],
117
+ blue600: baseColors.blue[600],
118
+ blue700: baseColors.blue[700],
119
+ blue800: baseColors.blue[800],
120
+ blue900: baseColors.blue[900],
121
+
122
+ // Base Colors - Pink (Accent)
123
+ pink50: baseColors.pink[50],
124
+ pink100: baseColors.pink[100],
125
+ pink200: baseColors.pink[200],
126
+ pink300: baseColors.pink[300],
127
+ pink400: baseColors.pink[400],
128
+ pink500: baseColors.pink[500],
129
+ pink600: baseColors.pink[600],
130
+ pink700: baseColors.pink[700],
131
+ pink800: baseColors.pink[800],
132
+ pink900: baseColors.pink[900],
133
+
134
+ // Base Colors - Yellow (Warning/Accent)
135
+ yellow50: baseColors.yellow[50],
136
+ yellow100: baseColors.yellow[100],
137
+ yellow200: baseColors.yellow[200],
138
+ yellow300: baseColors.yellow[300],
139
+ yellow400: baseColors.yellow[400],
140
+ yellow500: baseColors.yellow[500],
141
+ yellow600: baseColors.yellow[600],
142
+ yellow700: baseColors.yellow[700],
143
+ yellow800: baseColors.yellow[800],
144
+ yellow900: baseColors.yellow[900],
145
+
146
+ // Base Colors - Green (Success)
147
+ green50: baseColors.green[50],
148
+ green100: baseColors.green[100],
149
+ green200: baseColors.green[200],
150
+ green300: baseColors.green[300],
151
+ green400: baseColors.green[400],
152
+ green500: baseColors.green[500],
153
+ green600: baseColors.green[600],
154
+ green700: baseColors.green[700],
155
+ green800: baseColors.green[800],
156
+ green900: baseColors.green[900],
157
+
158
+ // Base Colors - Orange (Secondary accent)
159
+ orange50: baseColors.orange[50],
160
+ orange100: baseColors.orange[100],
161
+ orange200: baseColors.orange[200],
162
+ orange300: baseColors.orange[300],
163
+ orange400: baseColors.orange[400],
164
+ orange500: baseColors.orange[500],
165
+ orange600: baseColors.orange[600],
166
+ orange700: baseColors.orange[700],
167
+ orange800: baseColors.orange[800],
168
+ orange900: baseColors.orange[900],
169
+
170
+ // Base Colors - Amber (Alternative warning)
171
+ amber50: baseColors.amber[50],
172
+ amber100: baseColors.amber[100],
173
+ amber200: baseColors.amber[200],
174
+ amber300: baseColors.amber[300],
175
+ amber400: baseColors.amber[400],
176
+ amber500: baseColors.amber[500],
177
+ amber600: baseColors.amber[600],
178
+ amber700: baseColors.amber[700],
179
+ amber800: baseColors.amber[800],
180
+ amber900: baseColors.amber[900],
181
+
182
+ // Base Colors - Red (Error)
183
+ red50: baseColors.red[50],
184
+ red100: baseColors.red[100],
185
+ red200: baseColors.red[200],
186
+ red300: baseColors.red[300],
187
+ red400: baseColors.red[400],
188
+ red500: baseColors.red[500],
189
+ red600: baseColors.red[600],
190
+ red700: baseColors.red[700],
191
+ red800: baseColors.red[800],
192
+ red900: baseColors.red[900],
193
+
194
+ // Base Colors - Purple (Decorative)
195
+ purple50: baseColors.purple[50],
196
+ purple100: baseColors.purple[100],
197
+ purple200: baseColors.purple[200],
198
+ purple300: baseColors.purple[300],
199
+ purple400: baseColors.purple[400],
200
+ purple500: baseColors.purple[500],
201
+ purple600: baseColors.purple[600],
202
+ purple700: baseColors.purple[700],
203
+ purple800: baseColors.purple[800],
204
+ purple900: baseColors.purple[900],
205
+
206
+ // Base Colors - Cyan (Info/Accent)
207
+ cyan50: baseColors.cyan[50],
208
+ cyan100: baseColors.cyan[100],
209
+ cyan200: baseColors.cyan[200],
210
+ cyan300: baseColors.cyan[300],
211
+ cyan400: baseColors.cyan[400],
212
+ cyan500: baseColors.cyan[500],
213
+ cyan600: baseColors.cyan[600],
214
+ cyan700: baseColors.cyan[700],
215
+ cyan800: baseColors.cyan[800],
216
+ cyan900: baseColors.cyan[900],
217
+
218
+ // Base Colors - Deep Purple (Special)
219
+ deepPurple50: baseColors.deepPurple[50],
220
+ deepPurple100: baseColors.deepPurple[100],
221
+ deepPurple200: baseColors.deepPurple[200],
222
+ deepPurple300: baseColors.deepPurple[300],
223
+ deepPurple400: baseColors.deepPurple[400],
224
+ deepPurple500: baseColors.deepPurple[500],
225
+ deepPurple600: baseColors.deepPurple[600],
226
+ deepPurple700: baseColors.deepPurple[700],
227
+ deepPurple800: baseColors.deepPurple[800],
228
+ deepPurple900: baseColors.deepPurple[900],
229
+
230
+ // Base Colors - Gray
231
+ gray50: baseColors.gray[50],
232
+ gray100: baseColors.gray[100],
233
+ gray200: baseColors.gray[200],
234
+ gray300: baseColors.gray[300],
235
+ gray400: baseColors.gray[400],
236
+ gray500: baseColors.gray[500],
237
+ gray600: baseColors.gray[600],
238
+ gray700: baseColors.gray[700],
239
+ gray800: baseColors.gray[800],
240
+ gray900: baseColors.gray[900],
241
+
242
+ // Base Colors - Pure
243
+ white: baseColors.white,
244
+ black: baseColors.black,
245
+
246
+ // Text Color Aliases (for semantic usage like color="primary")
247
+ // These map to the flattened text colors for convenience
248
+ primary: semanticColors.text.primary,
249
+ secondary: semanticColors.text.secondary,
250
+ tertiary: semanticColors.text.tertiary,
251
+ disabled: semanticColors.text.disabled,
252
+ inverse: semanticColors.text.inverse,
253
+ link: semanticColors.text.link,
254
+ success: semanticColors.feedback.success,
255
+ warning: semanticColors.feedback.warning,
256
+ error: semanticColors.feedback.error,
257
+ info: semanticColors.feedback.info,
258
+ }) as const;
259
+
260
+ // =============================================================================
261
+ // COLOR PALETTES
262
+ // =============================================================================
263
+
264
+ const lightColors = flattenColors(lightSemanticColors);
265
+ const darkColors = flattenColors(darkSemanticColors);
266
+
267
+ // =============================================================================
268
+ // RESTYLE THEME DEFINITION
269
+ // =============================================================================
270
+
271
+ // =============================================================================
272
+ // HELPER: CREATE BASE THEME CONFIG
273
+ // Shared configuration for both light and dark themes
274
+ // =============================================================================
275
+
276
+ export const createBaseThemeConfig = (
277
+ colors: ReturnType<typeof flattenColors>,
278
+ ) => ({
279
+ colors,
280
+ spacing,
281
+ borderRadii: radii,
282
+ textVariants: {
283
+ defaults: {
284
+ color: "textPrimary",
285
+ },
286
+ // Display variants
287
+ displayLarge: {
288
+ fontSize: typographyPresets.displayLarge.fontSize,
289
+ lineHeight: typographyPresets.displayLarge.lineHeight,
290
+ fontWeight: typographyPresets.displayLarge.fontWeight,
291
+ letterSpacing: typographyPresets.displayLarge.letterSpacing,
292
+ fontFamily: fontFamily.bold,
293
+ },
294
+ displayMedium: {
295
+ fontSize: typographyPresets.displayMedium.fontSize,
296
+ lineHeight: typographyPresets.displayMedium.lineHeight,
297
+ fontWeight: typographyPresets.displayMedium.fontWeight,
298
+ letterSpacing: typographyPresets.displayMedium.letterSpacing,
299
+ fontFamily: fontFamily.bold,
300
+ },
301
+ displaySmall: {
302
+ fontSize: typographyPresets.displaySmall.fontSize,
303
+ lineHeight: typographyPresets.displaySmall.lineHeight,
304
+ fontWeight: typographyPresets.displaySmall.fontWeight,
305
+ letterSpacing: typographyPresets.displaySmall.letterSpacing,
306
+ fontFamily: fontFamily.bold,
307
+ },
308
+ // Heading variants
309
+ headingLarge: {
310
+ fontSize: typographyPresets.headingLarge.fontSize,
311
+ lineHeight: typographyPresets.headingLarge.lineHeight,
312
+ fontWeight: typographyPresets.headingLarge.fontWeight,
313
+ letterSpacing: typographyPresets.headingLarge.letterSpacing,
314
+ fontFamily: fontFamily.semibold,
315
+ },
316
+ headingMedium: {
317
+ fontSize: typographyPresets.headingMedium.fontSize,
318
+ lineHeight: typographyPresets.headingMedium.lineHeight,
319
+ fontWeight: typographyPresets.headingMedium.fontWeight,
320
+ letterSpacing: typographyPresets.headingMedium.letterSpacing,
321
+ fontFamily: fontFamily.semibold,
322
+ },
323
+ headingSmall: {
324
+ fontSize: typographyPresets.headingSmall.fontSize,
325
+ lineHeight: typographyPresets.headingSmall.lineHeight,
326
+ fontWeight: typographyPresets.headingSmall.fontWeight,
327
+ letterSpacing: typographyPresets.headingSmall.letterSpacing,
328
+ fontFamily: fontFamily.semibold,
329
+ },
330
+ // Body variants
331
+ bodyLarge: {
332
+ fontSize: typographyPresets.bodyLarge.fontSize,
333
+ lineHeight: typographyPresets.bodyLarge.lineHeight,
334
+ fontWeight: typographyPresets.bodyLarge.fontWeight,
335
+ letterSpacing: typographyPresets.bodyLarge.letterSpacing,
336
+ fontFamily: fontFamily.regular,
337
+ },
338
+ bodyMedium: {
339
+ fontSize: typographyPresets.bodyMedium.fontSize,
340
+ lineHeight: typographyPresets.bodyMedium.lineHeight,
341
+ fontWeight: typographyPresets.bodyMedium.fontWeight,
342
+ letterSpacing: typographyPresets.bodyMedium.letterSpacing,
343
+ fontFamily: fontFamily.regular,
344
+ },
345
+ bodySmall: {
346
+ fontSize: typographyPresets.bodySmall.fontSize,
347
+ lineHeight: typographyPresets.bodySmall.lineHeight,
348
+ fontWeight: typographyPresets.bodySmall.fontWeight,
349
+ letterSpacing: typographyPresets.bodySmall.letterSpacing,
350
+ fontFamily: fontFamily.regular,
351
+ },
352
+ // Label variants
353
+ labelLarge: {
354
+ fontSize: typographyPresets.labelLarge.fontSize,
355
+ lineHeight: typographyPresets.labelLarge.lineHeight,
356
+ fontWeight: typographyPresets.labelLarge.fontWeight,
357
+ letterSpacing: typographyPresets.labelLarge.letterSpacing,
358
+ fontFamily: fontFamily.medium,
359
+ },
360
+ labelMedium: {
361
+ fontSize: typographyPresets.labelMedium.fontSize,
362
+ lineHeight: typographyPresets.labelMedium.lineHeight,
363
+ fontWeight: typographyPresets.labelMedium.fontWeight,
364
+ letterSpacing: typographyPresets.labelMedium.letterSpacing,
365
+ fontFamily: fontFamily.medium,
366
+ },
367
+ labelSmall: {
368
+ fontSize: typographyPresets.labelSmall.fontSize,
369
+ lineHeight: typographyPresets.labelSmall.lineHeight,
370
+ fontWeight: typographyPresets.labelSmall.fontWeight,
371
+ letterSpacing: typographyPresets.labelSmall.letterSpacing,
372
+ fontFamily: fontFamily.medium,
373
+ },
374
+ // Caption variants
375
+ caption: {
376
+ fontSize: typographyPresets.caption.fontSize,
377
+ lineHeight: typographyPresets.caption.lineHeight,
378
+ fontWeight: typographyPresets.caption.fontWeight,
379
+ letterSpacing: typographyPresets.caption.letterSpacing,
380
+ fontFamily: fontFamily.regular,
381
+ },
382
+ captionSmall: {
383
+ fontSize: typographyPresets.captionSmall.fontSize,
384
+ lineHeight: typographyPresets.captionSmall.lineHeight,
385
+ fontWeight: typographyPresets.captionSmall.fontWeight,
386
+ letterSpacing: typographyPresets.captionSmall.letterSpacing,
387
+ fontFamily: fontFamily.regular,
388
+ },
389
+ // Overline variant
390
+ overline: {
391
+ fontSize: typographyPresets.overline.fontSize,
392
+ lineHeight: typographyPresets.overline.lineHeight,
393
+ fontWeight: typographyPresets.overline.fontWeight,
394
+ letterSpacing: typographyPresets.overline.letterSpacing,
395
+ textTransform: typographyPresets.overline.textTransform,
396
+ fontFamily: fontFamily.semibold,
397
+ },
398
+ // Code variant
399
+ code: {
400
+ fontSize: typographyPresets.code.fontSize,
401
+ lineHeight: typographyPresets.code.lineHeight,
402
+ fontWeight: typographyPresets.code.fontWeight,
403
+ letterSpacing: typographyPresets.code.letterSpacing,
404
+ fontFamily: fontFamily.mono,
405
+ },
406
+ },
407
+ breakpoints: {
408
+ phone: 0,
409
+ tablet: 768,
410
+ },
411
+ zIndices: {
412
+ behind: zIndex.behind,
413
+ base: zIndex.base,
414
+ raised: zIndex.raised,
415
+ dropdown: zIndex.dropdown,
416
+ sticky: zIndex.sticky,
417
+ overlay: zIndex.overlay,
418
+ modal: zIndex.modal,
419
+ popover: zIndex.popover,
420
+ toast: zIndex.toast,
421
+ max: zIndex.max,
422
+ },
423
+ // ==========================================================================
424
+ // BUTTON SIZES
425
+ // ==========================================================================
426
+ // Mathematical relationship: Icon matches text visual weight (1:1)
427
+ //
428
+ // | Size | Height | Icon | Text Variant | Touch Target |
429
+ // |------|--------|------|--------------|--------------|
430
+ // | sm | 36px | 16px | labelSmall | 36px (native)|
431
+ // | md | 44px | 20px | labelMedium | 44px (native)|
432
+ // | lg | 52px | 24px | labelLarge | 52px (native)|
433
+ //
434
+ // See: tokens/scales.ts BUTTON_ICON_SIZE, BUTTON_TEXT_VARIANT
435
+ buttonSizes: {
436
+ defaults: {
437
+ height: 44,
438
+ paddingHorizontal: "md",
439
+ borderRadius: "md",
440
+ },
441
+ sm: {
442
+ height: 36,
443
+ paddingHorizontal: "sm",
444
+ },
445
+ md: {
446
+ height: 44,
447
+ paddingHorizontal: "md",
448
+ },
449
+ lg: {
450
+ height: 52,
451
+ paddingHorizontal: "lg",
452
+ },
453
+ },
454
+ // Button variants - visual styles only
455
+ buttonVariants: {
456
+ defaults: {
457
+ borderWidth: 0,
458
+ },
459
+ solid: {
460
+ borderWidth: 0,
461
+ },
462
+ outline: {
463
+ backgroundColor: "transparent",
464
+ borderWidth: 1.5,
465
+ },
466
+ ghost: {
467
+ backgroundColor: "transparent",
468
+ borderWidth: 0,
469
+ },
470
+ disabled: {
471
+ borderWidth: 0,
472
+ },
473
+ },
474
+ // ==========================================================================
475
+ // CHECKBOX SIZES
476
+ // ==========================================================================
477
+ // Mathematical relationship: Icon = Container × ~75% (toggleControl ratio)
478
+ //
479
+ // | Size | Container | Icon | Ratio | hitSlop | Touch Target |
480
+ // |------|-----------|------|-------|---------|--------------|
481
+ // | sm | 20px | 16px | 80% | 12px | 44px |
482
+ // | md | 24px | 20px | 83% | 10px | 44px |
483
+ // | lg | 32px | 24px | 75% | 6px | 44px |
484
+ //
485
+ // See: tokens/scales.ts CHECKBOX_ICON_SIZE, CHECKBOX_HIT_SLOP
486
+ checkboxSizes: {
487
+ defaults: {
488
+ width: 24,
489
+ height: 24,
490
+ borderRadius: "xs",
491
+ borderWidth: 2,
492
+ },
493
+ sm: {
494
+ width: 20,
495
+ height: 20,
496
+ },
497
+ md: {
498
+ width: 24,
499
+ height: 24,
500
+ },
501
+ lg: {
502
+ width: 32,
503
+ height: 32,
504
+ borderRadius: "sm",
505
+ },
506
+ },
507
+ // ==========================================================================
508
+ // RADIO BUTTON SIZES
509
+ // ==========================================================================
510
+ // Uses same container sizes as Checkbox but with circular shape (full radius).
511
+ // Inner dot size: ~40% of container for visual balance.
512
+ //
513
+ // | Size | Container | Inner Dot | hitSlop | Touch |
514
+ // |------|-----------|-----------|---------|-------|
515
+ // | sm | 20px | 8px | 12px | 44px |
516
+ // | md | 24px | 10px | 10px | 44px |
517
+ // | lg | 32px | 14px | 6px | 44px |
518
+ //
519
+ // See: tokens/scales.ts TOGGLE_CONTAINER_SIZES, RADIO_BUTTON_INNER_SIZE
520
+ radioButtonSizes: {
521
+ defaults: {
522
+ width: 24,
523
+ height: 24,
524
+ borderRadius: "full",
525
+ borderWidth: 2,
526
+ },
527
+ sm: {
528
+ width: 20,
529
+ height: 20,
530
+ },
531
+ md: {
532
+ width: 24,
533
+ height: 24,
534
+ },
535
+ lg: {
536
+ width: 32,
537
+ height: 32,
538
+ },
539
+ },
540
+ // ==========================================================================
541
+ // SWITCH SIZES
542
+ // ==========================================================================
543
+ // Mathematical relationship: Thumb = TrackHeight - (THUMB_INSET × 2)
544
+ // THUMB_INSET = 2px (from tokens/scales.ts)
545
+ //
546
+ // | Size | Track W | Track H | Thumb | W:H Ratio | hitSlop | Touch |
547
+ // |------|---------|---------|-------|-----------|---------|-------|
548
+ // | sm | 40px | 24px | 20px | 1.67:1 | 10px | 44px |
549
+ // | md | 48px | 28px | 24px | 1.71:1 | 8px | 44px |
550
+ // | lg | 56px | 32px | 28px | 1.75:1 | 6px | 44px |
551
+ //
552
+ // See: tokens/scales.ts SWITCH_DIMENSIONS, SWITCH_THUMB_INSET
553
+ switchSizes: {
554
+ defaults: {
555
+ // Track dimensions
556
+ width: 48,
557
+ height: 28,
558
+ borderRadius: "full",
559
+ },
560
+ sm: {
561
+ width: 40,
562
+ height: 24,
563
+ },
564
+ md: {
565
+ width: 48,
566
+ height: 28,
567
+ },
568
+ lg: {
569
+ width: 56,
570
+ height: 32,
571
+ },
572
+ },
573
+ // ==========================================================================
574
+ // TEXT INPUT VARIANTS
575
+ // ==========================================================================
576
+ // Visual style variants for TextInput. Actual border/background styling
577
+ // is resolved in TextInput.helpers.ts; keys here establish the type
578
+ // contract so TextInputVariant derives from the theme.
579
+ //
580
+ // | Variant | Background | Border | Use Case |
581
+ // |----------|----------------|-------------|----------|
582
+ // | outlined | transparent | 1.5px solid | Default, most forms |
583
+ // | filled | backgroundSecondary | subtle | Dense/compact UIs |
584
+ // | textarea | transparent | 1.5px solid | Multi-line text input |
585
+ textInputVariants: {
586
+ defaults: {},
587
+ outlined: {},
588
+ filled: {},
589
+ textarea: {},
590
+ },
591
+ // ==========================================================================
592
+ // TEXT INPUT SIZES
593
+ // ==========================================================================
594
+ // Height/padding presets for TextInput. Actual dimensions are
595
+ // resolved in TextInput.helpers.ts; keys establish the type contract.
596
+ //
597
+ // | Size | Height | Padding H | Font Size | Use Case |
598
+ // |------|--------|-----------|-----------|----------|
599
+ // | sm | 40px | 12px | 14px | Compact forms |
600
+ // | md | 48px | 16px | 16px | Default mobile |
601
+ // | lg | 56px | 20px | 18px | Tablets, emphasis |
602
+ textInputSizes: {
603
+ defaults: {},
604
+ sm: {},
605
+ md: {},
606
+ lg: {},
607
+ },
608
+ // ==========================================================================
609
+ // SELECT SHEET VARIANTS
610
+ // ==========================================================================
611
+ // Industry-standard dimensions based on Material Design 3 and iOS HIG.
612
+ //
613
+ // Variant Positioning:
614
+ // - center: Centered modal dialog with max-width constraint
615
+ // - bottom: Bottom sheet anchored to screen bottom
616
+ //
617
+ // Size Scale:
618
+ // | Size | Max Width | List Height | Header | Use Case |
619
+ // |------|-----------|-------------|--------|----------|
620
+ // | sm | 320px | 200px | 48px | Few options |
621
+ // | md | 400px | 300px | 56px | Default |
622
+ // SelectSheet - Simplified consistent width like Modal
623
+ // Phone: Full width - 16px margins
624
+ // Tablet (≥768px): Capped at 480px max-width for phone-like experience
625
+ //
626
+ // See: tokens/scales.ts SELECT_SHEET_LAYOUT
627
+ selectSheetVariants: {
628
+ defaults: {
629
+ backgroundColor: "surfaceElevated",
630
+ borderRadius: "xl",
631
+ overflow: "hidden",
632
+ },
633
+ },
634
+ // SelectSheet header - Consistent height
635
+ selectSheetHeader: {
636
+ height: 56,
637
+ paddingHorizontal: "lg",
638
+ borderBottomWidth: 1,
639
+ borderBottomColor: "borderSubtle",
640
+ flexDirection: "row",
641
+ alignItems: "center",
642
+ justifyContent: "space-between",
643
+ },
644
+ // SelectSheet option row - Consistent height with touch targets
645
+ selectSheetOptionRow: {
646
+ height: 52,
647
+ paddingHorizontal: "lg",
648
+ paddingVertical: "md",
649
+ flexDirection: "row",
650
+ alignItems: "center",
651
+ gap: "md",
652
+ },
653
+ // Card variants - visual styles
654
+ cardVariants: {
655
+ defaults: {
656
+ borderWidth: 0,
657
+ borderRadius: "lg",
658
+ },
659
+ flat: {
660
+ backgroundColor: "backgroundSecondary",
661
+ borderWidth: 0,
662
+ borderRadius: "lg",
663
+ },
664
+ outlined: {
665
+ backgroundColor: "backgroundSecondary",
666
+ borderWidth: 1,
667
+ borderColor: "borderDefault",
668
+ borderRadius: "lg",
669
+ },
670
+ },
671
+ // Header variants
672
+ headerVariants: {
673
+ defaults: {
674
+ backgroundColor: "surfacePrimary",
675
+ borderBottomWidth: 1,
676
+ borderBottomColor: "borderSubtle",
677
+ flexDirection: "row",
678
+ alignItems: "center",
679
+ gap: "xs",
680
+ paddingHorizontal: "lg", // 16px from spacing tokens
681
+ },
682
+ primary: {
683
+ backgroundColor: "surfacePrimary",
684
+ borderBottomWidth: 1,
685
+ borderBottomColor: "borderSubtle",
686
+ },
687
+ transparent: {
688
+ backgroundColor: "transparent",
689
+ borderBottomWidth: 0,
690
+ },
691
+ elevated: {
692
+ backgroundColor: "surfaceElevated",
693
+ borderBottomWidth: 0,
694
+ },
695
+ },
696
+ // Header sizes
697
+ // Content height only - safe area inset is added at runtime
698
+ // - sm (44px): Compact headers, modals - matches iOS minimum touch target
699
+ // - md (56px): Standard navigation, phone default
700
+ // - lg (64px): Prominent headers, tablet default
701
+ headerSizes: {
702
+ defaults: {
703
+ height: 56,
704
+ },
705
+ sm: {
706
+ height: 44,
707
+ },
708
+ md: {
709
+ height: 56,
710
+ },
711
+ lg: {
712
+ height: 64,
713
+ },
714
+ },
715
+ // Icon sizes
716
+ // Scale: 12 → 16 → 20 → 24 (+4px) → 32 → 40 → 48 (+8px)
717
+ // Smaller icons need finer control; larger icons can have bigger jumps
718
+ // - xs (12px): Badges, inline text indicators, status dots
719
+ // - sm (16px): Compact buttons, dense lists, checkbox icons (sm)
720
+ // - md (20px): Phone default, standard buttons, checkbox icons (md)
721
+ // - lg (24px): Primary actions, phone headers, checkbox icons (lg)
722
+ // - xl (32px): Tablet headers, emphasized actions
723
+ // - 2xl (40px): Empty states, onboarding illustrations
724
+ // - 3xl (48px): Hero sections, large feature illustrations
725
+ iconSizes: {
726
+ defaults: {
727
+ width: 20,
728
+ height: 20,
729
+ },
730
+ xs: {
731
+ width: 12,
732
+ height: 12,
733
+ },
734
+ sm: {
735
+ width: 16,
736
+ height: 16,
737
+ },
738
+ md: {
739
+ width: 20,
740
+ height: 20,
741
+ },
742
+ lg: {
743
+ width: 24,
744
+ height: 24,
745
+ },
746
+ xl: {
747
+ width: 32,
748
+ height: 32,
749
+ },
750
+ "2xl": {
751
+ width: 40,
752
+ height: 40,
753
+ },
754
+ "3xl": {
755
+ width: 48,
756
+ height: 48,
757
+ },
758
+ },
759
+ // IconButton variants (visual styles)
760
+ iconButtonVariants: {
761
+ defaults: {
762
+ borderRadius: "full",
763
+ borderWidth: 0,
764
+ backgroundColor: "accentPrimary", // Default to contained style
765
+ borderColor: "transparent",
766
+ },
767
+ contained: {
768
+ borderRadius: "full",
769
+ borderWidth: 0,
770
+ backgroundColor: "accentPrimary", // Default background, can be overridden via style prop
771
+ borderColor: "transparent",
772
+ },
773
+ outlined: {
774
+ borderRadius: "full",
775
+ borderWidth: 2,
776
+ backgroundColor: "transparent",
777
+ borderColor: "accentPrimary", // Default border color, can be overridden via style prop
778
+ },
779
+ ghost: {
780
+ borderRadius: "full",
781
+ borderWidth: 0,
782
+ backgroundColor: "transparent",
783
+ borderColor: "transparent",
784
+ },
785
+ },
786
+ // ==========================================================================
787
+ // ICON BUTTON SIZES
788
+ // ==========================================================================
789
+ // Mathematical relationship: Icon = Container × ~45% (circularButton ratio)
790
+ //
791
+ // | Size | Container | Icon | Ratio | hitSlop | Touch Target |
792
+ // |------|-----------|------|-------|---------|--------------|
793
+ // | sm | 36px | 16px | 44% | 4px | 44px |
794
+ // | md | 44px | 20px | 45% | 0px | 44px |
795
+ // | lg | 56px | 24px | 43% | 0px | 56px |
796
+ //
797
+ // Ghost variant uses icon size for hitSlop calculation:
798
+ // | Size | Icon | hitSlop | Touch Target |
799
+ // |------|------|---------|--------------|
800
+ // | sm | 16px | 14px | 44px |
801
+ // | md | 20px | 12px | 44px |
802
+ // | lg | 24px | 10px | 44px |
803
+ //
804
+ // See: tokens/scales.ts ICON_BUTTON_ICON_SIZE, ICON_BUTTON_HIT_SLOP
805
+ iconButtonSizes: {
806
+ defaults: {
807
+ width: 44,
808
+ height: 44,
809
+ alignItems: "center",
810
+ justifyContent: "center",
811
+ },
812
+ sm: {
813
+ width: 36,
814
+ height: 36,
815
+ },
816
+ md: {
817
+ width: 44,
818
+ height: 44,
819
+ },
820
+ lg: {
821
+ width: 56,
822
+ height: 56,
823
+ },
824
+ },
825
+ // ==========================================================================
826
+ // PROGRESS BAR SIZES
827
+ // ==========================================================================
828
+ // Height scales for progress bar track
829
+ //
830
+ // | Size | Height | Border Radius | Use Case |
831
+ // |------|--------|---------------|----------|
832
+ // | sm | 4px | 2px | Inline, compact indicators |
833
+ // | md | 8px | 4px | Standard progress bars |
834
+ // | lg | 12px | 6px | Prominent indicators |
835
+ //
836
+ // See: ProgressBar.helpers.ts PROGRESS_BAR_HEIGHTS
837
+ progressBarSizes: {
838
+ defaults: {
839
+ height: 8,
840
+ width: "100%",
841
+ },
842
+ sm: {
843
+ height: 4,
844
+ },
845
+ md: {
846
+ height: 8,
847
+ },
848
+ lg: {
849
+ height: 12,
850
+ },
851
+ },
852
+ // NOTE: progressBarVariants removed — ProgressBar now accepts a `color` prop
853
+ // (RestyleColor) instead of a variant key. Track background is always "borderSubtle".
854
+ // ==========================================================================
855
+ // SPINNER SIZES
856
+ // ==========================================================================
857
+ // Maps to React Native ActivityIndicator sizes
858
+ //
859
+ // | Size | ActivityIndicator | Use Case |
860
+ // |------|-------------------|----------|
861
+ // | sm | "small" | Inline loading, buttons |
862
+ // | lg | "large" | Full-screen loading, cards |
863
+ spinnerSizes: {
864
+ defaults: {},
865
+ sm: {},
866
+ lg: {},
867
+ },
868
+ // ==========================================================================
869
+ // AVATAR SIZES
870
+ // ==========================================================================
871
+ // Profile images with fallback initials following 8px grid
872
+ //
873
+ // | Size | Dimensions | Font | Use Case |
874
+ // |------|------------|------|----------|
875
+ // | sm | 32×32 | 12px | Compact lists, comments |
876
+ // | md | 40×40 | 14px | Standard avatar (default) |
877
+ // | lg | 56×56 | 20px | Profile headers, featured |
878
+ avatarSizes: {
879
+ defaults: {
880
+ borderRadius: "full",
881
+ alignItems: "center",
882
+ justifyContent: "center",
883
+ },
884
+ sm: {
885
+ width: 32,
886
+ height: 32,
887
+ },
888
+ md: {
889
+ width: 40,
890
+ height: 40,
891
+ },
892
+ lg: {
893
+ width: 56,
894
+ height: 56,
895
+ },
896
+ },
897
+ // ==========================================================================
898
+ // SKELETON VARIANTS
899
+ // ==========================================================================
900
+ // Shape variants for Skeleton. Actual border-radius/dimension logic
901
+ // is resolved in Skeleton.helpers.ts; keys establish the type contract.
902
+ //
903
+ // | Variant | Shape | Use Case |
904
+ // |--------------|-------------------|----------|
905
+ // | text | Rounded rectangle | Text placeholders |
906
+ // | circular | Circle | Avatar/icon placeholders |
907
+ // | rectangular | Sharp corners | Image/card placeholders |
908
+ skeletonVariants: {
909
+ defaults: {},
910
+ text: {},
911
+ circular: {},
912
+ rectangular: {},
913
+ },
914
+ // ==========================================================================
915
+ // SKELETON SIZES
916
+ // ==========================================================================
917
+ // Size presets for Skeleton. Actual dimensions vary by variant
918
+ // and are resolved in Skeleton.helpers.ts.
919
+ //
920
+ // | Size | Text Height | Circular | Rectangular | Use Case |
921
+ // |------|-------------|----------|-------------|----------|
922
+ // | sm | 16px | 32px | 80px | Compact elements |
923
+ // | md | 20px | 48px | 120px | Standard content |
924
+ // | lg | 28px | 64px | 160px | Headings/prominent |
925
+ skeletonSizes: {
926
+ defaults: {},
927
+ sm: {},
928
+ md: {},
929
+ lg: {},
930
+ },
931
+ // ==========================================================================
932
+ // CHIP SIZES
933
+ // ==========================================================================
934
+ // Compact elements for tags, filters, and selections
935
+ // Professional sizing: 28/32/40px with optimal density-to-usability ratio
936
+ //
937
+ // | Size | Height | Padding H | Icon | Text Variant | Use Case |
938
+ // |------|--------|-----------|------|--------------|----------|
939
+ // | sm | 28px | sm (8px) | xs | captionSmall | Dense UIs, compact tags |
940
+ // | md | 32px | md (12px) | sm | labelSmall | Standard (default) |
941
+ // | lg | 40px | lg (16px) | md | labelMedium | Prominent filters |
942
+ chipSizes: {
943
+ defaults: {
944
+ borderRadius: "full",
945
+ alignItems: "center",
946
+ justifyContent: "center",
947
+ flexDirection: "row",
948
+ gap: "xs",
949
+ },
950
+ sm: {
951
+ height: 28,
952
+ paddingHorizontal: "sm",
953
+ },
954
+ md: {
955
+ height: 32,
956
+ paddingHorizontal: "md",
957
+ },
958
+ lg: {
959
+ height: 40,
960
+ paddingHorizontal: "lg",
961
+ },
962
+ },
963
+ // Chip variants - visual styles (colors handled dynamically via logic hook)
964
+ chipVariants: {
965
+ defaults: {
966
+ borderRadius: "full",
967
+ borderWidth: 0,
968
+ },
969
+ filled: {
970
+ borderWidth: 0,
971
+ },
972
+ outlined: {
973
+ borderWidth: 1.5,
974
+ backgroundColor: "transparent",
975
+ },
976
+ },
977
+ // ==========================================================================
978
+ // BADGE SIZES
979
+ // ==========================================================================
980
+ // Compact status indicators, counts, and labels
981
+ // Heights follow 4px grid: 16/20/24px for visual consistency
982
+ //
983
+ // | Size | Height | Min Width | Dot Size | Padding H | Use Case |
984
+ // |------|--------|-----------|----------|-----------|----------|
985
+ // | sm | 16px | 16px | 6px | 2xs (2px) | Inline indicators |
986
+ // | md | 20px | 20px | 8px | xs (4px) | Standard (default) |
987
+ // | lg | 24px | 24px | 10px | sm (8px) | Prominent badges |
988
+ badgeSizes: {
989
+ defaults: {
990
+ borderRadius: "full",
991
+ alignItems: "center",
992
+ justifyContent: "center",
993
+ },
994
+ sm: {
995
+ height: 16,
996
+ minWidth: 16,
997
+ paddingHorizontal: "2xs",
998
+ },
999
+ md: {
1000
+ height: 20,
1001
+ minWidth: 20,
1002
+ paddingHorizontal: "xs",
1003
+ },
1004
+ lg: {
1005
+ height: 24,
1006
+ minWidth: 24,
1007
+ paddingHorizontal: "sm",
1008
+ },
1009
+ },
1010
+ // Badge variants - visual styles (colors handled dynamically via logic hook)
1011
+ badgeVariants: {
1012
+ defaults: {
1013
+ borderRadius: "full",
1014
+ borderWidth: 0,
1015
+ },
1016
+ filled: {
1017
+ borderWidth: 0,
1018
+ },
1019
+ outlined: {
1020
+ borderWidth: 1.5,
1021
+ backgroundColor: "transparent",
1022
+ },
1023
+ },
1024
+ // ==========================================================================
1025
+ // LIST ITEM SIZES
1026
+ // ==========================================================================
1027
+ // Flexible list item with leading/trailing content slots
1028
+ //
1029
+ // | Size | Min Height | Padding V | Padding H | Use Case |
1030
+ // |------|------------|-----------|-----------|----------|
1031
+ // | sm | 44px | xs (4px) | md (12px) | Compact lists, dense UIs |
1032
+ // | md | 56px | sm (8px) | md (12px) | Standard (default) |
1033
+ // | lg | 72px | md (12px) | lg (16px) | Prominent items, settings |
1034
+ listItemSizes: {
1035
+ defaults: {
1036
+ minHeight: 56,
1037
+ paddingHorizontal: "md",
1038
+ paddingVertical: "sm",
1039
+ },
1040
+ sm: {
1041
+ minHeight: 44,
1042
+ paddingHorizontal: "md",
1043
+ paddingVertical: "xs",
1044
+ },
1045
+ md: {
1046
+ minHeight: 56,
1047
+ paddingHorizontal: "md",
1048
+ paddingVertical: "sm",
1049
+ },
1050
+ lg: {
1051
+ minHeight: 72,
1052
+ paddingHorizontal: "lg",
1053
+ paddingVertical: "md",
1054
+ },
1055
+ },
1056
+ // ==========================================================================
1057
+ // TOAST VARIANTS
1058
+ // ==========================================================================
1059
+ // Toast notifications for user feedback
1060
+ // Consistent 48px min-height for comfortable reading and touch dismissal
1061
+ //
1062
+ // | Variant | Use Case |
1063
+ // |---------|----------|
1064
+ // | success | Positive feedback, operation completed |
1065
+ // | error | Error state, operation failed |
1066
+ // | warning | Caution, potential issue |
1067
+ // | info | Informational message |
1068
+ //
1069
+ // Colors are applied dynamically via component logic for theme awareness
1070
+ toastVariants: {
1071
+ defaults: {
1072
+ borderRadius: "md",
1073
+ borderWidth: 1,
1074
+ padding: "sm",
1075
+ flexDirection: "row",
1076
+ alignItems: "center",
1077
+ gap: "sm",
1078
+ minHeight: 48,
1079
+ },
1080
+ success: {},
1081
+ error: {},
1082
+ warning: {},
1083
+ info: {},
1084
+ },
1085
+ // ==========================================================================
1086
+ // DIVIDER VARIANTS
1087
+ // ==========================================================================
1088
+ // Visual separators for content sections
1089
+ //
1090
+ // | Variant | Color | Use Case |
1091
+ // |---------|-------|----------|
1092
+ // | subtle | borderSubtle | Light separation (default) |
1093
+ // | default | borderDefault | Standard separation |
1094
+ // | strong | borderStrong | Prominent separation |
1095
+ dividerVariants: {
1096
+ defaults: {},
1097
+ subtle: {
1098
+ backgroundColor: "borderSubtle",
1099
+ },
1100
+ default: {
1101
+ backgroundColor: "borderDefault",
1102
+ },
1103
+ strong: {
1104
+ backgroundColor: "borderStrong",
1105
+ },
1106
+ },
1107
+ // Divider thickness sizes
1108
+ dividerSizes: {
1109
+ defaults: {},
1110
+ thin: {
1111
+ height: 1,
1112
+ },
1113
+ medium: {
1114
+ height: 2,
1115
+ },
1116
+ thick: {
1117
+ height: 4,
1118
+ },
1119
+ },
1120
+ // ==========================================================================
1121
+ // CALENDAR STRIP SIZES
1122
+ // ==========================================================================
1123
+ // Horizontal row of tappable day cards
1124
+ //
1125
+ // | Size | Container Gap | Day Padding V | Day Number | Label |
1126
+ // |------|---------------|---------------|-------------|-------------|
1127
+ // | sm | xs (4px) | xs (4px) | labelSmall | captionSmall|
1128
+ // | md | md (12px) | md (12px) | labelMedium | captionSmall|
1129
+ // | lg | lg (16px) | lg (16px) | labelLarge | caption |
1130
+ // ScheduleItem sizes
1131
+ // | Size | Padding | Indicator H | Content Gap | Title | Time |
1132
+ // | sm | xs | 32px | 2xs | labelSmall | captionSmall |
1133
+ // | md | sm | 48px | 2xs | labelSmall | captionSmall |
1134
+ // | lg | md | 64px | xs | labelMedium | bodySmall |
1135
+ scheduleItemSizes: {
1136
+ defaults: {
1137
+ flexDirection: "row",
1138
+ alignItems: "center",
1139
+ borderRadius: "sm",
1140
+ backgroundColor: "backgroundSecondary",
1141
+ gap: "sm",
1142
+ },
1143
+ sm: { padding: "xs" },
1144
+ md: { padding: "sm" },
1145
+ lg: { padding: "md" },
1146
+ },
1147
+
1148
+ calendarStripSizes: {
1149
+ defaults: {
1150
+ flexDirection: "row",
1151
+ },
1152
+ sm: {
1153
+ gap: "xs",
1154
+ },
1155
+ md: {
1156
+ gap: "md",
1157
+ },
1158
+ lg: {
1159
+ gap: "lg",
1160
+ },
1161
+ },
1162
+ // ==========================================================================
1163
+ // EMPTY STATE SIZES
1164
+ // ==========================================================================
1165
+ // Centered empty state layouts
1166
+ //
1167
+ // | Variant | Icon Size | Title | Description | Padding | Use Case |
1168
+ // |---------|-----------|-------|-------------|---------|----------|
1169
+ // | default | xl (32px) | headingSmall | bodyMedium | xl | Full-page states |
1170
+ // | compact | lg (24px) | labelLarge | bodySmall | lg | Card/section states |
1171
+ emptyStateSizes: {
1172
+ defaults: {
1173
+ alignItems: "center",
1174
+ justifyContent: "center",
1175
+ flex: 1,
1176
+ },
1177
+ default: {
1178
+ padding: "xl",
1179
+ gap: "lg",
1180
+ },
1181
+ compact: {
1182
+ padding: "lg",
1183
+ gap: "md",
1184
+ },
1185
+ },
1186
+ // ==========================================================================
1187
+ // EMPTY STATE VARIANTS
1188
+ // ==========================================================================
1189
+ // Visual style variants for EmptyState. Layout dimensions live in
1190
+ // emptyStateSizes above; keys here provide the variant type contract
1191
+ // so EmptyStateVariant derives from the theme.
1192
+ //
1193
+ // | Variant | Padding | Gap | Title | Description | Use Case |
1194
+ // |---------|---------|-----|--------------|--------------|----------|
1195
+ // | default | xl | lg | headingSmall | bodyMedium | Full-page states |
1196
+ // | compact | lg | md | labelLarge | bodySmall | Card/section states |
1197
+ emptyStateVariants: {
1198
+ defaults: {},
1199
+ default: {},
1200
+ compact: {},
1201
+ },
1202
+ // ==========================================================================
1203
+ // SEGMENTED CONTROL SIZES
1204
+ // ==========================================================================
1205
+ // Toggle between multiple options - professional sizing with 44px touch target
1206
+ // Container heights: 36/44/52px matching button scale for visual harmony
1207
+ //
1208
+ // | Size | Height | Segment H | Padding | Gap | Text Variant | Use Case |
1209
+ // |------|--------|-----------|---------|-----|--------------|----------|
1210
+ // | sm | 36px | 28px | xs | 2xs | labelSmall | Compact filters |
1211
+ // | md | 44px | 36px | xs | 2xs | labelMedium | Standard (default) |
1212
+ // | lg | 52px | 44px | sm | xs | labelLarge | Prominent controls |
1213
+ segmentedControlSizes: {
1214
+ defaults: {
1215
+ borderRadius: "lg",
1216
+ flexDirection: "row",
1217
+ alignItems: "center",
1218
+ },
1219
+ sm: {
1220
+ height: 36,
1221
+ padding: "xs",
1222
+ gap: "2xs",
1223
+ },
1224
+ md: {
1225
+ height: 44,
1226
+ padding: "xs",
1227
+ gap: "2xs",
1228
+ },
1229
+ lg: {
1230
+ height: 52,
1231
+ padding: "sm",
1232
+ gap: "xs",
1233
+ },
1234
+ },
1235
+ // Segmented control segment sizes (inner segment dimensions)
1236
+ segmentedControlSegmentSizes: {
1237
+ defaults: {
1238
+ borderRadius: "md",
1239
+ alignItems: "center",
1240
+ justifyContent: "center",
1241
+ flex: 1,
1242
+ },
1243
+ sm: {
1244
+ height: 28,
1245
+ paddingHorizontal: "sm",
1246
+ },
1247
+ md: {
1248
+ height: 36,
1249
+ paddingHorizontal: "md",
1250
+ },
1251
+ lg: {
1252
+ height: 44,
1253
+ paddingHorizontal: "lg",
1254
+ },
1255
+ },
1256
+ // Segmented control variants - visual styles for container
1257
+ segmentedControlVariants: {
1258
+ defaults: {
1259
+ borderRadius: "lg",
1260
+ borderWidth: 0,
1261
+ },
1262
+ default: {
1263
+ backgroundColor: "backgroundTertiary",
1264
+ borderWidth: 0,
1265
+ },
1266
+ outline: {
1267
+ backgroundColor: "transparent",
1268
+ borderWidth: 1.5,
1269
+ borderColor: "borderDefault",
1270
+ },
1271
+ },
1272
+ });
1273
+
1274
+ // =============================================================================
1275
+ // RESTYLE THEMES
1276
+ // =============================================================================
1277
+
1278
+ export const restyleLightTheme = createTheme(
1279
+ createBaseThemeConfig(lightColors),
1280
+ );
1281
+ export const restyleDarkTheme = createTheme(createBaseThemeConfig(darkColors));
1282
+
1283
+ // Default export for backwards compatibility
1284
+ export const restyleTheme = restyleLightTheme;
1285
+
1286
+ export type RestyleTheme = typeof restyleLightTheme;
1287
+
1288
+ /**
1289
+ * Augmentable interface for app-specific color tokens.
1290
+ *
1291
+ * Apps extend the design system palette by augmenting this interface
1292
+ * via TypeScript declaration merging. Once augmented, the new color
1293
+ * token names are accepted by components whose color prop uses
1294
+ * `AppThemeColors` (e.g. Chip).
1295
+ *
1296
+ * @example
1297
+ * ```ts
1298
+ * // app-theme.d.ts (in your app, NOT in the package)
1299
+ * declare module "@praxiis/ui" {
1300
+ * interface AppThemeColors {
1301
+ * brandOrange: string;
1302
+ * brandTeal: string;
1303
+ * }
1304
+ * }
1305
+ * ```
1306
+ *
1307
+ * At runtime, provide a theme with matching color keys via
1308
+ * `<DesignSystemProvider lightTheme={...} darkTheme={...}>`.
1309
+ */
1310
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
1311
+ export interface AppThemeColors {}
1312
+
1313
+ /**
1314
+ * Build a Restyle theme entirely from scratch.
1315
+ *
1316
+ * Use this when you want to define every color yourself with no defaults merged in.
1317
+ * Provide a complete SemanticColors object (same shape as lightSemanticColors /
1318
+ * darkSemanticColors) and get back a fully configured RestyleTheme.
1319
+ *
1320
+ * @example
1321
+ * const myLight = buildRestyleTheme({ background: { primary: '#fff', ... }, ... });
1322
+ */
1323
+ export function buildRestyleTheme(
1324
+ colors: SemanticColorsInput,
1325
+ ): typeof restyleLightTheme {
1326
+ return createTheme(createBaseThemeConfig(flattenColors(colors)));
1327
+ }
1328
+
1329
+ /**
1330
+ * Build a Restyle theme from ThemeColors overrides.
1331
+ * Merges overrides into the base semantic colors, keeping base primitives intact.
1332
+ */
1333
+ export function buildRestyleThemeFromThemeColors(
1334
+ baseSemanticColors: SemanticColorsInput,
1335
+ overrides: DeepPartial<ThemeColors>,
1336
+ ): typeof restyleLightTheme {
1337
+ const merged = {
1338
+ ...baseSemanticColors,
1339
+ background: { ...baseSemanticColors.background, ...overrides.background },
1340
+ surface: { ...baseSemanticColors.surface, ...overrides.surface },
1341
+ text: { ...baseSemanticColors.text, ...overrides.text },
1342
+ border: { ...baseSemanticColors.border, ...overrides.border },
1343
+ accent: { ...baseSemanticColors.accent, ...overrides.accent },
1344
+ interactive: {
1345
+ ...baseSemanticColors.interactive,
1346
+ ...overrides.interactive,
1347
+ },
1348
+ feedback: { ...baseSemanticColors.feedback, ...overrides.feedback },
1349
+ special: { ...baseSemanticColors.special, ...overrides.special },
1350
+ };
1351
+ return createTheme(createBaseThemeConfig(flattenColors(merged)));
1352
+ }