@umituz/react-native-design-system 2.5.9 → 2.5.10

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 (34) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/atoms/AtomicButton.tsx +2 -5
  4. package/src/atoms/AtomicChip.tsx +13 -13
  5. package/src/atoms/AtomicIcon.tsx +1 -8
  6. package/src/atoms/AtomicPicker.tsx +6 -5
  7. package/src/atoms/__tests__/AtomicIcon.test.tsx +0 -6
  8. package/src/atoms/input/hooks/useInputState.ts +0 -6
  9. package/src/atoms/picker/components/PickerModal.tsx +15 -6
  10. package/src/atoms/picker/types/index.ts +17 -4
  11. package/src/device/detection/deviceDetection.ts +7 -20
  12. package/src/layouts/ScreenHeader/ScreenHeader.tsx +1 -2
  13. package/src/molecules/alerts/AlertToast.tsx +1 -1
  14. package/src/molecules/animation/presentation/hooks/useFireworks.ts +1 -3
  15. package/src/molecules/animation/presentation/providers/AnimationThemeProvider.tsx +1 -3
  16. package/src/molecules/avatar/Avatar.tsx +2 -2
  17. package/src/molecules/bottom-sheet/components/BottomSheetModal.tsx +0 -6
  18. package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +2 -2
  19. package/src/molecules/navigation/StackNavigator.tsx +6 -9
  20. package/src/molecules/navigation/TabsNavigator.tsx +9 -13
  21. package/src/molecules/navigation/utils/AppNavigation.ts +0 -2
  22. package/src/molecules/navigation/utils/LabelProcessor.ts +1 -10
  23. package/src/molecules/navigation/utils/NavigationCleanup.ts +4 -8
  24. package/src/molecules/navigation/utils/NavigationValidator.ts +2 -11
  25. package/src/presentation/utils/variants/compound.ts +0 -4
  26. package/src/presentation/utils/variants/core.ts +0 -4
  27. package/src/presentation/utils/variants/helpers.ts +0 -6
  28. package/src/safe-area/components/SafeAreaProvider.tsx +0 -10
  29. package/src/safe-area/utils/validation.ts +3 -27
  30. package/src/theme/core/CustomColors.ts +2 -8
  31. package/src/theme/core/colors/ColorUtils.ts +0 -6
  32. package/src/theme/infrastructure/storage/ThemeStorage.ts +2 -16
  33. package/src/typography/presentation/utils/textColorUtils.ts +0 -3
  34. package/src/utilities/clipboard/ClipboardUtils.ts +1 -5
package/README.md CHANGED
@@ -23,7 +23,7 @@ npm install @umituz/react-native-design-system
23
23
  ### Peer Dependencies
24
24
 
25
25
  ```bash
26
- npm install react@18.3.1 react-native@0.76.3 react-native-reanimated@~3.10.1 react-native-svg@^15.0.0 lucide-react-native@^0.468.0
26
+ npm install react@18.3.1 react-native@0.76.3 react-native-reanimated@~3.10.1 react-native-svg@^15.0.0
27
27
  ```
28
28
 
29
29
  > **v1.3.0 Breaking Change**: React Native Paper dependency removed! All components now use pure React Native implementation for lighter bundle size and full control over styling.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "2.5.9",
