@umituz/react-native-design-system 4.27.14 → 4.27.16

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 (59) hide show
  1. package/package.json +11 -6
  2. package/src/atoms/GlassView/GlassView.tsx +0 -2
  3. package/src/core/cache/domain/CleanupStrategy.ts +115 -0
  4. package/src/core/cache/domain/UnifiedCache.ts +196 -0
  5. package/src/core/cache/domain/types.ts +18 -0
  6. package/src/core/cache/index.ts +17 -0
  7. package/src/core/cache/infrastructure/CacheFactory.ts +102 -0
  8. package/src/core/index.ts +23 -0
  9. package/src/core/permissions/domain/PermissionHandler.ts +139 -0
  10. package/src/core/permissions/domain/types.ts +49 -0
  11. package/src/core/permissions/index.ts +15 -0
  12. package/src/core/repositories/domain/RepositoryKeyFactory.ts +41 -0
  13. package/src/core/repositories/domain/RepositoryUtils.ts +86 -0
  14. package/src/core/repositories/domain/types.ts +59 -0
  15. package/src/core/repositories/index.ts +23 -0
  16. package/src/device/detection/deviceDetection.ts +8 -2
  17. package/src/haptics/infrastructure/services/HapticService.ts +4 -1
  18. package/src/hooks/index.ts +22 -25
  19. package/src/index.ts +1 -0
  20. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +32 -29
  21. package/src/media/domain/strategies/CameraPickerStrategy.ts +61 -0
  22. package/src/media/domain/strategies/LibraryPickerStrategy.ts +54 -0
  23. package/src/media/domain/strategies/PickerStrategy.ts +61 -0
  24. package/src/media/domain/strategies/index.ts +13 -0
  25. package/src/media/infrastructure/services/MediaPickerService.ts +109 -110
  26. package/src/media/infrastructure/utils/PermissionManager.ts +68 -66
  27. package/src/media/infrastructure/utils/mediaPickerMappers.ts +29 -6
  28. package/src/media/presentation/hooks/useMedia.ts +16 -4
  29. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +0 -1
  30. package/src/offline/index.ts +1 -1
  31. package/src/offline/presentation/hooks/useOffline.ts +0 -8
  32. package/src/storage/README.md +0 -1
  33. package/src/storage/cache/domain/types/README.md +0 -1
  34. package/src/storage/cache/infrastructure/TTLCache.ts +3 -0
  35. package/src/storage/cache/presentation/README.md +0 -1
  36. package/src/storage/cache/presentation/useCachedValue.ts +12 -2
  37. package/src/storage/domain/constants/README.md +0 -1
  38. package/src/storage/infrastructure/adapters/README.md +0 -1
  39. package/src/storage/presentation/hooks/README.md +0 -6
  40. package/src/storage/presentation/hooks/useStorageState.ts +13 -4
  41. package/src/tanstack/domain/repositories/BaseRepository.ts +18 -1
  42. package/src/theme/hooks/useAppDesignTokens.ts +29 -3
  43. package/src/timezone/infrastructure/services/TimezoneProvider.ts +2 -2
  44. package/src/uuid/infrastructure/utils/UUIDUtils.ts +4 -1
  45. package/src/init/index.ts +0 -29
  46. package/src/layouts/ScreenLayout/index.ts +0 -1
  47. package/src/layouts/index.ts +0 -5
  48. package/src/molecules/SearchBar/index.ts +0 -4
  49. package/src/molecules/StepProgress/index.ts +0 -1
  50. package/src/molecules/alerts/index.ts +0 -47
  51. package/src/molecules/bottom-sheet/index.ts +0 -10
  52. package/src/molecules/circular-menu/index.ts +0 -3
  53. package/src/molecules/filter-group/index.ts +0 -3
  54. package/src/molecules/index.ts +0 -38
  55. package/src/molecules/info-grid/index.ts +0 -3
  56. package/src/molecules/swipe-actions/index.ts +0 -6
  57. package/src/presentation/utils/variants/index.ts +0 -6
  58. package/src/timezone/infrastructure/utils/SimpleCache.ts +0 -109
  59. package/src/utilities/index.ts +0 -6
