@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,251 @@
1
+ /**
2
+ * StayEasy Design System - Typography Tokens
3
+ *
4
+ * Typography philosophy:
5
+ * - System fonts first for performance and native feel
6
+ * - Clear hierarchy with distinct sizes
7
+ * - Generous line heights for readability
8
+ * - Consistent letter spacing
9
+ *
10
+ * @example
11
+ * <Text variant="bodyLarge">Content</Text>
12
+ */
13
+
14
+ import { Platform, TextStyle } from 'react-native';
15
+
16
+ // =============================================================================
17
+ // FONT FAMILIES
18
+ // =============================================================================
19
+
20
+ /**
21
+ * System font stack
22
+ * Uses platform-native fonts for optimal performance and native feel
23
+ */
24
+ export const fontFamily = {
25
+ // Primary system font
26
+ regular: Platform.select({
27
+ ios: 'System',
28
+ android: 'Roboto',
29
+ default: 'System',
30
+ }),
31
+
32
+ // Medium weight
33
+ medium: Platform.select({
34
+ ios: 'System',
35
+ android: 'Roboto-Medium',
36
+ default: 'System',
37
+ }),
38
+
39
+ // Semibold weight
40
+ semibold: Platform.select({
41
+ ios: 'System',
42
+ android: 'Roboto-Medium', // Android doesn't have semibold
43
+ default: 'System',
44
+ }),
45
+
46
+ // Bold weight
47
+ bold: Platform.select({
48
+ ios: 'System',
49
+ android: 'Roboto-Bold',
50
+ default: 'System',
51
+ }),
52
+
53
+ // Monospace (for code snippets)
54
+ mono: Platform.select({
55
+ ios: 'Menlo',
56
+ android: 'monospace',
57
+ default: 'monospace',
58
+ }),
59
+ } as const;
60
+
61
+ // =============================================================================
62
+ // FONT WEIGHTS
63
+ // =============================================================================
64
+
65
+ export const fontWeight = {
66
+ regular: '400' as TextStyle['fontWeight'],
67
+ medium: '500' as TextStyle['fontWeight'],
68
+ semibold: '600' as TextStyle['fontWeight'],
69
+ bold: '700' as TextStyle['fontWeight'],
70
+ } as const;
71
+
72
+ // =============================================================================
73
+ // FONT SIZES (in points)
74
+ // =============================================================================
75
+
76
+ export const fontSize = {
77
+ xs: 11,
78
+ sm: 13,
79
+ md: 15,
80
+ lg: 17,
81
+ xl: 20,
82
+ '2xl': 24,
83
+ '3xl': 30,
84
+ '4xl': 36,
85
+ '5xl': 48,
86
+ } as const;
87
+
88
+ // =============================================================================
89
+ // LINE HEIGHTS
90
+ // =============================================================================
91
+
92
+ export const lineHeight = {
93
+ tight: 1.2, // Headings
94
+ snug: 1.375, // Subheadings
95
+ normal: 1.5, // Body text
96
+ relaxed: 1.625, // Long-form reading
97
+ loose: 2, // Special cases
98
+ } as const;
99
+
100
+ // Computed line heights (fontSize * multiplier)
101
+ export const lineHeightValues = {
102
+ xs: Math.round(fontSize.xs * lineHeight.normal), // 17
103
+ sm: Math.round(fontSize.sm * lineHeight.normal), // 20
104
+ md: Math.round(fontSize.md * lineHeight.normal), // 23
105
+ lg: Math.round(fontSize.lg * lineHeight.normal), // 26
106
+ xl: Math.round(fontSize.xl * lineHeight.snug), // 28
107
+ '2xl': Math.round(fontSize['2xl'] * lineHeight.snug), // 33
108
+ '3xl': Math.round(fontSize['3xl'] * lineHeight.tight), // 36
109
+ '4xl': Math.round(fontSize['4xl'] * lineHeight.tight), // 43
110
+ '5xl': Math.round(fontSize['5xl'] * lineHeight.tight), // 58
111
+ } as const;
112
+
113
+ // =============================================================================
114
+ // LETTER SPACING
115
+ // =============================================================================
116
+
117
+ export const letterSpacing = {
118
+ tighter: -0.8,
119
+ tight: -0.4,
120
+ normal: 0,
121
+ wide: 0.4,
122
+ wider: 0.8,
123
+ widest: 1.6,
124
+ } as const;
125
+
126
+ // =============================================================================
127
+ // TYPOGRAPHY PRESETS
128
+ // =============================================================================
129
+
130
+ export const typographyPresets = {
131
+ // Display styles (heroes, splash screens)
132
+ displayLarge: {
133
+ fontSize: fontSize['5xl'],
134
+ lineHeight: lineHeightValues['5xl'],
135
+ fontWeight: fontWeight.bold,
136
+ letterSpacing: letterSpacing.tighter,
137
+ },
138
+ displayMedium: {
139
+ fontSize: fontSize['4xl'],
140
+ lineHeight: lineHeightValues['4xl'],
141
+ fontWeight: fontWeight.bold,
142
+ letterSpacing: letterSpacing.tighter,
143
+ },
144
+ displaySmall: {
145
+ fontSize: fontSize['3xl'],
146
+ lineHeight: lineHeightValues['3xl'],
147
+ fontWeight: fontWeight.bold,
148
+ letterSpacing: letterSpacing.tight,
149
+ },
150
+
151
+ // Heading styles
152
+ headingLarge: {
153
+ fontSize: fontSize['2xl'],
154
+ lineHeight: lineHeightValues['2xl'],
155
+ fontWeight: fontWeight.semibold,
156
+ letterSpacing: letterSpacing.tight,
157
+ },
158
+ headingMedium: {
159
+ fontSize: fontSize.xl,
160
+ lineHeight: lineHeightValues.xl,
161
+ fontWeight: fontWeight.semibold,
162
+ letterSpacing: letterSpacing.tight,
163
+ },
164
+ headingSmall: {
165
+ fontSize: fontSize.lg,
166
+ lineHeight: lineHeightValues.lg,
167
+ fontWeight: fontWeight.semibold,
168
+ letterSpacing: letterSpacing.normal,
169
+ },
170
+
171
+ // Body styles
172
+ bodyLarge: {
173
+ fontSize: fontSize.lg,
174
+ lineHeight: lineHeightValues.lg,
175
+ fontWeight: fontWeight.regular,
176
+ letterSpacing: letterSpacing.normal,
177
+ },
178
+ bodyMedium: {
179
+ fontSize: fontSize.md,
180
+ lineHeight: lineHeightValues.md,
181
+ fontWeight: fontWeight.regular,
182
+ letterSpacing: letterSpacing.normal,
183
+ },
184
+ bodySmall: {
185
+ fontSize: fontSize.sm,
186
+ lineHeight: lineHeightValues.sm,
187
+ fontWeight: fontWeight.regular,
188
+ letterSpacing: letterSpacing.normal,
189
+ },
190
+
191
+ // Label styles (buttons, form labels)
192
+ labelLarge: {
193
+ fontSize: fontSize.lg,
194
+ lineHeight: lineHeightValues.lg,
195
+ fontWeight: fontWeight.medium,
196
+ letterSpacing: letterSpacing.normal,
197
+ },
198
+ labelMedium: {
199
+ fontSize: fontSize.md,
200
+ lineHeight: lineHeightValues.md,
201
+ fontWeight: fontWeight.medium,
202
+ letterSpacing: letterSpacing.wide,
203
+ },
204
+ labelSmall: {
205
+ fontSize: fontSize.sm,
206
+ lineHeight: lineHeightValues.sm,
207
+ fontWeight: fontWeight.medium,
208
+ letterSpacing: letterSpacing.wide,
209
+ },
210
+
211
+ // Caption styles
212
+ caption: {
213
+ fontSize: fontSize.sm,
214
+ lineHeight: lineHeightValues.sm,
215
+ fontWeight: fontWeight.regular,
216
+ letterSpacing: letterSpacing.wide,
217
+ },
218
+ captionSmall: {
219
+ fontSize: fontSize.xs,
220
+ lineHeight: lineHeightValues.xs,
221
+ fontWeight: fontWeight.regular,
222
+ letterSpacing: letterSpacing.wide,
223
+ },
224
+
225
+ // Overline (small uppercase labels)
226
+ overline: {
227
+ fontSize: fontSize.xs,
228
+ lineHeight: lineHeightValues.xs,
229
+ fontWeight: fontWeight.semibold,
230
+ letterSpacing: letterSpacing.widest,
231
+ textTransform: 'uppercase' as TextStyle['textTransform'],
232
+ },
233
+
234
+ // Code/mono styles
235
+ code: {
236
+ fontSize: fontSize.sm,
237
+ lineHeight: lineHeightValues.sm,
238
+ fontWeight: fontWeight.regular,
239
+ letterSpacing: letterSpacing.normal,
240
+ },
241
+ } as const;
242
+
243
+ // =============================================================================
244
+ // TYPE EXPORTS
245
+ // =============================================================================
246
+
247
+ export type FontFamily = typeof fontFamily;
248
+ export type FontWeight = typeof fontWeight;
249
+ export type FontSize = typeof fontSize;
250
+ export type TypographyPresets = typeof typographyPresets;
251
+ export type TypographyVariant = keyof typeof typographyPresets;
package/src/types.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * El Sendero Design System - Shared Types
3
+ *
4
+ * Types shared across the entire design system that can be used
5
+ * throughout the application.
6
+ */
7
+
8
+ import MaterialIcons from "@expo/vector-icons/MaterialIcons";
9
+ import { RestyleTheme, AppThemeColors } from "./core/restyle";
10
+
11
+ /**
12
+ * Material Design icon name (strongly typed from @expo/vector-icons/MaterialIcons)
13
+ *
14
+ * This type represents all available Material Icons from the Material Icons library.
15
+ * It is used throughout the design system for icon-based components.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * import { MaterialIconName } from '@/src/design-system';
20
+ *
21
+ * const iconName: MaterialIconName = 'add';
22
+ * ```
23
+ */
24
+ export type MaterialIconName = keyof typeof MaterialIcons.glyphMap;
25
+
26
+ /**
27
+ * Built-in theme color type — only the colors defined in the base Restyle theme.
28
+ * Used internally by components when passing color tokens to Restyle primitives
29
+ * (Box, Text, etc.) which are typed against the base theme.
30
+ *
31
+ * @internal
32
+ */
33
+ export type BaseThemeColor = keyof RestyleTheme["colors"];
34
+
35
+ /**
36
+ * Restyle color type — represents all available colors in the design system theme,
37
+ * including any app-specific tokens registered via `AppThemeColors` augmentation.
38
+ *
39
+ * This unified type is used across all components that accept a color prop.
40
+ * Apps extend the palette by augmenting `AppThemeColors` in a `.d.ts` file
41
+ * and providing a matching theme to `DesignSystemProvider`.
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import { RestyleColor } from '@praxiis/ui';
46
+ *
47
+ * const color: RestyleColor = 'accentPrimary';
48
+ * ```
49
+ */
50
+ export type RestyleColor = keyof RestyleTheme["colors"] | keyof AppThemeColors;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * StayEasy Design System - Accessibility Utilities
3
+ *
4
+ * Helpers for building accessible components.
5
+ */
6
+
7
+ import { AccessibilityRole, AccessibilityState } from "react-native";
8
+
9
+ /**
10
+ * Common accessibility roles mapped to their purposes
11
+ */
12
+ export const a11yRoles = {
13
+ button: "button" as AccessibilityRole,
14
+ link: "link" as AccessibilityRole,
15
+ search: "search" as AccessibilityRole,
16
+ image: "image" as AccessibilityRole,
17
+ header: "header" as AccessibilityRole,
18
+ text: "text" as AccessibilityRole,
19
+ checkbox: "checkbox" as AccessibilityRole,
20
+ slider: "adjustable" as AccessibilityRole,
21
+ tab: "tab" as AccessibilityRole,
22
+ tablist: "tablist" as AccessibilityRole,
23
+ menu: "menu" as AccessibilityRole,
24
+ menuitem: "menuitem" as AccessibilityRole,
25
+ progressbar: "progressbar" as AccessibilityRole,
26
+ alert: "alert" as AccessibilityRole,
27
+ none: "none" as AccessibilityRole,
28
+ };
29
+
30
+ /**
31
+ * Create accessibility state object
32
+ *
33
+ * @example
34
+ * <Pressable accessibilityState={a11yState({ selected: isSelected, disabled })} />
35
+ */
36
+ export function a11yState(state: {
37
+ disabled?: boolean;
38
+ selected?: boolean;
39
+ checked?: boolean | "mixed";
40
+ busy?: boolean;
41
+ expanded?: boolean;
42
+ }): AccessibilityState {
43
+ return state;
44
+ }
45
+
46
+ /**
47
+ * Generate accessibility props for a button
48
+ */
49
+ export function buttonA11yProps(options: {
50
+ label: string;
51
+ hint?: string;
52
+ disabled?: boolean;
53
+ }) {
54
+ return {
55
+ accessible: true,
56
+ accessibilityRole: a11yRoles.button,
57
+ accessibilityLabel: options.label,
58
+ accessibilityHint: options.hint,
59
+ accessibilityState: a11yState({ disabled: options.disabled }),
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Generate accessibility props for a checkbox
65
+ */
66
+ export function checkboxA11yProps(options: {
67
+ label: string;
68
+ checked: boolean;
69
+ disabled?: boolean;
70
+ }) {
71
+ return {
72
+ accessible: true,
73
+ accessibilityRole: a11yRoles.checkbox,
74
+ accessibilityLabel: options.label,
75
+ accessibilityState: a11yState({
76
+ checked: options.checked,
77
+ disabled: options.disabled,
78
+ }),
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Generate accessibility props for an image
84
+ */
85
+ export function imageA11yProps(options: {
86
+ label: string;
87
+ isDecorative?: boolean;
88
+ }) {
89
+ if (options.isDecorative) {
90
+ return {
91
+ accessible: false,
92
+ accessibilityElementsHidden: true,
93
+ importantForAccessibility: "no-hide-descendants" as const,
94
+ };
95
+ }
96
+
97
+ return {
98
+ accessible: true,
99
+ accessibilityRole: a11yRoles.image,
100
+ accessibilityLabel: options.label,
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Generate accessibility props for a heading
106
+ */
107
+ export function headingA11yProps(
108
+ options: { level?: 1 | 2 | 3 | 4 | 5 | 6 } = {}
109
+ ) {
110
+ return {
111
+ accessible: true,
112
+ accessibilityRole: a11yRoles.header,
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Calculate if a color combination meets WCAG contrast requirements
118
+ * Returns approximate ratio (not perfect but useful for dev-time checks)
119
+ *
120
+ * @param foreground - Hex color string
121
+ * @param background - Hex color string
122
+ * @returns Approximate contrast ratio
123
+ */
124
+ export function getContrastRatio(
125
+ foreground: string,
126
+ background: string
127
+ ): number {
128
+ const getLuminance = (hex: string): number => {
129
+ const rgb = hex
130
+ .replace("#", "")
131
+ .match(/.{2}/g)
132
+ ?.map((c) => {
133
+ const val = parseInt(c, 16) / 255;
134
+ return val <= 0.03928
135
+ ? val / 12.92
136
+ : Math.pow((val + 0.055) / 1.055, 2.4);
137
+ });
138
+
139
+ if (!rgb) return 0;
140
+ return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
141
+ };
142
+
143
+ const l1 = getLuminance(foreground);
144
+ const l2 = getLuminance(background);
145
+ const lighter = Math.max(l1, l2);
146
+ const darker = Math.min(l1, l2);
147
+
148
+ return (lighter + 0.05) / (darker + 0.05);
149
+ }
150
+
151
+ /**
152
+ * Check if contrast meets WCAG AA for normal text (4.5:1)
153
+ */
154
+ export function meetsContrastAA(
155
+ foreground: string,
156
+ background: string
157
+ ): boolean {
158
+ return getContrastRatio(foreground, background) >= 4.5;
159
+ }
160
+
161
+ /**
162
+ * Check if contrast meets WCAG AA for large text (3:1)
163
+ */
164
+ export function meetsContrastAALarge(
165
+ foreground: string,
166
+ background: string
167
+ ): boolean {
168
+ return getContrastRatio(foreground, background) >= 3;
169
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * StayEasy Design System - Utils Exports
3
+ */
4
+
5
+ export {
6
+ isIOS,
7
+ isAndroid,
8
+ platformSelect,
9
+ iosOnly,
10
+ androidOnly,
11
+ getStatusBarHeight,
12
+ MIN_TOUCH_TARGET,
13
+ } from './platform';
14
+
15
+ export {
16
+ a11yRoles,
17
+ a11yState,
18
+ buttonA11yProps,
19
+ checkboxA11yProps,
20
+ imageA11yProps,
21
+ headingA11yProps,
22
+ getContrastRatio,
23
+ meetsContrastAA,
24
+ meetsContrastAALarge,
25
+ } from './accessibility';
@@ -0,0 +1,72 @@
1
+ /**
2
+ * StayEasy Design System - Platform Utilities
3
+ *
4
+ * Cross-platform helpers for consistent behavior across iOS and Android.
5
+ */
6
+
7
+ import { Platform } from 'react-native';
8
+
9
+ /**
10
+ * Check if running on iOS
11
+ */
12
+ export const isIOS = Platform.OS === 'ios';
13
+
14
+ /**
15
+ * Check if running on Android
16
+ */
17
+ export const isAndroid = Platform.OS === 'android';
18
+
19
+ /**
20
+ * Get platform-specific value
21
+ *
22
+ * @example
23
+ * const padding = platformSelect({ ios: 16, android: 12 });
24
+ */
25
+ export function platformSelect<T>(specifics: { ios: T; android: T }): T {
26
+ return Platform.select(specifics) as T;
27
+ }
28
+
29
+ /**
30
+ * Apply iOS-only styles
31
+ *
32
+ * @example
33
+ * const styles = StyleSheet.create({
34
+ * container: {
35
+ * ...iosOnly({ shadowOpacity: 0.1 }),
36
+ * },
37
+ * });
38
+ */
39
+ export function iosOnly<T extends object>(styles: T): T | object {
40
+ return isIOS ? styles : {};
41
+ }
42
+
43
+ /**
44
+ * Apply Android-only styles
45
+ *
46
+ * @example
47
+ * const styles = StyleSheet.create({
48
+ * container: {
49
+ * ...androidOnly({ elevation: 4 }),
50
+ * },
51
+ * });
52
+ */
53
+ export function androidOnly<T extends object>(styles: T): T | object {
54
+ return isAndroid ? styles : {};
55
+ }
56
+
57
+ /**
58
+ * Get the status bar height for the platform
59
+ */
60
+ export function getStatusBarHeight(): number {
61
+ return Platform.select({
62
+ ios: 44, // Approximate, use SafeAreaView for accuracy
63
+ android: 24,
64
+ default: 0,
65
+ });
66
+ }
67
+
68
+ /**
69
+ * Get minimum touch target size per platform guidelines
70
+ * iOS: 44pt, Android: 48dp (we use 44 for consistency)
71
+ */
72
+ export const MIN_TOUCH_TARGET = 44;