@umituz/react-native-design-system 4.25.47 → 4.25.49

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.25.47",
3
+ "version": "4.25.49",
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",
@@ -222,9 +222,57 @@
222
222
  "@react-navigation/native": {
223
223
  "optional": true
224
224
  },
225
+ "@react-navigation/bottom-tabs": {
226
+ "optional": true
227
+ },
228
+ "@react-navigation/stack": {
229
+ "optional": true
230
+ },
231
+ "@tanstack/query-async-storage-persister": {
232
+ "optional": true
233
+ },
234
+ "@tanstack/react-query": {
235
+ "optional": true
236
+ },
237
+ "@tanstack/react-query-persist-client": {
238
+ "optional": true
239
+ },
225
240
  "expo-application": {
226
241
  "optional": true
227
242
  },
243
+ "expo-clipboard": {
244
+ "optional": true
245
+ },
246
+ "expo-crypto": {
247
+ "optional": true
248
+ },
249
+ "expo-font": {
250
+ "optional": true
251
+ },
252
+ "expo-haptics": {
253
+ "optional": true
254
+ },
255
+ "expo-image": {
256
+ "optional": true
257
+ },
258
+ "expo-image-manipulator": {
259
+ "optional": true
260
+ },
261
+ "expo-image-picker": {
262
+ "optional": true
263
+ },
264
+ "expo-network": {
265
+ "optional": true
266
+ },
267
+ "expo-secure-store": {
268
+ "optional": true
269
+ },
270
+ "expo-sharing": {
271
+ "optional": true
272
+ },
273
+ "expo-video": {
274
+ "optional": true
275
+ },
228
276
  "@react-native-community/datetimepicker": {
229
277
  "optional": true
230
278
  }
@@ -6,7 +6,7 @@
6
6
  * Artificial delays cause poor UX - the splash should transition as soon as app is ready.
7
7
  */
8
8
 
9
- import { useState, useEffect } from 'react';
9
+ import { useState, useEffect, useRef } from 'react';
10
10
  import { DeviceEventEmitter } from 'react-native';
11
11
 
12
12
  export interface UseSplashFlowOptions {
@@ -28,11 +28,13 @@ export interface UseSplashFlowResult {
28
28
  export const useSplashFlow = (options: UseSplashFlowOptions = {}): UseSplashFlowResult => {
29
29
  const { isAppReady, duration } = options;
30
30
  const [isInitialized, setIsInitialized] = useState(false);
31
+ const isInitializedRef = useRef(false);
31
32
 
32
33
  useEffect(() => {
33
34
  // Primary: Use external app ready signal (preferred)
34
35
  if (isAppReady !== undefined) {
35
- if (isAppReady && !isInitialized) {
36
+ if (isAppReady && !isInitializedRef.current) {
37
+ isInitializedRef.current = true;
36
38
  setIsInitialized(true);
37
39
  DeviceEventEmitter.emit('splash-ready');
38
40
  }
@@ -42,15 +44,18 @@ export const useSplashFlow = (options: UseSplashFlowOptions = {}): UseSplashFlow
42
44
  // Timer-based fallback when isAppReady is not provided
43
45
  if (duration !== undefined) {
44
46
  const timer = setTimeout(() => {
45
- setIsInitialized(true);
46
- DeviceEventEmitter.emit('splash-ready');
47
+ if (!isInitializedRef.current) {
48
+ isInitializedRef.current = true;
49
+ setIsInitialized(true);
50
+ DeviceEventEmitter.emit('splash-ready');
51
+ }
47
52
  }, duration);
48
53
 
49
54
  return () => clearTimeout(timer);
50
55
  }
51
56
 
52
57
  return undefined;
53
- }, [isAppReady, duration, isInitialized]);
58
+ }, [isAppReady, duration]);
54
59
 
55
60
  return { isInitialized };
56
61
  };
@@ -72,10 +72,12 @@ export function useAsyncOperation<T, E = Error>(
72
72
  const lastArgsRef = useRef<any[]>([]);
73
73
  const retryCountRef = useRef(0);
74
74
 
75
- // Stable callback refs
75
+ // Stable callback refs — prevents inline functions from causing execute to be recreated
76
76
  const onSuccessRef = useRef(onSuccess);
77
77
  const onErrorRef = useRef(onError);
78
78
  const onFinallyRef = useRef(onFinally);
79
+ const operationRef = useRef(operation);
80
+ const errorHandlerRef = useRef(errorHandler);
79
81
 
80
82
  useEffect(() => {
81
83
  onSuccessRef.current = onSuccess;
@@ -83,6 +85,10 @@ export function useAsyncOperation<T, E = Error>(
83
85
  onFinallyRef.current = onFinally;
84
86
  }, [onSuccess, onError, onFinally]);
85
87
 
88
+ // Keep operation and errorHandler in refs so execute doesn't need them as deps
89
+ operationRef.current = operation;
90
+ errorHandlerRef.current = errorHandler;
91
+
86
92
  // Cleanup on unmount
87
93
  useEffect(() => {
88
94
  return () => {
@@ -104,7 +110,7 @@ export function useAsyncOperation<T, E = Error>(
104
110
  }
105
111
 
106
112
  try {
107
- const result = await operation(...args);
113
+ const result = await operationRef.current(...args);
108
114
 
109
115
  if (isMountedRef.current) {
110
116
  setData(result);
@@ -114,7 +120,7 @@ export function useAsyncOperation<T, E = Error>(
114
120
 
115
121
  return result;
116
122
  } catch (err) {
117
- const handledError = errorHandler(err);
123
+ const handledError = errorHandlerRef.current(err);
118
124
 
119
125
  if (isMountedRef.current) {
120
126
  setErrorState(handledError);
@@ -129,7 +135,7 @@ export function useAsyncOperation<T, E = Error>(
129
135
  }
130
136
  }
131
137
  },
132
- [operation, skip, errorHandler]
138
+ [skip]
133
139
  );
134
140
 
135
141
  const retry = useCallback(async (): Promise<T | null> => {