@umituz/react-native-design-system 4.23.46 → 4.23.47

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": "4.23.46",
3
+ "version": "4.23.47",
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",
@@ -1,70 +1,77 @@
1
1
  /**
2
2
  * Theme Storage
3
- * Persists theme preference using AsyncStorage
4
- *
5
- * CRITICAL: This is a standalone storage utility for theme package.
6
- * Apps should use this for theme persistence.
3
+ * Persists theme mode and custom colors using AsyncStorage
7
4
  */
8
5
 
9
6
  import { storageRepository, unwrap } from '../../../storage';
10
7
  import type { ThemeMode } from '../../core/ColorPalette';
8
+ import type { CustomThemeColors } from '../../core/CustomColors';
11
9
  import { DESIGN_CONSTANTS } from '../../core/constants/DesignConstants';
12
10
 
13
- const STORAGE_KEY = `${DESIGN_CONSTANTS.STORAGE_NAMESPACE}/mode`;
11
+ const MODE_KEY = `${DESIGN_CONSTANTS.STORAGE_NAMESPACE}/mode`;
12
+ const COLORS_KEY = `${DESIGN_CONSTANTS.STORAGE_NAMESPACE}/colors`;
14
13
 
15
14
  export class ThemeStorage {
16
- /**
17
- * Get stored theme mode
18
- */
19
15
  static async getThemeMode(): Promise<ThemeMode | null> {
20
16
  try {
21
- const result = await storageRepository.getString(STORAGE_KEY, '');
17
+ const result = await storageRepository.getString(MODE_KEY, '');
22
18
  const value = unwrap(result, '');
23
-
24
- if (!value) {
25
- return null;
26
- }
27
-
28
- // Validate theme mode value
29
- if (value === 'light' || value === 'dark') {
30
- return value as ThemeMode;
31
- }
32
-
19
+ if (!value) return null;
20
+ if (value === 'light' || value === 'dark') return value as ThemeMode;
33
21
  return null;
34
22
  } catch {
35
- // Return null instead of throwing to prevent app crashes
36
23
  return null;
37
24
  }
38
25
  }
39
26
 
40
- /**
41
- * Save theme mode
42
- */
43
27
  static async setThemeMode(mode: ThemeMode): Promise<void> {
44
28
  try {
45
- // Validate input
46
29
  if (!mode || (mode !== 'light' && mode !== 'dark')) {
47
30
  throw new Error(`Invalid theme mode: ${mode}`);
48
31
  }
49
-
50
- await storageRepository.setString(STORAGE_KEY, mode);
32
+ await storageRepository.setString(MODE_KEY, mode);
51
33
  } catch (error) {
52
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
53
- // Re-throw validation errors but swallow storage errors to prevent app crashes
54
- if (errorMessage.includes('Invalid theme mode')) {
55
- throw error;
56
- }
34
+ const msg = error instanceof Error ? error.message : '';
35
+ if (msg.includes('Invalid theme mode')) throw error;
57
36
  }
58
37
  }
59
38
 
60
- /**
61
- * Clear stored theme mode
62
- */
63
39
  static async clearThemeMode(): Promise<void> {
64
40
  try {
65
- await storageRepository.removeItem(STORAGE_KEY);
41
+ await storageRepository.removeItem(MODE_KEY);
42
+ } catch {
43
+ // Silent fail
44
+ }
45
+ }
46
+
47
+ static async getCustomColors(): Promise<CustomThemeColors | undefined> {
48
+ try {
49
+ const result = await storageRepository.getString(COLORS_KEY, '');
50
+ const value = unwrap(result, '');
51
+ if (!value) return undefined;
52
+ return JSON.parse(value) as CustomThemeColors;
53
+ } catch {
54
+ return undefined;
55
+ }
56
+ }
57
+
58
+ static async setCustomColors(colors?: CustomThemeColors): Promise<void> {
59
+ try {
60
+ if (!colors || Object.keys(colors).length === 0) {
61
+ await storageRepository.removeItem(COLORS_KEY);
62
+ return;
63
+ }
64
+ await storageRepository.setString(COLORS_KEY, JSON.stringify(colors));
65
+ } catch {
66
+ // Silent fail
67
+ }
68
+ }
69
+
70
+ static async clearCustomColors(): Promise<void> {
71
+ try {
72
+ await storageRepository.removeItem(COLORS_KEY);
66
73
  } catch {
67
- // Don't throw - clearing storage is not critical
74
+ // Silent fail
68
75
  }
69
76
  }
70
77
  }
@@ -1,13 +1,8 @@
1
1
  /**
2
2
  * Theme Store - Zustand State Management
3
3
  *
4
- * CRITICAL: NO Context Provider pattern - uses Zustand for global state
5
- *
6
- * Architecture:
7
- * - Zustand for state management (NOT Context API)
8
- * - AsyncStorage for persistence via ThemeStorage
9
- * - Automatic initialization on app launch
10
- * - Syncs with design system global theme store
4
+ * Single source of truth for theme mode AND custom colors.
5
+ * Uses AsyncStorage for persistence via ThemeStorage.
11
6
  */
12
7
 
13
8
  import { createStore } from '../../../storage';
@@ -15,82 +10,66 @@ import { lightTheme, darkTheme, type Theme } from '../../core/themes';
15
10
  import { ThemeStorage } from '../storage/ThemeStorage';
16
11
  import { useDesignSystemTheme } from '../globalThemeStore';
17
12
  import type { ThemeMode } from '../../core/ColorPalette';
13
+ import type { CustomThemeColors } from '../../core/CustomColors';
18
14
 
19
15
  interface ThemeState {
20
16
  theme: Theme;
21
17
  themeMode: ThemeMode;
18
+ customColors?: CustomThemeColors;
22
19
  isDark: boolean;
23
20
  isInitialized: boolean;
24
21
  }
