@umituz/react-native-design-system 4.27.15 → 4.27.17

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 (78) hide show
  1. package/dist/core/cache/domain/CleanupStrategy.d.ts +62 -0
  2. package/dist/core/cache/domain/UnifiedCache.d.ts +82 -0
  3. package/dist/core/cache/domain/types.d.ts +15 -0
  4. package/dist/core/cache/index.d.ts +13 -0
  5. package/dist/core/cache/infrastructure/CacheFactory.d.ts +63 -0
  6. package/dist/core/index.d.ts +17 -0
  7. package/dist/core/permissions/domain/PermissionHandler.d.ts +82 -0
  8. package/dist/core/permissions/domain/types.d.ts +42 -0
  9. package/dist/core/permissions/index.d.ts +7 -0
  10. package/dist/core/repositories/domain/RepositoryKeyFactory.d.ts +25 -0
  11. package/dist/core/repositories/domain/RepositoryUtils.d.ts +39 -0
  12. package/dist/core/repositories/domain/types.d.ts +53 -0
  13. package/dist/core/repositories/index.d.ts +10 -0
  14. package/dist/hooks/index.d.ts +27 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/media/domain/strategies/CameraPickerStrategy.d.ts +25 -0
  17. package/dist/media/domain/strategies/LibraryPickerStrategy.d.ts +18 -0
  18. package/dist/media/domain/strategies/PickerStrategy.d.ts +55 -0
  19. package/dist/media/domain/strategies/index.d.ts +10 -0
  20. package/dist/media/infrastructure/services/MediaPickerService.d.ts +49 -6
  21. package/dist/media/infrastructure/utils/PermissionManager.d.ts +6 -0
  22. package/dist/media/infrastructure/utils/mediaPickerMappers.d.ts +15 -1
  23. package/dist/molecules/calendar/infrastructure/services/CalendarService.d.ts +1 -0
  24. package/dist/molecules/calendar/infrastructure/storage/CalendarStore.d.ts +2 -2
  25. package/dist/molecules/filter-group/FilterGroup.d.ts +1 -1
  26. package/dist/molecules/navigation/index.d.ts +1 -1
  27. package/dist/offline/index.d.ts +1 -1
  28. package/dist/offline/presentation/hooks/useOffline.d.ts +0 -5
  29. package/dist/tanstack/domain/repositories/BaseRepository.d.ts +5 -1
  30. package/dist/tanstack/infrastructure/monitoring/DevMonitor.d.ts +1 -0
  31. package/dist/utils/constants/TimeConstants.d.ts +27 -0
  32. package/package.json +11 -6
  33. package/src/atoms/GlassView/GlassView.tsx +0 -2
  34. package/src/atoms/picker/components/PickerChips.tsx +27 -21
  35. package/src/core/cache/index.ts +3 -2
  36. package/src/core/index.ts +5 -3
  37. package/src/core/repositories/domain/RepositoryUtils.ts +4 -4
  38. package/src/core/repositories/domain/types.ts +2 -2
  39. package/src/hooks/index.ts +22 -25
  40. package/src/image/presentation/components/ImageGallery.tsx +25 -21
  41. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +32 -29
  42. package/src/media/domain/strategies/CameraPickerStrategy.ts +4 -8
  43. package/src/media/domain/strategies/index.ts +1 -1
  44. package/src/media/infrastructure/services/MediaPickerService.ts +3 -14
  45. package/src/media/infrastructure/utils/mediaPickerMappers.ts +29 -6
  46. package/src/molecules/avatar/AvatarGroup.tsx +137 -62
  47. package/src/molecules/filter-group/FilterGroup.tsx +31 -22
  48. package/src/molecules/icon-grid/IconGrid.tsx +52 -20
  49. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +0 -1
  50. package/src/offline/index.ts +1 -1
  51. package/src/offline/presentation/hooks/useOffline.ts +0 -8
  52. package/src/onboarding/presentation/components/BackgroundImageCollage.tsx +32 -23
  53. package/src/storage/README.md +0 -1
  54. package/src/storage/cache/domain/types/README.md +0 -1
  55. package/src/storage/cache/presentation/README.md +0 -1
  56. package/src/storage/cache/presentation/useCachedValue.ts +12 -2
  57. package/src/storage/domain/constants/README.md +0 -1
  58. package/src/storage/infrastructure/adapters/README.md +0 -1
  59. package/src/storage/presentation/hooks/README.md +0 -6
  60. package/src/storage/presentation/hooks/useStorageState.ts +13 -4
  61. package/src/tanstack/domain/repositories/BaseRepository.ts +1 -1
  62. package/src/theme/hooks/useAppDesignTokens.ts +29 -3
  63. package/src/timezone/infrastructure/services/TimezoneProvider.ts +2 -2
  64. package/src/init/index.ts +0 -29
  65. package/src/layouts/ScreenLayout/index.ts +0 -1
  66. package/src/layouts/index.ts +0 -5
  67. package/src/molecules/SearchBar/index.ts +0 -4
  68. package/src/molecules/StepProgress/index.ts +0 -1
  69. package/src/molecules/alerts/index.ts +0 -47
  70. package/src/molecules/bottom-sheet/index.ts +0 -10
  71. package/src/molecules/circular-menu/index.ts +0 -3
  72. package/src/molecules/filter-group/index.ts +0 -3
  73. package/src/molecules/index.ts +0 -38
  74. package/src/molecules/info-grid/index.ts +0 -3
  75. package/src/molecules/swipe-actions/index.ts +0 -6
  76. package/src/presentation/utils/variants/index.ts +0 -6
  77. package/src/timezone/infrastructure/utils/SimpleCache.ts +0 -64
  78. package/src/utilities/index.ts +0 -6
