@umituz/react-native-design-system 2.10.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "2.10.1",
3
+ "version": "2.11.0",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -158,5 +158,8 @@
158
158
  "src",
159
159
  "README.md",
160
160
  "LICENSE"
161
- ]
161
+ ],
162
+ "dependencies": {
163
+ "@umituz/react-native-design-system": "^2.10.1"
164
+ }
162
165
  }
@@ -1,38 +1,126 @@
1
1
  /**
2
2
  * Custom Colors Types
3
- *
3
+ *
4
4
  * Types for custom theme color overrides
5
+ *
6
+ * ARCHITECTURE:
7
+ * - Apps provide CustomThemeColors to DesignSystemProvider
8
+ * - These colors override the default palette
9
+ * - Supports both light and dark mode overrides
10
+ * - Apps control their own brand colors completely
11
+ *
12
+ * BEST PRACTICES (based on Shopify Restyle, React Native Paper, Tamagui):
13
+ * - All color keys are optional - only override what you need
14
+ * - Provide separate light/dark palettes for proper theme switching
15
+ * - Use semantic color names (primary, surface, etc.) not literal colors
5
16
  */
6
17
 
7
18
  import type { ColorPalette } from './ColorPalette';
8
19
  import { isValidHexColor } from './colors/ColorUtils';
9
20
 
10
21
  /**
11
- * Custom theme colors that can override default colors
22
+ * Complete custom theme colors - can override ANY color in the palette
23
+ * All properties are optional - apps only provide what they want to customize
12
24
  */
13
25
  export interface CustomThemeColors {
26
+ // PRIMARY BRAND COLORS
14
27
  primary?: string;
15
28
  primaryLight?: string;
16
29
  primaryDark?: string;
30
+
31
+ // SECONDARY COLORS
17
32
  secondary?: string;
18
33
  secondaryLight?: string;
19
34
  secondaryDark?: string;
35
+
36
+ // ACCENT COLORS
20
37
  accent?: string;
21
38
  accentLight?: string;
22
39
  accentDark?: string;
23
- buttonPrimary?: string;
24
- buttonSecondary?: string;
25
-
26
- // Background overrides
40
+
41
+ // ON-COLORS (text on colored backgrounds - CRITICAL for contrast)
42
+ onPrimary?: string;
43
+ onSecondary?: string;
44
+ onSuccess?: string;
45
+ onError?: string;
46
+ onWarning?: string;
47
+ onInfo?: string;
48
+ onSurface?: string;
49
+ onBackground?: string;
50
+ onSurfaceDisabled?: string;
51
+ onSurfaceVariant?: string;
52
+
53
+ // CONTAINER COLORS
54
+ primaryContainer?: string;
55
+ onPrimaryContainer?: string;
56
+ secondaryContainer?: string;
57
+ onSecondaryContainer?: string;
58
+ errorContainer?: string;
59
+ onErrorContainer?: string;
60
+
61
+ // OUTLINE COLORS
62
+ outline?: string;
63
+ outlineVariant?: string;
64
+ outlineDisabled?: string;
65
+
66
+ // SEMANTIC UI COLORS
67
+ success?: string;
68
+ successLight?: string;
69
+ successDark?: string;
70
+ error?: string;
71
+ errorLight?: string;
72
+ errorDark?: string;
73
+ warning?: string;
74
+ warningLight?: string;
75
+ warningDark?: string;
76
+ info?: string;
77
+ infoLight?: string;
78
+ infoDark?: string;
79
+
80
+ // SEMANTIC CONTAINER COLORS
81
+ successContainer?: string;
82
+ onSuccessContainer?: string;
83
+ warningContainer?: string;
84
+ onWarningContainer?: string;
85
+ infoContainer?: string;
86
+ onInfoContainer?: string;
87
+
88
+ // BACKGROUND COLORS
27
89
  backgroundPrimary?: string;
28
90
  backgroundSecondary?: string;
91
+
92
+ // SURFACE COLORS
29
93
  surface?: string;
30
94
  surfaceVariant?: string;
31
-
32
- // Text overrides
95
+ surfaceSecondary?: string;
96
+ surfaceDisabled?: string;
97
+
98
+ // TEXT COLORS
33
99
  textPrimary?: string;
34
100
  textSecondary?: string;
35
101
  textTertiary?: string;
102
+ textDisabled?: string;
103
+ textInverse?: string;
104
+
105
+ // BORDER COLORS
106
+ border?: string;
107
+ borderLight?: string;
108
+ borderMedium?: string;
109
+ borderFocus?: string;
110
+ borderDisabled?: string;
111
+
112
+ // COMPONENT-SPECIFIC COLORS
113
+ buttonPrimary?: string;
114
+ buttonSecondary?: string;
115
+ inputBackground?: string;
116
+ inputBorder?: string;
117
+ cardBackground?: string;
118
+
119
+ // SPECIAL & UTILITY COLORS
120
+ transparent?: string;
121
+ black?: string;
122
+ white?: string;
123
+ modalOverlay?: string;
36
124
  }