25
22
 
26
23
  interface ThemeActions {
27
24
  setThemeMode: (mode: ThemeMode) => Promise<void>;
25
+ setCustomColors: (colors?: CustomThemeColors) => Promise<void>;
28
26
  toggleTheme: () => Promise<void>;
29
27
  initialize: () => Promise<void>;
30
28
  }
31
29
 
32
- // Mutex to prevent race condition in setThemeMode
33
30
  let themeUpdateInProgress = false;
34
- // Mutex to prevent race condition in initialize
35
31
  let themeInitInProgress = false;
36
32
 
37
- /**
38
- * Theme Store - Global state management for theme
39
- *
40
- * Usage:
41
- * ```typescript
42
- * import { useTheme } from '@umituz/react-native-design-system';
43
- *
44
- * const MyComponent = () => {
45
- * const { theme, themeMode, setThemeMode, toggleTheme } = useTheme();
46
- * // ...
47
- * };
48
- * ```
49
- *
50
- * NOTE: Make sure to wrap your app with DesignSystemProvider for auto-initialization
51
- */
52
33
  export const useTheme = createStore<ThemeState, ThemeActions>({
53
34
  name: 'theme-store',
54
35
  initialState: {
55
36
  theme: lightTheme,
56
37
  themeMode: 'light',
38
+ customColors: undefined,
57
39
  isDark: false,
58
40
  isInitialized: false,
59
41
  },
60
42
  persist: false,
61
43
  actions: (set, get) => ({
62
44
  initialize: async () => {
63
- // Atomic check with mutex
64
45
  const { isInitialized } = get();
65
- if (isInitialized || themeInitInProgress) {
66
- return;
67
- }
46
+ if (isInitialized || themeInitInProgress) return;
68
47
 
69
48
  themeInitInProgress = true;
70
49
 
71
50
  try {
72
- const savedMode = await ThemeStorage.getThemeMode();
73
- if (savedMode) {
74
- const theme = savedMode === 'light' ? lightTheme : darkTheme;
75
- set({
76
- themeMode: savedMode,
77
- theme,
78
- isDark: savedMode === 'dark',
79
- isInitialized: true,
80
- });
81
-
82
- // Sync with design system global theme
83
- useDesignSystemTheme.getState().setThemeMode(savedMode);
84
- } else {
85
- // No saved mode - use default 'light' and sync to design system store
86
- set({ isInitialized: true });
87
- // Ensure design system store is synced even if no saved mode exists
88
- useDesignSystemTheme.getState().setThemeMode('light');
89
- }
51
+ const [savedMode, savedColors] = await Promise.all([
52
+ ThemeStorage.getThemeMode(),
53
+ ThemeStorage.getCustomColors(),
54
+ ]);
55
+
56
+ const mode = savedMode || 'light';
57
+ const theme = mode === 'light' ? lightTheme : darkTheme;
58
+
59
+ set({
60
+ themeMode: mode,
61
+ theme,
62
+ customColors: savedColors,
63
+ isDark: mode === 'dark',
64
+ isInitialized: true,
65
+ });
66
+
67
+ // Sync with design system global theme
68
+ const dsTheme = useDesignSystemTheme.getState();
69
+ dsTheme.setThemeMode(mode);
70
+ dsTheme.setCustomColors(savedColors);
90
71
  } catch {
91
- // Silent failure - still mark as initialized to prevent blocking
92
72
  set({ isInitialized: true });
93
- // Ensure design system store is synced even on error
94
73
  useDesignSystemTheme.getState().setThemeMode('light');
95
74
  } finally {
96
75
  themeInitInProgress = false;
@@ -98,44 +77,34 @@ export const useTheme = createStore<ThemeState, ThemeActions>({
98
77
  },
99
78
 
100
79
  setThemeMode: async (mode: ThemeMode) => {
101
- // Skip if another update is in progress
102
- if (themeUpdateInProgress) {
103
- return;
104
- }
105
-
80
+ if (themeUpdateInProgress) return;
106
81
  themeUpdateInProgress = true;
107
82
 
108
83
  try {
109
84
  const theme = mode === 'light' ? lightTheme : darkTheme;
110
-
111
- // Set state first
112
- set({
113
- themeMode: mode,
114
- theme,
115
- isDark: mode === 'dark',
116
- });
117
-
118
- // Then persist (even if this fails, UI is already updated)
85
+ set({ themeMode: mode, theme, isDark: mode === 'dark' });
119
86
  await ThemeStorage.setThemeMode(mode);
120
-
121
- // Sync with design system global theme
122
87
  useDesignSystemTheme.getState().setThemeMode(mode);
123
88
  } catch {
124
- // Silent failure - UI already updated, just storage failed
89
+ // Silent failure
125
90
  } finally {
126
91
  themeUpdateInProgress = false;
127
92
  }
128
93
  },
129
94
 
95
+ setCustomColors: async (colors?: CustomThemeColors) => {
96
+ set({ customColors: colors });
97
+ await ThemeStorage.setCustomColors(colors);
98
+ useDesignSystemTheme.getState().setCustomColors(colors);
99
+ },
100
+
130
101
  toggleTheme: async () => {
131
102
  const { themeMode, setThemeMode } = get();
132
- const newMode: ThemeMode = themeMode === 'light' ? 'dark' : 'light';
133
- await setThemeMode(newMode);
103
+ await setThemeMode(themeMode === 'light' ? 'dark' : 'light');
134
104
  },
135
105
  }),
136
106
  });
137
107
 
138
- // Export internal store for DesignSystemProvider
139
108
  export const useThemeStore = useTheme;
140
109
 
141
110