@@ -84,7 +84,6 @@ Constant values for time-based calculations and default configuration. Located a
84
84
  - MUST increment CACHE_VERSION on schema changes
85
85
  - MUST implement migration for old versions
86
86
  - MUST document breaking changes
87
- - MUST support backward compatibility where possible
88
87
 
89
88
  ### Export Rules
90
89
  - MUST export all constants
@@ -137,7 +137,6 @@ Storage adapter implementations for Zustand persist middleware. Located at `src/
137
137
  - MUST migrate data on read
138
138
  - MUST clean up old data after migration
139
139
  - MUST handle migration failures
140
- - MUST be backward compatible
141
140
 
142
141
  ### Error Handling
143
142
  - MUST catch all exceptions in adapter methods
@@ -120,9 +120,3 @@ This directory contains React hooks that integrate storage and cache functionali
120
120
  - MUST use `useMemo` for computed values
121
121
  - MUST implement proper dependency arrays
122
122
  - MUST avoid unnecessary re-renders
123
-
124
- ### Deprecation
125
- - MUST document deprecated hooks
126
- - MUST provide migration path for deprecated hooks
127
- - MUST maintain backward compatibility when possible
128
- - MUST remove deprecated hooks after major version bump
@@ -28,20 +28,29 @@ export const useStorageState = <T>(
28
28
  const [state, setState] = useState<T>(defaultValue);
29
29
  const [isLoading, setIsLoading] = useState(true);
30
30
  const isMountedRef = useRef(true);
31
+ const defaultValueRef = useRef(defaultValue);
32
+
33
+ // Update ref when defaultValue changes
34
+ useEffect(() => {
35
+ defaultValueRef.current = defaultValue;
36
+ }, [defaultValue]);
31
37
 
32
38
  useEffect(() => {
33
39
  isMountedRef.current = true;
34
40
  setIsLoading(true);
35
41
 
36
42
  storageRepository
37
- .getItem<T>(keyString, defaultValue)
43
+ .getItem<T>(keyString, defaultValueRef.current)
38
44
  .then((result) => {
39
45
  if (isMountedRef.current) {
40
- setState(unwrap(result, defaultValue));
46
+ setState(unwrap(result, defaultValueRef.current));
41
47
  }
42
48
  })
43
- .catch(() => {
49
+ .catch((error) => {
44
50
  // Keep defaultValue on error
51
+ if (__DEV__) {
52
+ console.warn('[useStorageState] Failed to load from storage:', error);
53
+ }
45
54
  })
46
55
  .finally(() => {
47
56
  if (isMountedRef.current) {
@@ -52,7 +61,7 @@ export const useStorageState = <T>(
52
61
  return () => {
53
62
  isMountedRef.current = false;
54
63
  };
55
- }, [keyString, defaultValue]);
64
+ }, [keyString]);
56
65
 
57
66
  // Update state and persist to storage
58
67
  const updateState = useCallback(
@@ -3,7 +3,7 @@
3
3
  * Domain layer - Abstract repository for data operations
4
4
  *
5
5
  * Provides generic CRUD operations with TanStack Query integration.
6
- * Subclass this for specific entities to get type-safe data operations.
6
+ * Now uses common repository utilities from core/repositories.
7
7
  *
8
8
  * @example
9
9
  * ```typescript