@@ -2,18 +2,61 @@
2
2
  * Media Domain - Media Picker Service
3
3
  *
4
4
  * Service for picking images/videos using expo-image-picker.
5
- * Handles camera, gallery, and media library permissions.
5
+ * Refactored to use strategy pattern to reduce code duplication.
6
+ *
7
+ * Before: 182 LOC with 4 similar methods
8
+ * After: ~120 LOC with 1 generic launcher + convenience wrappers - 34% reduction
6
9
  */
7
- import type { MediaPickerOptions, MediaPickerResult, CameraOptions } from "../../domain/entities/Media";
10
+ import type { MediaPickerOptions, MediaPickerResult, CameraOptions } from '../../domain/entities/Media';
11
+ import type { PickerStrategy, LaunchOptions } from '../../domain/strategies/PickerStrategy';
8
12
  /**
9
13
  * Media picker service for selecting images/videos
14
+ * Uses strategy pattern to support different picker types
10
15
  */
11
16
  export declare class MediaPickerService {
17
+ /**
18
+ * Generic media picker launcher using strategy pattern
19
+ *
20
+ * @param strategy - Picker strategy to use
21
+ * @param options - Picker options
22
+ * @returns Picker result
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const strategy = new CameraPickerStrategy({ mediaType: 'images' });
27
+ * const result = await MediaPickerService.launchMediaPicker(strategy, {
28
+ * quality: 0.8,
29
+ * allowsEditing: true
30
+ * });
31
+ * ```
32
+ */
33
+ static launchMediaPicker(strategy: PickerStrategy, options?: LaunchOptions): Promise<MediaPickerResult>;
34
+ /**
35
+ * Launch camera for image capture
36
+ */
12
37
  static launchCamera(options?: CameraOptions): Promise<MediaPickerResult>;
38
+ /**
39
+ * Launch camera for video capture
40
+ */
13
41
  static launchCameraForVideo(options?: CameraOptions): Promise<MediaPickerResult>;
14
- static pickImage(options?: MediaPickerOptions): Promise<MediaPickerResult>;
15
- static pickSingleImage(options?: Omit<MediaPickerOptions, "allowsMultipleSelection">): Promise<MediaPickerResult>;
16
- static pickMultipleImages(options?: Omit<MediaPickerOptions, "allowsMultipleSelection">): Promise<MediaPickerResult>;
17
- static pickVideo(options?: Omit<MediaPickerOptions, "mediaTypes">): Promise<MediaPickerResult>;
42
+ /**
43
+ * Pick from library with file size validation
44
+ */
45
+ static pickFromLibrary(options?: MediaPickerOptions): Promise<MediaPickerResult>;
46
+ /**
47
+ * Pick single image from library
48
+ */
49
+ static pickSingleImage(options?: Omit<MediaPickerOptions, 'allowsMultipleSelection'>): Promise<MediaPickerResult>;
50
+ /**
51
+ * Pick multiple images from library
52
+ */
53
+ static pickMultipleImages(options?: Omit<MediaPickerOptions, 'allowsMultipleSelection'>): Promise<MediaPickerResult>;
54
+ /**
55
+ * Pick video from library
56
+ */
57
+ static pickVideo(options?: Omit<MediaPickerOptions, 'mediaTypes'>): Promise<MediaPickerResult>;
58
+ /**
59
+ * Pick any media from library
60
+ */
18
61
  static pickMedia(options?: MediaPickerOptions): Promise<MediaPickerResult>;
19
62
  }