37
125
 
38
126
  /**
@@ -54,8 +142,13 @@ export const validateCustomColors = (customColors: CustomThemeColors): boolean =
54
142
 
55
143
  /**
56
144
  * Apply custom colors to color palette
57
- * @param palette - Base color palette
58
- * @param customColors - Custom colors to apply
145
+ *
146
+ * This function takes a base palette and merges custom colors into it.
147
+ * Apps can override ANY color key - the system simply spreads custom values
148
+ * over the base palette.
149
+ *
150
+ * @param palette - Base color palette (light or dark)
151
+ * @param customColors - Custom colors to apply (partial override)
59
152
  * @returns Color palette with custom colors applied
60
153
  */
61
154
  export const applyCustomColors = (
@@ -68,90 +161,65 @@ export const applyCustomColors = (
68
161
 
69
162
  // Validate custom colors
70
163
  if (!validateCustomColors(customColors)) {
164
+ if (__DEV__) {
165
+ console.warn('[DesignSystem] Invalid custom colors provided - using default palette');
166
+ }
71
167
  return palette;
72
168
  }
73
169
 
170
+ // Start with base palette
74
171
  const result: Partial<ColorPalette> = {
75
172
  ...palette,
76
173
  };
77
174
 
78
- // Apply custom primary colors
79
- if (customColors.primary) {
80
- result.primary = customColors.primary;
81
- if (!customColors.buttonPrimary) {
82
- result.buttonPrimary = customColors.primary;
83
- }
84
- }
85
- if (customColors.primaryLight) {
86
- result.primaryLight = customColors.primaryLight;
87
- }
88
- if (customColors.primaryDark) {
89
- result.primaryDark = customColors.primaryDark;
90
- }
175
+ // Apply ALL custom colors dynamically
176
+ // This approach allows any color key to be overridden
177
+ const colorKeys = Object.keys(customColors) as (keyof CustomThemeColors)[];
91
178
 
92
- // Apply custom secondary colors
93
- if (customColors.secondary) {
94
- result.secondary = customColors.secondary;
95
- if (!customColors.buttonSecondary) {
96
- result.buttonSecondary = customColors.secondary;
179
+ for (const key of colorKeys) {
180
+ const value = customColors[key];
181
+ if (value !== undefined) {
182
+ // Direct assignment for matching keys
183
+ (result as Record<string, string>)[key] = value;
97
184
  }
98
185
  }
99
- if (customColors.secondaryLight) {
100
- result.secondaryLight = customColors.secondaryLight;
101
- }
102
- if (customColors.secondaryDark) {
103
- result.secondaryDark = customColors.secondaryDark;
104
- }
105
186
 
106
- // Apply custom accent colors
107
- if (customColors.accent) {
108
- result.accent = customColors.accent;
109
- }
110
- if (customColors.accentLight) {
111
- result.accentLight = customColors.accentLight;
112
- }
113
- if (customColors.accentDark) {
114
- result.accentDark = customColors.accentDark;
187
+ // Apply smart defaults and aliases
188
+ // Primary -> buttonPrimary (if buttonPrimary not explicitly set)
189
+ if (customColors.primary && !customColors.buttonPrimary) {
190
+ result.buttonPrimary = customColors.primary;
115
191
  }
116
192
 
117
- // Apply custom button colors (override primary/secondary if set)
118
- if (customColors.buttonPrimary) {
119
- result.buttonPrimary = customColors.buttonPrimary;
120
- }
121
- if (customColors.buttonSecondary) {
122
- result.buttonSecondary = customColors.buttonSecondary;
193
+ // Secondary -> buttonSecondary (if buttonSecondary not explicitly set)
194
+ if (customColors.secondary && !customColors.buttonSecondary) {
195
+ result.buttonSecondary = customColors.secondary;
123
196
  }
124
197
 
125
- // Apply background override
198
+ // Background aliases
126
199
  if (customColors.backgroundPrimary) {
127
- result.backgroundPrimary = customColors.backgroundPrimary;
128
- result.background = customColors.backgroundPrimary; // Alias
129
- }
130
- if (customColors.backgroundSecondary) {
131
- result.backgroundSecondary = customColors.backgroundSecondary;
200
+ result.background = customColors.backgroundPrimary;
132
201
  }
133
-
134
- // Apply surface overrides
202
+
203
+ // Surface aliases
135
204
  if (customColors.surface) {
136
- result.surface = customColors.surface;
137
- result.card = customColors.surface; // Alias
138
- result.cardBackground = customColors.surface; // Alias
205
+ result.card = customColors.surface;
206
+ result.cardBackground = customColors.surface;
139
207
  }
140
- if (customColors.surfaceVariant) {
141
- result.surfaceVariant = customColors.surfaceVariant;
142
- result.surfaceSecondary = customColors.surfaceVariant; // Alias
208
+ if (customColors.surfaceVariant && !customColors.surfaceSecondary) {
209
+ result.surfaceSecondary = customColors.surfaceVariant;
143
210
  }
144
-
145
- // Apply text overrides
211
+
212
+ // Text aliases
146
213
  if (customColors.textPrimary) {
147
- result.textPrimary = customColors.textPrimary;
148
- result.text = customColors.textPrimary; // Alias
214
+ result.text = customColors.textPrimary;
149
215
  }
150
- if (customColors.textSecondary) {
151
- result.textSecondary = customColors.textSecondary;
216
+
217
+ // Input aliases
218
+ if (customColors.inputBorder && !result.inputBorder) {
219
+ result.inputBorder = customColors.inputBorder;
152
220
  }
153
- if (customColors.textTertiary) {
154
- result.textTertiary = customColors.textTertiary;
221
+ if (customColors.border && !customColors.inputBorder) {
222
+ result.inputBorder = customColors.border;
155
223
  }
156
224
 
157
225
  return result as ColorPalette;
@@ -4,7 +4,7 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
4
4
  import { useFonts } from 'expo-font';
5
5
  import { SafeAreaProvider, initialWindowMetrics } from '../../../safe-area';
6
6
  import { useThemeStore } from '../stores/themeStore';
7
- import { useDesignSystemTheme } from '../globalThemeStore';
7
+ import { useDesignSystemTheme, type ThemeMode } from '../globalThemeStore';
8
8
  import type { CustomThemeColors } from '../../core/CustomColors';
9
9
  import { SplashScreen } from '../../../molecules/splash';
10
10
  import type { SplashScreenProps } from '../../../molecules/splash/types';
@@ -14,8 +14,24 @@ import { IconProvider, type IconRenderer } from '../../../atoms/IconRegistry';
14
14
  interface DesignSystemProviderProps {
15
15
  /** App content */
16
16
  children: ReactNode;
17
- /** Custom theme colors to override defaults */
17
+ /**
18
+ * Custom theme colors to override defaults
19
+ * Apps can override ANY color key from the palette
20
+ * @example
21
+ * customColors={{
22
+ * primary: '#FF6B6B',
23
+ * onPrimary: '#FFFFFF',
24
+ * backgroundPrimary: '#FFFFFF',
25
+ * textPrimary: '#1A1A1A',
26
+ * }}
27
+ */
18
28
  customColors?: CustomThemeColors;
29
+ /**
30
+ * Initial theme mode for the app
31
+ * Apps control whether they start in light or dark mode
32
+ * @default 'light'
33
+ */
34
+ initialThemeMode?: ThemeMode;
19
35
  /** Custom fonts to load (name -> source map) */
20
36
  fonts?: Record<string, any>;
21
37
  /** Show loading indicator while initializing (default: true) */
@@ -30,10 +46,10 @@ interface DesignSystemProviderProps {
30
46
  onError?: (error: unknown) => void;
31
47
  /**
32
48
  * Custom icon renderer function
33
- * Allows apps to use their own icon library instead of Ionicons
49
+ * Allows apps to use their own icon library
34
50
  * @example
35
51
  * iconRenderer={({ name, size, color }) => (
36
- * <MaterialIcons name={name} size={size} color={color} />
52
+ * <LucideIcons name={name} size={size} color={color} />
37
53
  * )}
38
54
  */
39
55
  iconRenderer?: IconRenderer;
@@ -41,11 +57,22 @@ interface DesignSystemProviderProps {
41
57
 
42
58
  /**
43
59
  * DesignSystemProvider
44
- * Initializes theme store and applies custom colors.
60
+ *
61
+ * Main provider for the design system. Wraps your app and provides:
62
+ * - Theme (colors, spacing, typography)
63
+ * - Custom icon rendering
64
+ * - Safe area handling
65
+ * - Gesture handling
66
+ *
67
+ * ARCHITECTURE (based on Shopify Restyle, React Native Paper, Tamagui):
68
+ * - Apps provide customColors to override default palette
69
+ * - Apps set initialThemeMode to control light/dark mode
70
+ * - All design system components use these values via useAppDesignTokens
45
71
  */
46
72
  export const DesignSystemProvider: React.FC<DesignSystemProviderProps> = ({
47
73
  children,
48
74
  customColors,
75
+ initialThemeMode = 'light', // Default to light mode (most common)
49
76
  fonts,
50
77
  showLoadingIndicator = true,
51
78
  splashConfig,
@@ -55,12 +82,14 @@ export const DesignSystemProvider: React.FC<DesignSystemProviderProps> = ({
55
82
  iconRenderer,
56
83
  }: DesignSystemProviderProps) => {
57
84
  const [isInitialized, setIsInitialized] = useState(false);
58
-
85
+
59
86
  // Load fonts if provided
60
87
  const [fontsLoaded, fontError] = fonts ? useFonts(fonts) : [true, null];
61
-
88
+
62
89
  const initialize = useThemeStore((state) => state.initialize);
90
+ const setThemeMode = useThemeStore((state) => state.setThemeMode);
63
91
  const setCustomColors = useDesignSystemTheme((state) => state.setCustomColors);
92
+ const setGlobalThemeMode = useDesignSystemTheme((state) => state.setThemeMode);
64
93
 
65
94
  useEffect(() => {
66
95
  // Apply custom colors if provided
@@ -68,16 +97,22 @@ export const DesignSystemProvider: React.FC<DesignSystemProviderProps> = ({
68
97
  setCustomColors(customColors);
69
98
  }
70
99
 
71
- // Initialize theme store
100
+ // Set initial theme mode from app
101
+ setGlobalThemeMode(initialThemeMode);
102
+
103
+ // Initialize theme store with the initial theme mode
72
104
  initialize()
73
- .then(() => {
105
+ .then(async () => {
106
+ // After initialization, set the theme mode from app config
107
+ // This overrides any persisted theme mode if app explicitly sets one
108
+ await setThemeMode(initialThemeMode);
74
109
  setIsInitialized(true);
75
110
  })
76
111
  .catch((error) => {
77
112
  setIsInitialized(true); // Still render app even on error
78
113
  onError?.(error);
79
114
  });
80
- }, [initialize, customColors, setCustomColors, onError]);
115
+ }, [initialize, customColors, initialThemeMode, setCustomColors, setGlobalThemeMode, setThemeMode, onError]);
81
116
 
82
117
  // Handle initialization completion when both theme and fonts are ready
83
118
  useEffect(() => {