@@ -47,6 +47,8 @@ import type {
47
47
  import { mergeRepositoryOptions, getCacheOptions } from './helpers/repositoryHelpers';
48
48
  import * as queryMethods from './mixins/repositoryQueryMethods';
49
49
  import * as invalidationMethods from './mixins/repositoryInvalidationMethods';
50
+ // Import common utilities from core
51
+ import { createRepositoryLogger } from '../../../core/repositories/domain/RepositoryUtils';
50
52
 
51
53
  /**
52
54
  * Base repository for CRUD operations
@@ -68,10 +70,16 @@ export abstract class BaseRepository<
68
70
  */
69
71
  public readonly keys: ReturnType<typeof createQueryKeyFactory>;
70
72
 
73
+ /**
74
+ * Debug logger for this repository
75
+ */
76
+ protected readonly log: (method: string, ...args: unknown[]) => void;
77
+
71
78
  constructor(resource: string, options: RepositoryOptions = {}) {
72
79
  this.resource = resource;
73
80
  this.options = mergeRepositoryOptions(options);
74
81
  this.keys = createQueryKeyFactory(this.resource);
82
+ this.log = createRepositoryLogger(resource, __DEV__);
75
83
  }
76
84
 
77
85
  /**
@@ -117,6 +125,7 @@ export abstract class BaseRepository<
117
125
  * Query all items with caching
118
126
  */
119
127
  async queryAll(params?: ListParams): Promise<TData[]> {
128
+ this.log('queryAll', params);
120
129
  return queryMethods.queryAll(this, params);
121
130
  }
122
131
 
@@ -124,6 +133,7 @@ export abstract class BaseRepository<
124
133
  * Query item by ID with caching
125
134
  */
126
135
  async queryById(id: string | number): Promise<TData | undefined> {
136
+ this.log('queryById', id);
127
137
  return queryMethods.queryById(this, id);
128
138
  }
129
139
 
@@ -131,6 +141,7 @@ export abstract class BaseRepository<
131
141
  * Prefetch all items
132
142
  */
133
143
  async prefetchAll(params?: ListParams): Promise<void> {
144
+ this.log('prefetchAll', params);
134
145
  return queryMethods.prefetchAll(this, params);
135
146
  }
136
147
 
@@ -138,6 +149,7 @@ export abstract class BaseRepository<
138
149
  * Prefetch item by ID
139
150
  */
140
151
  async prefetchById(id: string | number): Promise<void> {
152
+ this.log('prefetchById', id);
141
153
  return queryMethods.prefetchById(this, id);
142
154
  }
143
155
 
@@ -145,6 +157,7 @@ export abstract class BaseRepository<
145
157
  * Invalidate all queries for this resource
146
158
  */
147
159
  invalidateAll(): Promise<void> {
160
+ this.log('invalidateAll');
148
161
  return invalidationMethods.invalidateAll(this);
149
162
  }
150
163
 
@@ -152,6 +165,7 @@ export abstract class BaseRepository<
152
165
  * Invalidate list queries
153
166
  */
154
167
  invalidateLists(): Promise<void> {
168
+ this.log('invalidateLists');
155
169
  return invalidationMethods.invalidateLists(this);
156
170
  }
157
171
 
@@ -159,6 +173,7 @@ export abstract class BaseRepository<
159
173
  * Invalidate detail query
160
174
  */
161
175
  invalidateDetail(id: string | number): Promise<void> {
176
+ this.log('invalidateDetail', id);
162
177
  return invalidationMethods.invalidateDetail(this, id);
163
178
  }
164
179
 
@@ -166,6 +181,7 @@ export abstract class BaseRepository<
166
181
  * Set query data (optimistic update)
167
182
  */
168
183
  setData(id: string | number, data: TData): void {
184
+ this.log('setData', id);
169
185
  invalidationMethods.setData(this, id, data);
170
186
  }
171
187
 
@@ -180,6 +196,7 @@ export abstract class BaseRepository<
180
196
  * Remove query data from cache
181
197
  */
182
198
  clearData(id: string | number): void {
199
+ this.log('clearData', id);
183
200
  invalidationMethods.clearData(this, id);
184
201
  }
185
202
  }
@@ -1,8 +1,28 @@
1
- import { useMemo } from 'react';
1
+ import { useMemo, useRef } from 'react';
2
2
  import { useTheme } from '../infrastructure/stores/themeStore';
3
3
  import { createDesignTokens } from '../core/TokenFactory';
4
4
  import { useResponsive } from '../../responsive/useResponsive';
5
5
  import { type DesignTokens } from '../types/ThemeTypes';
