@umituz/react-native-settings 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ npm install @umituz/react-native-settings
20
20
  ## Peer Dependencies
21
21
 
22
22
  ```bash
23
- npm install zustand @umituz/react-native-storage @umituz/react-native-design-system @umituz/react-native-design-system-theme @umituz/react-native-localization @umituz/react-native-notifications react-native-paper expo-linear-gradient
23
+ npm install zustand lucide-react-native @umituz/react-native-storage @umituz/react-native-design-system @umituz/react-native-design-system-theme @umituz/react-native-localization @umituz/react-native-notifications react-native-paper expo-linear-gradient
24
24
  ```
25
25
 
26
26
  ## Usage
@@ -55,8 +55,25 @@ const MyComponent = () => {
55
55
  ```tsx
56
56
  import { SettingsScreen } from '@umituz/react-native-settings';
57
57
 
58
- // In your navigation stack
58
+ // Basic usage
59
59
  <Stack.Screen name="Settings" component={SettingsScreen} />
60
+
61
+ // With user profile header
62
+ <SettingsScreen
63
+ showUserProfile={true}
64
+ userProfile={{
65
+ displayName: "John Doe",
66
+ userId: "user123",
67
+ isGuest: false,
68
+ accountSettingsRoute: "AccountSettings",
69
+ }}
70
+ config={{
71
+ appearance: true,
72
+ notifications: true,
73
+ about: true,
74
+ legal: true,
75
+ }}
76
+ />
60
77
  ```
61
78
 
62
79
  ### Appearance Screen
@@ -81,17 +98,82 @@ import { LanguageSelectionScreen } from '@umituz/react-native-settings';
81
98
 
82
99
  ```tsx
83
100
  import { SettingItem } from '@umituz/react-native-settings';
101
+ import { Palette, Bell } from 'lucide-react-native';
84
102
 
103
+ // Basic setting item
85
104
  <SettingItem
86
- icon="Palette"
87
- title="Theme"
88
- description="Change app theme"
89
- value="Dark"
105
+ icon={Palette}
106
+ title="Appearance"
107
+ value="Theme and language settings"
90
108
  onPress={() => navigation.navigate('Appearance')}
91
- iconGradient={['#FF6B6B', '#4ECDC4']}
109
+ />
110
+
111
+ // With switch
112
+ <SettingItem
113
+ icon={Bell}
114
+ title="Notifications"
115
+ showSwitch={true}
116
+ switchValue={enabled}
117
+ onSwitchChange={setEnabled}
118
+ />
119
+
120
+ // Custom colors
121
+ <SettingItem
122
+ icon={Palette}
123
+ title="Appearance"
124
+ iconColor="#F59E0B"
125
+ titleColor="#F59E0B"
126
+ onPress={() => {}}
92
127
  />
93
128
  ```
94
129
 
130
+ ### Settings Section Component
131
+
132
+ ```tsx
133
+ import { SettingsSection, SettingItem } from '@umituz/react-native-settings';
134
+ import { Palette, Bell } from 'lucide-react-native';
135
+
136
+ <SettingsSection title="APP SETTINGS">
137
+ <SettingItem
138
+ icon={Palette}
139
+ title="Appearance"
140
+ value="Theme and language settings"
141
+ onPress={() => navigation.navigate('Appearance')}
142
+ />
143
+ <SettingItem
144
+ icon={Bell}
145
+ title="Notifications"
146
+ showSwitch={true}
147
+ switchValue={enabled}
148
+ onSwitchChange={setEnabled}
149
+ isLast={true}
150
+ />
151
+ </SettingsSection>
152
+ ```
153
+
154
+ ### User Profile Header Component
155
+
156
+ ```tsx
157
+ import { UserProfileHeader } from '@umituz/react-native-settings';
158
+
159
+ <UserProfileHeader
160
+ displayName="John Doe"
161
+ userId="user123"
162
+ isGuest={false}
163
+ avatarUrl="https://example.com/avatar.jpg"
164
+ accountSettingsRoute="AccountSettings"
165
+ onPress={() => navigation.navigate('AccountSettings')}
166
+ />
167
+ ```
168
+
169
+ ### Settings Footer Component
170
+
171
+ ```tsx
172
+ import { SettingsFooter } from '@umituz/react-native-settings';
173
+
174
+ <SettingsFooter versionText="Version 1.0.0" />
175
+ ```
176
+
95
177
  ### Disclaimer Setting Component
96
178
 
97
179
  ```tsx
@@ -122,7 +204,14 @@ Direct access to Zustand store.
122
204
 
123
205
  ### `SettingsScreen`
124
206
 
125
- Main settings screen component with sections for Appearance, General, About & Legal.
207
+ Modern settings screen with organized sections and optional user profile header.
208
+
209
+ **Props:**
210
+ - `config?: SettingsConfig` - Configuration for which features to show
211
+ - `showUserProfile?: boolean` - Show user profile header
212
+ - `userProfile?: UserProfileHeaderProps` - User profile props
213
+ - `showFooter?: boolean` - Show footer with version
214
+ - `footerText?: string` - Custom footer text
126
215
 
127
216
  ### `AppearanceScreen`
128
217
 
@@ -134,19 +223,46 @@ Language selection screen with search functionality.
134
223
 
135
224
  ### `SettingItem`
136
225
 
137
- Reusable setting item component with gradient icons and Material Design styling.
226
+ Modern setting item component with Lucide icons and switch support.
138
227
 
139
228
  **Props:**
140
- - `icon: IconName` - Icon name from Lucide library
229
+ - `icon: React.ComponentType` - Icon component from lucide-react-native
141
230
  - `title: string` - Main title text
142
- - `description?: string` - Optional description
143
- - `value?: string` - Optional value to display on right
231
+ - `value?: string` - Optional description/value text (shown below title)
144
232
  - `onPress?: () => void` - Callback when pressed
145
- - `showChevron?: boolean` - Show chevron arrow (default: true if onPress exists)
146
- - `rightElement?: React.ReactNode` - Custom right element
147
- - `iconGradient?: string[]` - Gradient colors for icon background
148
- - `disabled?: boolean` - Disable item
149
- - `testID?: string` - Test ID
233
+ - `showSwitch?: boolean` - Show switch instead of chevron
234
+ - `switchValue?: boolean` - Switch value
235
+ - `onSwitchChange?: (value: boolean) => void` - Switch change handler
236
+ - `isLast?: boolean` - Is last item (no divider)
237
+ - `iconColor?: string` - Custom icon color
238
+ - `titleColor?: string` - Custom title color
239
+
240
+ ### `SettingsSection`
241
+
242
+ Section container with title and styled content area.
243
+
244
+ **Props:**
245
+ - `title: string` - Section title (uppercase)
246
+ - `children: React.ReactNode` - Section content
247
+
248
+ ### `UserProfileHeader`
249
+
250
+ User profile header with avatar, name, and ID.
251
+
252
+ **Props:**
253
+ - `displayName?: string` - User display name
254
+ - `userId?: string` - User ID
255
+ - `isGuest?: boolean` - Whether user is guest
256
+ - `avatarUrl?: string` - Custom avatar URL
257
+ - `accountSettingsRoute?: string` - Navigation route for account settings
258
+ - `onPress?: () => void` - Custom onPress handler
259
+
260
+ ### `SettingsFooter`
261
+
262
+ Footer component displaying app version.
263
+
264
+ **Props:**
265
+ - `versionText?: string` - Custom version text (optional)
150
266
 
151
267
  ### `DisclaimerSetting`
152
268
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "Settings management for React Native apps - user preferences, theme, language, notifications",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -29,6 +29,7 @@
29
29
  "react": ">=18.2.0",
30
30
  "react-native": ">=0.74.0",
31
31
  "zustand": "^5.0.2",
32
+ "lucide-react-native": "^0.468.0",
32
33
  "@umituz/react-native-storage": "latest",
33
34
  "@umituz/react-native-design-system": "latest",
34
35
  "@umituz/react-native-design-system-theme": "latest",
package/src/index.ts CHANGED
@@ -48,5 +48,16 @@ export type { SettingsConfig } from './presentation/screens/types';
48
48
  // =============================================================================
49
49
 
50
50
  export { SettingItem } from './presentation/components/SettingItem';
51
+ export type { SettingItemProps } from './presentation/components/SettingItem';
52
+
53
+ export { SettingsSection } from './presentation/components/SettingsSection';
54
+ export type { SettingsSectionProps } from './presentation/components/SettingsSection';
55
+
56
+ export { SettingsFooter } from './presentation/components/SettingsFooter';
57
+ export type { SettingsFooterProps } from './presentation/components/SettingsFooter';
58
+
59
+ export { UserProfileHeader } from './presentation/components/UserProfileHeader';
60
+ export type { UserProfileHeaderProps } from './presentation/components/UserProfileHeader';
61
+
51
62
  export { DisclaimerSetting } from './presentation/components/DisclaimerSetting';
52
63
 
@@ -27,7 +27,7 @@ import {
27
27
  } from 'react-native';
28
28
 
29
29
  import { useAppDesignTokens, withAlpha } from '@umituz/react-native-design-system-theme';
30
- import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
30
+ import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system-atoms';
31
31
  import { useLocalization } from '@umituz/react-native-localization';
32
32
 
33
33
  type DesignTokens = ReturnType<typeof useAppDesignTokens>;
@@ -1,259 +1,167 @@
1
1
  /**
2
- * SettingItem Component - Paper List.Item Wrapper with Custom Styling
3
- *
4
- * Modern settings item built on React Native Paper:
5
- * - Wraps Paper List.Item for Material Design compliance
6
- * - Custom gradient icon backgrounds (LinearGradient)
7
- * - Lucide icons integration (AtomicIcon)
8
- * - Automatic theme-aware styling
9
- * - Built-in ripple effects
10
- * - Accessibility support
11
- * - Fixed title truncation with proper layout constraints
2
+ * Setting Item Component
3
+ * Single Responsibility: Render a single settings item
4
+ * Modern design with Lucide icons and switch support
12
5
  */
13
6
 
14
- import React from 'react';
15
- import { View, StyleSheet, TouchableOpacity } from 'react-native';
16
- import { LinearGradient } from 'expo-linear-gradient';
17
- import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
18
- import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
19
- import type { IconName } from '@umituz/react-native-design-system';
20
- import type { DesignTokens } from '@umituz/react-native-design-system';
7
+ import React from "react";
8
+ import { View, Text, TouchableOpacity, StyleSheet, Switch } from "react-native";
9
+ import { ChevronRight } from "lucide-react-native";
10
+ import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
21
11
 
22
- interface SettingItemProps {
23
- /** Icon name from Lucide library */
24
- icon: IconName;
12
+ export interface SettingItemProps {
13
+ /** Icon component from lucide-react-native */
14
+ icon: React.ComponentType<{ size?: number; color?: string }>;
25
15
  /** Main title text */
26
16
  title: string;
27
- /** Optional description text */
28
- description?: string;
29
- /** Optional value to display on the right */
17
+ /** Optional description/value text */
30
18
  value?: string;
31
19
  /** Callback when pressed */
32
20
  onPress?: () => void;
33
- /** Show chevron arrow on right (default: true if onPress exists) */
34
- showChevron?: boolean;
35
- /** Right element to display instead of chevron/value */
36
- rightElement?: React.ReactNode;
37
- /** Gradient colors for icon background */
38
- iconGradient?: string[];
39
- /** Make item look disabled */
40
- disabled?: boolean;
41
- /** Test ID for E2E testing */
42
- testID?: string;
21
+ /** Show switch instead of chevron */
22
+ showSwitch?: boolean;
23
+ /** Switch value */
24
+ switchValue?: boolean;
25
+ /** Switch change handler */
26
+ onSwitchChange?: (value: boolean) => void;
27
+ /** Is last item in section (no divider) */
28
+ isLast?: boolean;
29
+ /** Custom icon color */
30
+ iconColor?: string;
31
+ /** Custom title color */
32
+ titleColor?: string;
43
33
  }
44
34
 
45
35
  export const SettingItem: React.FC<SettingItemProps> = ({
46
- icon,
36
+ icon: Icon,
47
37
  title,
48
- description,
49
38
  value,
50
39
  onPress,
51
- showChevron,
52
- rightElement,
53
- iconGradient,
54
- disabled = false,
55
- testID,
40
+ showSwitch = false,
41
+ switchValue,
42
+ onSwitchChange,
43
+ isLast = false,
44
+ iconColor,
45
+ titleColor,
56
46
  }) => {
57
47
  const tokens = useAppDesignTokens();
58
- const styles = getStyles(tokens);
48
+ const colors = tokens.colors;
59
49
 
60
- // Gradient colors for icon background
61
- const gradientColors: readonly [string, string, ...string[]] = (iconGradient && iconGradient.length >= 2)
62
- ? (iconGradient as unknown as readonly [string, string, ...string[]])
63
- : [tokens.colors.surface, tokens.colors.surface] as const;
64
-
65
- if (onPress) {
66
- return (
50
+ return (
51
+ <>
67
52
  <TouchableOpacity
53
+ style={[
54
+ styles.container,
55
+ { backgroundColor: colors.backgroundPrimary },
56
+ ]}
68
57
  onPress={onPress}
69
- disabled={disabled}
58
+ disabled={showSwitch}
70
59
  activeOpacity={0.7}
71
- style={[styles.listItem, disabled && styles.disabled]}
72
- testID={testID}
73
60
  >
74
- {/* Left: Gradient Icon */}
75
- <View style={styles.leftContainer}>
76
- <LinearGradient
77
- colors={gradientColors}
78
- start={{ x: 0, y: 0 }}
79
- end={{ x: 1, y: 1 }}
80
- style={styles.iconContainer}
81
- >
82
- <AtomicIcon name={icon} size="md" customColor="#FFFFFF" />
83
- </LinearGradient>
84
- </View>
85
-
86
- {/* Center: Title and Description */}
87
- <View style={styles.contentContainer}>
88
- <AtomicText
89
- type="bodyLarge"
90
- color={disabled ? "textDisabled" : "onSurface"}
91
- style={styles.title}
92
- numberOfLines={2}
93
- ellipsizeMode="tail"
61
+ <View style={styles.content}>
62
+ <View
63
+ style={[
64
+ styles.iconContainer,
65
+ {
66
+ backgroundColor: iconColor
67
+ ? `${iconColor}15`
68
+ : `${colors.primary}15`,
69
+ },
70
+ ]}
94
71
  >
95
- {title}
96
- </AtomicText>
97
- {description && (
98
- <AtomicText
99
- type="bodySmall"
100
- color="textSecondary"
101
- style={styles.description}
102
- numberOfLines={2}
103
- ellipsizeMode="tail"
72
+ <Icon size={20} color={iconColor || colors.primary} />
73
+ </View>
74
+ <View style={styles.textContainer}>
75
+ <Text
76
+ style={[
77
+ styles.title,
78
+ { color: titleColor || colors.textPrimary },
79
+ ]}
80
+ numberOfLines={1}
104
81
  >
105
- {description}
106
- </AtomicText>
107
- )}
82
+ {title}
83
+ </Text>
84
+ {value && !showSwitch && (
85
+ <Text
86
+ style={[styles.value, { color: colors.textSecondary }]}
87
+ numberOfLines={1}
88
+ >
89
+ {value}
90
+ </Text>
91
+ )}
92
+ </View>
108
93
  </View>
109
94
 
110
- {/* Right: Value, Chevron, or Custom Element */}
111
- {rightElement ? (
112
- <View style={styles.rightContainer}>{rightElement}</View>
113
- ) : value ? (
114
- <View style={styles.rightContainer}>
115
- <AtomicText
116
- type="bodyMedium"
117
- color="textSecondary"
118
- style={styles.value}
119
- numberOfLines={2}
120
- textAlign="right"
121
- >
122
- {value}
123
- </AtomicText>
124
- </View>
125
- ) : (showChevron ?? true) ? (
126
- <View style={styles.rightContainer}>
127
- <AtomicIcon
128
- name="ChevronRight"
129
- size="sm"
130
- color="textSecondary"
131
- style={styles.chevron}
95
+ <View style={styles.rightContainer}>
96
+ {showSwitch ? (
97
+ <Switch
98
+ value={switchValue}
99
+ onValueChange={onSwitchChange}
100
+ trackColor={{
101
+ false: `${colors.textSecondary}30`,
102
+ true: colors.primary,
103
+ }}
104
+ thumbColor="#FFFFFF"
132
105
  />
133
- </View>
134
- ) : null}
106
+ ) : (
107
+ <ChevronRight size={18} color={colors.textSecondary} />
108
+ )}
109
+ </View>
135
110
  </TouchableOpacity>
136
- );
137
- }
138
111
 
139
- return (
140
- <View
141
- style={[styles.listItem, disabled && styles.disabled]}
142
- testID={testID}
143
- >
144
- {/* Left: Gradient Icon */}
145
- <View style={styles.leftContainer}>
146
- <LinearGradient
147
- colors={gradientColors}
148
- start={{ x: 0, y: 0 }}
149
- end={{ x: 1, y: 1 }}
150
- style={styles.iconContainer}
151
- >
152
- <AtomicIcon name={icon} size="md" customColor="#FFFFFF" />
153
- </LinearGradient>
154
- </View>
155
-
156
- {/* Center: Title and Description */}
157
- <View style={styles.contentContainer}>
158
- <AtomicText
159
- type="bodyLarge"
160
- color={disabled ? "textDisabled" : "onSurface"}
161
- style={styles.title}
162
- numberOfLines={2}
163
- ellipsizeMode="tail"
164
- >
165
- {title}
166
- </AtomicText>
167
- {description && (
168
- <AtomicText
169
- type="bodySmall"
170
- color="textSecondary"
171
- style={styles.description}
172
- numberOfLines={2}
173
- ellipsizeMode="tail"
174
- >
175
- {description}
176
- </AtomicText>
177
- )}
178
- </View>
179
-
180
- {/* Right: Value, Chevron, or Custom Element */}
181
- {rightElement ? (
182
- <View style={styles.rightContainer}>{rightElement}</View>
183
- ) : value ? (
184
- <View style={styles.rightContainer}>
185
- <AtomicText
186
- type="bodyMedium"
187
- color="textSecondary"
188
- style={styles.value}
189
- numberOfLines={2}
190
- textAlign="right"
191
- >
192
- {value}
193
- </AtomicText>
194
- </View>
195
- ) : null}
196
- </View>
112
+ {!isLast && (
113
+ <View
114
+ style={[
115
+ styles.divider,
116
+ { backgroundColor: `${colors.textSecondary}20` },
117
+ ]}
118
+ />
119
+ )}
120
+ </>
197
121
  );
198
122
  };
199
123
 
200
- const getStyles = (tokens: DesignTokens) =>
201
- StyleSheet.create({
202
- listItem: {
203
- flexDirection: 'row',
204
- alignItems: 'center',
205
- paddingVertical: tokens.spacing.md,
206
- paddingHorizontal: tokens.spacing.lg,
207
- minHeight: 72,
208
- },
209
- disabled: {
210
- opacity: 0.5,
211
- },
212
- leftContainer: {
213
- marginRight: tokens.spacing.md,
214
- justifyContent: 'center',
215
- },
216
- iconContainer: {
217
- width: 48,
218
- height: 48,
219
- borderRadius: 24,
220
- alignItems: 'center',
221
- justifyContent: 'center',
222
- overflow: 'hidden',
223
- borderWidth: 1,
224
- borderColor: `${tokens.colors.primary}15`,
225
- },
226
- contentContainer: {
227
- flex: 1,
228
- justifyContent: 'center',
229
- minWidth: 0,
230
- },
231
- title: {
232
- fontSize: tokens.typography.bodyLarge.fontSize,
233
- fontWeight: '600',
234
- flexShrink: 1,
235
- lineHeight: tokens.typography.bodyLarge.fontSize * 1.4,
236
- },
237
- description: {
238
- fontSize: tokens.typography.bodySmall.fontSize,
239
- marginTop: tokens.spacing.xs / 2,
240
- opacity: 0.7,
241
- flexShrink: 1,
242
- lineHeight: tokens.typography.bodySmall.fontSize * 1.4,
243
- },
244
- rightContainer: {
245
- justifyContent: 'center',
246
- alignItems: 'flex-end',
247
- marginLeft: tokens.spacing.md,
248
- maxWidth: '50%',
249
- flexShrink: 0,
250
- },
251
- value: {
252
- fontWeight: '500',
253
- lineHeight: tokens.typography.bodyMedium.fontSize * 1.4,
254
- },
255
- chevron: {
256
- opacity: 0.5,
257
- },
258
- });
259
-
124
+ const styles = StyleSheet.create({
125
+ container: {
126
+ flexDirection: "row",
127
+ alignItems: "center",
128
+ justifyContent: "space-between",
129
+ paddingHorizontal: 16,
130
+ paddingVertical: 14,
131
+ },
132
+ content: {
133
+ flexDirection: "row",
134
+ alignItems: "center",
135
+ flex: 1,
136
+ },
137
+ iconContainer: {
138
+ width: 40,
139
+ height: 40,
140
+ borderRadius: 8,
141
+ justifyContent: "center",
142
+ alignItems: "center",
143
+ marginRight: 12,
144
+ },
145
+ textContainer: {
146
+ flex: 1,
147
+ minWidth: 0,
148
+ },
149
+ title: {
150
+ fontSize: 16,
151
+ fontWeight: "500",
152
+ },
153
+ value: {
154
+ fontSize: 12,
155
+ fontWeight: "400",
156
+ marginTop: 2,
157
+ },
158
+ rightContainer: {
159
+ flexDirection: "row",
160
+ alignItems: "center",
161
+ gap: 8,
162
+ },
163
+ divider: {
164
+ height: 1,
165
+ marginLeft: 68,
166
+ },
167
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Settings Footer Component
3
+ * Single Responsibility: Display app version information
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet } from "react-native";
8
+ import { useLocalization } from "@umituz/react-native-localization";
9
+ import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
10
+
11
+ export interface SettingsFooterProps {
12
+ /** Custom version text (optional) */
13
+ versionText?: string;
14
+ }
15
+
16
+ export const SettingsFooter: React.FC<SettingsFooterProps> = ({
17
+ versionText,
18
+ }) => {
19
+ const { t } = useLocalization();
20
+ const tokens = useAppDesignTokens();
21
+ const colors = tokens.colors;
22
+
23
+ const displayText =
24
+ versionText ||
25
+ `${t("settings.about.version")} ${t("settings.about.versionNumber")}`;
26
+
27
+ return (
28
+ <View style={styles.container}>
29
+ <Text style={[styles.text, { color: colors.textSecondary }]}>
30
+ {displayText}
31
+ </Text>
32
+ </View>
33
+ );
34
+ };
35
+
36
+ const styles = StyleSheet.create({
37
+ container: {
38
+ paddingVertical: 24,
39
+ alignItems: "center",
40
+ },
41
+ text: {
42
+ fontSize: 12,
43
+ fontWeight: "500",
44
+ },
45
+ });
46
+