@zezosoft/zezo-ott-react-native-ui-kit 1.0.6 → 1.0.8

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 (107) hide show
  1. package/lib/module/components/Auth/SplashScreen/components/SplashVideo/SplashVideo.js +54 -56
  2. package/lib/module/components/Auth/SplashScreen/components/SplashVideo/SplashVideo.js.map +1 -1
  3. package/lib/module/components/Content/Card/components/CardPoster.js +5 -0
  4. package/lib/module/components/Content/Card/components/CardPoster.js.map +1 -1
  5. package/lib/module/components/Content/Content.js +22 -7
  6. package/lib/module/components/Content/Content.js.map +1 -1
  7. package/lib/module/components/ContentView/ContentView.js +99 -83
  8. package/lib/module/components/ContentView/ContentView.js.map +1 -1
  9. package/lib/module/components/ContentView/components/AboutSection.js +15 -1
  10. package/lib/module/components/ContentView/components/AboutSection.js.map +1 -1
  11. package/lib/module/components/ContentView/components/CastCard.js +1 -1
  12. package/lib/module/components/ContentView/components/HeroBanner.js +44 -17
  13. package/lib/module/components/ContentView/components/HeroBanner.js.map +1 -1
  14. package/lib/module/components/ContentView/components/MiniInfo.js +136 -0
  15. package/lib/module/components/ContentView/components/MiniInfo.js.map +1 -0
  16. package/lib/module/components/ContentView/components/Title.js +19 -27
  17. package/lib/module/components/ContentView/components/Title.js.map +1 -1
  18. package/lib/module/components/{Content/Card/components → Fallbacks}/NoContentFallback.js +49 -32
  19. package/lib/module/components/Fallbacks/NoContentFallback.js.map +1 -0
  20. package/lib/module/components/Fallbacks/NotFoundFallback.js +79 -0
  21. package/lib/module/components/Fallbacks/NotFoundFallback.js.map +1 -0
  22. package/lib/module/components/Fallbacks/index.js +5 -0
  23. package/lib/module/components/Fallbacks/index.js.map +1 -0
  24. package/lib/module/components/Input/InputOne.js +9 -3
  25. package/lib/module/components/Input/InputOne.js.map +1 -1
  26. package/lib/module/components/Subscription/SubOne.js +13 -6
  27. package/lib/module/components/Subscription/SubOne.js.map +1 -1
  28. package/lib/module/components/Text/Text.js +31 -10
  29. package/lib/module/components/Text/Text.js.map +1 -1
  30. package/lib/module/components/User/ProfileUpdate/ProfileUpdate.js +2 -2
  31. package/lib/module/components/User/ProfileUpdate/ProfileUpdate.js.map +1 -1
  32. package/lib/module/components/View/View.js.map +1 -1
  33. package/lib/module/components/index.js +3 -1
  34. package/lib/module/components/index.js.map +1 -1
  35. package/lib/module/store/themeStore.js +26 -29
  36. package/lib/module/store/themeStore.js.map +1 -1
  37. package/lib/module/theme/ThemeProvider.js.map +1 -1
  38. package/lib/module/theme/hook/useInternalTheme.js +36 -25
  39. package/lib/module/theme/hook/useInternalTheme.js.map +1 -1
  40. package/lib/module/theme/themes.js +14 -2
  41. package/lib/module/theme/themes.js.map +1 -1
  42. package/lib/typescript/src/components/Auth/SplashScreen/components/SplashVideo/SplashVideo.d.ts +7 -6
  43. package/lib/typescript/src/components/Auth/SplashScreen/components/SplashVideo/SplashVideo.d.ts.map +1 -1
  44. package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts +4 -0
  45. package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts.map +1 -1
  46. package/lib/typescript/src/components/Content/Content.d.ts +2 -0
  47. package/lib/typescript/src/components/Content/Content.d.ts.map +1 -1
  48. package/lib/typescript/src/components/ContentView/ContentView.d.ts +1 -5
  49. package/lib/typescript/src/components/ContentView/ContentView.d.ts.map +1 -1
  50. package/lib/typescript/src/components/ContentView/components/AboutSection.d.ts +6 -3
  51. package/lib/typescript/src/components/ContentView/components/AboutSection.d.ts.map +1 -1
  52. package/lib/typescript/src/components/ContentView/components/HeroBanner.d.ts.map +1 -1
  53. package/lib/typescript/src/components/ContentView/components/MiniInfo.d.ts +22 -0
  54. package/lib/typescript/src/components/ContentView/components/MiniInfo.d.ts.map +1 -0
  55. package/lib/typescript/src/components/Fallbacks/NoContentFallback.d.ts +16 -0
  56. package/lib/typescript/src/components/Fallbacks/NoContentFallback.d.ts.map +1 -0
  57. package/lib/typescript/src/components/Fallbacks/NotFoundFallback.d.ts +19 -0
  58. package/lib/typescript/src/components/Fallbacks/NotFoundFallback.d.ts.map +1 -0
  59. package/lib/typescript/src/components/Fallbacks/index.d.ts +3 -0
  60. package/lib/typescript/src/components/Fallbacks/index.d.ts.map +1 -0
  61. package/lib/typescript/src/components/Input/InputOne.d.ts.map +1 -1
  62. package/lib/typescript/src/components/Text/Text.d.ts +1 -4
  63. package/lib/typescript/src/components/Text/Text.d.ts.map +1 -1
  64. package/lib/typescript/src/components/View/View.d.ts +2 -2
  65. package/lib/typescript/src/components/View/View.d.ts.map +1 -1
  66. package/lib/typescript/src/components/index.d.ts +3 -1
  67. package/lib/typescript/src/components/index.d.ts.map +1 -1
  68. package/lib/typescript/src/store/themeStore.d.ts +19 -1
  69. package/lib/typescript/src/store/themeStore.d.ts.map +1 -1
  70. package/lib/typescript/src/theme/ThemeProvider.d.ts.map +1 -1
  71. package/lib/typescript/src/theme/hook/useInternalTheme.d.ts +4 -0
  72. package/lib/typescript/src/theme/hook/useInternalTheme.d.ts.map +1 -1
  73. package/lib/typescript/src/theme/themes.d.ts +6 -0
  74. package/lib/typescript/src/theme/themes.d.ts.map +1 -1
  75. package/lib/typescript/src/types/content/content-view.types.d.ts +7 -0
  76. package/lib/typescript/src/types/content/content-view.types.d.ts.map +1 -1
  77. package/lib/typescript/src/types/content/index.d.ts +1 -1
  78. package/lib/typescript/src/types/content/index.d.ts.map +1 -1
  79. package/package.json +1 -1
  80. package/src/components/Auth/SplashScreen/components/SplashVideo/SplashVideo.tsx +64 -79
  81. package/src/components/Content/Card/components/CardPoster.tsx +5 -0
  82. package/src/components/Content/Content.tsx +23 -3
  83. package/src/components/ContentView/ContentView.tsx +110 -86
  84. package/src/components/ContentView/components/AboutSection.tsx +23 -3
  85. package/src/components/ContentView/components/CastCard.tsx +1 -1
  86. package/src/components/ContentView/components/HeroBanner.tsx +45 -17
  87. package/src/components/ContentView/components/MiniInfo.tsx +193 -0
  88. package/src/components/ContentView/components/Title.tsx +17 -26
  89. package/src/components/Fallbacks/NoContentFallback.tsx +172 -0
  90. package/src/components/Fallbacks/NotFoundFallback.tsx +86 -0
  91. package/src/components/Fallbacks/index.ts +2 -0
  92. package/src/components/Input/InputOne.tsx +26 -3
  93. package/src/components/Subscription/SubOne.tsx +9 -5
  94. package/src/components/Text/Text.tsx +21 -11
  95. package/src/components/User/ProfileUpdate/ProfileUpdate.tsx +2 -2
  96. package/src/components/View/View.tsx +2 -1
  97. package/src/components/index.ts +3 -1
  98. package/src/store/themeStore.ts +33 -43
  99. package/src/theme/ThemeProvider.tsx +0 -1
  100. package/src/theme/hook/useInternalTheme.ts +46 -24
  101. package/src/theme/themes.ts +20 -0
  102. package/src/types/content/content-view.types.ts +7 -0
  103. package/src/types/content/index.ts +1 -5
  104. package/lib/module/components/Content/Card/components/NoContentFallback.js.map +0 -1
  105. package/lib/typescript/src/components/Content/Card/components/NoContentFallback.d.ts +0 -17
  106. package/lib/typescript/src/components/Content/Card/components/NoContentFallback.d.ts.map +0 -1
  107. package/src/components/Content/Card/components/NoContentFallback.tsx +0 -147
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useMemo, useCallback } from 'react';
7
- import { View, StyleSheet, Animated, Text } from 'react-native';
7
+ import { View, StyleSheet, Animated } from 'react-native';
8
8
  import LinearGradient from 'react-native-linear-gradient';