6
+ import type { CustomThemeColors } from '../core/CustomColors';
7
+
8
+ /**
9
+ * Shallow equality check for CustomThemeColors
10
+ */
11
+ function areCustomColorsEqual(a?: CustomThemeColors, b?: CustomThemeColors): boolean {
12
+ if (a === b) return true;
13
+ if (!a || !b) return false;
14
+
15
+ const keysA = Object.keys(a) as (keyof CustomThemeColors)[];
16
+ const keysB = Object.keys(b) as (keyof CustomThemeColors)[];
17
+
18
+ if (keysA.length !== keysB.length) return false;
19
+
20
+ for (const key of keysA) {
21
+ if (a[key] !== b[key]) return false;
22
+ }
23
+
24
+ return true;
25
+ }
6
26
 
7
27
  /**
8
28
  * Hook to access current design tokens (colors, spacing, typography, etc.)
@@ -13,8 +33,14 @@ export const useAppDesignTokens = (): DesignTokens => {
13
33
  const { themeMode, customColors } = useTheme();
14
34
  const { spacingMultiplier, getFontSize } = useResponsive();
15
35
 
36
+ // Stabilize customColors reference to prevent unnecessary re-computation
37
+ const customColorsRef = useRef(customColors);
38
+ if (!areCustomColorsEqual(customColorsRef.current, customColors)) {
39
+ customColorsRef.current = customColors;
40
+ }
41
+
16
42
  return useMemo(
17
- () => createDesignTokens(themeMode, customColors, spacingMultiplier, getFontSize),
18
- [themeMode, customColors, spacingMultiplier, getFontSize]
43
+ () => createDesignTokens(themeMode, customColorsRef.current, spacingMultiplier, getFontSize),
44
+ [themeMode, spacingMultiplier, getFontSize]
19
45
  );
20
46
  };
@@ -1,12 +1,12 @@
1
1
  import { TimezoneInfo } from '../../domain/entities/Timezone';
2
- import { SimpleCache } from '../utils/SimpleCache';
2
+ import { UnifiedCache } from '../../../core/cache/domain/UnifiedCache';
3
3
 
4
4
  /**
5
5
  * TimezoneProvider
6
6
  * Responsible for discovering device timezone and providing available timezones
7
7
  */
8
8
  export class TimezoneProvider {
9
- private cache = new SimpleCache<TimezoneInfo[]>(300000); // 5 min cache
9
+ private cache = new UnifiedCache<TimezoneInfo[]>({ defaultTTL: 300000 }); // 5 min cache
10
10
  /**
11
11
  * Get current device timezone using Intl API
12
12
  */
@@ -17,7 +17,10 @@ const getCryptoModule = (): typeof import('expo-crypto') | null => {
17
17
  // eslint-disable-next-line @typescript-eslint/no-require-imports
18
18
  _cryptoModule = require('expo-crypto') as typeof import('expo-crypto');
19
19
  return _cryptoModule;
20
- } catch {
20
+ } catch (error) {
21
+ if (__DEV__) {
22
+ console.warn('[UUIDUtils] expo-crypto not available, using Math.random fallback:', error);
23
+ }
21
24
  return null;
22
25
  }
23
26
  };
