@umituz/react-native-settings 4.23.71 → 4.23.73

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.
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Memo Utilities
3
+ * Centralized memoization helpers to reduce code duplication
4
+ */
5
+ import { useMemo, useCallback, useRef, DependencyList } from 'react';
6
+ import type { DesignTokens } from '@umituz/react-native-design-system';
7
+
8
+ /**
9
+ * Custom hook to create memoized styles from a style factory function
10
+ * @param styleFactory Function that creates styles
11
+ * @param tokens Design tokens
12
+ * @param deps Dependencies for memoization
13
+ * @returns Memoized styles object
14
+ */
15
+ export function useMemoizedStyles<T>(
16
+ styleFactory: (tokens: DesignTokens) => T,
17
+ tokens: DesignTokens,
18
+ deps: DependencyList = []
19
+ ): T {
20
+ return useMemo(() => styleFactory(tokens), [tokens, ...deps]);
21
+ }
22
+
23
+ /**
24
+ * Custom hook to create a memoized callback with proper type inference
25
+ * @param callback Function to memoize
26
+ * @param deps Dependencies for memoization
27
+ * @returns Memoized callback
28
+ */
29
+ export function useMemoizedCallback<T extends (...args: any[]) => any>(
30
+ callback: T,
31
+ deps: DependencyList
32
+ ): T {
33
+ return useCallback(callback, deps) as T;
34
+ }
35
+
36
+ /**
37
+ * Custom hook to create a memoized value with proper type inference
38
+ * @param factory Function that creates the value
39
+ * @param deps Dependencies for memoization
40
+ * @returns Memoized value
41
+ */
42
+ export function useMemoizedValue<T>(
43
+ factory: () => T,
44
+ deps: DependencyList
45
+ ): T {
46
+ return useMemo(factory, deps);
47
+ }
48
+
49
+ /**
50
+ * Creates a memoized style object with proper caching
51
+ * @param styleCreator Function that creates styles
52
+ * @param deps Dependencies for memoization
53
+ * @returns Memoized styles
54
+ */
55
+ export function useStyledMemo<T extends Record<string, any>>(
56
+ styleCreator: () => T,
57
+ deps: DependencyList = []
58
+ ): T {
59
+ return useMemo(styleCreator, deps);
60
+ }
61
+
62
+ /**
63
+ * Memoizes a value with a custom equality check (non-hook version)
64
+ * @param value Value to memoize
65
+ * @param _isEqual Custom equality function
66
+ * @returns Memoized value
67
+ */
68
+ export function memoWithEquality<T>(
69
+ value: T,
70
+ _isEqual: (prev: T, next: T) => boolean
71
+ ): T {
72
+ // This is a utility function, not a hook
73
+ // It cannot use hooks internally
74
+ return value;
75
+ }
76
+
77
+ /**
78
+ * Creates a cache key for style memoization
79
+ * @param tokens Design tokens
80
+ * @param prefix Optional prefix for the key
81
+ * @returns Cache key string
82
+ */
83
+ export function createStyleCacheKey(
84
+ tokens: DesignTokens,
85
+ prefix: string = ''
86
+ ): string {
87
+ const { colors, spacing, typography } = tokens;
88
+
89
+ return `${prefix}-${JSON.stringify({
90
+ colors: { primary: colors.primary, background: colors.backgroundPrimary },
91
+ spacing: { md: spacing.md, lg: spacing.lg },
92
+ typography: { body: typography.bodyMedium.responsiveFontSize },
93
+ })}`;
94
+ }
95
+
96
+ /**
97
+ * Memoizes a value with a custom equality check
98
+ * @param value Value to memoize
99
+ * @param _isEqual Custom equality function
100
+ * @returns Memoized value
101
+ */
102
+ export function useMemoWithEquality<T>(
103
+ value: T,
104
+ _isEqual: (prev: T, next: T) => boolean
105
+ ): T {
106
+ const ref = useRef<T>(value);
107
+
108
+ return useMemo(() => {
109
+ if (!_isEqual(ref.current, value)) {
110
+ ref.current = value;
111
+ }
112
+ return ref.current;
113
+ }, [value, _isEqual]);
114
+ }
115
+
116
+ /**
117
+ * Custom hook that creates a debounced callback
118
+ * @param callback Function to debounce
119
+ * @param delay Delay in milliseconds
120
+ * @returns Debounced callback
121
+ */
122
+ export function useDebouncedCallback<T extends (...args: any[]) => any>(
123
+ callback: T,
124
+ delay: number
125
+ ): T {
126
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null);
127
+
128
+ return useCallback((...args: Parameters<T>) => {
129
+ if (timeoutRef.current) {
130
+ clearTimeout(timeoutRef.current);
131
+ }
132
+
133
+ timeoutRef.current = setTimeout(() => {
134
+ callback(...args);
135
+ }, delay);
136
+ }, [callback, delay]) as T;
137
+ }
138
+
139
+ /**
140
+ * Custom hook that creates a throttled callback
141
+ * @param callback Function to throttle
142
+ * @param delay Delay in milliseconds
143
+ * @returns Throttled callback
144
+ */
145
+ export function useThrottledCallback<T extends (...args: any[]) => any>(
146
+ callback: T,
147
+ delay: number
148
+ ): T {
149
+ const lastRunRef = useRef<number>(0);
150
+
151
+ return useCallback((...args: Parameters<T>) => {
152
+ const now = Date.now();
153
+
154
+ if (now - lastRunRef.current >= delay) {
155
+ callback(...args);
156
+ lastRunRef.current = now;
157
+ }
158
+ }, [callback, delay]) as T;
159
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Style Utilities
3
+ * Centralized style creation functions to reduce code duplication
4
+ */
5
+ import { StyleSheet, ViewStyle, TextStyle, ImageStyle } from 'react-native';
6
+ import type { DesignTokens } from '@umituz/react-native-design-system';
7
+
8
+ /**
9
+ * Creates a container style with flex 1
10
+ */
11
+ export const createContainerStyle = (overrides: ViewStyle = {}): ViewStyle => ({
12
+ flex: 1,
13
+ ...overrides,
14
+ });
15
+
16
+ /**
17
+ * Creates a centered container style
18
+ */
19
+ export const createCenteredContainerStyle = (overrides: ViewStyle = {}): ViewStyle => ({
20
+ flex: 1,
21
+ justifyContent: 'center',
22
+ alignItems: 'center',
23
+ ...overrides,
24
+ });
25
+
26
+ /**
27
+ * Creates a row style for horizontal layouts
28
+ */
29
+ export const createRowStyle = (overrides: ViewStyle = {}): ViewStyle => ({
30
+ flexDirection: 'row',
31
+ alignItems: 'center',
32
+ ...overrides,
33
+ });
34
+
35
+ /**
36
+ * Creates a header style
37
+ */
38
+ export const createHeaderStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
39
+ paddingHorizontal: tokens.spacing.lg,
40
+ paddingVertical: tokens.spacing.md,
41
+ ...overrides,
42
+ });
43
+
44
+ /**
45
+ * Creates a section style
46
+ */
47
+ export const createSectionStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
48
+ padding: tokens.spacing.lg,
49
+ ...overrides,
50
+ });
51
+
52
+ /**
53
+ * Creates a card style
54
+ */
55
+ export const createCardStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
56
+ backgroundColor: tokens.colors.surface,
57
+ borderRadius: tokens.borders.radius.md,
58
+ padding: tokens.spacing.lg,
59
+ ...overrides,
60
+ });
61
+
62
+ /**
63
+ * Creates a title text style
64
+ */
65
+ export const createTitleStyle = (tokens: DesignTokens, overrides: TextStyle = {}): TextStyle => ({
66
+ fontSize: tokens.typography.headlineMedium.responsiveFontSize,
67
+ fontWeight: '600',
68
+ color: tokens.colors.textPrimary,
69
+ ...overrides,
70
+ });
71
+
72
+ /**
73
+ * Creates a subtitle text style
74
+ */
75
+ export const createSubtitleStyle = (tokens: DesignTokens, overrides: TextStyle = {}): TextStyle => ({
76
+ fontSize: tokens.typography.bodyMedium.responsiveFontSize,
77
+ color: tokens.colors.textSecondary,
78
+ ...overrides,
79
+ });
80
+
81
+ /**
82
+ * Creates a button style
83
+ */
84
+ export const createButtonStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
85
+ backgroundColor: tokens.colors.primary,
86
+ borderRadius: tokens.borders.radius.md,
87
+ paddingVertical: tokens.spacing.md,
88
+ paddingHorizontal: tokens.spacing.lg,
89
+ ...overrides,
90
+ });
91
+
92
+ /**
93
+ * Creates an icon container style
94
+ */
95
+ export const createIconContainerStyle = (
96
+ size: number = 48,
97
+ tokens: DesignTokens,
98
+ overrides: ViewStyle = {}
99
+ ): ViewStyle => ({
100
+ width: size,
101
+ height: size,
102
+ borderRadius: size / 2,
103
+ justifyContent: 'center',
104
+ alignItems: 'center',
105
+ backgroundColor: tokens.colors.surfaceSecondary,
106
+ ...overrides,
107
+ });
108
+
109
+ /**
110
+ * Creates a scroll content style
111
+ */
112
+ export const createScrollContentStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
113
+ padding: tokens.spacing.lg,
114
+ ...overrides,
115
+ });
116
+
117
+ /**
118
+ * Creates a separator/border style
119
+ */
120
+ export const createSeparatorStyle = (tokens: DesignTokens, overrides: ViewStyle = {}): ViewStyle => ({
121
+ height: 1,
122
+ backgroundColor: tokens.colors.border,
123
+ ...overrides,
124
+ });
125
+
126
+ /**
127
+ * Creates a margin utility style
128
+ */
129
+ export const createMarginStyle = (
130
+ spacing: 'xs' | 'sm' | 'md' | 'lg' | 'xl',
131
+ tokens: DesignTokens,
132
+ overrides: ViewStyle = {}
133
+ ): ViewStyle => ({
134
+ margin: tokens.spacing[spacing],
135
+ ...overrides,
136
+ });
137
+
138
+ /**
139
+ * Creates a padding utility style
140
+ */
141
+ export const createPaddingStyle = (
142
+ spacing: 'xs' | 'sm' | 'md' | 'lg' | 'xl',
143
+ tokens: DesignTokens,
144
+ overrides: ViewStyle = {}
145
+ ): ViewStyle => ({
146
+ padding: tokens.spacing[spacing],
147
+ ...overrides,
148
+ });
149
+
150
+ /**
151
+ * Combines multiple styles into one
152
+ */
153
+ export const combineStyles = (
154
+ ...styles: (ViewStyle | TextStyle | ImageStyle | undefined | false)[]
155
+ ): ViewStyle | TextStyle | ImageStyle => {
156
+ return StyleSheet.flatten(styles.filter(Boolean));
157
+ };
158
+
159
+ /**
160
+ * Creates a responsive style based on screen dimensions
161
+ */
162
+ export const createResponsiveStyle = (
163
+ _tokens: DesignTokens,
164
+ phoneStyle: ViewStyle,
165
+ _tabletStyle?: ViewStyle
166
+ ): ViewStyle => {
167
+ // For now, return phone style. Can be enhanced with actual responsive logic
168
+ return phoneStyle;
169
+ };
170
+
171
+ /**
172
+ * Type guard for ViewStyle
173
+ */
174
+ export const isViewStyle = (style: any): style is ViewStyle => {
175
+ return style && typeof style === 'object';
176
+ };
177
+
178
+ /**
179
+ * Creates a safe area aware style
180
+ */
181
+ export const createSafeAreaStyle = (
182
+ insets: { top?: number; bottom?: number; left?: number; right?: number },
183
+ overrides: ViewStyle = {}
184
+ ): ViewStyle => ({
185
+ paddingTop: insets.top,
186
+ paddingBottom: insets.bottom,
187
+ paddingLeft: insets.left,
188
+ paddingRight: insets.right,
189
+ ...overrides,
190
+ });
@@ -10,7 +10,6 @@ import {
10
10
  } from "@umituz/react-native-design-system";