@@ -2,6 +2,10 @@
2
2
  * Permission Manager
3
3
  *
4
4
  * Centralized permission handling for media operations.
5
+ * Refactored to use generic PermissionHandler to reduce duplication.
6
+ *
7
+ * Before: 4 similar methods (~80 LOC)
8
+ * After: 1 generic handler (~50 LOC) - 37% reduction
5
9
  */
6
10
  import { MediaLibraryPermission } from "../../domain/entities/Media";
7
11
  /**
@@ -10,8 +14,10 @@ import { MediaLibraryPermission } from "../../domain/entities/Media";
10
14
  export type PermissionType = 'camera' | 'mediaLibrary';
11
15
  /**
12
16
  * Permission manager for media operations
17
+ * Uses generic PermissionHandler to reduce code duplication
13
18
  */
14
19
  export declare class PermissionManager {
20
+ private static handler;
15
21
  /**
16
22
  * Requests camera permission
17
23
  */
@@ -7,7 +7,7 @@ import { MediaLibraryPermission, MediaType, type MediaPickerResult } from "../..
7
7
  /**
8
8
  * Map expo-image-picker permission status to MediaLibraryPermission
9
9
  */
10
- export declare const mapPermissionStatus: (status: ImagePicker.PermissionStatus) => MediaLibraryPermission;
10
+ export declare const mapPermissionStatus: (status: string) => MediaLibraryPermission;
11
11
  /**
12
12
  * Map MediaType to expo-image-picker media types
13
13
  */
@@ -16,3 +16,17 @@ export declare const mapMediaType: (type?: MediaType) => ImagePicker.MediaType[]
16
16
  * Map expo-image-picker result to MediaPickerResult
17
17
  */
18
18
  export declare const mapPickerResult: (result: ImagePicker.ImagePickerResult) => MediaPickerResult;
19
+ /**
20
+ * Map PickerStrategy result to MediaPickerResult
21
+ */
22
+ export declare const mapPickerResultFromStrategy: (result: {
23
+ canceled: boolean;
24
+ assets?: Array<{
25
+ uri: string;
26
+ width?: number;
27
+ height?: number;
28
+ type?: "image" | "video";
29
+ duration?: number;
30
+ fileSize?: number;
31
+ }>;
32
+ }) => MediaPickerResult;
@@ -17,6 +17,7 @@ import type { CalendarEvent } from '../../domain/entities/CalendarEvent.entity';
17
17
  * Follows SOLID principles with composition over inheritance.
18
18
  */
19
19
  export declare class CalendarService {
20
+ private static weekdayNamesCache;
20
21
  /**
21
22
  * Generate calendar days for a specific month
22
23
  */
@@ -30,7 +30,7 @@ export declare const useCalendar: () => {
30
30
  setCurrentMonth: (date: Date) => void;
31
31
  viewMode: import("./CalendarStore").CalendarViewMode;
32
32
  setViewMode: (mode: import("./CalendarStore").CalendarViewMode) => void;
33
- getEventsForDate: (date: Date) => import("../..").CalendarEvent[];
33
+ getEventsForDate: (date: Date | null | undefined) => import("../..").CalendarEvent[];
34
34
  getEventsForMonth: (year: number, month: number) => import("../..").CalendarEvent[];
35
35
  };
36
36
  /**
@@ -55,7 +55,7 @@ export declare const useCalendarStore: () => {
55
55
  navigateMonth: (direction: "prev" | "next") => void;
56
56
  setCurrentMonth: (date: Date) => void;
57
57
  setViewMode: (mode: import("./CalendarStore").CalendarViewMode) => void;
58
- getEventsForDate: (date: Date) => import("../..").CalendarEvent[];
58
+ getEventsForDate: (date: Date | null | undefined) => import("../..").CalendarEvent[];
59
59
  getEventsForMonth: (year: number, month: number) => import("../..").CalendarEvent[];
60
60
  clearError: () => void;
61
61
  clearAllEvents: () => Promise<void>;
@@ -1,3 +1,3 @@
1
1
  import React from 'react';
2
2
  import type { FilterGroupProps } from './types';
3
- export declare function FilterGroup<T = string>({ items, selectedValue, onSelect, multiSelect, style, contentContainerStyle, itemStyle, }: FilterGroupProps<T>): React.JSX.Element;
3
+ export declare const FilterGroup: React.MemoExoticComponent<(<T = string>({ items, selectedValue, onSelect, multiSelect, style, contentContainerStyle, itemStyle, }: FilterGroupProps<T>) => React.JSX.Element)>;
@@ -21,7 +21,7 @@ export type { NavigationCleanup } from "./utils/NavigationCleanup";
21
21
  */
22
22
  export { AppNavigation } from "./utils/AppNavigation";
23
23
  export { TabLabel, type TabLabelProps } from "./components/TabLabel";
24
- export * from "./components/NavigationHeader";
24
+ export { NavigationHeader, type NavigationHeaderProps } from "./components/NavigationHeader";
25
25
  export { useTabBarStyles, type TabBarConfig } from "./hooks/useTabBarStyles";
26
26
  export { useTabConfig, type UseTabConfigProps } from "./hooks/useTabConfig";
27
27
  /**
@@ -5,7 +5,7 @@
5
5
  export type { NetworkState, OfflineState, OfflineStore, OfflineConfig, ConnectionQuality, } from './types';
6
6
  export { useOfflineStore } from './infrastructure/storage/OfflineStore';
7
7
  export { useOfflineConfigStore } from './infrastructure/storage/OfflineConfigStore';
8
- export { useOffline, configureOffline } from './presentation/hooks/useOffline';
8
+ export { useOffline } from './presentation/hooks/useOffline';
9
9
  export { useOfflineState } from './presentation/hooks/useOfflineState';
10
10
  export { useOfflineWithMutations } from './presentation/hooks/useOfflineWithMutations';
11
11
  export { OfflineBanner } from './presentation/components/OfflineBanner';
@@ -4,11 +4,6 @@
4
4
  * Automatically subscribes to network changes via expo-network (lazy loaded)
5
5
  */
6
6
  import type { OfflineConfig } from '../../types';
7
- /**
8
- * Configure offline settings globally
9
- * This is a facade over the config store for backward compatibility
10
- */
11
- export declare const configureOffline: (config: OfflineConfig) => void;
12
7
  export declare const useOffline: (config?: OfflineConfig) => {
13
8
  isOnline: boolean;
14
9
  isOffline: boolean;
@@ -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
@@ -51,6 +51,10 @@ export declare abstract class BaseRepository<TData, TCreateVariables = unknown,
51
51
  * Query key factory for this repository
52
52
  */
53
53
  readonly keys: ReturnType<typeof createQueryKeyFactory>;
54
+ /**
55
+ * Debug logger for this repository
56
+ */
57
+ protected readonly log: (method: string, ...args: unknown[]) => void;
54
58
  constructor(resource: string, options?: RepositoryOptions);
55
59
  /**
56
60
  * Get query client instance
@@ -14,6 +14,7 @@ declare class DevMonitorClass {
14
14
  private statsInterval;
15
15
  private cacheSubscription;
16
16
  private isEnabled;
17
+ private maxMetrics;
17
18
  constructor(options?: DevMonitorOptions);
18
19
  private init;
19
20
  private trackQuery;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Time Constants
3
+ *
4
+ * Centralized time-related constants to replace magic numbers
5
+ */
6
+ export declare const MILLISECONDS_PER_SECOND = 1000;
7
+ export declare const MILLISECONDS_PER_MINUTE: number;
8
+ export declare const MILLISECONDS_PER_HOUR: number;
9
+ export declare const MILLISECONDS_PER_DAY: number;
10
+ export declare const SECONDS_PER_MINUTE = 60;
11
+ export declare const SECONDS_PER_HOUR: number;
12
+ export declare const SECONDS_PER_DAY: number;
13
+ export declare const MINUTES_PER_HOUR = 60;
14
+ export declare const MINUTES_PER_DAY: number;
15
+ export declare const ONE_SECOND_MS = 1000;
16
+ export declare const FIVE_SECONDS_MS: number;
17
+ export declare const TEN_SECONDS_MS: number;
18
+ export declare const THIRTY_SECONDS_MS: number;
19
+ export declare const ONE_MINUTE_MS: number;
20
+ export declare const FIVE_MINUTES_MS: number;
21
+ export declare const TEN_MINUTES_MS: number;
22
+ export declare const THIRTY_MINUTES_MS: number;
23
+ export declare const ONE_HOUR_MS: number;
24
+ export declare const ONE_DAY_MS: number;
25
+ export declare const DEFAULT_TIMEOUT_MS: number;
26
+ export declare const DEFAULT_LONG_TIMEOUT_MS: number;
27
+ export declare const DEFAULT_CACHE_TTL_MS: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.27.15",
3
+ "version": "4.27.17",
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",
@@ -208,13 +208,14 @@
208
208
  "url": "https://github.com/umituz/react-native-design-system"
209
209
  },
210
210
  "peerDependencies": {
211
- "expo": ">=54.0.0",
211
+ "@react-native-community/datetimepicker": ">=8.0.0",
212
212
  "@react-navigation/bottom-tabs": ">=7.0.0",
213
213
  "@react-navigation/native": ">=7.0.0",
214
214
  "@react-navigation/stack": ">=7.0.0",
215
215
  "@tanstack/query-async-storage-persister": ">=5.0.0",
216
216
  "@tanstack/react-query": ">=5.0.0",
217
217
  "@tanstack/react-query-persist-client": ">=5.0.0",
218
+ "expo": ">=54.0.0",
218
219
  "expo-application": ">=5.0.0",
219
220
  "expo-clipboard": ">=8.0.0",
220
221
  "expo-crypto": ">=13.0.0",
@@ -230,10 +231,9 @@
230
231
  "react": ">=19.0.0",
231
232
  "react-native": "*",
232
233
  "react-native-gesture-handler": ">=2.20.0",
234
+ "react-native-keyboard-controller": ">=1.0.0",
233
235
  "react-native-safe-area-context": ">=5.6.2",
234
- "zustand": ">=5.0.0",
235
- "@react-native-community/datetimepicker": ">=8.0.0",
236
- "react-native-keyboard-controller": ">=1.0.0"
236
+ "zustand": ">=5.0.0"
237
237
  },
238
238
  "peerDependenciesMeta": {
239
239
  "react-native-keyboard-controller": {
@@ -298,13 +298,18 @@
298
298
  "@eslint/js": "^9.39.2",
299
299
  "@react-native-async-storage/async-storage": "^2.2.0",
300
300
  "@react-native-community/datetimepicker": "^8.5.1",
301
+ "@react-navigation/bottom-tabs": "^7.15.5",
302
+ "@react-navigation/native": "^7.1.33",
303
+ "@react-navigation/stack": "^7.8.5",
301
304
  "@tanstack/query-async-storage-persister": "^5.66.7",
302
305
  "@tanstack/react-query": "^5.66.7",
303
306
  "@tanstack/react-query-persist-client": "^5.66.7",
304
307
  "@testing-library/react": "^16.3.1",
305
308
  "@testing-library/react-native": "^13.3.3",
306
309
  "@types/jest": "^30.0.0",
307
- "@types/react": "^19.1.0",
310
+ "@types/node": "^25.5.0",
311
+ "@types/react": "^19.2.14",
312
+ "@types/react-native": "^0.72.8",
308
313
  "@typescript-eslint/eslint-plugin": "^8.50.1",
309
314
  "@typescript-eslint/parser": "^8.50.1",
310
315
  "eslint": "^9.39.2",
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet, ViewStyle, StyleProp, View } from 'react-native';
3
- // Remove expo-blur import to fix native module error
4
- // import { BlurView, BlurTint } from 'expo-blur';
5
3
  import { useDesignSystemTheme } from '../../theme';
6
4
  import { intensityToOpacity } from '../../utils/math';
7
5
 
@@ -5,7 +5,7 @@
5
5
  * Extracted from AtomicPicker for better separation of concerns.
6
6
  */
7
7
 
8
- import React from 'react';
8
+ import React, { useMemo, useCallback } from 'react';
9
9
  import { View, TouchableOpacity, GestureResponderEvent } from 'react-native';
10
10
  import { useAppDesignTokens } from '../../../theme';
11
11
  import { PickerOption } from '../types';
@@ -30,30 +30,36 @@ export const PickerChips: React.FC<PickerChipsProps> = React.memo(({
30
30
  const tokens = useAppDesignTokens();
31
31
  const closeIcon = useIconName('close');
32
32
 
33
- const chipContainerStyles = getChipContainerStyles(tokens);
34
- const chipStyles = getChipStyles(tokens);
35
- const chipTextStyles = getChipTextStyles(tokens);
33
+ // Memoize styles to prevent recalculation
34
+ const chipContainerStyles = useMemo(() => getChipContainerStyles(tokens), [tokens]);
35
+ const chipStyles = useMemo(() => getChipStyles(tokens), [tokens]);
36
+ const chipTextStyles = useMemo(() => getChipTextStyles(tokens), [tokens]);
36
37
 
37
- if (selectedOptions.length === 0) return null;
38
+ // Memoized chip renderer - handleRemove created inline to avoid useCallback inside callback
39
+ const renderChip = useCallback((opt: PickerOption) => {
40
+ const handleRemove = (e: GestureResponderEvent) => {
41
+ e.stopPropagation();
42
+ onRemoveChip(opt.value);
43
+ };
44
+
45
+ return (
46
+ <View key={opt.value} style={chipStyles}>
47
+ <AtomicText style={chipTextStyles}>{opt.label}</AtomicText>
48
+ <TouchableOpacity
49
+ onPress={handleRemove}
50
+ hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
51
+ accessibilityRole="button"
52
+ accessibilityLabel={`Remove ${opt.label}`}
53
+ >
54
+ <AtomicIcon name={closeIcon} size="sm" color="primary" />
55
+ </TouchableOpacity>
56
+ </View>
57
+ );
58
+ }, [chipStyles, chipTextStyles, closeIcon, onRemoveChip]);
38
59
 
39
60
  return (
40
61
  <View style={chipContainerStyles}>
41
- {selectedOptions.map((opt) => (
42
- <View key={opt.value} style={chipStyles}>
43
- <AtomicText style={chipTextStyles}>{opt.label}</AtomicText>
44
- <TouchableOpacity
45
- onPress={(e: GestureResponderEvent) => {
46
- e.stopPropagation();
47
- onRemoveChip(opt.value);
48
- }}
49
- hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
50
- accessibilityRole="button"
51
- accessibilityLabel={`Remove ${opt.label}`}
52
- >
53
- <AtomicIcon name={closeIcon} size="sm" color="primary" />
54
- </TouchableOpacity>
55
- </View>
56
- ))}
62
+ {selectedOptions.map(renderChip)}
57
63
  </View>
58
64
  );
59
65
  });
@@ -8,8 +8,9 @@
8
8
  export { UnifiedCache } from './domain/UnifiedCache';
9
9
  export type { UnifiedCacheConfig } from './domain/UnifiedCache';
10
10
 
11
- export { CleanupStrategy, IntervalCleanupStrategy, TimeoutCleanupStrategy } from './domain/CleanupStrategy';
12
- export type { CleanupType } from './domain/CleanupStrategy';
11
+ export type { CleanupStrategy } from './domain/CleanupStrategy';
12
+ export { IntervalCleanupStrategy, TimeoutCleanupStrategy } from './domain/CleanupStrategy';
13
+ export type { CleanupType } from './domain/types';
13
14
 
14
15
  export { CacheFactory } from './infrastructure/CacheFactory';
15
16
 
package/src/core/index.ts CHANGED
@@ -6,10 +6,12 @@
6
6
  */
7
7
 
8
8
  // Cache
9
- export { UnifiedCache, CacheFactory } from './cache/domain/UnifiedCache';
10
- export { CleanupStrategy, IntervalCleanupStrategy, TimeoutCleanupStrategy } from './cache/domain/CleanupStrategy';
9
+ export { UnifiedCache } from './cache/domain/UnifiedCache';
10
+ export { CacheFactory } from './cache/infrastructure/CacheFactory';
11
+ export type { CleanupStrategy } from './cache/domain/CleanupStrategy';
12
+ export { IntervalCleanupStrategy, TimeoutCleanupStrategy } from './cache/domain/CleanupStrategy';
11
13
  export type { UnifiedCacheConfig } from './cache/domain/UnifiedCache';
12
- export type { CacheEntry, CacheConfig } from './cache/domain/types';
14
+ export type { CacheEntry, CacheConfig, CleanupType } from './cache/domain/types';
13
15
 
14
16
  // Permissions
15
17
  export { PermissionHandler } from './permissions/domain/PermissionHandler';
@@ -12,7 +12,7 @@ import type { RepositoryOptions, ListParams } from './types';
12
12
  */
13
13
  const DEFAULT_CACHE_OPTIONS = {
14
14
  staleTime: 5 * 60 * 1000, // 5 minutes
15
- gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
15
+ gcTime: 10 * 60 * 1000, // 10 minutes
16
16
  };
17
17
 
18
18
  /**
@@ -43,10 +43,10 @@ export function getCacheOptions(options: RepositoryOptions): {
43
43
  staleTime: number;
44
44
  gcTime: number;
45
45
  } {
46
- const merged = mergeRepositoryOptions(options);
46
+ const cache = options.cache ?? {};
47
47
  return {
48
- staleTime: merged.cache.staleTime,
49
- gcTime: merged.cache.gcTime,
48
+ staleTime: cache.staleTime ?? DEFAULT_CACHE_OPTIONS.staleTime,
49
+ gcTime: cache.gcTime ?? DEFAULT_CACHE_OPTIONS.gcTime,
50
50
  };
51
51
  }
52
52
 
@@ -53,7 +53,7 @@ export interface UpdateParams<TVariables> {
53
53
  export type QueryKeyFactory = {
54
54
  all: () => readonly string[];
55
55
  lists: () => readonly string[];
56
- list: (params: ListParams) => readonly string[];
56
+ list: (params: ListParams) => readonly unknown[];
57
57
  details: () => readonly string[];
58
- detail: (id: string | number) => readonly string[];
58
+ detail: (id: string | number) => readonly unknown[];
59
59
  };
@@ -20,11 +20,6 @@
20
20
 
21
21
  export {
22
22
  useAppDesignTokens,
23
- useDesignSystemTheme,
24
- useTheme,
25
- useThemedStyles,
26
- useThemedStyleSheet,
27
- useCommonStyles,
28
23
  } from '../theme/hooks/useAppDesignTokens';
29
24
 
30
25
  export { useTheme as useThemeStore } from '../theme/infrastructure/stores/themeStore';
@@ -35,9 +30,10 @@ export { useTheme as useThemeStore } from '../theme/infrastructure/stores/themeS
35
30
 
36
31
  export {
37
32
  useResponsive,
38
- useBreakpoint,
39
- useOrientation,
40
- type Breakpoint,
33
+ useScreenWidth,
34
+ useScreenHeight,
35
+ useScreenDimensions,
36
+ type UseResponsiveReturn,
41
37
  } from '../responsive';
42
38
 
43
39
  // =============================================================================
@@ -45,7 +41,6 @@ export {
45
41
  // =============================================================================
46
42
 
47
43
  export {
48
- useSafeArea,
49
44
  useSafeAreaInsets,
50
45
  } from '../safe-area';
51
46
 
@@ -55,8 +50,8 @@ export {
55
50
 
56
51
  export {
57
52
  useInfiniteScroll,
58
- type UseInfiniteScrollOptions,
59
- type UseInfiniteScrollResult,
53
+ type InfiniteScrollConfig,
54
+ type UseInfiniteScrollReturn,
60
55
  } from '../infinite-scroll';
61
56
 
62
57
  // =============================================================================
@@ -65,7 +60,7 @@ export {
65
60
 
66
61
  export {
67
62
  useOffline,
68
- type NetworkStatus,
63
+ type NetworkState,
69
64
  } from '../offline';
70
65
 
71
66
  // =============================================================================
@@ -73,9 +68,11 @@ export {
73
68
  // =============================================================================
74
69
 
75
70
  export {
76
- useDeviceContext,
77
71
  useDeviceInfo,
72
+ useDeviceCapabilities,
73
+ useDeviceId,
78
74
  type DeviceInfo,
75
+ type AnonymousUser,
79
76
  } from '../device';
80
77
 
81
78
  // =============================================================================
@@ -84,8 +81,14 @@ export {
84
81
 
85
82
  export {
86
83
  useStorage,
87
- useAsyncStorage,
88
- useSecureStorage,
84
+ useStorageState,
85
+ useStore,
86
+ usePersistentCache,
87
+ useCache,
88
+ useCachedValue,
89
+ useCacheState,
90
+ type PersistentCacheOptions,
91
+ type PersistentCacheResult,
89
92
  } from '../storage';
90
93
 
91
94
  // =============================================================================
@@ -93,10 +96,8 @@ export {
93
96
  // =============================================================================
94
97
 
95
98
  export {
96
- useImagePicker,
97
- useImageLibrary,
98
- useCamera,
99
- type ImagePickerResult,
99
+ useMedia,
100
+ type MediaPickerResult,
100
101
  } from '../media';
101
102
 
102
103
  // =============================================================================
@@ -105,7 +106,6 @@ export {
105
106
 
106
107
  export {
107
108
  useTimezone,
108
- useLocalTime,
109
109
  type TimezoneInfo,
110
110
  } from '../timezone';
111
111
 
@@ -115,9 +115,6 @@ export {
115
115
 
116
116
  export {
117
117
  useHaptics,
118
- useImpact,
119
- useNotification,
120
- useSelection,
121
118
  } from '../haptics';
122
119
 
123
120
  // =============================================================================
@@ -125,6 +122,6 @@ export {
125
122
  // =============================================================================
126
123
 
127
124
  export {
128
- useLoading,
129
- useLoadingState,
125
+ useGlobalLoading,
126
+ type LoadingState,
130
127
  } from '../loading';
@@ -20,6 +20,29 @@ try {
20
20
  // expo-image not installed — using React Native Image fallback
21
21
  }
22
22
 
23
+ // Memoized image component (outside main component to avoid dependency issues)
24
+ const GalleryImage = React.memo<{ item: ImageViewerItem; style: any }>(({ item, style }) => (
25
+ <View style={style.imageWrapper}>
26
+ {ExpoImage ? (
27
+ <ExpoImage
28
+ source={{ uri: item.uri }}
29
+ style={style.fullImage}
30
+ contentFit="contain"
31
+ cachePolicy="memory-disk"
32
+ onError={() => { if (__DEV__) console.warn('[ImageGallery] Failed to load image:', item.uri); }}
33
+ />
34
+ ) : (
35
+ <RNImage
36
+ source={{ uri: item.uri }}
37
+ style={style.fullImage}
38
+ resizeMode="contain"
39
+ onError={() => { if (__DEV__) console.warn('[ImageGallery] Failed to load image:', item.uri); }}
40
+ />
41
+ )}
42
+ </View>
43
+ ));
44
+ GalleryImage.displayName = 'GalleryImage';
45
+
23
46
  export interface ImageGalleryProps extends ImageGalleryOptions {
24
47
  images: ImageViewerItem[];
25
48
  visible: boolean;
@@ -44,7 +67,6 @@ export const ImageGallery: React.FC<ImageGalleryProps> = ({
44
67
  const insets = useSafeAreaInsets();
45
68
  const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = useWindowDimensions();
46
69
  const currentIndexRef = useRef(index);
47
- const [, forceRender] = React.useReducer((x: number) => x + 1, 0);
48
70
 
49
71
  const styles = useMemo(() => StyleSheet.create({
50
72
  container: { flex: 1 },
@@ -81,30 +103,12 @@ export const ImageGallery: React.FC<ImageGalleryProps> = ({
81
103
  if (nextIndex !== currentIndexRef.current) {
82
104
  currentIndexRef.current = nextIndex;
83
105
  onIndexChange?.(nextIndex);
84
- forceRender();
85
106
  }
86
107
  }, [onIndexChange, SCREEN_WIDTH, images.length]);
87
108
 
88
109
  const renderItem = useCallback(({ item }: { item: ImageViewerItem }) => (
89
- <View style={styles.imageWrapper}>
90
- {ExpoImage ? (
91
- <ExpoImage
92
- source={{ uri: item.uri }}
93
- style={styles.fullImage}
94
- contentFit="contain"
95
- cachePolicy="memory-disk"
96
- onError={() => { if (__DEV__) console.warn('[ImageGallery] Failed to load image:', item.uri); }}
97
- />
98
- ) : (
99
- <RNImage
100
- source={{ uri: item.uri }}
101
- style={styles.fullImage}
102
- resizeMode="contain"
103
- onError={() => { if (__DEV__) console.warn('[ImageGallery] Failed to load image:', item.uri); }}
104
- />
105
- )}
106
- </View>
107
- ), [styles]);
110
+ <GalleryImage item={item} style={{ imageWrapper: styles.imageWrapper, fullImage: styles.fullImage }} />
111
+ ), [styles.imageWrapper, styles.fullImage]);
108
112
 
109
113
  const getItemLayout = useCallback((_: unknown, i: number) => ({
110
114
  length: SCREEN_WIDTH,