package/src/init/index.ts DELETED
@@ -1,29 +0,0 @@
1
- /**
2
- * App Initialization Module
3
- *
4
- * Provides utilities for app initialization:
5
- * - createAppInitializer: Factory for creating app initializers
6
- * - useAppInitialization: Hook for managing initialization state
7
- * - createEnvConfig: Environment configuration factory
8
- */
9
-
10
- // App Initializer
11
- export {
12
- createAppInitializer,
13
- createInitModule,
14
- } from "./createAppInitializer";
15
-
16
- // Initialization Hook
17
- export { useAppInitialization } from "./useAppInitialization";
18
-
19
- // Environment Configuration
20
- export * from "./env";
21
-
22
- // Types
23
- export type {
24
- InitModule,
25
- AppInitializerConfig,
26
- AppInitializerResult,
27
- UseAppInitializationOptions,
28
- UseAppInitializationReturn,
29
- } from "./types";
@@ -1 +0,0 @@
1
- export * from './ScreenLayout';
@@ -1,5 +0,0 @@
1
- export * from './Container';
2
- export * from './FormLayout';
3
- export * from './Grid';
4
- export * from './ScreenLayout';
5
- export * from './ScreenHeader/ScreenHeader';
@@ -1,4 +0,0 @@
1
- export * from './SearchBar';
2
- export * from './SearchHistory';
3
- export * from './SearchSuggestions';
4
- export * from './types';
@@ -1 +0,0 @@
1
- export * from "./StepProgress";
@@ -1,47 +0,0 @@
1
- /**
2
- * Alerts Molecule - Public API
3
- */
4
-
5
- export * from './AlertTypes';
6
- export { useAlertStore } from './AlertStore';
7
- export { AlertService } from './AlertService';
8
- export { AlertBanner } from './AlertBanner';
9
- export { AlertToast } from './AlertToast';
10
- export { AlertInline } from './AlertInline';
11
- export { AlertModal } from './AlertModal';
12
- export { AlertContainer } from './AlertContainer';
13
- export { AlertProvider } from './AlertProvider';
14
- export { useAlert } from './useAlert';
15
-
16
- import { AlertService } from './AlertService';
17
- import { useAlertStore } from './AlertStore';
18
- import { AlertOptions } from './AlertTypes';
19
-
20
- /**
21
- * Convenience alert service for use outside of components
22
- */
23
- export const alertService = {
24
- error: (title: string, message?: string, options?: AlertOptions) => {
25
- const alert = AlertService.createErrorAlert(title, message, options);
26
- useAlertStore.getState().addAlert(alert);
27
- return alert.id;
28
- },
29
- success: (title: string, message?: string, options?: AlertOptions) => {
30
- const alert = AlertService.createSuccessAlert(title, message, options);
31
- useAlertStore.getState().addAlert(alert);
32
- return alert.id;
33
- },
34
- warning: (title: string, message?: string, options?: AlertOptions) => {
35
- const alert = AlertService.createWarningAlert(title, message, options);
36
- useAlertStore.getState().addAlert(alert);
37
- return alert.id;
38
- },
39
- info: (title: string, message?: string, options?: AlertOptions) => {
40
- const alert = AlertService.createInfoAlert(title, message, options);
41
- useAlertStore.getState().addAlert(alert);
42
- return alert.id;
43
- },
44
- dismiss: (id: string) => {
45
- useAlertStore.getState().dismissAlert(id);
46
- },
47
- };
@@ -1,10 +0,0 @@
1
- export * from './components/BottomSheet';
2
- export * from './components/BottomSheetModal';
3
-
4
- export * from './components/filter/FilterBottomSheet';
5
- export * from './components/filter/FilterSheet';
6
- export * from './hooks/useBottomSheet';
7
- export * from './hooks/useBottomSheetModal';
8
- export * from './hooks/useListFilters';
9
- export * from './types/BottomSheet';
10
- export * from './types/Filter';
@@ -1,3 +0,0 @@
1
- export * from "./CircularMenu";
2
- export * from "./CircularMenuBackground";
3
- export * from "./CircularMenuCloseButton";
@@ -1,3 +0,0 @@
1
-
2
- export * from './FilterGroup';
3
- export * from './types';
@@ -1,38 +0,0 @@
1
- /**
2
- * Molecules - Composite UI components
3
- * Built from atoms following atomic design principles
4
- */
5
-
6
- // Component exports
7
- export * from './avatar';
8
- export * from './bottom-sheet';
9
- export { FormField, type FormFieldProps } from './FormField';
10
- export { ListItem, type ListItemProps } from './ListItem';
11
- export { SearchBar, type SearchBarProps } from './SearchBar';
12
- export { IconContainer } from './IconContainer';
13
- export { BaseModal, type BaseModalProps } from './BaseModal';
14
- export { ConfirmationModal } from './ConfirmationModalMain';
15
- export { useConfirmationModal } from './confirmation-modal/useConfirmationModal';
16
-
17
- // Other components
18
- export * from './Divider/Divider';
19
- export * from './Divider/types';
20
- export * from './StepProgress';
21
- export * from './List';
22
- export * from './alerts';
23
- export * from './calendar';
24
- export * from './swipe-actions';
25
- export * from './navigation';
26
- export * from './long-press-menu';
27
- export * from './StepHeader';
28
- export * from './emoji';
29
- export * from './countdown';
30
- export * from './splash';
31
- export * from './filter-group';
32
- export * from './action-footer/ActionFooter';
33
- export * from './action-footer/types';
34
- export * from './hero-section/HeroSection';
35
- export * from './hero-section/types';
36
- export * from './info-grid';
37
- export * from './circular-menu';
38
- export * from './icon-grid';
@@ -1,3 +0,0 @@
1
-
2
- export * from './InfoGrid';
3
- export * from './types';
@@ -1,6 +0,0 @@
1
- /**
2
- * Swipe Actions Domain - Barrel Export
3
- */
4
-
5
- export * from './domain/entities/SwipeAction';
6
- export * from './presentation/components/SwipeActionButton';
@@ -1,6 +0,0 @@
1
- /**
2
- * Variant utilities for style management
3
- */
4
-
5
- export * from './core';
6
- export * from './helpers';
@@ -1,109 +0,0 @@
1
- /**
2
- * SimpleCache
3
- *
4
- * Lightweight in-memory cache for performance optimization
5
- * No external dependencies - pure TypeScript implementation
6
- */
7
-
8
- import { ONE_MINUTE_MS } from '../../../utils/constants/TimeConstants';
9
-
10
- interface CacheEntry<T> {
11
- value: T;
12
- expires: number;
13
- }
14
-
15
- export class SimpleCache<T> {
16
- private cache = new Map<string, CacheEntry<T>>();
17
- private defaultTTL: number;
18
- private cleanupTimeout: ReturnType<typeof setTimeout> | null = null;
19
- private destroyed = false;
20
- private cleanupScheduleLock = false;
21
-
22
- constructor(defaultTTL: number = ONE_MINUTE_MS) {
23
- this.defaultTTL = defaultTTL;
24
- this.scheduleCleanup();
25
- }
26
-
27
- /**
28
- * Destroy the cache and stop cleanup timer
29
- */
30
- destroy(): void {
31
- this.destroyed = true;
32
- this.cleanupScheduleLock = false;
33
- if (this.cleanupTimeout) {
34
- clearTimeout(this.cleanupTimeout);
35
- this.cleanupTimeout = null;
36
- }
37
- this.cache.clear();
38
- }
39
-
40
- set(key: string, value: T, ttl?: number): void {
41
- if (this.destroyed) return;
42
- const expires = Date.now() + (ttl ?? this.defaultTTL);
43
- this.cache.set(key, { value, expires });
44
- }
45
-
46
- get(key: string): T | undefined {
47
- const entry = this.cache.get(key);
48
-
49
- if (!entry) {
50
- return undefined;
51
- }
52
-
53
- if (Date.now() > entry.expires) {
54
- this.cache.delete(key);
55
- return undefined;
56
- }
57
-
58
- return entry.value;
59
- }
60
-
61
- has(key: string): boolean {
62
- return this.get(key) !== undefined;
63
- }
64
-
65
- clear(): void {
66
- this.cache.clear();
67
- }
68
-
69
- delete(key: string): void {
70
- this.cache.delete(key);
71
- }
72
-
73
- private cleanup(): void {
74
- const now = Date.now();
75
- for (const [key, entry] of this.cache.entries()) {
76
- if (now > entry.expires) {
77
- this.cache.delete(key);
78
- }
79
- }
80
- }
81
-
82
- private scheduleCleanup(): void {
83
- if (this.destroyed || this.cleanupScheduleLock) return;
84
-
85
- this.cleanupScheduleLock = true;
86
-
87
- try {
88
- if (this.cleanupTimeout) {
89
- clearTimeout(this.cleanupTimeout);
90
- }
91
-
92
- this.cleanup();
93
-
94
- if (!this.destroyed) {
95
- this.cleanupTimeout = setTimeout(() => {
96
- if (!this.destroyed) {
97
- this.cleanupScheduleLock = false;
98
- this.scheduleCleanup();
99
- }
100
- }, ONE_MINUTE_MS);
101
- } else {
102
- this.cleanupScheduleLock = false;
103
- }
104
- } catch (error) {
105
- this.cleanupScheduleLock = false;
106
- throw error;
107
- }
108
- }
109
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Utilities - Public API
3
- */
4
-
5
- export * from './clipboard';
6
- export * from './sharing';