11
11
  import { SettingsHeader } from "./components/SettingsHeader";
12
12
  import { SettingsContent } from "./components/SettingsContent";
13
- import { SettingsErrorBoundary } from "../components/SettingsErrorBoundary";
14
13
  import { normalizeSettingsConfig } from "./utils/normalizeConfig";
15
14
  import { useFeatureDetection } from "./hooks/useFeatureDetection";
16
15
  import type { SettingsConfig, CustomSettingsSection } from "./types";
@@ -95,7 +94,6 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
95
94
  // Workaround: Use conditional rendering with type assertion
96
95
  if (showHeader) {
97
96
  return <ScreenLayout header={<SettingsHeader showCloseButton={showCloseButton} onClose={onClose} />}>
98
- <SettingsErrorBoundary>
99
97
  {children ?? (
100
98
  <SettingsContent
101
99
  normalizedConfig={normalizedConfig}
@@ -110,12 +108,10 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
110
108
  gamificationConfig={gamificationConfig}
111
109
  />
112
110
  )}
113
- </SettingsErrorBoundary>
114
111
  </ScreenLayout>;
115
112
  }
116
113
 
117
114
  return <ScreenLayout>
118
- <SettingsErrorBoundary>
119
115
  {children ?? (
120
116
  <SettingsContent
121
117
  normalizedConfig={normalizedConfig}
@@ -130,6 +126,5 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
130
126
  gamificationConfig={gamificationConfig}
131
127
  />
132
128
  )}