3
+ "version": "2.5.10",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -41,9 +41,6 @@ export const AtomicButton: React.FC<AtomicButtonProps> = React.memo(({
41
41
 
42
42
  const handlePress = () => {
43
43
  if (!disabled) {
44
- if (__DEV__) {
45
- console.log('[AtomicButton] Button pressed:', { title, variant, disabled });
46
- }
47
44
  onPress();
48
45
  }
49
46
  };
@@ -115,7 +112,7 @@ export const AtomicButton: React.FC<AtomicButtonProps> = React.memo(({
115
112
  return {
116
113
  container: {
117
114
  ...baseStyle,
118
- backgroundColor: 'transparent',
115
+ backgroundColor: undefined,
119
116
  borderWidth: 1,
120
117
  borderColor: tokens.colors.border,
121
118
  },
@@ -129,7 +126,7 @@ export const AtomicButton: React.FC<AtomicButtonProps> = React.memo(({
129
126
  return {
130
127
  container: {
131
128
  ...baseStyle,
132
- backgroundColor: 'transparent',
129
+ backgroundColor: undefined,
133
130
  },
134
131
  text: {
135
132
  ...baseTextStyle,
@@ -108,37 +108,37 @@ export const AtomicChip: React.FC<AtomicChipProps> = React.memo(({
108
108
 
109
109
  const sizeConfig = sizeMap[size];
110
110
 
111
- // Color mapping
111
+ // Color mapping - using undefined for transparent backgrounds
112
112
  const colorMap = {
113
113
  primary: {
114
114
  filled: { bg: tokens.colors.primary, text: tokens.colors.onPrimary, border: tokens.colors.primary },
115
- outlined: { bg: 'transparent', text: tokens.colors.primary, border: tokens.colors.primary },
116
- soft: { bg: tokens.colors.primaryContainer, text: tokens.colors.onPrimaryContainer, border: 'transparent' },
115
+ outlined: { bg: undefined, text: tokens.colors.primary, border: tokens.colors.primary },
116
+ soft: { bg: tokens.colors.primaryContainer, text: tokens.colors.onPrimaryContainer, border: undefined },
117
117
  },
118
118
  secondary: {
119
119
  filled: { bg: tokens.colors.secondary, text: tokens.colors.onSecondary, border: tokens.colors.secondary },
120
- outlined: { bg: 'transparent', text: tokens.colors.secondary, border: tokens.colors.secondary },
121
- soft: { bg: tokens.colors.secondaryContainer, text: tokens.colors.onSecondaryContainer, border: 'transparent' },
120
+ outlined: { bg: undefined, text: tokens.colors.secondary, border: tokens.colors.secondary },
121
+ soft: { bg: tokens.colors.secondaryContainer, text: tokens.colors.onSecondaryContainer, border: undefined },
122
122
  },
123
123
  success: {
124
124
  filled: { bg: tokens.colors.success, text: tokens.colors.onSuccess, border: tokens.colors.success },
125
- outlined: { bg: 'transparent', text: tokens.colors.success, border: tokens.colors.success },
126
- soft: { bg: tokens.colors.successContainer, text: tokens.colors.onSuccessContainer, border: 'transparent' },
125
+ outlined: { bg: undefined, text: tokens.colors.success, border: tokens.colors.success },
126
+ soft: { bg: tokens.colors.successContainer, text: tokens.colors.onSuccessContainer, border: undefined },
127
127
  },
128
128
  warning: {
129
129
  filled: { bg: tokens.colors.warning, text: tokens.colors.onWarning, border: tokens.colors.warning },
130
- outlined: { bg: 'transparent', text: tokens.colors.warning, border: tokens.colors.warning },
131
- soft: { bg: tokens.colors.warningContainer, text: tokens.colors.onWarningContainer, border: 'transparent' },
130
+ outlined: { bg: undefined, text: tokens.colors.warning, border: tokens.colors.warning },
131
+ soft: { bg: tokens.colors.warningContainer, text: tokens.colors.onWarningContainer, border: undefined },
132
132
  },
133
133
  error: {
134
134
  filled: { bg: tokens.colors.error, text: tokens.colors.onError, border: tokens.colors.error },
135
- outlined: { bg: 'transparent', text: tokens.colors.error, border: tokens.colors.error },
136
- soft: { bg: tokens.colors.errorContainer, text: tokens.colors.onErrorContainer, border: 'transparent' },
135
+ outlined: { bg: undefined, text: tokens.colors.error, border: tokens.colors.error },
136
+ soft: { bg: tokens.colors.errorContainer, text: tokens.colors.onErrorContainer, border: undefined },
137
137
  },
138
138
  info: {
139
139
  filled: { bg: tokens.colors.info, text: tokens.colors.onInfo, border: tokens.colors.info },
140
- outlined: { bg: 'transparent', text: tokens.colors.info, border: tokens.colors.info },
141
- soft: { bg: tokens.colors.infoContainer, text: tokens.colors.onInfoContainer, border: 'transparent' },
140
+ outlined: { bg: undefined, text: tokens.colors.info, border: tokens.colors.info },
141
+ soft: { bg: tokens.colors.infoContainer, text: tokens.colors.onInfoContainer, border: undefined },
142
142
  },
143
143
  };
144
144
 
@@ -122,17 +122,10 @@ export const AtomicIcon: React.FC<AtomicIconProps> = React.memo(({
122
122
  ? getSemanticColor(color, tokens)
123
123
  : tokens.colors.textPrimary;
124
124
 
125
- // Validate icon
125
+ // Validate icon - use fallback silently if invalid
126
126
  const isValidIcon = name in Ionicons.glyphMap;
127
127
  const iconName = isValidIcon ? name : FALLBACK_ICON;
128
128
 
129
- if (__DEV__ && !isValidIcon) {
130
- console.warn(
131
- `[AtomicIcon] Invalid icon name: "${name}". Using fallback icon "${FALLBACK_ICON}". ` +
132
- `Available icons: https://icons.expo.fyi/`
133
- );
134
- }
135
-
136
129
  const iconElement = (
137
130
  <Ionicons
138
131
  name={iconName as keyof typeof Ionicons.glyphMap}
@@ -73,7 +73,7 @@ export const AtomicPicker: React.FC<AtomicPickerProps> = ({
73
73
  onChange,
74
74
  options,
75
75
  label,
76
- placeholder = 'Select...',
76
+ placeholder,
77
77
  error,
78
78
  disabled = false,
79
79
  multiple = false,
@@ -82,9 +82,10 @@ export const AtomicPicker: React.FC<AtomicPickerProps> = ({
82
82
  autoClose = true,
83
83
  size = 'md',
84
84
  modalTitle,
85
- emptyMessage = 'No options available',
86
- clearAccessibilityLabel = 'Clear selection',
87
- closeAccessibilityLabel = 'Close picker',
85
+ emptyMessage,
86
+ searchPlaceholder,
87
+ clearAccessibilityLabel,
88
+ closeAccessibilityLabel,
88
89
  style,
89
90
  labelStyle,
90
91
  testID,
@@ -294,7 +295,7 @@ export const AtomicPicker: React.FC<AtomicPickerProps> = ({
294
295
  filteredOptions={filteredOptions}
295
296
  multiple={multiple}
296
297
  emptyMessage={emptyMessage}
297
- searchPlaceholder="Search..."
298
+ searchPlaceholder={searchPlaceholder}
298
299
  closeAccessibilityLabel={closeAccessibilityLabel}
299
300
  testID={testID}
300
301
  />
@@ -18,12 +18,6 @@ jest.mock('@umituz/react-native-design-system-theme', () => ({
18
18
  }),
19
19
  }));
20
20
 
21
- // Mock Lucide icons
22
- jest.mock('lucide-react-native', () => ({
23
- Settings: () => 'Settings-Icon',
24
- Heart: () => 'Heart-Icon',
25
- }));
26
-
27
21
  describe('AtomicIcon', () => {
28
22
  it('renders with default props', () => {
29
23
  const { getByTestId } = render(
@@ -35,17 +35,11 @@ export const useInputState = ({
35
35
  const [isPasswordVisible, setIsPasswordVisible] = useState(!secureTextEntry);
36
36
 
37
37
  const handleTextChange = useCallback((text: string) => {
38
- if (__DEV__) {
39
- console.log('[useInputState] Text changed:', { text, length: text.length });
40
- }
41
38
  setLocalValue(text);
42
39
  onChangeText?.(text);
43
40
  }, [onChangeText]);
44
41
 
45
42
  const togglePasswordVisibility = useCallback(() => {
46
- if (__DEV__) {
47
- console.log('[useInputState] Password visibility toggled');
48
- }
49
43
  setIsPasswordVisible((prev) => !prev);
50
44
  }, []);
51
45
 
@@ -38,6 +38,12 @@ import {
38
38
  getEmptyStateTextStyles,
39
39
  } from '../styles/pickerStyles';
40
40
 
41
+ /**
42
+ * PickerModalProps
43
+ *
44
+ * IMPORTANT: String props are REQUIRED for proper i18n support.
45
+ * Pass translated strings from your app's i18n system.
46
+ */
41
47
  interface PickerModalProps {
42
48
  visible: boolean;
43
49
  onClose: () => void;
@@ -50,9 +56,12 @@ interface PickerModalProps {
50
56
  onSearchChange: (query: string) => void;
51
57
  filteredOptions: PickerOption[];
52
58
  multiple?: boolean;
53
- emptyMessage?: string;
54
- searchPlaceholder?: string;
55
- closeAccessibilityLabel?: string;
59
+ /** Empty state message - REQUIRED for i18n */
60
+ emptyMessage: string;
61
+ /** Search placeholder - REQUIRED for i18n */
62
+ searchPlaceholder: string;
63
+ /** Close accessibility label - REQUIRED for i18n */
64
+ closeAccessibilityLabel: string;
56
65
  testID?: string;
57
66
  }
58
67
 
@@ -66,9 +75,9 @@ export const PickerModal: React.FC<PickerModalProps> = React.memo(({
66
75
  searchQuery,
67
76
  onSearchChange,
68
77
  filteredOptions,
69
- emptyMessage = 'No options available',
70
- searchPlaceholder = 'Search...',
71
- closeAccessibilityLabel = 'Close picker',
78
+ emptyMessage,
79
+ searchPlaceholder,
80
+ closeAccessibilityLabel,
72
81
  testID,
73
82
  }) => {
74
83
  const tokens = useAppDesignTokens();
@@ -18,12 +18,20 @@ export interface PickerOption {
18
18
 
19
19
  export type PickerSize = 'sm' | 'md' | 'lg';
20
20
 
21
+ /**
22
+ * AtomicPickerProps
23
+ *
24
+ * IMPORTANT: String props (placeholder, emptyMessage, etc.) are REQUIRED
25
+ * for proper i18n support. Pass translated strings from your app's i18n system.
26
+ * Do NOT rely on default English values.
27
+ */
21
28
  export interface AtomicPickerProps {
22
29
  value: string | string[];
23
30
  onChange: (value: string | string[]) => void;
24
31
  options: PickerOption[];
25
32
  label?: string;
26
- placeholder?: string;
33
+ /** Placeholder text - REQUIRED for i18n, pass translated string */
34
+ placeholder: string;
27
35
  error?: string;
28
36
  disabled?: boolean;
29
37
  multiple?: boolean;
@@ -33,9 +41,14 @@ export interface AtomicPickerProps {
33
41
  color?: IconColor;
34
42
  size?: PickerSize;
35
43
  modalTitle?: string;
36
- emptyMessage?: string;
37
- clearAccessibilityLabel?: string;
38
- closeAccessibilityLabel?: string;
44
+ /** Empty state message - REQUIRED for i18n, pass translated string */
45
+ emptyMessage: string;
46
+ /** Search placeholder text - REQUIRED for i18n, pass translated string */
47
+ searchPlaceholder: string;
48
+ /** Clear button accessibility label - REQUIRED for i18n, pass translated string */
49
+ clearAccessibilityLabel: string;
50
+ /** Close button accessibility label - REQUIRED for i18n, pass translated string */
51
+ closeAccessibilityLabel: string;
39
52
  style?: ViewStyle | ViewStyle[];
40
53
  labelStyle?: TextStyle | TextStyle[];
41
54
  testID?: string;
@@ -13,20 +13,15 @@ import { validateScreenDimensions } from '../../responsive/validation';
13
13
  * Helper function for device detection with fallback
14
14
  * @param operation - Operation to perform
15
15
  * @param fallback - Fallback value if operation fails
16
- * @param warningMessage - Warning message for __DEV__
17
16
  * @returns Operation result or fallback
18
17
  */
19
18
  const withDeviceDetectionFallback = <T>(
20
19
  operation: () => T,
21
- fallback: T,
22
- warningMessage: string
20
+ fallback: T
23
21
  ): T => {
24
22
  try {
25
23
  return operation();
26
24
  } catch {
27
- if (__DEV__) {
28
- console.warn(`[DeviceDetection] ${warningMessage}`);
29
- }
30
25
  return fallback;
31
26
  }
32
27
  };
@@ -53,9 +48,6 @@ export const getScreenDimensions = () => {
53
48
  validateScreenDimensions(width, height);
54
49
  return { width, height };
55
50
  } catch {
56
- if (__DEV__) {
57
- console.warn('[getScreenDimensions] Invalid screen dimensions detected, using fallback values');
58
- }
59
51
  // Fallback to safe default dimensions
60
52
  return { width: 414, height: 896 };
61
53
  }
@@ -71,8 +63,7 @@ export const isSmallPhone = (): boolean => {
71
63
  const { width } = getScreenDimensions();
72
64
  return width <= DEVICE_BREAKPOINTS.SMALL_PHONE;
73
65
  },
74
- false,
75
- 'Error detecting device type, assuming standard phone'
66
+ false
76
67
  );
77
68
  };
78
69
 
@@ -86,8 +77,7 @@ export const isTablet = (): boolean => {
86
77
  const { width } = getScreenDimensions();
87
78
  return width >= DEVICE_BREAKPOINTS.SMALL_TABLET;
88
79
  },
89
- false,
90
- 'Error detecting device type, assuming phone'
80
+ false
91
81
  );
92
82
  };
93
83
 
@@ -101,8 +91,7 @@ export const isLandscape = (): boolean => {
101
91
  const { width, height } = getScreenDimensions();
102
92
  return width > height;
103
93
  },
104
- false,
105
- 'Error detecting orientation, assuming portrait'
94
+ false
106
95
  );
107
96
  };
108
97
 
@@ -125,15 +114,14 @@ export const getDeviceType = (): DeviceType => {
125
114
 
126
115
  return DeviceType.TABLET;
127
116
  },
128
- DeviceType.MEDIUM_PHONE,
129
- 'Error detecting device type, assuming medium phone'
117
+ DeviceType.MEDIUM_PHONE
130
118
  );
131
119
  };
132
120
 
133
121
  /**
134
122
  * Responsive spacing multiplier
135
123
  * Returns a multiplier for spacing based on device size
136
- *
124
+ *
137
125
  * @returns Spacing multiplier (0.9-1.2)
138
126
  */
139
127
  export const getSpacingMultiplier = (): number => {
@@ -149,7 +137,6 @@ export const getSpacingMultiplier = (): number => {
149
137
 
150
138
  return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD;
151
139
  },
152
- LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD,
153
- 'Error calculating spacing multiplier, using fallback'
140
+ LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD
154
141
  );
155
142
  };
@@ -74,9 +74,8 @@ const ScreenHeaderBackButton: React.FC<{
74
74
  const handleBackPress = React.useCallback(() => {
75
75
  if (onBackPress) {
76
76
  onBackPress();
77
- } else if (__DEV__) {
78
- console.warn('ScreenHeader: onBackPress is required when back button is visible');
79
77
  }
78
+ // If no onBackPress provided, do nothing silently
80
79
  }, [onBackPress]);
81
80
 
82
81
  if (hideBackButton) return null;
@@ -48,7 +48,7 @@ export function AlertToast({ alert }: AlertToastProps) {
48
48
  return { backgroundColor: tokens.colors.backgroundPrimary };
49
49
  case 'secondary':
50
50
  return {
51
- backgroundColor: 'transparent',
51
+ backgroundColor: undefined,
52
52
  borderWidth: 1,
53
53
  borderColor: tokens.colors.textInverse,
54
54
  };
@@ -38,9 +38,7 @@ export const useFireworks = (config: FireworksConfig) => {
38
38
  } = config;
39
39
 
40
40
  if (!colors || colors.length === 0) {
41
- if (__DEV__) {
42
- console.warn('useFireworks: colors array is required and cannot be empty');
43
- }
41
+ // Return no-op when colors not provided
44
42
  return { particles: [], trigger: () => { }, isActive: false };
45
43
  }
46
44
 
@@ -50,9 +50,7 @@ export const AnimationThemeProvider: React.FC<AnimationThemeProviderProps> = ({
50
50
  export const useAnimationTheme = (): ThemeContext => {
51
51
  const context = useContext(ThemeContext);
52
52
  if (!context) {
53
- if (__DEV__) {
54
- console.warn('useAnimationTheme must be used within AnimationThemeProvider');
55
- }
53
+ // Return default theme if used outside provider
56
54
  return {
57
55
  theme: DEFAULT_ANIMATION_THEME,
58
56
  setTheme: () => {},
@@ -129,7 +129,7 @@ export const Avatar: React.FC<AvatarProps> = ({
129
129
  styles.initials,
130
130
  {
131
131
  fontSize: config.fontSize,
132
- color: '#FFFFFF',
132
+ color: tokens.colors.textInverse,
133
133
  },
134
134
  ]}
135
135
  >
@@ -143,7 +143,7 @@ export const Avatar: React.FC<AvatarProps> = ({
143
143
  <AtomicIcon
144
144
  name={icon}
145
145
  customSize={config.iconSize}
146
- customColor="#FFFFFF"
146
+ customColor={tokens.colors.textInverse}
147
147
  />
148
148
  );
149
149
  };
@@ -1,5 +1,3 @@
1
- declare const __DEV__: boolean;
2
-
3
1
  import React, { forwardRef, useCallback, useMemo, useImperativeHandle, useRef } from 'react';
4
2
  import { StyleSheet } from 'react-native';
5
3
  import {
@@ -78,10 +76,6 @@ export const BottomSheetModal = forwardRef<BottomSheetModalRef, BottomSheetModal
78
76
 
79
77
  useImperativeHandle(ref, () => ({
80
78
  present: () => {
81
- if (__DEV__) {
82
- console.log('[BottomSheetModal] present() called');
83
- console.log('[BottomSheetModal] modalRef.current:', modalRef.current);
84
- }
85
79
  modalRef.current?.present();
86
80
  },
87
81
  dismiss: () => modalRef.current?.dismiss(),
@@ -11,8 +11,8 @@
11
11
  * - Timezone-aware via CalendarService
12
12
  */
13
13
 
14
- import { create, type StateCreator } from 'zustand';
15
- import { persist, createJSONStorage, type PersistOptions } from 'zustand/middleware';
14
+ import { create } from 'zustand';
15
+ import { persist, createJSONStorage } from 'zustand/middleware';
16
16
  import AsyncStorage from '@react-native-async-storage/async-storage';
17
17
  import type { CalendarEvent, CreateCalendarEventRequest, UpdateCalendarEventRequest } from '../../domain/entities/CalendarEvent.entity';
18
18
  import { CalendarService } from '../services/CalendarService';
@@ -22,14 +22,12 @@ export interface StackNavigatorProps<T extends ParamListBase> {
22
22
  export function StackNavigator<T extends ParamListBase>({ config }: StackNavigatorProps<T>) {
23
23
  const tokens = useAppDesignTokens();
24
24
 
25
- // Validate configuration
26
- if (__DEV__) {
27
- try {
28
- NavigationValidator.validateScreens(config.screens, "stack");
29
- NavigationValidator.validateInitialRoute(config.initialRouteName, config.screens);
30
- } catch (error) {
31
- if (__DEV__) console.error('[StackNavigator] Configuration validation failed:', error);
32
- }
25
+ // Validate configuration silently
26
+ try {
27
+ NavigationValidator.validateScreens(config.screens, "stack");
28
+ NavigationValidator.validateInitialRoute(config.initialRouteName, config.screens);
29
+ } catch {
30
+ // Silent validation failure
33
31
  }
34
32
 
35
33
  const { screens } = config;
@@ -55,7 +53,6 @@ export function StackNavigator<T extends ParamListBase>({ config }: StackNavigat
55
53
  }), [tokens]);
56
54
 
57
55
  if (screens.length === 0) {
58
- if (__DEV__) console.warn('[StackNavigator] No screens found');
59
56
  return null;
60
57
  }
61
58
 
@@ -24,18 +24,15 @@ export function TabsNavigator<T extends ParamListBase>({
24
24
  }: TabsNavigatorProps<T>) {
25
25
  const tokens = useAppDesignTokens();
26
26
 
27
- // Validate configuration
28
- if (__DEV__) {
29
- try {
30
- NavigationValidator.validateScreens(config.screens, "tab");
31
- NavigationValidator.validateInitialRoute(
32
- config.initialRouteName,
33
- config.screens
34
- );
35
- } catch (error) {
36
- if (__DEV__)
37
- console.error("[TabsNavigator] Configuration validation failed:", error);
38
- }
27
+ // Validate configuration silently
28
+ try {
29
+ NavigationValidator.validateScreens(config.screens, "tab");
30
+ NavigationValidator.validateInitialRoute(
31
+ config.initialRouteName,
32
+ config.screens
33
+ );
34
+ } catch {
35
+ // Silent validation failure
39
36
  }
40
37
 
41
38
  // Memoize filtered screens
@@ -74,7 +71,6 @@ export function TabsNavigator<T extends ParamListBase>({
74
71
  );
75
72
 
76
73
  if (visibleScreens.length === 0) {
77
- if (__DEV__) console.warn("[TabsNavigator] No visible screens found");
78
74
  return null;
79
75
  }
80
76
 
@@ -31,8 +31,6 @@ export class AppNavigation {
31
31
  static navigate(name: string, params?: object): void {
32
32
  if (this.navigationRef?.isReady()) {
33
33
  this.navigationRef.navigate(name, params);
34
- } else if (__DEV__) {
35
- console.warn('[AppNavigation] Navigation ref is not ready. Call setRef() first.');
36
34
  }
37
35
  }
38
36
 
@@ -28,10 +28,7 @@ export class LabelProcessor {
28
28
  try {
29
29
  const processedLabel = getLabel(label);
30
30
  result = typeof processedLabel === "string" ? processedLabel : label;
31
- } catch (error) {
32
- if (__DEV__) {
33
- console.error(`[LabelProcessor] Error processing label: ${label}`, error);
34
- }
31
+ } catch {
35
32
  result = label;
36
33
  }
37
34
  }
@@ -45,12 +42,6 @@ export class LabelProcessor {
45
42
  }
46
43
  this.labelCache.set(cacheKey, result);
47
44
 
48
- // Log cache performance in development
49
- if (__DEV__ && (this.cacheHits + this.cacheMisses) % 100 === 0) {
50
- const hitRate = (this.cacheHits / (this.cacheHits + this.cacheMisses)) * 100;
51
- console.log(`[LabelProcessor] Cache hit rate: ${hitRate.toFixed(1)}%`);
52
- }
53
-
54
45
  return result;
55
46
  }
56
47
 
@@ -36,10 +36,8 @@ export class NavigationCleanupManager {
36
36
  unsubscribers.forEach(unsubscribe => {
37
37
  try {
38
38
  unsubscribe();
39
- } catch (error) {
40
- if (__DEV__) {
41
- console.warn('[NavigationCleanupManager] Error during cleanup:', error);
42
- }
39
+ } catch {
40
+ // Silent cleanup error handling
43
41
  }
44
42
  });
45
43
  };
@@ -52,10 +50,8 @@ export class NavigationCleanupManager {
52
50
  return () => {
53
51
  try {
54
52
  unsubscribe();
55
- } catch (error) {
56
- if (__DEV__) {
57
- console.warn('[NavigationCleanupManager] Error during cleanup:', error);
58
- }
53
+ } catch {
54
+ // Silent cleanup error handling
59
55
  }
60
56
  };
61
57
  }
@@ -7,9 +7,6 @@ export class NavigationValidator {
7
7
  }
8
8
 
9
9
  if (screens.length === 0) {
10
- if (__DEV__) {
11
- console.warn(`[NavigationValidator] No screens provided for ${type} navigator`);
12
- }
13
10
  return;
14
11
  }
15
12
 
@@ -43,11 +40,8 @@ export class NavigationValidator {
43
40
  }
44
41
  }
45
42
 
46
- if (tabScreen.icon !== undefined && (typeof tabScreen.icon !== "string" || tabScreen.icon.trim() === "")) {
47
- if (__DEV__) {
48
- console.warn(`[NavigationValidator] Tab screen '${screen.name}' has invalid icon, it will be ignored`);
49
- }
50
- }
43
+ // Invalid icon check - silently handled
44
+ void (tabScreen.icon !== undefined && (typeof tabScreen.icon !== "string" || tabScreen.icon.trim() === ""));
51
45
  }
52
46
  });
53
47
  }
@@ -55,9 +49,6 @@ export class NavigationValidator {
55
49
  static validateInitialRoute(initialRouteName: string | undefined, screens: TabScreen[] | StackScreen[]): void {
56
50
  if (initialRouteName && !screens.find(screen => screen.name === initialRouteName)) {
57
51
  const error = `Initial route '${initialRouteName}' not found in screens. Available screens: ${screens.map(s => s.name).join(", ")}`;
58
- if (__DEV__) {
59
- console.error(`[NavigationValidator] ${error}`);
60
- }
61
52
  throw new Error(error);
62
53
  }
63
54
  }
@@ -18,10 +18,6 @@ export function createAdvancedVariants<T extends Record<string, Record<string, S
18
18
  return (props: VariantProps<T> = {}): Style => {
19
19
  let result = baseVariantFn(props);
20
20
 
21
- if (__DEV__) {
22
- console.log('[Design System] Creating advanced variant with compound conditions');
23
- }
24
-
25
21
  if (config.compoundVariants) {
26
22
  config.compoundVariants.forEach(compound => {
27
23
  const conditionsMet = Object.entries(compound.conditions).every(
@@ -18,10 +18,6 @@ export function createVariants<T extends Record<string, Record<string, Style>>>(
18
18
  return (props: VariantProps<T> = {}): Style => {
19
19
  let result: Style = { ...config.base };
20
20
 
21
- if (__DEV__) {
22
- console.log('[Design System] Creating variant with props:', props);
23
- }
24
-
25
21
  // Apply default variants
26
22
  if (config.defaultVariants) {
27
23
  Object.entries(config.defaultVariants).forEach(([variantKey, defaultValue]) => {
@@ -14,9 +14,6 @@ export function conditionalStyle<T extends Style>(
14
14
  trueStyle: T,
15
15
  falseStyle?: T
16
16
  ): T | undefined {
17
- if (__DEV__) {
18
- console.log('[Design System] Conditional style applied:', condition);
19
- }
20
17
  return condition ? trueStyle : falseStyle;
21
18
  }
22
19
 
@@ -25,9 +22,6 @@ export function responsiveStyle<T extends Style>(
25
22
  medium?: T,
26
23
  large?: T
27
24
  ): T {
28
- if (__DEV__) {
29
- console.log('[Design System] Responsive style - using small breakpoint');
30
- }
31
25
  void medium;
32
26
  void large;
33
27
  return small;
@@ -36,16 +36,6 @@ export const SafeAreaProvider: React.FC<SafeAreaProviderProps> = ({
36
36
  }) => {
37
37
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
38
38
 
39
- if (__DEV__) {
40
- if (config) {
41
- Object.entries(config).forEach(([key, value]) => {
42
- if (typeof value !== 'number' && typeof value !== 'boolean') {
43
- console.warn(`SafeAreaProvider: ${key} must be a number or boolean, got ${typeof value}`);
44
- }
45
- });
46
- }
47
- }
48
-
49
39
  return (
50
40
  <SafeAreaConfigContext.Provider value={mergedConfig}>
51
41
  <NativeSafeAreaProvider {...nativeProps}>
@@ -39,33 +39,9 @@ export const validateNumericInput = (
39
39
  return isValid;
40
40
  };
41
41
 
42
- // Throttled console warning to prevent spam
43
- // Uses requestAnimationFrame for better performance
44
- const warningTimes = new Map<string, number>();
45
- const WARNING_THROTTLE = 1000; // 1 second
46
-
47
- export const throttledWarn = (message: string): void => {
48
- if (!__DEV__) {
49
- return;
50
- }
51
-
52
- const now = Date.now();
53
- const lastTime = warningTimes.get(message) || 0;
54
-
55
- if (now - lastTime > WARNING_THROTTLE) {
56
- console.warn(message);
57
- warningTimes.set(message, now);
58
-
59
- // Clean up old entries to prevent memory leaks
60
- if (warningTimes.size > 50) {
61
- const cutoffTime = now - WARNING_THROTTLE * 10;
62
- for (const [key, time] of warningTimes.entries()) {
63
- if (time < cutoffTime) {
64
- warningTimes.delete(key);
65
- }
66
- }
67
- }
68
- }
42
+ export const throttledWarn = (_message: string): void => {
43
+ // Silent validation - no console output in production
44
+ void _message;
69
45
  };
70
46
 
71
47
  // Cleanup function to clear validation cache
@@ -31,16 +31,13 @@ export interface CustomThemeColors {
31
31
  */
32
32
  export const validateCustomColors = (customColors: CustomThemeColors): boolean => {
33
33
  const colorValues = Object.values(customColors).filter(Boolean) as string[];
34
-
34
+
35
35
  for (const color of colorValues) {
36
36
  if (!isValidHexColor(color)) {
37
- if (__DEV__) {
38
- console.warn('[validateCustomColors] Invalid hex color:', color);
39
- }
40
37
  return false;
41
38
  }
42
39
  }
43
-
40
+
44
41
  return true;
45
42
  };
46
43
 
@@ -60,9 +57,6 @@ export const applyCustomColors = (
60
57
 
61
58
  // Validate custom colors
62
59
  if (!validateCustomColors(customColors)) {
63
- if (__DEV__) {
64
- console.error('[applyCustomColors] Invalid custom colors provided, using defaults');
65
- }
66
60
  return palette;
67
61
  }
68
62
 
@@ -27,16 +27,10 @@ export const isValidHexColor = (hexColor: string): boolean => {
27
27
  */
28
28
  export const withAlpha = (hexColor: string, alpha: number): string => {
29
29
  if (!isValidHexColor(hexColor)) {
30
- if (__DEV__) {
31
- console.warn('[withAlpha] Invalid hex color format:', hexColor);
32
- }
33
30
  return hexColor;
34
31
  }
35
32
 
36
33
  if (typeof alpha !== 'number' || alpha < 0 || alpha > 1) {
37
- if (__DEV__) {
38
- console.warn('[withAlpha] Invalid alpha value, must be 0-1:', alpha);
39
- }
40
34
  return hexColor;
41
35
  }
42
36
 
@@ -28,15 +28,8 @@ export class ThemeStorage {
28
28
  return value as ThemeMode;
29
29
  }
30
30
 
31
- if (__DEV__) {
32
- console.warn('[ThemeStorage] Invalid theme mode value stored:', value);
33
- }
34
31
  return null;
35
- } catch (error) {
36
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
37
- if (__DEV__) {
38
- console.error('[ThemeStorage] Error getting theme mode:', errorMessage);
39
- }
32
+ } catch {
40
33
  // Return null instead of throwing to prevent app crashes
41
34
  return null;
42
35
  }
@@ -55,9 +48,6 @@ export class ThemeStorage {
55
48
  await AsyncStorage.setItem(STORAGE_KEY, mode);
56
49
  } catch (error) {
57
50
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
58
- if (__DEV__) {
59
- console.error('[ThemeStorage] Error saving theme mode:', errorMessage);
60
- }
61
51
  // Re-throw validation errors but swallow storage errors to prevent app crashes
62
52
  if (errorMessage.includes('Invalid theme mode')) {
63
53
  throw error;
@@ -71,11 +61,7 @@ export class ThemeStorage {
71
61
  static async clearThemeMode(): Promise<void> {
72
62
  try {
73
63
  await AsyncStorage.removeItem(STORAGE_KEY);
74
- } catch (error) {
75
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
76
- if (__DEV__) {
77
- console.error('[ThemeStorage] Error clearing theme mode:', errorMessage);
78
- }
64
+ } catch {
79
65
  // Don't throw - clearing storage is not critical
80
66
  }
81
67
  }
@@ -123,9 +123,6 @@ class MaterialColorMapper implements ColorMapper {
123
123
  return tokens.colors.textSecondary;
124
124
 
125
125
  default:
126
- if (__DEV__) {
127
- console.warn(`Unknown color variant: ${color}`);
128
- }
129
126
  return tokens.colors.textPrimary;
130
127
  }
131
128
  }
@@ -28,7 +28,6 @@ export class ClipboardUtils {
28
28
  try {
29
29
  await Clipboard.setStringAsync(text);
30
30
  } catch (error) {
31
- console.error('[ClipboardUtils] Failed to copy to clipboard:', error);
32
31
  throw error;
33
32
  }
34
33
  }
@@ -40,7 +39,6 @@ export class ClipboardUtils {
40
39
  try {
41
40
  return await Clipboard.getStringAsync();
42
41
  } catch (error) {
43
- console.error('[ClipboardUtils] Failed to get from clipboard:', error);
44
42
  throw error;
45
43
  }
46
44
  }
@@ -51,8 +49,7 @@ export class ClipboardUtils {
51
49
  static async hasContent(): Promise<boolean> {
52
50
  try {
53
51
  return await Clipboard.hasStringAsync();
54
- } catch (error) {
55
- console.error('[ClipboardUtils] Failed to check clipboard:', error);
52
+ } catch {
56
53
  return false;
57
54
  }
58
55
  }
@@ -64,7 +61,6 @@ export class ClipboardUtils {
64
61
  try {
65
62
  await Clipboard.setStringAsync('');
66
63
  } catch (error) {
67
- console.error('[ClipboardUtils] Failed to clear clipboard:', error);
68
64
  throw error;
69
65
  }
70
66
  }