@umituz/react-native-design-system 4.25.117 → 4.26.0

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.
@@ -2,6 +2,7 @@
2
2
  * Image Infrastructure - Conversion Service
3
3
  *
4
4
  * Handles format conversion, compression, and thumbnail generation
5
+ * Lazy loads expo-image-manipulator to reduce bundle size
5
6
  */
6
7
  import type { ImageSaveOptions, ImageManipulationResult, SaveFormat } from '../../domain/entities/ImageTypes';
7
8
  export declare class ImageConversionService {
@@ -13,7 +13,7 @@ export { BaseRepository } from './domain/repositories/BaseRepository';
13
13
  export type { CreateParams, UpdateParams, ListParams, RepositoryOptions, } from './domain/repositories/RepositoryTypes';
14
14
  export { RepositoryFactory } from './domain/repositories/RepositoryFactory';
15
15
  export { CacheStrategies, createQueryClient, getCacheStrategy, type QueryClientFactoryOptions, } from './infrastructure/config/QueryClientConfig';
16
- export { createPersister, clearPersistedCache, getPersistedCacheSize, type PersisterFactoryOptions, } from './infrastructure/config/PersisterConfig';
16
+ export { clearPersistedCache, getPersistedCacheSize, type PersisterFactoryOptions, } from './infrastructure/config/PersisterConfig';
17
17
  export { getGlobalQueryClient, hasGlobalQueryClient, setGlobalQueryClient, clearGlobalQueryClient, } from './infrastructure/config/QueryClientSingleton';
18
18
  export { DevMonitor } from './infrastructure/monitoring/DevMonitor';
19
19
  export type { QueryMetrics, CacheStats as QueryCacheStats, DevMonitorOptions, } from './infrastructure/monitoring/DevMonitor.types';
@@ -3,8 +3,8 @@
3
3
  * Infrastructure layer - AsyncStorage persistence setup
4
4
  *
5
5
  * General-purpose persistence configuration for any React Native app
6
+ * Lazy loads TanStack persistence packages to reduce bundle size
6
7
  */
7
- import type { Persister } from '@tanstack/react-query-persist-client';
8
8
  /**
9
9
  * Persister factory options
10
10
  */
@@ -33,19 +33,6 @@ export interface PersisterFactoryOptions {
33
33
  */
34
34
  throttleTime?: number;
35
35
  }
36
- /**
37
- * Create an AsyncStorage persister for TanStack Query
38
- *
39
- * @example
40
- * ```typescript
41
- * const persister = createPersister({
42
- * keyPrefix: 'myapp',
43
- * maxAge: 24 * 60 * 60 * 1000, // 24 hours
44
- * busterVersion: '1',
45
- * });
46
- * ```
47
- */
48
- export declare function createPersister(options?: PersisterFactoryOptions): Persister;
49
36
  /**
50
37
  * Clear all persisted cache data
51
38
  * Useful for logout or cache reset scenarios
@@ -1,53 +1,26 @@
1
1
  import React from 'react';
2
- import { QueryClient } from '@tanstack/react-query';
3
- import type { Persister } from '@tanstack/react-query-persist-client';
4
2
  import { type QueryClientFactoryOptions } from '../config/QueryClientConfig';
5
- import { type PersisterFactoryOptions } from '../config/PersisterConfig';
3
+ /**
4
+ * Persister factory options
5
+ */
6
+ export interface PersisterFactoryOptions {
7
+ keyPrefix?: string;
8
+ maxAge?: number;
9
+ busterVersion?: string;
10
+ throttleTime?: number;
11
+ }
6
12
  /**
7
13
  * TanStack provider props
8
14
  */
9
15
  export interface TanstackProviderProps {
10
- /**
11
- * Child components
12
- */
13
16
  children: React.ReactNode;
14
- /**
15
- * Custom QueryClient instance
16
- * If not provided, a default one will be created
17
- */
18
- queryClient?: QueryClient;
19
- /**
20
- * QueryClient configuration options
21
- * Only used if queryClient is not provided
22
- */
17
+ queryClient?: any;
23
18
  queryClientOptions?: QueryClientFactoryOptions;
24
- /**
25
- * Enable AsyncStorage persistence
26
- * @default true
27
- */
28
19
  enablePersistence?: boolean;
29
- /**
30
- * Enable DevMonitor logging (development only)
31
- * @default false
32
- */
33
20
  enableDevTools?: boolean;
34
- /**
35
- * Custom persister instance
36
- * Only used if enablePersistence is true
37
- */
38
- persister?: Persister;
39
- /**
40
- * Persister configuration options
41
- * Only used if enablePersistence is true and persister is not provided
42
- */
21
+ persister?: any;
43
22
  persisterOptions?: PersisterFactoryOptions;
44
- /**
45
- * Callback when persistence is successfully restored
46
- */
47
23
  onPersistSuccess?: () => void;
48
- /**
49
- * Callback when persistence restoration fails
50
- */
51
24
  onPersistError?: () => void;
52
25
  }
53
26
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.25.117",
3
+ "version": "4.26.0",
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 - TanStack persistence and expo-image-manipulator now lazy loaded",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./dist/index.d.ts",
@@ -41,7 +41,16 @@ export const BaseModal: React.FC<BaseModalProps> = ({
41
41
  }
42
42
  }, [dismissOnBackdrop, onClose]);
