@umituz/react-native-design-system 4.28.4 → 4.28.6

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/atoms/AtomicInput.tsx +2 -2
  3. package/src/index.ts +1 -1
  4. package/src/molecules/Divider/Divider.tsx +2 -3
  5. package/src/molecules/Divider/types.ts +22 -5
  6. package/src/molecules/StepHeader/StepHeader.constants.ts +48 -0
  7. package/src/molecules/StepHeader/StepHeader.tsx +29 -23
  8. package/src/molecules/StepProgress/StepProgress.constants.ts +23 -0
  9. package/src/molecules/StepProgress/StepProgress.tsx +9 -6
  10. package/src/molecules/avatar/Avatar.constants.ts +20 -2
  11. package/src/molecules/avatar/Avatar.tsx +5 -3
  12. package/src/molecules/avatar/Avatar.utils.ts +4 -4
  13. package/src/molecules/avatar/AvatarGroup.tsx +2 -2
  14. package/src/molecules/listitem/styles/listItemStyles.ts +2 -3
  15. package/src/molecules/navigation/hooks/useAppFocusEffect.ts +14 -11
  16. package/src/molecules/navigation/hooks/useAppIsFocused.ts +1 -2
  17. package/src/molecules/navigation/hooks/useAppNavigation.ts +88 -118
  18. package/src/molecules/navigation/hooks/useAppRoute.ts +26 -27
  19. package/src/onboarding/domain/entities/ChatMessage.ts +19 -0
  20. package/src/onboarding/domain/entities/ChatStep.ts +72 -0
  21. package/src/onboarding/index.ts +29 -0
  22. package/src/onboarding/infrastructure/hooks/useChatAnimations.ts +145 -0
  23. package/src/onboarding/presentation/components/chat/ChatMessage.tsx +166 -0
  24. package/src/onboarding/presentation/components/chat/ChatOptionButton.tsx +145 -0
  25. package/src/onboarding/presentation/components/chat/TypingIndicator.tsx +99 -0
  26. package/src/onboarding/presentation/components/chat/index.ts +12 -0
  27. package/src/onboarding/presentation/hooks/useChatOnboarding.ts +278 -0
  28. package/src/onboarding/presentation/screens/ChatOnboardingScreen.tsx +276 -0
  29. package/src/utils/index.ts +13 -0
  30. package/src/utils/responsiveUtils.ts +110 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.28.4",
3
+ "version": "4.28.6",
4
4
  "description": "Universal design system for React Native apps with safe navigation hooks - updated SKILL.md with navigation documentation",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./dist/index.d.ts",
@@ -92,12 +92,12 @@ export const AtomicInput = React.forwardRef<React.ElementRef<typeof TextInput>,
92
92
  fontSize: sizeConfig.fontSize,
93
93
  lineHeight: (sizeConfig.fontSize || 16) * 1.2,
94
94
  color: textColor,
95
- paddingVertical: 4,
95
+ paddingVertical: Math.floor(4 * tokens.spacingMultiplier),
96
96
  paddingLeft: leadingIcon ? iconPadding : undefined,
97
97
  paddingRight: (trailingIcon || showPasswordToggle) ? iconPadding : undefined,
98
98
  },
99
99
  inputStyle,
100
- ], [sizeConfig, textColor, leadingIcon, trailingIcon, showPasswordToggle, iconPadding, inputStyle]);
100
+ ], [sizeConfig, textColor, leadingIcon, trailingIcon, showPasswordToggle, iconPadding, inputStyle, tokens.spacingMultiplier]);
101
101
 
