@umituz/react-native-design-system 2.6.107 → 2.6.111

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 (35) hide show
  1. package/package.json +2 -2
  2. package/src/exception/domain/entities/ExceptionEntity.ts +115 -0
  3. package/src/exception/domain/repositories/IExceptionRepository.ts +37 -0
  4. package/src/exception/index.ts +65 -0
  5. package/src/exception/infrastructure/services/ExceptionHandler.ts +93 -0
  6. package/src/exception/infrastructure/services/ExceptionLogger.ts +142 -0
  7. package/src/exception/infrastructure/services/ExceptionReporter.ts +134 -0
  8. package/src/exception/infrastructure/services/ExceptionService.ts +154 -0
  9. package/src/exception/infrastructure/storage/ExceptionStore.ts +44 -0
  10. package/src/exception/presentation/components/ErrorBoundary.tsx +129 -0
  11. package/src/exception/presentation/components/ExceptionEmptyState.tsx +123 -0
  12. package/src/exception/presentation/components/ExceptionErrorState.tsx +118 -0
  13. package/src/exports/exception.ts +7 -0
  14. package/src/exports/infinite-scroll.ts +7 -0
  15. package/src/exports/uuid.ts +7 -0
  16. package/src/index.ts +15 -0
  17. package/src/infinite-scroll/domain/interfaces/infinite-scroll-list-props.ts +67 -0
  18. package/src/infinite-scroll/domain/types/infinite-scroll-config.ts +108 -0
  19. package/src/infinite-scroll/domain/types/infinite-scroll-return.ts +40 -0
  20. package/src/infinite-scroll/domain/types/infinite-scroll-state.ts +58 -0
  21. package/src/infinite-scroll/domain/utils/pagination-utils.ts +63 -0
  22. package/src/infinite-scroll/domain/utils/type-guards.ts +53 -0
  23. package/src/infinite-scroll/index.ts +62 -0
  24. package/src/infinite-scroll/presentation/components/empty.tsx +44 -0
  25. package/src/infinite-scroll/presentation/components/error.tsx +66 -0
  26. package/src/infinite-scroll/presentation/components/infinite-scroll-list.tsx +120 -0
  27. package/src/infinite-scroll/presentation/components/loading-more.tsx +38 -0
  28. package/src/infinite-scroll/presentation/components/loading.tsx +40 -0
  29. package/src/infinite-scroll/presentation/components/types.ts +124 -0
  30. package/src/infinite-scroll/presentation/hooks/pagination.helper.ts +83 -0
  31. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +327 -0
  32. package/src/uuid/index.ts +15 -0
  33. package/src/uuid/infrastructure/utils/UUIDUtils.ts +75 -0
  34. package/src/uuid/package-lock.json +14255 -0
  35. package/src/uuid/types/UUID.ts +36 -0
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Infinite Scroll Configuration Types
3
+ *
4
+ * Domain types for infinite scroll configuration
5
+ * Follows SOLID, DRY, KISS principles
6
+ */
7
+
8
+ /**
9
+ * Paginated result for cursor-based pagination
10
+ */
11
+ export interface PaginatedResult<T> {
12
+ items: T[];
13
+ nextCursor: string | null;
14
+ hasMore: boolean;
15
+ }
16
+
17
+ /**
18
+ * Base configuration shared by all pagination modes
19
+ */
20
+ interface BaseConfig<T> {
21
+ /**
22
+ * Total number of items available (optional, for progress tracking)
23
+ */
24
+ totalItems?: number;
25
+
26
+ /**
27
+ * Number of items to load per page
28
+ * Default: 20
29
+ */
30
+ pageSize?: number;
31
+
32
+ /**
33
+ * Number of items from the end to trigger loading more
34
+ * Default: 5 (loads more when 5 items from bottom)
35
+ */
36
+ threshold?: number;
37
+
38
+ /**
39
+ * Enable automatic loading when threshold is reached
40
+ * Default: true
41
+ */
42
+ autoLoad?: boolean;
43
+
44
+ /**
45
+ * Optional: Function to get unique key for each item
46
+ * If not provided, uses array index
47
+ * @param item - Item to get key for
48
+ * @param index - Item index
49
+ * @returns Unique key string
50
+ */
51
+ getItemKey?: (item: T, index: number) => string;
52
+ }
53
+
54
+ /**
55
+ * Page-based pagination configuration (default, backward compatible)
56
+ */
57
+ export interface PageBasedConfig<T> extends BaseConfig<T> {
58
+ /**
59
+ * Initial page number (0-indexed)
60
+ * Default: 0
61
+ */
62
+ initialPage?: number;
63
+
64
+ /**
65
+ * Function to fetch data for a specific page
66
+ * @param page - Page number (0-indexed)
67
+ * @param pageSize - Number of items per page
68
+ * @returns Promise resolving to array of items
69
+ */
70
+ fetchData: (page: number, pageSize: number) => Promise<T[]>;
71
+
72
+ /**
73
+ * Optional: Function to check if there are more items
74
+ * If not provided, checks if last page has fewer items than pageSize
75
+ * @param lastPage - Last fetched page of items
76
+ * @param allPages - All fetched pages
77
+ * @returns true if there are more items to load
78
+ */
79
+ hasMore?: (lastPage: T[], allPages: T[][]) => boolean;
80
+ }
81
+
82
+ /**
83
+ * Cursor-based pagination configuration (new, for Firestore)
84
+ */
85
+ export interface CursorBasedConfig<T> extends BaseConfig<T> {
86
+ /**
87
+ * Discriminator for cursor-based mode
88
+ */
89
+ paginationMode: "cursor";
90
+
91
+ /**
92
+ * Function to fetch data using cursor
93
+ * @param cursor - Cursor for next page (undefined for first page)
94
+ * @param pageSize - Number of items per page
95
+ * @returns Promise resolving to paginated result with cursor
96
+ */
97
+ fetchCursor: (
98
+ cursor: string | undefined,
99
+ pageSize: number,
100
+ ) => Promise<PaginatedResult<T>>;
101
+ }
102
+
103
+ /**
104
+ * Infinite scroll configuration (discriminated union)
105
+ */
106
+ export type InfiniteScrollConfig<T> =
107
+ | PageBasedConfig<T>
108
+ | CursorBasedConfig<T>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Infinite Scroll Return Types
3
+ *
4
+ * Domain types for hook return values
5
+ * Follows SOLID, DRY, KISS principles
6
+ */
7
+
8
+ import type { InfiniteScrollState } from "./infinite-scroll-state";
9
+
10
+ export interface UseInfiniteScrollReturn<T> {
11
+ /**
12
+ * All loaded items (flattened)
13
+ */
14
+ items: T[];
15
+
16
+ /**
17
+ * Current state
18
+ */
19
+ state: InfiniteScrollState<T>;
20
+
21
+ /**
22
+ * Load next page of items
23
+ */
24
+ loadMore: () => Promise<void>;
25
+
26
+ /**
27
+ * Refresh all data (resets to page 0)
28
+ */
29
+ refresh: () => Promise<void>;
30
+
31
+ /**
32
+ * Reset to initial state
33
+ */
34
+ reset: () => void;
35
+
36
+ /**
37
+ * Check if can load more
38
+ */
39
+ canLoadMore: boolean;
40
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Infinite Scroll State Types
3
+ *
4
+ * Domain types for infinite scroll state management
5
+ * Follows SOLID, DRY, KISS principles
6
+ */
7
+
8
+ export interface InfiniteScrollState<T> {
9
+ /**
10
+ * All loaded items (flattened from pages)
11
+ */
12
+ items: T[];
13
+
14
+ /**
15
+ * All pages of items (used in page-based mode)
16
+ */
17
+ pages: T[][];
18
+
19
+ /**
20
+ * Current page number (0-indexed, page-based mode)
21
+ */
22
+ currentPage: number;
23
+
24
+ /**
25
+ * Current cursor (cursor-based mode)
26
+ */
27
+ cursor: string | null;
28
+
29
+ /**
30
+ * Whether more items are available
31
+ */
32
+ hasMore: boolean;
33
+
34
+ /**
35
+ * Whether currently loading initial data
36
+ */
37
+ isLoading: boolean;
38
+
39
+ /**
40
+ * Whether currently loading more items
41
+ */
42
+ isLoadingMore: boolean;
43
+
44
+ /**
45
+ * Whether currently refreshing
46
+ */
47
+ isRefreshing: boolean;
48
+
49
+ /**
50
+ * Error message if any
51
+ */
52
+ error: string | null;
53
+
54
+ /**
55
+ * Total number of items (if known)
56
+ */
57
+ totalItems?: number;
58
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Pagination Utilities
3
+ *
4
+ * Pure functions for pagination calculations
5
+ * Follows SOLID, DRY, KISS principles
6
+ */
7
+
8
+ /**
9
+ * Calculate onEndReachedThreshold from threshold value
10
+ * Converts threshold (number of items) to percentage (0-1)
11
+ *
12
+ * @param threshold - Number of items from bottom to trigger load
13
+ * @param defaultThreshold - Default threshold if not provided (default: 0.1 = 10%)
14
+ * @returns Threshold value between 0.01 and 1.0
15
+ */
16
+ export function calculateEndReachedThreshold(
17
+ threshold?: number,
18
+ defaultThreshold = 0.1,
19
+ ): number {
20
+ if (!threshold) {
21
+ return defaultThreshold;
22
+ }
23
+
24
+ // Convert threshold to percentage (0-1 range)
25
+ // Ensure minimum 0.01 (1%) and maximum 1.0 (100%)
26
+ const calculated = threshold / 100;
27
+ return Math.max(0.01, Math.min(1.0, calculated));
28
+ }
29
+
30
+ /**
31
+ * Calculate pagination slice for client-side pagination
32
+ *
33
+ * @param items - All items to paginate
34
+ * @param page - Page number (0-indexed)
35
+ * @param pageSize - Number of items per page
36
+ * @returns Slice of items for the requested page
37
+ */
38
+ export function getPageSlice<T>(
39
+ items: T[],
40
+ page: number,
41
+ pageSize: number,
42
+ ): T[] {
43
+ const start = page * pageSize;
44
+ const end = start + pageSize;
45
+ return items.slice(start, end);
46
+ }
47
+
48
+ /**
49
+ * Check if there are more items to load
50
+ *
51
+ * @param lastPage - Last fetched page
52
+ * @param allPages - All fetched pages
53
+ * @param pageSize - Page size
54
+ * @returns True if there are more items to load
55
+ */
56
+ export function hasMoreItems<T>(
57
+ lastPage: T[],
58
+ allPages: T[][],
59
+ pageSize: number,
60
+ ): boolean {
61
+ // If last page has fewer items than pageSize, we've reached the end
62
+ return lastPage.length >= pageSize;
63
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Type Guard Utilities
3
+ *
4
+ * Runtime type checking for better type safety
5
+ */
6
+
7
+ import type { InfiniteScrollConfig, PageBasedConfig, CursorBasedConfig } from "../types/infinite-scroll-config";
8
+
9
+ /**
10
+ * Check if config is page-based pagination
11
+ */
12
+ export function isPageBasedConfig<T>(
13
+ config: InfiniteScrollConfig<T>,
14
+ ): config is PageBasedConfig<T> {
15
+ return "fetchData" in config && typeof config.fetchData === "function";
16
+ }
17
+
18
+ /**
19
+ * Check if config is cursor-based pagination
20
+ */
21
+ export function isCursorBasedConfig<T>(
22
+ config: InfiniteScrollConfig<T>,
23
+ ): config is CursorBasedConfig<T> {
24
+ return "paginationMode" in config && config.paginationMode === "cursor";
25
+ }
26
+
27
+ /**
28
+ * Check if value is a valid error
29
+ */
30
+ export function isError(value: unknown): value is Error {
31
+ return value instanceof Error;
32
+ }
33
+
34
+ /**
35
+ * Check if value is a non-null object
36
+ */
37
+ export function isNonNullObject<T>(value: T | null | undefined): value is T {
38
+ return value !== null && value !== undefined;
39
+ }
40
+
41
+ /**
42
+ * Check if array has items
43
+ */
44
+ export function hasItems<T>(items: T[] | null | undefined): items is T[] {
45
+ return Array.isArray(items) && items.length > 0;
46
+ }
47
+
48
+ /**
49
+ * Check if string is not empty
50
+ */
51
+ export function isNonEmptyString(value: string | null | undefined): value is string {
52
+ return typeof value === "string" && value.length > 0;
53
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * React Native Infinite Scroll
3
+ *
4
+ * Modern infinite scroll system for React Native
5
+ * Follows SOLID, DRY, KISS principles
6
+ *
7
+ * Features:
8
+ * - Page-based and cursor-based pagination
9
+ * - Automatic retry with exponential backoff
10
+ * - Request cancellation with AbortController
11
+ * - Performance monitoring in __DEV__ mode
12
+ * - Full accessibility support
13
+ * - Type-safe utilities
14
+ */
15
+
16
+ // Domain Layer
17
+ export type {
18
+ InfiniteScrollConfig,
19
+ PaginatedResult,
20
+ PageBasedConfig,
21
+ CursorBasedConfig,
22
+ } from "./domain/types/infinite-scroll-config";
23
+ export type { InfiniteScrollState } from "./domain/types/infinite-scroll-state";
24
+ export type { UseInfiniteScrollReturn } from "./domain/types/infinite-scroll-return";
25
+ export type { InfiniteScrollListProps } from "./domain/interfaces/infinite-scroll-list-props";
26
+
27
+ // Domain Utils
28
+ export {
29
+ calculateEndReachedThreshold,
30
+ getPageSlice,
31
+ hasMoreItems,
32
+ } from "./domain/utils/pagination-utils";
33
+
34
+ // Type Guards
35
+ export {
36
+ isPageBasedConfig,
37
+ isCursorBasedConfig,
38
+ isError,
39
+ isNonNullObject,
40
+ hasItems,
41
+ isNonEmptyString,
42
+ } from "./domain/utils/type-guards";
43
+
44
+ // Presentation Layer - Hooks
45
+ export { useInfiniteScroll } from "./presentation/hooks/useInfiniteScroll";
46
+
47
+ // Presentation Layer - Components
48
+ export { InfiniteScrollList } from "./presentation/components/infinite-scroll-list";
49
+
50
+ // Component Types
51
+ export type {
52
+ EmptyProps,
53
+ ErrorProps,
54
+ LoadingProps,
55
+ LoadingMoreProps,
56
+ } from "./presentation/components/types";
57
+
58
+ // State Components
59
+ export { Loading } from "./presentation/components/loading";
60
+ export { LoadingMore } from "./presentation/components/loading-more";
61
+ export { Empty } from "./presentation/components/empty";
62
+ export { Error } from "./presentation/components/error";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Empty Component
3
+ *
4
+ * Presentation component for empty state
5
+ * Fully customizable via props
6
+ * Accessibility support included
7
+ */
8
+
9
+ import React from "react";
10
+ import { View, Text, StyleSheet } from "react-native";
11
+ import type { EmptyProps } from "./types";
12
+
13
+ export const Empty = React.memo<EmptyProps>(({
14
+ text = "No items found",
15
+ containerStyle,
16
+ textStyle,
17
+ accessibilityLabel = "Empty list",
18
+ ...accessibilityProps
19
+ }) => (
20
+ <View
21
+ style={[styles.container, containerStyle]}
22
+ accessibilityLabel={accessibilityLabel}
23
+ accessibilityRole="text"
24
+ accessibilityValue={{ text }}
25
+ {...accessibilityProps}
26
+ >
27
+ <Text style={[styles.text, textStyle]}>{text}</Text>
28
+ </View>
29
+ ));
30
+
31
+ Empty.displayName = "Empty";
32
+
33
+ const styles = StyleSheet.create({
34
+ container: {
35
+ flex: 1,
36
+ justifyContent: "center",
37
+ alignItems: "center",
38
+ padding: 20,
39
+ },
40
+ text: {
41
+ fontSize: 16,
42
+ textAlign: "center",
43
+ },
44
+ });
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Error Component
3
+ *
4
+ * Presentation component for error state
5
+ * Fully customizable via props
6
+ * Accessibility support included
7
+ */
8
+
9
+ import React from "react";
10
+ import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
11
+ import type { ErrorProps } from "./types";
12
+
13
+ export const Error = React.memo<ErrorProps>(({
14
+ error,
15
+ onRetry,
16
+ retryText = "Tap to retry",
17
+ containerStyle,
18
+ errorTextStyle,
19
+ retryTextStyle,
20
+ accessibilityLabel,
21
+ retryAccessibilityHint = "Double tap to retry",
22
+ ...accessibilityProps
23
+ }) => (
24
+ <View
25
+ style={[styles.container, containerStyle]}
26
+ accessibilityLabel={accessibilityLabel || `Error: ${error}`}
27
+ accessibilityRole="alert"
28
+ {...accessibilityProps}
29
+ >
30
+ <Text
31
+ style={[styles.errorText, errorTextStyle]}
32
+ accessibilityRole="text"
33
+ >
34
+ {error}
35
+ </Text>
36
+ <TouchableOpacity
37
+ onPress={onRetry}
38
+ accessibilityRole="button"
39
+ accessibilityLabel={retryText}
40
+ accessibilityHint={retryAccessibilityHint}
41
+ >
42
+ <Text style={[styles.retryText, retryTextStyle]}>{retryText}</Text>
43
+ </TouchableOpacity>
44
+ </View>
45
+ ));
46
+
47
+ Error.displayName = "Error";
48
+
49
+ const styles = StyleSheet.create({
50
+ container: {
51
+ flex: 1,
52
+ justifyContent: "center",
53
+ alignItems: "center",
54
+ padding: 20,
55
+ },
56
+ errorText: {
57
+ fontSize: 16,
58
+ textAlign: "center",
59
+ marginBottom: 8,
60
+ },
61
+ retryText: {
62
+ fontSize: 14,
63
+ textAlign: "center",
64
+ marginTop: 8,
65
+ },
66
+ });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * InfiniteScrollList Component
3
+ *
4
+ * Presentation component for infinite scroll list
5
+ * Optimized with React.memo for performance
6
+ */
7
+
8
+ import React from "react";
9
+ import { FlatList } from "react-native";
10
+ import { useInfiniteScroll } from "../hooks/useInfiniteScroll";
11
+ import { calculateEndReachedThreshold } from "../../domain/utils/pagination-utils";
12
+ import type { InfiniteScrollListProps } from "../../domain/interfaces/infinite-scroll-list-props";
13
+ import { Loading } from "./loading";
14
+ import { LoadingMore } from "./loading-more";
15
+ import { Empty } from "./empty";
16
+ import { Error } from "./error";
17
+
18
+ /**
19
+ * Render error component
20
+ */
21
+ function renderErrorComponent(
22
+ error: string,
23
+ retry: () => void,
24
+ errorComponent?: (error: string, retry: () => void) => React.ReactElement,
25
+ ): React.ReactElement {
26
+ if (errorComponent) {
27
+ return errorComponent(error, retry);
28
+ }
29
+ return <Error error={error} onRetry={retry} />;
30
+ }
31
+
32
+ /**
33
+ * InfiniteScrollList Component
34
+ *
35
+ * FlatList wrapper with automatic infinite scroll and pagination
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <InfiniteScrollList
40
+ * config={{
41
+ * pageSize: 20,
42
+ * threshold: 5,
43
+ * fetchData: async (page, pageSize) => {
44
+ * const response = await api.getItems({ page, limit: pageSize });
45
+ * return response.data;
46
+ * },
47
+ * }}
48
+ * renderItem={(item) => <ItemCard item={item} />}
49
+ * />
50
+ * ```
51
+ */
52
+ function InfiniteScrollListComponent<T>({
53
+ config,
54
+ renderItem,
55
+ loadingComponent,
56
+ loadingMoreComponent,
57
+ emptyComponent,
58
+ errorComponent,
59
+ ListHeaderComponent,
60
+ ListFooterComponent,
61
+ flatListProps,
62
+ }: InfiniteScrollListProps<T>): React.ReactElement {
63
+ const { items, state, loadMore, refresh, canLoadMore } = useInfiniteScroll(config);
64
+
65
+ const handleEndReached = React.useCallback(() => {
66
+ if (canLoadMore && config.autoLoad !== false) {
67
+ loadMore();
68
+ }
69
+ }, [canLoadMore, loadMore, config.autoLoad]);
70
+
71
+ const getItemKey = React.useCallback(
72
+ (item: T, index: number): string => {
73
+ if (config.getItemKey) {
74
+ return config.getItemKey(item, index);
75
+ }
76
+ return `item-${index}`;
77
+ },
78
+ [config],
79
+ );
80
+
81
+ // Loading state
82
+ if (state.isLoading) {
83
+ return loadingComponent || <Loading />;
84
+ }
85
+
86
+ // Error state
87
+ if (state.error) {
88
+ return renderErrorComponent(state.error, refresh, errorComponent);
89
+ }
90
+
91
+ // Empty state
92
+ if (items.length === 0 && !state.isLoading) {
93
+ return emptyComponent || <Empty />;
94
+ }
95
+
96
+ // Render list
97
+ return (
98
+ <FlatList
99
+ data={items}
100
+ renderItem={({ item, index }) => renderItem(item, index)}
101
+ keyExtractor={(item, index) => getItemKey(item, index)}
102
+ onEndReached={handleEndReached}
103
+ onEndReachedThreshold={calculateEndReachedThreshold(config.threshold)}
104
+ onRefresh={refresh}
105
+ refreshing={state.isRefreshing}
106
+ ListHeaderComponent={ListHeaderComponent}
107
+ ListFooterComponent={
108
+ <>
109
+ {ListFooterComponent}
110
+ {state.isLoadingMore && (loadingMoreComponent || <LoadingMore />)}
111
+ </>
112
+ }
113
+ {...flatListProps}
114
+ />
115
+ );
116
+ }
117
+
118
+ export const InfiniteScrollList = React.memo(InfiniteScrollListComponent) as <T>(
119
+ props: InfiniteScrollListProps<T>,
120
+ ) => React.ReactElement;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Loading More Component
3
+ *
4
+ * Presentation component for loading more state
5
+ * Fully customizable via props
6
+ * Accessibility support included
7
+ */
8
+
9
+ import React from "react";
10
+ import { View, ActivityIndicator, StyleSheet } from "react-native";
11
+ import type { LoadingMoreProps } from "./types";
12
+
13
+ export const LoadingMore = React.memo<LoadingMoreProps>(({
14
+ containerStyle,
15
+ size = "small",
16
+ color,
17
+ accessibilityLabel = "Loading more",
18
+ ...accessibilityProps
19
+ }) => (
20
+ <View
21
+ style={[styles.container, containerStyle]}
22
+ accessibilityLabel={accessibilityLabel}
23
+ accessibilityRole="progressbar"
24
+ accessibilityState={{ busy: true }}
25
+ {...accessibilityProps}
26
+ >
27
+ <ActivityIndicator size={size} color={color} />
28
+ </View>
29
+ ));
30
+
31
+ LoadingMore.displayName = "LoadingMore";
32
+
33
+ const styles = StyleSheet.create({
34
+ container: {
35
+ padding: 16,
36
+ alignItems: "center",
37
+ },
38
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Loading Component
3
+ *
4
+ * Presentation component for loading state
5
+ * Fully customizable via props
6
+ * Accessibility support included
7
+ */
8
+
9
+ import React from "react";
10
+ import { View, ActivityIndicator, StyleSheet } from "react-native";
11
+ import type { LoadingProps } from "./types";
12
+
13
+ export const Loading = React.memo<LoadingProps>(({
14
+ containerStyle,
15
+ size = "large",
16
+ color,
17
+ accessibilityLabel = "Loading",
18
+ ...accessibilityProps
19
+ }) => (
20
+ <View
21
+ style={[styles.container, containerStyle]}
22
+ accessibilityLabel={accessibilityLabel}
23
+ accessibilityRole="progressbar"
24
+ accessibilityState={{ busy: true }}
25
+ {...accessibilityProps}
26
+ >
27
+ <ActivityIndicator size={size} color={color} />
28
+ </View>
29
+ ));
30
+
31
+ Loading.displayName = "Loading";
32
+
33
+ const styles = StyleSheet.create({
34
+ container: {
35
+ flex: 1,
36
+ justifyContent: "center",
37
+ alignItems: "center",
38
+ padding: 20,
39
+ },
40
+ });