43
43
 
44
- if (!visible) return null;
44
+ if (__DEV__) {
45
+ console.log("[BaseModal] Render:", { visible, testID, hasChildren: !!children });
46
+ }
47
+
48
+ if (!visible) {
49
+ if (__DEV__) {
50
+ console.log("[BaseModal] Early returning (visible = false)");
51
+ }
52
+ return null;
53
+ }
45
54
 
46
55
  return (
47
56
  <Modal
@@ -9,12 +9,14 @@ export interface NavigationHeaderProps {
9
9
  title: string;
10
10
  onBackPress?: () => void;
11
11
  rightElement?: React.ReactNode;
12
+ centerTitle?: boolean;
12
13
  }
13
14
 
14
15
  export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
15
16
  title,
16
17
  onBackPress,
17
18
  rightElement,
19
+ centerTitle = true,
18
20
  }) => {
19
21
  const tokens = useAppDesignTokens();
20
22
  const insets = useSafeAreaInsets();
@@ -43,13 +45,16 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
43
45
  },
44
46
  title: {
45
47
  flex: 1,
46
- textAlign: 'left',
48
+ textAlign: centerTitle ? 'center' : 'left',
47
49
  },
48
- }), [tokens, insets]);
50
+ sideElement: {
51
+ width: centerTitle ? 40 : 'auto',
52
+ }
53
+ }), [tokens, insets, centerTitle]);
49
54
 
50
55
  return (
51
56
  <View style={styles.container}>
52
- {onBackPress && (
57
+ {onBackPress ? (
53
58
  <TouchableOpacity
54
59
  onPress={onBackPress}
55
60
  style={styles.backButton}
@@ -62,10 +67,12 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
62
67
  color="textPrimary"
63
68
  />
64
69
  </TouchableOpacity>
65
- )}
70
+ ) : centerTitle ? (
71
+ <View style={styles.sideElement} />
72
+ ) : null}
66
73
 
67
74
  <AtomicText
68
- type="titleMedium"
75
+ type="titleLarge"
69
76
  color="textPrimary"
70
77
  numberOfLines={1}
71
78
  style={styles.title}
@@ -73,11 +80,13 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
73
80
  {title}
74
81
  </AtomicText>
75
82
 
76
- {rightElement && (
77
- <View>
83
+ {rightElement ? (
84
+ <View style={styles.sideElement}>
78
85
  {rightElement}
79
86
  </View>
80
- )}
87
+ ) : centerTitle ? (
88
+ <View style={styles.sideElement} />
89
+ ) : null}
81
90
  </View>
82
91
  );
83
92
  };
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { storageService } from '../../../storage';
10
- import { DEFAULT_GC_TIME } from '../../domain/constants/CacheDefaults';
10
+
11
11
 
12
12
  /**
13
13
  * Persister factory options
@@ -1,5 +1,5 @@
1
1
  import React, { useState, lazy, Suspense } from 'react';
2
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
2
+ import { QueryClientProvider } from '@tanstack/react-query';
3
3
  import { createQueryClient, type QueryClientFactoryOptions } from '../config/QueryClientConfig';
4
4
  import { setGlobalQueryClient } from '../config/QueryClientSingleton';
5
5
  import { DevMonitor } from '../monitoring/DevMonitor';
@@ -100,6 +100,9 @@ export interface ITimezoneManipulation {
100
100
  /** Get middle of day (12:00:00) */
101
101
  getMiddleOfDay(date: Date | string | number): Date;