133
- </SettingsErrorBoundary>
134
129
  </ScreenLayout>;
135
130
  };
@@ -1,67 +0,0 @@
1
- # Settings Error Boundary
2
-
3
- ## Purpose
4
-
5
- Error boundary component for catching and handling errors in settings screens and components, providing fallback UI and error recovery options.
6
-
7
- ## File Paths
8
-
9
- - **Component**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/presentation/components/SettingsErrorBoundary/SettingsErrorBoundary.tsx`
10
-
11
- ## Strategy
12
-
13
- 1. **Error Containment**: Catches JavaScript errors in the component tree below it, preventing app crashes
14
- 2. **User-Friendly Fallback**: Displays clear, non-technical error messages to users
15
- 3. **Error Recovery**: Provides retry or reset actions to recover from errors
16
- 4. **Development Support**: Shows detailed error information in development mode for debugging
17
- 5. **Error Reporting**: Integrates with error tracking services for monitoring
18
-
19
- ## Restrictions (Forbidden)
20
-
21
- ### DO NOT
22
- - ❌ DO NOT wrap individual small components (use at screen or major section level)
23
- - ❌ DO NOT use error boundaries to handle expected errors (e.g., network failures)
24
- - ❌ DO NOT show technical stack traces to end users in production
25
-
26
- ### NEVER
27
- - ❌ NEVER use error boundaries inside event handlers or async code
28
- - ❌ NEVER use error boundaries to control flow or business logic
29
- - ❌ NEVER expose sensitive information in error messages
30
-
31
- ### AVOID
32
- - ❌ AVOID nesting multiple error boundaries without clear purpose
33
- - ❌ AVOID generic error messages that don't help users understand what happened
34
- - ❌ AVOID blocking the entire app when a recoverable error occurs
35
-
36
- ## Rules (Mandatory)
37
-
38
- ### ALWAYS
39
- - ✅ ALWAYS provide a clear fallback UI when errors occur
40
- - ✅ ALWAYS log errors for debugging and monitoring
41
- - ✅ ALWAYS integrate with error tracking services (e.g., Sentry)
42
- - ✅ ALWAYS show user-friendly error messages in production
43
-
44
- ### MUST
45
- - ✅ MUST offer recovery options (retry, reset, or navigation) to users
46
- - ✅ MUST ensure error boundaries don't interfere with normal error handling
47
- - ✅ MUST test error scenarios during development
48
-
49
- ### SHOULD
50
- - ✅ SHOULD provide context-specific error messages when possible
51
- - ✅ SHOULD include development-only error details for debugging
52
- - ✅ SHOULD offer a way to report errors or contact support
53
-
54
- ## AI Agent Guidelines
55
-
56
- 1. **File Reference**: When implementing error handling, refer to `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/presentation/components/SettingsErrorBoundary/SettingsErrorBoundary.tsx`
57
- 2. **Placement Strategy**: Place error boundaries at strategic locations (screen level, major feature sections)
58
- 3. **Fallback Design**: Design fallback UIs that match your app's visual design
59
- 4. **Error Tracking**: Always integrate with error tracking services like Sentry or Crashlytics
60
- 5. **Recovery Logic**: Implement appropriate recovery actions based on error type and context
61
-
62
- ## Component Reference
63
-
64
- Related components:
65
- - **SettingsScreen**: Main screen component that uses error boundaries
66
- - **SettingsContent**: Content component wrapped by error boundaries
67
- - **React Error Boundaries**: Official React documentation for error boundaries
@@ -1,139 +0,0 @@
1
- /**
2
- * Settings Error Boundary Component
3
- * Catches and handles errors in settings components
4
- */
5
-
6
- import React, { Component, ReactNode } from 'react';
7
- import { View, StyleSheet } from 'react-native';
8
- import { useAppDesignTokens } from '@umituz/react-native-design-system';
9
- import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
10
- import { useLocalization } from '../../domains/localization';
11
-
12
- interface Props {
13
- children: ReactNode;
14
- fallback?: ReactNode;
15
- fallbackTitle?: string;
16
- fallbackMessage?: string;
17
- }
18
-
19
- interface State {
20
- hasError: boolean;
21
- error?: Error;
22
- }
23
-
24
- export class SettingsErrorBoundary extends Component<Props, State> {
25
- override state: State = {
26
- hasError: false,
27
- error: undefined,
28
- };
29
-
30
- static getDerivedStateFromError(error: Error): State {
31
- return { hasError: true, error };
32
- }
33
-
34
- override componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
35
- // Log error to console in development
36
- if (__DEV__) {
37
- console.error('Settings Error Boundary caught an error:', error);
38
- console.error('Error Info:', errorInfo);
39
- }
40
-
41
- // TODO: Send to error tracking service in production
42
- // Example: Sentry.captureException(error, { contexts: { react: { errorInfo } } });
43
- }
44
-
45
- override render(): ReactNode {
46
- const { hasError, error } = this.state;
47
- const { children, fallback, fallbackTitle, fallbackMessage } = this.props;
48
-
49
- if (hasError) {
50
- if (fallback) {
51
- return fallback;
52
- }
53
-
54
- return (
55
- <ErrorBoundaryFallback
56
- error={error}
57
- fallbackTitle={fallbackTitle}
58
- fallbackMessage={fallbackMessage}
59
- />
60
- );
61
- }
62
-
63
- return children;
64
- }
65
- }
66
-
67
- interface ErrorBoundaryFallbackProps {
68
- error?: Error;
69
- fallbackTitle?: string;
70
- fallbackMessage?: string;
71
- }
72
-
73
- const ErrorBoundaryFallback: React.FC<ErrorBoundaryFallbackProps> = ({
74
- error,
75
- fallbackTitle,
76
- fallbackMessage
77
- }) => {
78
- const tokens = useAppDesignTokens();
79
- const { t } = useLocalization();
80
-
81
- const title = __DEV__ && error?.message
82
- ? t("error_boundary.dev_title")
83
- : (fallbackTitle || t("error_boundary.title"));
84
-
85
- const message = __DEV__ && error?.message
86
- ? `${t("error_boundary.dev_message")}: ${error.message}`
87
- : (fallbackMessage || t("error_boundary.message"));
88
-
89
- return (
90
- <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
91
- <View style={[styles.content, { backgroundColor: tokens.colors.surface }]}>
92
- <AtomicIcon
93
- name="alert-circle"
94
- color="warning"
95
- size="lg"
96
- style={styles.icon}
97
- />
98
- <AtomicText
99
- type="headlineSmall"
100
- color="primary"
101
- style={styles.title}
102
- >
103
- {title}
104
- </AtomicText>
105
- <AtomicText
106
- type="bodyMedium"
107
- color="secondary"
108
- style={styles.message}
109
- >
110
- {message}
111
- </AtomicText>
112
- </View>
113
- </View>
114
- );
115
- };
116
-
117
- const styles = StyleSheet.create({
118
- container: {
119
- flex: 1,
120
- padding: 16,
121
- justifyContent: 'center',
122
- },
123
- content: {
124
- alignItems: 'center',
125
- padding: 24,
126
- borderRadius: 12,
127
- },
128
- icon: {
129
- marginBottom: 16,
130
- },
131
- title: {
132
- marginBottom: 8,
133
- textAlign: 'center',
134
- },
135
- message: {
136
- textAlign: 'center',
137
- lineHeight: 20,
138
- },
139
- });