9
9
  import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
10
10
  import { scale, verticalScale } from 'react-native-size-matters';
@@ -18,6 +18,7 @@ import type { HeroBannerProps } from '../../../types/content/content-view.types'
18
18
  import { RFValue } from 'react-native-responsive-fontsize';
19
19
  import RentOrBuyIcon from '../../Content/Card/components/RentOrBuyIcon';
20
20
  import { useInternalTheme } from '../../../theme/hook';
21
+ import { Text } from '../../Text';
21
22
 
22
23
  const SKELETON_CIRCLE_SIZE = scale(50);
23
24
  const BANNER_HEIGHT = verticalScale(200);
@@ -130,6 +131,14 @@ export const HeroBanner = ({
130
131
  zIndex: 4,
131
132
  backgroundColor: theme.colors.background,
132
133
  },
134
+ badge: {
135
+ position: 'absolute',
136
+ bottom: verticalScale(20),
137
+ left: scale(10),
138
+ paddingHorizontal: scale(8),
139
+ paddingVertical: scale(4),
140
+ borderRadius: scale(8),
141
+ },
133
142
  }),
134
143
  [theme]
135
144
  );
@@ -192,34 +201,53 @@ export const HeroBanner = ({
192
201
  {/* Gradient Overlay */}
193
202
  <LinearGradient
194
203
  colors={theme.colors.heroBannerGradient}
195
- style={[StyleSheet.absoluteFill, { zIndex: 3 }]}
204
+ style={[StyleSheet.absoluteFill, { zIndex: 1 }]}
196
205
  locations={GRADIENT_LOCATIONS}
197
206
  />
198
207
 
199
208
  {/* Background Image */}
200
209
  {!isLoading && (
201
- <View style={styles.imageContainer}>
210
+ <>
211
+ <View style={styles.imageContainer}>
212
+ <FastImage
213
+ style={StyleSheet.absoluteFillObject}
214
+ source={{
215
+ uri: backgroundImage,
216
+ cache: FastImage.cacheControl.immutable,
217
+ }}
218
+ resizeMode={FastImage.resizeMode.cover}
219
+ onLoad={() => setHasImageLoaded(true)}
220
+ onError={() => setImageLoadError(true)}
221
+ accessibilityLabel={`Background image for ${title}`}
222
+ />
223
+ </View>
224
+ {/* Badge above gradient */}
225
+ {content_offering_type && content_offering_type === 'FREE' && (
226
+ <View
227
+ style={[
228
+ styles.badge,
229
+ { backgroundColor: theme.colors.primary, zIndex: 2 },
230
+ ]}
231
+ >
232
+ <Text
233
+ type="caption"
234
+ style={{ color: theme.colors.onPrimary, fontWeight: '600' }}
235
+ theme={themeOverride}
236
+ >
237
+ {content_offering_type}
238
+ </Text>
239
+ </View>
240
+ )}
241
+
202
242
  {content_offering_type && (
203
243
  <RentOrBuyIcon
204
244
  size={30}
205
245
  theme={theme}
206
- style={styles.rentOrBuyIcon}
246
+ style={[styles.rentOrBuyIcon, { zIndex: 2 }]}
207
247
  content_offering_type={content_offering_type}
208
248
  />
209
249
  )}
210
-
211
- <FastImage
212
- style={StyleSheet.absoluteFillObject}
213
- source={{
214
- uri: backgroundImage,
215
- cache: FastImage.cacheControl.immutable,
216
- }}
217
- resizeMode={FastImage.resizeMode.cover}
218
- onLoad={() => setHasImageLoaded(true)}
219
- onError={() => setImageLoadError(true)}
220
- accessibilityLabel={`Background image for ${title}`}
221
- />
222
- </View>
250
+ </>
223
251
  )}
224
252
 
225
253
  {/* Skeleton UI */}
@@ -0,0 +1,193 @@
1
+ import React from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ type StyleProp,
6
+ type ViewStyle,
7
+ type TextStyle,
8
+ } from 'react-native';
9
+ import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
10
+ import { scale } from 'react-native-size-matters';
11
+ import { Text } from '../../Text';
12
+ import type { IContentData } from '../../../types';
13
+ import type { ThemeOverride } from '../../../theme/themes';
14
+ import { RFValue } from 'react-native-responsive-fontsize';
15
+ import { useInternalTheme } from '../../../theme/hook';
16
+
17
+ type Props = {
18
+ content?: IContentData;
19
+ theme?: ThemeOverride;
20
+ isLoading?: boolean;
21
+ style?: {
22
+ container?: StyleProp<ViewStyle>;
23
+ row?: StyleProp<ViewStyle>;
24
+ title?: StyleProp<TextStyle>;
25
+ subTitle?: StyleProp<TextStyle>;
26
+ badge?: StyleProp<ViewStyle>;
27
+ price?: StyleProp<TextStyle>;
28
+ rating?: StyleProp<TextStyle>;
29
+ };
30
+ };
31
+
32
+ export function formatCurrency(
33
+ amount: number,
34
+ currency: string = 'INR'
35
+ ): string {
36
+ return new Intl.NumberFormat('en-IN', {
37
+ style: 'currency',
38
+ currency,
39
+ minimumFractionDigits: 0,
40
+ maximumFractionDigits: 2,
41
+ }).format(amount);
42
+ }
43
+
44
+ export const MiniInfo = ({
45
+ content,
46
+ theme,
47
+ isLoading = false,
48
+ style,
49
+ }: Props): React.ReactElement | null => {
50
+ const { theme: appliedTheme } = useInternalTheme(theme);
51
+
52
+ if (isLoading) {
53
+ // Skeleton Placeholder
54
+ return (
55
+ <View
56
+ style={[
57
+ styles.container,
58
+ style?.container,
59
+ {
60
+ backgroundColor: appliedTheme.colors.background,
61
+ borderColor: appliedTheme.colors.border,
62
+ },
63
+ ]}
64
+ >
65
+ <SkeletonPlaceholder
66
+ backgroundColor={appliedTheme.colors.skeletonBaseColor}
67
+ highlightColor={appliedTheme.colors.skeletonHighlightColor}
68
+ >
69
+ <SkeletonPlaceholder.Item
70
+ flexDirection="row"
71
+ alignItems="center"
72
+ marginBottom={scale(6)}
73
+ >
74
+ <SkeletonPlaceholder.Item
75
+ width={scale(100)}
76
+ height={scale(20)}
77
+ borderRadius={scale(4)}
78
+ />
79
+ <SkeletonPlaceholder.Item
80
+ width={scale(60)}
81
+ height={scale(20)}
82
+ borderRadius={scale(4)}
83
+ marginLeft={scale(8)}
84
+ />
85
+ </SkeletonPlaceholder.Item>
86
+ <SkeletonPlaceholder.Item
87
+ width={scale(120)}
88
+ height={scale(16)}
89
+ borderRadius={scale(4)}
90
+ marginBottom={scale(4)}
91
+ />
92
+ <SkeletonPlaceholder.Item
93
+ width={scale(80)}
94
+ height={scale(14)}
95
+ borderRadius={scale(4)}
96
+ />
97
+ </SkeletonPlaceholder>
98
+ </View>
99
+ );
100
+ }
101
+
102
+ if (!content) return null;
103
+
104
+ const { content_offering_type, price, is_buy_or_rent, rent_duration } =
105
+ content;
106
+
107
+ if (content_offering_type !== 'BUY_OR_RENT') return null;
108
+
109
+ const renderBadge = () => (
110
+ <View
111
+ style={[
112
+ styles.badge,
113
+ {
114
+ backgroundColor: appliedTheme.colors.primary,
115
+ shadowColor: appliedTheme.colors.textPrimary,
116
+ },
117
+ style?.badge,
118
+ ]}
119
+ >
120
+ <Text
121
+ type="caption"
122
+ style={{ color: appliedTheme.colors.onPrimary, fontWeight: '600' }}
123
+ theme={theme}
124
+ >
125
+ {content_offering_type === 'BUY_OR_RENT' ? 'BUY OR RENT' : 'BUY'}
126
+ </Text>
127
+ </View>
128
+ );
129
+
130
+ const renderPriceInfo = () => {
131
+ if (!price) return null;
132
+ const text =
133
+ is_buy_or_rent === 'BUY'
134
+ ? `Price: ${formatCurrency(price)}`
135
+ : `Rent: ${formatCurrency(price)} for ${rent_duration ?? 1} day(s)`;
136
+
137
+ return (
138
+ <Text
139
+ type="subtitle"
140
+ style={[
141
+ styles.subTitle,
142
+ { color: appliedTheme.colors.textPrimary },
143
+ style?.price,
144
+ ]}
145
+ theme={theme}
146
+ >
147
+ {text}
148
+ </Text>
149
+ );
150
+ };
151
+
152
+ return (
153
+ <View
154
+ style={[
155
+ styles.container,
156
+ style?.container,
157
+ {
158
+ backgroundColor: appliedTheme.colors.background,
159
+ borderColor: appliedTheme.colors.border,
160
+ },
161
+ ]}
162
+ >
163
+ <View style={styles.headerRow}>{renderBadge()}</View>
164
+ {renderPriceInfo()}
165
+ </View>
166
+ );
167
+ };
168
+
169
+ const styles = StyleSheet.create({
170
+ container: {
171
+ borderWidth: 1,
172
+ borderRadius: scale(14),
173
+ padding: scale(10),
174
+ marginHorizontal: scale(6),
175
+ marginVertical: scale(6),
176
+ },
177
+ headerRow: {
178
+ flexDirection: 'row',
179
+ justifyContent: 'space-between',
180
+ alignItems: 'center',
181
+ marginBottom: scale(6),
182
+ },
183
+ badge: {
184
+ paddingHorizontal: scale(10),
185
+ paddingVertical: scale(5),
186
+ borderRadius: scale(10),
187
+ },
188
+ subTitle: {
189
+ fontSize: RFValue(12),
190
+ marginTop: scale(3),
191
+ fontWeight: '500',
192
+ },
193
+ });
@@ -78,26 +78,26 @@ export const Title = ({
78
78
 
79
79
  return (
80
80
  <View style={StyleSheet.flatten([styles.container, style?.container])}>
81
- <View style={styles.row}>
81
+ <View>
82
82
  <Text
83
83
  color={theme.colors.textPrimary}
84
84
  style={StyleSheet.flatten([styles.title, style?.title])}
85
- numberOfLines={1}
85
+ // numberOfLines={1}
86
86
  ellipsizeMode="tail"
87
87
  >
88
88
  {title}
89
+ {!!subtitle && (
90
+ <Text
91
+ color={theme.colors.textSecondary}
92
+ style={StyleSheet.flatten([styles.subTitle, style?.subTitle])}
93
+ // numberOfLines={1}
94
+ ellipsizeMode="tail"
95
+ >
96
+ {' '}
97
+ {`: ${subtitle}`}
98
+ </Text>
99
+ )}
89
100
  </Text>
90
-
91
- {!!subtitle && (
92
- <Text
93
- color={theme.colors.textSecondary}
94
- style={StyleSheet.flatten([styles.subTitle, style?.subTitle])}
95
- numberOfLines={1}
96
- ellipsizeMode="tail"
97
- >
98
- {`: ${subtitle}`}
99
- </Text>
100
- )}
101
101
  </View>
102
102
 
103
103
  {!!rating && (
@@ -117,25 +117,16 @@ const styles = StyleSheet.create({
117
117
  paddingHorizontal: scale(12),
118
118
  marginTop: scale(5),
119
119
  },
120
- row: {
121
- flexDirection: 'row',
122
- alignItems: 'center',
123
- maxWidth: '100%',
124
- },
125
120
  title: {
126
- fontSize: RFValue(17),
121
+ fontSize: RFValue(15),
127
122
  fontWeight: 'bold',
128
- flexShrink: 1,
129
- maxWidth: '60%',
130
123
  },
131
124
  subTitle: {
132
- fontSize: RFValue(17),
133
- marginLeft: scale(4),
134
- flexShrink: 1,
135
- maxWidth: '40%',
125
+ fontSize: RFValue(15),
126
+ marginLeft: scale(6),
136
127
  },
137
128
  rating: {
138
- fontSize: RFValue(13),
129
+ fontSize: RFValue(12),
139
130
  marginTop: scale(4),
140
131
  },
141
132
  });
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @author Naresh Dhamu
3
+ * @lastModified Sat 25 Oct 2025 at 11:15 AM
4
+ */
5
+
6
+ import { useCallback } from 'react';
7
+ import {
8
+ TouchableOpacity,
9
+ StyleSheet,
10
+ ActivityIndicator,
11
+ type StyleProp,
12
+ type ViewStyle,
13
+ } from 'react-native';
14
+ import Animated, {
15
+ useSharedValue,
16
+ useAnimatedStyle,
17
+ withSpring,
18
+ } from 'react-native-reanimated';
19
+ import { scale, verticalScale } from 'react-native-size-matters';
20
+ import { Text } from '../Text';
21
+ import { useInternalTheme } from '../../theme/hook/useInternalTheme';
22
+ import type { ThemeOverride } from '../../theme/themes';
23
+ import { RFValue } from 'react-native-responsive-fontsize';
24
+ import { AlertCircle } from 'lucide-react-native';
25
+
26
+ export type NoContentFallbackProps = {
27
+ message?: string;
28
+ retryText?: string;
29
+ onRetry?: () => void;
30
+ isLoading?: boolean;
31
+ theme?: ThemeOverride;
32
+ style?: StyleProp<ViewStyle>;
33
+ };
34
+
35
+ export const NoContentFallback = ({
36
+ message = 'No content available right now.\nPlease check back later.',
37
+ retryText = 'Try Again',
38
+ onRetry,
39
+ isLoading = false,
40
+ theme,
41
+ style,
42
+ }: NoContentFallbackProps) => {
43
+ const { theme: appliedTheme } = useInternalTheme(theme);
44
+ const scaleValue = useSharedValue(1);
45
+
46
+ const handlePressIn = useCallback(() => {
47
+ if (isLoading) return; // disable press animation during loading
48
+ scaleValue.value = withSpring(0.95, { damping: 15, stiffness: 200 });
49
+ }, [scaleValue, isLoading]);
50
+
51
+ const handlePressOut = useCallback(() => {
52
+ if (isLoading) return;
53
+ scaleValue.value = withSpring(1, { damping: 15, stiffness: 200 });
54
+ }, [scaleValue, isLoading]);
55
+
56
+ const animatedButtonStyle = useAnimatedStyle(() => ({
57
+ transform: [{ scale: scaleValue.value }],
58
+ }));
59
+
60
+ return (
61
+ <Animated.View
62
+ style={[styles.container, style]}
63
+ accessibilityLabel="No content available"
64
+ accessibilityHint="Check back later or try again"
65
+ >
66
+ <AlertCircle
67
+ size={RFValue(63)}
68
+ color={
69
+ appliedTheme?.colors?.textPrimary ??
70
+ appliedTheme?.colors?.textSecondary ??
71
+ '#999'
72
+ }
73
+ style={{ marginBottom: scale(20) }}
74
+ />
75
+
76
+ <Text
77
+ style={[styles.message, { color: appliedTheme.colors.textSecondary }]}
78
+ >
79
+ {message}
80
+ </Text>
81
+
82
+ {onRetry && (
83
+ <TouchableOpacity
84
+ onPress={!isLoading ? onRetry : undefined}
85
+ onPressIn={handlePressIn}
86
+ onPressOut={handlePressOut}
87
+ activeOpacity={0.7}
88
+ disabled={isLoading}
89
+ style={[
90
+ styles.retryButton,
91
+ {
92
+ backgroundColor: isLoading
93
+ ? appliedTheme.colors.surfaceDisabled
94
+ : appliedTheme.colors.primary,
95
+ borderColor: appliedTheme.colors.outline,
96
+ opacity: isLoading ? 0.8 : 1,
97
+ },
98
+ ]}
99
+ accessibilityLabel={retryText}
100
+ accessibilityRole="button"
101
+ >
102
+ <Animated.View
103
+ style={[
104
+ animatedButtonStyle,
105
+ {
106
+ flexDirection: 'row',
107
+ alignItems: 'center',
108
+ justifyContent: 'center',
109
+ },
110
+ ]}
111
+ >
112
+ {isLoading ? (
113
+ <>
114
+ <ActivityIndicator
115
+ size="small"
116
+ color={appliedTheme.colors.onPrimary}
117
+ style={{ marginRight: scale(8) }}
118
+ />
119
+ <Text
120
+ style={[
121
+ styles.retryText,
122
+ { color: appliedTheme.colors.onPrimary },
123
+ ]}
124
+ >
125
+ Loading...
126
+ </Text>
127
+ </>
128
+ ) : (
129
+ <Text
130
+ style={[
131
+ styles.retryText,
132
+ { color: appliedTheme.colors.onPrimary },
133
+ ]}
134
+ >
135
+ {retryText}
136
+ </Text>
137
+ )}
138
+ </Animated.View>
139
+ </TouchableOpacity>
140
+ )}
141
+ </Animated.View>
142
+ );
143
+ };
144
+
145
+ const styles = StyleSheet.create({
146
+ container: {
147
+ flex: 1,
148
+ alignItems: 'center',
149
+ justifyContent: 'center',
150
+ paddingHorizontal: scale(20),
151
+ paddingVertical: verticalScale(40),
152
+ },
153
+ message: {
154
+ fontSize: RFValue(15),
155
+ textAlign: 'center',
156
+ fontWeight: '500',
157
+ lineHeight: verticalScale(22),
158
+ marginBottom: verticalScale(20),
159
+ },
160
+ retryButton: {
161
+ paddingHorizontal: scale(18),
162
+ paddingVertical: verticalScale(10),
163
+ borderRadius: scale(8),
164
+ borderWidth: scale(1),
165
+ alignItems: 'center',
166
+ },
167
+ retryText: {
168
+ fontSize: RFValue(13),
169
+ fontWeight: '600',
170
+ textAlign: 'center',
171
+ },
172
+ });
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @author Naresh Dhamu
3
+ * @lastModified Tue 01 Jul 2025 at 02:28 PM
4
+ */
5
+
6
+ import React from 'react';
7
+ import { StyleSheet } from 'react-native';
8
+ import { scale } from 'react-native-size-matters';
9
+ import { Button } from '../Button';
10
+ import type { ThemeOverride } from '../../theme';
11
+ import { View } from '../View';
12
+ import { Text } from '../Text';
13
+ import { AlertCircle } from 'lucide-react-native';
14
+ import { useInternalTheme } from '../../theme/hook';
15
+
16
+ interface NotFoundFallbackProps {
17
+ title?: string;
18
+ subtitle?: string;
19
+ content?: React.ReactNode;
20
+ onPressBack?: () => void;
21
+ backButtonText?: string;
22
+ theme?: ThemeOverride;
23
+ iconSize?: number;
24
+ iconColor?: string;
25
+ }
26
+
27
+ export const NotFoundFallback: React.FC<NotFoundFallbackProps> = ({
28
+ title = 'Content Not Found',
29
+ subtitle = 'We couldn’t find anything to show here. Please check back later.',
30
+ content,
31
+ onPressBack,
32
+ backButtonText = 'Go Back',
33
+ theme,
34
+ iconSize = scale(60),
35
+ iconColor,
36
+ }) => {
37
+ const { theme: appliedTheme } = useInternalTheme(theme);
38
+ if (content) return <>{content}</>;
39
+
40
+ return (
41
+ <View style={styles.container}>
42
+ <AlertCircle
43
+ size={iconSize}
44
+ color={iconColor ?? appliedTheme?.colors?.textSecondary ?? '#999'}
45
+ style={{ marginBottom: scale(20) }}
46
+ />
47
+
48
+ <Text style={styles.title} type="title" theme={theme}>
49
+ {title}
50
+ </Text>
51
+ <Text style={styles.subtitle} type="subtitle" theme={theme}>
52
+ {subtitle}
53
+ </Text>
54
+
55
+ {onPressBack && (
56
+ <Button.Primary
57
+ theme={theme}
58
+ title={backButtonText}
59
+ onPress={onPressBack}
60
+ />
61
+ )}
62
+ </View>
63
+ );
64
+ };
65
+
66
+ const styles = StyleSheet.create({
67
+ container: {
68
+ flex: 1,
69
+ justifyContent: 'center',
70
+ alignItems: 'center',
71
+ paddingHorizontal: scale(30),
72
+ paddingBottom: scale(30),
73
+ backgroundColor: 'transparent',
74
+ },
75
+ title: {
76
+ fontSize: scale(18),
77
+ fontWeight: '700',
78
+ marginBottom: scale(8),
79
+ textAlign: 'center',
80
+ },
81
+ subtitle: {
82
+ fontSize: scale(14),
83
+ textAlign: 'center',
84
+ marginBottom: scale(20),
85
+ },
86
+ });
@@ -0,0 +1,2 @@
1
+ export * from './NotFoundFallback';
2
+ export * from './NoContentFallback';
@@ -45,6 +45,7 @@ const InputOne: React.FC<InputOneProps> = ({
45
45
  }) => {
46
46
  const { theme: appliedTheme } = useInternalTheme(theme);
47
47
  const [showPassword, setShowPassword] = useState(false);
48
+ const [isFocused, setIsFocused] = useState(false); // 👈 focus state जोड़ी गई
48
49
  const isPasswordField = !!secureTextEntry;
49
50
  const inputSecure = isPasswordField && !showPassword;
50
51
 
@@ -56,6 +57,7 @@ const InputOne: React.FC<InputOneProps> = ({
56
57
  outlineDisabled,
57
58
  error: inputErrorColor,
58
59
  background,
60
+ primary, // अगर theme में primary color हो तो उसे भी use करेंगे
59
61
  } = appliedTheme?.colors || {};
60
62
 
61
63
  return (
@@ -87,13 +89,14 @@ const InputOne: React.FC<InputOneProps> = ({
87
89
  <View
88
90
  style={[
89
91
  styles.inputWrapper,
90
-
91
92
  {
92
93
  borderColor: disabled
93
94
  ? outlineDisabled
94
95
  : error
95
96
  ? inputErrorColor
96
- : outline,
97
+ : isFocused
98
+ ? primary || '#007AFF'
99
+ : outline,
97
100
  backgroundColor: disabled
98
101
  ? appliedTheme.colors.backgroundDisabled
99
102
  : error
@@ -107,6 +110,8 @@ const InputOne: React.FC<InputOneProps> = ({
107
110
  <TextInput
108
111
  {...props}
109
112
  editable={!disabled}
113
+ onFocus={() => setIsFocused(true)}
114
+ onBlur={() => setIsFocused(false)}
110
115
  placeholderTextColor={
111
116
  placeholderTextColor || (disabled ? textDisabled : textSecondary)
112
117
  }
@@ -114,6 +119,24 @@ const InputOne: React.FC<InputOneProps> = ({
114
119
  textContentType={
115
120
  isPasswordField ? 'oneTimeCode' : props.textContentType || 'none'
116
121
  }
122
+ cursorColor={
123
+ disabled
124
+ ? textDisabled
125
+ : error
126
+ ? inputErrorColor
127
+ : isFocused
128
+ ? primary || '#007AFF'
129
+ : textPrimary
130
+ }
131
+ selectionColor={
132
+ disabled
133
+ ? textDisabled
134
+ : error
135
+ ? inputErrorColor
136
+ : isFocused
137
+ ? primary || '#007AFF'
138
+ : textPrimary
139
+ }
117
140
  style={[
118
141
  styles.input,
119
142
  {
@@ -189,7 +212,7 @@ const styles = StyleSheet.create({
189
212
  },
190
213
  inputWrapper: {
191
214
  width: '100%',
192
- borderWidth: scale(1),
215
+ borderWidth: scale(1.4),
193
216
  borderRadius: moderateScale(10),
194
217
  paddingHorizontal: scale(10),
195
218
  paddingVertical: verticalScale(6),