102
102
 
103
+ /** Set specific time of day (hours and minutes) */
104
+ setTimeOfDay(date: Date | string | number, hours: number, minutes: number): Date;
105
+
103
106
  /** Convert date from one timezone to another */
104
107
  convertTimezone(
105
108
  date: Date | string | number,
@@ -29,3 +29,13 @@ export { timezoneService, TimezoneService } from './infrastructure/services/Time
29
29
 
30
30
  export { useTimezone } from './presentation/hooks/useTimezone';
31
31
  export type { UseTimezoneReturn } from './presentation/hooks/useTimezone';
32
+
33
+ // =============================================================================
34
+ // UTILITIES
35
+ // =============================================================================
36
+
37
+ export {
38
+ formatTimeComponent,
39
+ parseTimeComponent,
40
+ millisecondsToSeconds,
41
+ } from './infrastructure/utils/TimeUtils';
@@ -103,6 +103,12 @@ export class CalendarManager {
103
103
  return result;
104
104
  }
105
105
 
106
+ setTimeOfDay(date: Date | string | number, hours: number, minutes: number): Date {
107
+ const result = this.parse(date);
108
+ result.setHours(hours, minutes, 0, 0);
109
+ return result;
110
+ }
111
+
106
112
  getDifferenceInDays(date1: Date | string | number, date2: Date | string | number): number {
107
113
  const d1 = this.parse(date1);
108
114
  const d2 = this.parse(date2);
@@ -162,8 +162,6 @@ export class DateFormatter {
162
162
  ): string {
163
163
  const d = this.parse(date);
164
164
  const now = new Date();
165
- const diffInMs = now.getTime() - d.getTime();
166
- const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
167
165
 
168
166
  // Check for today (today at midnight vs date at midnight)
169
167
  const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
@@ -52,6 +52,7 @@ export class TimezoneService implements ITimezoneService {
52
52
  addDays(date: Date | string | number, days: number): Date { return this.calendar.addDays(date, days); }
53
53
  startOfDay(date: Date | string | number): Date { return this.calendar.startOfDay(date); }
54
54
  endOfDay(date: Date | string | number): Date { return this.calendar.endOfDay(date); }
55
+ setTimeOfDay(date: Date | string | number, hours: number, minutes: number): Date { return this.calendar.setTimeOfDay(date, hours, minutes); }
55
56
 
56
57
  formatDateToString(date: Date | string | number): string { return this.formatter.formatDateToString(date); }
57
58
  getCurrentISOString(): string { return this.formatter.formatToISOString(new Date()); }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Time Utilities
3
+ * Utility functions for time formatting and conversion
4
+ */
5
+
6
+ /**
7
+ * Format hours and minutes as "HH:MM" string
8
+ *
9
+ * @example
10
+ * formatTimeComponent(14, 30) // Returns "14:30"
11
+ * formatTimeComponent(9, 5) // Returns "09:05"
12
+ *
13
+ * @param hours - Hours (0-23)
14
+ * @param minutes - Minutes (0-59)
15
+ * @returns Formatted time string
16
+ */
17
+ export function formatTimeComponent(hours: number, minutes: number): string {
18
+ const h = String(hours).padStart(2, '0');
19
+ const m = String(minutes).padStart(2, '0');
20
+ return `${h}:${m}`;
21
+ }
22
+
23
+ /**
24
+ * Parse a time string "HH:MM" to hours and minutes
25
+ *
26
+ * @example
27
+ * parseTimeComponent("14:30") // Returns { hours: 14, minutes: 30 }
28
+ * parseTimeComponent("09:05") // Returns { hours: 9, minutes: 5 }
29
+ *
30
+ * @param timeStr - Time string in "HH:MM" format
31
+ * @returns Object with hours and minutes
32
+ */
33
+ export function parseTimeComponent(timeStr: string): { hours: number; minutes: number } {
34
+ const [hours, minutes] = timeStr.split(':').map(Number);
35
+ return { hours, minutes };
36
+ }
37
+
38
+ /**
39
+ * Convert milliseconds to seconds
40
+ *
41
+ * @example
42
+ * millisecondsToSeconds(5000) // Returns 5
43
+ *
44
+ * @param ms - Milliseconds
45
+ * @returns Seconds
46
+ */
47
+ export function millisecondsToSeconds(ms: number): number {
48
+ return Math.floor(ms / 1000);
49
+ }