102
102
  return (
103
103
  <View testID={testID}>
package/src/index.ts CHANGED
@@ -31,7 +31,7 @@
31
31
  * /tanstack - TanstackProvider
32
32
  * /loading - LoadingProvider, useGlobalLoading
33
33
  * /haptics - HapticService, useHaptics
34
- * /onboarding - OnboardingScreen
34
+ * /onboarding - OnboardingScreen, ChatOnboardingScreen (chat-based)
35
35
  * /gallery - gallerySaveService
36
36
  * /carousel - Carousel components
37
37
  * /init - createAppInitializer, createEnvConfig
@@ -75,7 +75,7 @@ export const Divider: React.FC<DividerProps> = ({
75
75
  style,
76
76
  }) => {
77
77
  const tokens = useAppDesignTokens();
78
- const spacingValue = DividerUtils.getSpacing(spacing);
78
+ const spacingValue = DividerUtils.getSpacing(spacing, tokens.spacingMultiplier);
79
79
  const borderColor = color || tokens.colors.border;
80
80
 
81
81
  // Determine border style based on lineStyle
@@ -144,7 +144,7 @@ export const Divider: React.FC<DividerProps> = ({
144
144
  <AtomicText
145
145
  type="bodySmall"
146
146
  color="secondary"
147
- style={styles.textLabel}
147
+ style={[styles.textLabel, { marginHorizontal: Math.floor(12 * tokens.spacingMultiplier) }]}
148
148
  >
149
149
  {text}
150
150
  </AtomicText>
@@ -181,7 +181,6 @@ const styles = StyleSheet.create({
181
181
  flex: 1,
182
182
  },
183
183
  textLabel: {
184
- marginHorizontal: 12,
185
184
  fontWeight: '500',
186
185
  },
187
186
  });
@@ -42,24 +42,41 @@ export interface DividerConfig {
42
42
  }
43
43
 
44
44
  /**
45
- * Spacing configurations (px)
45
+ * Base spacing configurations (px) - will be multiplied by spacingMultiplier
46
46
  */
47
- export const SPACING_CONFIGS: Record<DividerSpacing, number> = {
47
+ const BASE_SPACING_CONFIGS: Record<DividerSpacing, number> = {
48
48
  none: 0,
49
49
  small: 8,
50
50
  medium: 16,
51
51
  large: 24,
52
52
  };
53
53
 
54
+ /**
55
+ * Get responsive spacing value
56
+ * Multiplies base spacing by spacingMultiplier for tablet/small device support
57
+ */
58
+ export const getSpacingConfigs = (spacingMultiplier: number): Record<DividerSpacing, number> => {
59
+ return Object.entries(BASE_SPACING_CONFIGS).reduce((acc, [key, value]) => {
60
+ acc[key as DividerSpacing] = Math.floor(value * spacingMultiplier);
61
+ return acc;
62
+ }, {} as Record<DividerSpacing, number>);
63
+ };
64
+
65
+ /**
66
+ * @deprecated Use getSpacingConfigs(spacingMultiplier) instead
67
+ * Kept for backward compatibility
68
+ */
69
+ export const SPACING_CONFIGS = BASE_SPACING_CONFIGS;
70
+
54
71
  /**
55
72
  * Divider utility class
56
73
  */
57
74
  export class DividerUtils {
58
75
  /**
59
- * Get spacing value
76
+ * Get spacing value (responsive)
60
77
  */
61
- static getSpacing(spacing: DividerSpacing): number {
62
- return SPACING_CONFIGS[spacing];
78
+ static getSpacing(spacing: DividerSpacing, spacingMultiplier: number = 1): number {
79
+ return Math.floor(BASE_SPACING_CONFIGS[spacing] * spacingMultiplier);
63
80
  }
64
81
 
65
82
  /**
@@ -0,0 +1,48 @@
1
+ /**
2
+ * StepHeader Constants
3
+ *
4
+ * Base size configurations for StepHeader component.
5
+ * All sizes will be multiplied by spacingMultiplier at runtime.
6
+ */
7
+
8
+ /**
9
+ * Base font sizes (px) - before spacingMultiplier
10
+ */
11
+ export const BASE_FONT_SIZES = {
12
+ title: 28,
13
+ subtitle: 16,
14
+ } as const;
15
+
16
+ /**
17
+ * Base spacing (px) - before spacingMultiplier
18
+ */
19
+ export const BASE_SPACING = {
20
+ marginBottom: 32,
21
+ paddingHorizontal: 24,
22
+ stepIndicatorMarginBottom: 12,
23
+ titleMarginBottom: 12,
24
+ } as const;
25
+
26
+ /**
27
+ * Base step dot sizes (px) - before spacingMultiplier
28
+ */
29
+ export const BASE_STEP_DOT_SIZES = {
30
+ width: 8,
31
+ height: 8,
32
+ borderRadius: 4,
33
+ marginHorizontal: 4,
34
+ } as const;
35
+
36
+ /**
37
+ * Default configuration
38
+ */
39
+ export const DEFAULT_CONFIG = {
40
+ showStepIndicator: false,
41
+ titleAlignment: "left" as const,
42
+ titleFontSize: BASE_FONT_SIZES.title,
43
+ subtitleFontSize: BASE_FONT_SIZES.subtitle,
44
+ spacing: {
45
+ marginBottom: BASE_SPACING.marginBottom,
46
+ paddingHorizontal: BASE_SPACING.paddingHorizontal,
47
+ },
48
+ } as const;
@@ -9,6 +9,16 @@ import React, { useMemo } from "react";
9
9
  import { View, StyleSheet, type ViewStyle, type StyleProp } from "react-native";
10
10
  import { AtomicText } from "../../atoms/AtomicText";
11
11
  import { useAppDesignTokens } from "../../theme/hooks/useAppDesignTokens";
12
+ import {
13
+ calculateResponsiveSize,
14
+ calculateLineHeight,
15
+ } from "../../utils/responsiveUtils";
16
+ import {
17
+ BASE_FONT_SIZES,
18
+ BASE_SPACING,
19
+ BASE_STEP_DOT_SIZES,
20
+ DEFAULT_CONFIG,
21
+ } from "./StepHeader.constants";
12
22
 
13
23
  export interface StepHeaderConfig {
14
24
  showStepIndicator?: boolean;
@@ -30,17 +40,6 @@ export interface StepHeaderProps {
30
40
  style?: StyleProp<ViewStyle>;
31
41
  }
32
42
 
33
- const DEFAULT_CONFIG: StepHeaderConfig = {
34
- showStepIndicator: false,
35
- titleAlignment: "left",
36
- titleFontSize: 28,
37
- subtitleFontSize: 16,
38
- spacing: {
39
- marginBottom: 32,
40
- paddingHorizontal: 24,
41
- },
42
- };
43
-
44
43
  export const StepHeader: React.FC<StepHeaderProps> = ({
45
44
  title,
46
45
  subtitle,
@@ -49,24 +48,31 @@ export const StepHeader: React.FC<StepHeaderProps> = ({
49
48
  }) => {
50
49
  const tokens = useAppDesignTokens();
51
50
  const cfg = useMemo(() => ({ ...DEFAULT_CONFIG, ...config }), [config]);
51
+ const spacingMultiplier = tokens.spacingMultiplier;
52
52
 
53
53
  const styles = useMemo(
54
54
  () =>
55
55
  StyleSheet.create({
56
56
  container: {
57
- paddingHorizontal: cfg.spacing?.paddingHorizontal ?? 24,
58
- marginBottom: cfg.spacing?.marginBottom ?? 32,
57
+ paddingHorizontal: calculateResponsiveSize(
58
+ cfg.spacing?.paddingHorizontal ?? BASE_SPACING.paddingHorizontal,
59
+ spacingMultiplier
60
+ ),
61
+ marginBottom: calculateResponsiveSize(
62
+ cfg.spacing?.marginBottom ?? BASE_SPACING.marginBottom,
63
+ spacingMultiplier
64
+ ),
59
65
  },
60
66
  stepIndicator: {
61
67
  flexDirection: "row",
62
68
  alignItems: "center",
63
- marginBottom: 12,
69
+ marginBottom: calculateResponsiveSize(BASE_SPACING.stepIndicatorMarginBottom, spacingMultiplier),
64
70
  },
65
71
  stepDot: {
66
- width: 8,
67
- height: 8,
68
- borderRadius: 4,
69
- marginHorizontal: 4,
72
+ width: calculateResponsiveSize(BASE_STEP_DOT_SIZES.width, spacingMultiplier),
73
+ height: calculateResponsiveSize(BASE_STEP_DOT_SIZES.height, spacingMultiplier),
74
+ borderRadius: calculateResponsiveSize(BASE_STEP_DOT_SIZES.borderRadius, spacingMultiplier),
75
+ marginHorizontal: calculateResponsiveSize(BASE_STEP_DOT_SIZES.marginHorizontal, spacingMultiplier),
70
76
  },
71
77
  activeDot: {
72
78
  backgroundColor: tokens.colors.primary,
@@ -75,23 +81,23 @@ export const StepHeader: React.FC<StepHeaderProps> = ({
75
81
  backgroundColor: `${tokens.colors.primary}30`,
76
82
  },
77
83
  title: {
78
- fontSize: cfg.titleFontSize,
84
+ fontSize: calculateResponsiveSize(cfg.titleFontSize ?? BASE_FONT_SIZES.title, spacingMultiplier),
79
85
  fontWeight: "900",
80
86
  color: tokens.colors.textPrimary,
81
87
  textAlign: cfg.titleAlignment,
82
- marginBottom: subtitle ? 12 : 0,
88
+ marginBottom: subtitle ? calculateResponsiveSize(BASE_SPACING.titleMarginBottom, spacingMultiplier) : 0,
83
89
  letterSpacing: 0.3,
84
90
  },
85
91
  subtitle: {
86
- fontSize: cfg.subtitleFontSize,
92
+ fontSize: calculateResponsiveSize(cfg.subtitleFontSize ?? BASE_FONT_SIZES.subtitle, spacingMultiplier),
87
93
  fontWeight: "500",
88
94
  color: tokens.colors.textSecondary,
89
95
  textAlign: cfg.titleAlignment,
90
- lineHeight: (cfg.subtitleFontSize ?? 16) * 1.5,
96
+ lineHeight: calculateLineHeight(cfg.subtitleFontSize ?? BASE_FONT_SIZES.subtitle, spacingMultiplier),
91
97
  opacity: 0.9,
92
98
  },
93
99
  }),
94
- [tokens, cfg, subtitle],
100
+ [tokens, cfg, subtitle, spacingMultiplier],
95
101
  );
96
102
 
97
103
  return (
@@ -0,0 +1,23 @@
1
+ /**
2
+ * StepProgress Constants
3
+ *
4
+ * Base size configurations for StepProgress component.
5
+ * All sizes will be multiplied by spacingMultiplier at runtime.
6
+ */
7
+
8
+ /**
9
+ * Base spacing (px) - before spacingMultiplier
10
+ */
11
+ export const BASE_SPACING = {
12
+ gap: 8,
13
+ paddingHorizontal: 24,
14
+ paddingVertical: 16,
15
+ } as const;
16
+
17
+ /**
18
+ * Base step dimensions (px) - before spacingMultiplier
19
+ */
20
+ export const BASE_STEP_DIMENSIONS = {
21
+ height: 4,
22
+ borderRadius: 2,
23
+ } as const;
@@ -1,6 +1,8 @@
1
1
  import React, { useMemo } from "react";
2
2
  import { View, StyleSheet, ViewStyle } from "react-native";
3
3
  import { useAppDesignTokens } from '../../theme/hooks/useAppDesignTokens';
4
+ import { calculateResponsiveSize } from '../../utils/responsiveUtils';
5
+ import { BASE_SPACING, BASE_STEP_DIMENSIONS } from './StepProgress.constants';
4
6
 
5
7
  export interface StepProgressProps {
6
8
  currentStep: number;
@@ -14,27 +16,28 @@ export const StepProgress: React.FC<StepProgressProps> = ({
14
16
  style,
15
17
  }) => {
16
18
  const tokens = useAppDesignTokens();
19
+ const spacingMultiplier = tokens.spacingMultiplier;
17
20
 
18
21
  const styles = useMemo(
19
22
  () =>
20
23
  StyleSheet.create({
21
24
  container: {
22
25
  flexDirection: "row",
23
- gap: 8,
24
- paddingHorizontal: 24,
25
- paddingVertical: 16,
26
+ gap: calculateResponsiveSize(BASE_SPACING.gap, spacingMultiplier),
27
+ paddingHorizontal: calculateResponsiveSize(BASE_SPACING.paddingHorizontal, spacingMultiplier),
28
+ paddingVertical: calculateResponsiveSize(BASE_SPACING.paddingVertical, spacingMultiplier),
26
29
  },
27
30
  step: {
28
31
  flex: 1,
29
- height: 4,
30
- borderRadius: 2,
32
+ height: calculateResponsiveSize(BASE_STEP_DIMENSIONS.height, spacingMultiplier),
33
+ borderRadius: calculateResponsiveSize(BASE_STEP_DIMENSIONS.borderRadius, spacingMultiplier),
31
34
  backgroundColor: tokens.colors.border,
32
35
  },
33
36
  activeStep: {
34
37
  backgroundColor: tokens.colors.primary,
35
38
  },
36
39
  }),
37
- [tokens],
40
+ [tokens, spacingMultiplier],
38
41
  );
39
42
 
40
43
  return (
@@ -4,11 +4,12 @@
4
4
  */
5
5
 
6
6
  import type { AvatarSize, AvatarShape, AvatarType, SizeConfig } from './Avatar.types';
7
+ import { calculateResponsiveSize, calculateResponsiveSizeSubtle } from '../../utils/responsiveUtils';
7
8
 
8
9
  /**
9
- * Size configurations (px)
10
+ * Base size configurations (px) - will be multiplied by spacingMultiplier
10
11
  */
11
- export const SIZE_CONFIGS: Record<AvatarSize, SizeConfig> = {
12
+ export const BASE_SIZE_CONFIGS: Record<AvatarSize, SizeConfig> = {
12
13
  xs: {
13
14
  size: 24,
14
15
  fontSize: 10,
@@ -53,6 +54,23 @@ export const SIZE_CONFIGS: Record<AvatarSize, SizeConfig> = {
53
54
  },
54
55
  };
55
56
 
57
+ /**
58
+ * Get responsive size configurations
59
+ * Multiplies base sizes by spacingMultiplier for tablet/small device support
60
+ */
61
+ export const getSizeConfigs = (spacingMultiplier: number): Record<AvatarSize, SizeConfig> => {
62
+ return Object.entries(BASE_SIZE_CONFIGS).reduce((acc, [key, config]) => {
63
+ acc[key as AvatarSize] = {
64
+ size: calculateResponsiveSize(config.size, spacingMultiplier),
65
+ fontSize: calculateResponsiveSize(config.fontSize, spacingMultiplier),
66
+ iconSize: calculateResponsiveSize(config.iconSize, spacingMultiplier),
67
+ statusSize: calculateResponsiveSize(config.statusSize, spacingMultiplier),
68
+ borderWidth: calculateResponsiveSizeSubtle(config.borderWidth, spacingMultiplier),
69
+ };
70
+ return acc;
71
+ }, {} as Record<AvatarSize, SizeConfig>);
72
+ };
73
+
56
74
  /**
57
75
  * Avatar background colors
58
76
  * Vibrant, accessible colors with good contrast
@@ -10,7 +10,8 @@ import { View, Image, StyleSheet, TouchableOpacity, type StyleProp, type ViewSty
10
10
  import { useAppDesignTokens } from '../../theme';
11
11
  import { AtomicText, AtomicIcon } from '../../atoms';
12
12
  import type { AvatarSize, AvatarShape } from './Avatar.types';
13
- import { SIZE_CONFIGS, AVATAR_CONSTANTS } from './Avatar.constants';
13
+ import type { SizeConfig } from './Avatar.types';
14
+ import { getSizeConfigs, AVATAR_CONSTANTS } from './Avatar.constants';
14
15
  import { AvatarUtils } from './Avatar.utils';
15
16
 
16
17
  export interface AvatarProps {
@@ -33,7 +34,7 @@ interface AvatarContentProps {
33
34
  uri?: string;
34
35
  initials: string;
35
36
  icon: string;
36
- config: typeof SIZE_CONFIGS[AvatarSize];
37
+ config: SizeConfig;
37
38
  borderRadius: number;
38
39
  imageStyle?: StyleProp<ImageStyle>;
39
40
  }
@@ -107,7 +108,8 @@ export const Avatar: React.FC<AvatarProps> = ({
107
108
  onPress,
108
109
  }) => {
109
110
  const tokens = useAppDesignTokens();
110
- const config = useMemo(() => SIZE_CONFIGS[size], [size]);
111
+ const sizeConfigs = useMemo(() => getSizeConfigs(tokens.spacingMultiplier), [tokens.spacingMultiplier]);
112
+ const config = useMemo(() => sizeConfigs[size], [size, sizeConfigs]);
111
113
 
112
114
  const hasImage = !!uri;
113
115
  const hasName = !!name;
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { AvatarSize, AvatarShape, AvatarConfig, SizeConfig } from './Avatar.types';
8
- import { AVATAR_COLORS, STATUS_COLORS, SHAPE_CONFIGS, SIZE_CONFIGS } from './Avatar.constants';
8
+ import { AVATAR_COLORS, STATUS_COLORS, SHAPE_CONFIGS, BASE_SIZE_CONFIGS } from './Avatar.constants';
9
9
 
10
10
  /**
11
11
  * Avatar utility class
@@ -71,10 +71,10 @@ export class AvatarUtils {
71
71
  }
72
72
 
73
73
  /**
74
- * Get size config
74
+ * Get base size config (before spacingMultiplier)
75
75
  */
76
- static getSizeConfig(size: AvatarSize): SizeConfig {
77
- return SIZE_CONFIGS[size] ?? SIZE_CONFIGS.md;
76
+ static getBaseSizeConfig(size: AvatarSize): SizeConfig {
77
+ return BASE_SIZE_CONFIGS[size] ?? BASE_SIZE_CONFIGS.md;
78
78
  }
79
79
 
80
80
  /**
@@ -11,7 +11,7 @@ import { useAppDesignTokens } from '../../theme';
11
11
  import { AtomicText } from '../../atoms';
12
12
  import { Avatar } from './Avatar';
13
13
  import type { AvatarSize, AvatarShape } from './Avatar.types';
14
- import { SIZE_CONFIGS, AVATAR_CONSTANTS } from './Avatar.constants';
14
+ import { BASE_SIZE_CONFIGS, AVATAR_CONSTANTS } from './Avatar.constants';
15
15
 
16
16
  /**
17
17
  * Avatar item for group
@@ -138,7 +138,7 @@ export const AvatarGroup: React.FC<AvatarGroupProps> = React.memo(({
138
138
  style,
139
139
  }) => {
140
140
  const tokens = useAppDesignTokens();
141
- const config = SIZE_CONFIGS[size];
141
+ const config = BASE_SIZE_CONFIGS[size];
142
142
 
143
143
  // Memoize calculations to prevent recalculation on every render
144
144
  const { visibleItems, overflowCount, hasOverflow } = useMemo(() => {
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import type { ViewStyle, TextStyle } from 'react-native';
5
5
  import type { DesignTokens } from '../../../theme';
6
- import { isTablet } from '../../../device/detection';
7
6
 
8
7
  export interface ListItemStyles {
9
8
  container: ViewStyle;
@@ -14,8 +13,8 @@ export interface ListItemStyles {
14
13
  }
15
14
 
16
15
  export const getListItemStyles = (tokens: DesignTokens): ListItemStyles => {
17
- // Responsive minHeight: 56px on phone, 64px on tablet for better ergonomics
18
- const minHeight = isTablet() ? 64 : 56;
16
+ // Responsive minHeight: uses base height (56) multiplied by spacingMultiplier
17
+ const minHeight = Math.floor(56 * tokens.spacingMultiplier);
19
18
 
20
19
  return {
21
20
  container: {
@@ -22,21 +22,24 @@ import { useEffect } from "react";
22
22
  * ```
23
23
  */
24
24
  export function useAppFocusEffect(effect: () => void | (() => void)): void {
25
+ // Always run the effect - if navigation is ready, useFocusEffect will handle it
26
+ // Otherwise, useEffect will run it once
27
+ useEffect(() => {
28
+ const cleanup = effect();
29
+ return () => {
30
+ if (typeof cleanup === 'function') {
31
+ cleanup();
32
+ }
33
+ };
34
+ }, [effect]);
35
+
36
+ // Try to use React Navigation's useFocusEffect if available
25
37
  try {
26
- // Try to use React Navigation's useFocusEffect
27
38
  useRNFocusEffect(effect);
28
- } catch (error) {
29
- // Navigation not ready - run effect once and cleanup
39
+ } catch (_error) {
40
+ // Navigation not ready - useEffect above handles it
30
41
  if (__DEV__) {
31
42
  console.warn('[useAppFocusEffect] Navigation not ready. Running effect once instead.');
32
43
  }
33
- useEffect(() => {
34
- const cleanup = effect();
35
- return () => {
36
- if (typeof cleanup === 'function') {
37
- cleanup();
38
- }
39
- };
40
- }, [effect]);
41
44
  }
42
45
  }
@@ -1,5 +1,4 @@
1
1
  import { useIsFocused as useRNIsFocused } from "@react-navigation/native";
2
- import { useMemo } from "react";
3
2
 
4
3
  /**
5
4
  * useAppIsFocused Hook
@@ -18,7 +17,7 @@ import { useMemo } from "react";
18
17
  export function useAppIsFocused(): boolean {
19
18
  try {
20
19
  return useRNIsFocused();
21
- } catch (error) {
20
+ } catch (_error) {
22
21
  // Navigation not ready - return false
23
22
  if (__DEV__) {
24
23
  console.warn('[useAppIsFocused] Navigation not ready. Returning false.');