@umituz/react-native-settings 4.20.57 → 4.20.58
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 +1 -1
- package/package.json +1 -1
- package/src/__tests__/setup.ts +1 -4
- package/src/domains/appearance/presentation/components/README.md +493 -0
- package/src/presentation/components/SettingsErrorBoundary/README.md +35 -41
- package/src/presentation/components/SettingsItemCard/README.md +3 -3
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ npm install @umituz/react-native-settings
|
|
|
33
33
|
## Peer Dependencies
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npm install zustand @umituz/react-native-storage @umituz/react-native-design-system @umituz/react-native-localization @react-navigation/native @react-navigation/stack react-native-safe-area-context
|
|
36
|
+
npm install zustand @umituz/react-native-storage @umituz/react-native-design-system @umituz/react-native-localization @react-navigation/native @react-navigation/stack react-native-safe-area-context
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Usage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "4.20.
|
|
3
|
+
"version": "4.20.58",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/__tests__/setup.ts
CHANGED
|
@@ -122,10 +122,7 @@ jest.mock('react-native-safe-area-context', () => ({
|
|
|
122
122
|
}),
|
|
123
123
|
}));
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
jest.mock('expo-linear-gradient', () => ({
|
|
127
|
-
LinearGradient: ({ children }: any) => children,
|
|
128
|
-
}));
|
|
125
|
+
|
|
129
126
|
|
|
130
127
|
// Mock notification service
|
|
131
128
|
jest.mock('@umituz/react-native-notifications', () => ({
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Appearance Components
|
|
2
|
+
|
|
3
|
+
Components for theme management and appearance customization including theme selection, color picking, and live preview.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### AppearanceScreen
|
|
8
|
+
|
|
9
|
+
Main screen for managing appearance settings including theme mode and custom colors.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { AppearanceScreen } from '@umituz/react-native-settings';
|
|
13
|
+
|
|
14
|
+
function AppearanceStack() {
|
|
15
|
+
return (
|
|
16
|
+
<Stack.Screen
|
|
17
|
+
name="Appearance"
|
|
18
|
+
component={AppearanceScreen}
|
|
19
|
+
options={{ title: 'Appearance' }}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
#### Features
|
|
26
|
+
|
|
27
|
+
- Theme mode selection (light/dark/auto)
|
|
28
|
+
- Custom color palette configuration
|
|
29
|
+
- Live theme preview
|
|
30
|
+
- Reset to defaults
|
|
31
|
+
|
|
32
|
+
#### Props
|
|
33
|
+
|
|
34
|
+
| Prop | Type | Default | Description |
|
|
35
|
+
|------|------|---------|-------------|
|
|
36
|
+
| `route` | `RouteProp` | **Required** | Route with optional config |
|
|
37
|
+
| `navigation` | `NavigationProp` | **Required** | Navigation object |
|
|
38
|
+
|
|
39
|
+
#### Route Params
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
interface AppearanceScreenParams {
|
|
43
|
+
showThemeSection?: boolean;
|
|
44
|
+
showColorsSection?: boolean;
|
|
45
|
+
showPreviewSection?: boolean;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### ThemeModeSection
|
|
50
|
+
|
|
51
|
+
Section component for selecting theme mode (light, dark, or auto/system).
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { ThemeModeSection } from '@umituz/react-native-settings';
|
|
55
|
+
|
|
56
|
+
function ThemeSelector() {
|
|
57
|
+
const { themeMode, setThemeMode } = useAppearance();
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<ThemeModeSection
|
|
61
|
+
themeMode={themeMode}
|
|
62
|
+
onThemeModeChange={setThemeMode}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Props
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Default | Description |
|
|
71
|
+
|------|------|---------|-------------|
|
|
72
|
+
| `themeMode` | `'light' \| 'dark' \| 'auto'` | **Required** | Current theme mode |
|
|
73
|
+
| `onThemeModeChange` | `(mode: 'light' \| 'dark' \| 'auto') => void` | **Required** | Theme change handler |
|
|
74
|
+
| `showPreview` | `boolean` | `true` | Show theme preview |
|
|
75
|
+
| `title` | `string` | `'Theme'` | Section title |
|
|
76
|
+
|
|
77
|
+
#### Example
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
<ThemeModeSection
|
|
81
|
+
themeMode="dark"
|
|
82
|
+
onThemeModeChange={(mode) => {
|
|
83
|
+
console.log('Theme changed to:', mode);
|
|
84
|
+
setThemeMode(mode);
|
|
85
|
+
}}
|
|
86
|
+
showPreview={true}
|
|
87
|
+
title="Appearance"
|
|
88
|
+
/>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### CustomColorsSection
|
|
92
|
+
|
|
93
|
+
Section component for customizing color palette.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { CustomColorsSection } from '@umituz/react-native-settings';
|
|
97
|
+
|
|
98
|
+
function ColorCustomizer() {
|
|
99
|
+
const { customColors, setCustomColors } = useAppearanceActions();
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<CustomColorsSection
|
|
103
|
+
colors={customColors || defaultColors}
|
|
104
|
+
onColorsChange={setCustomColors}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Props
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Default | Description |
|
|
113
|
+
|------|------|---------|-------------|
|
|
114
|
+
| `colors` | `ColorPalette` | **Required** | Current color palette |
|
|
115
|
+
| `onColorsChange` | `(colors: ColorPalette) => void` | **Required** | Color change handler |
|
|
116
|
+
| `availableColors` | `string[]` | `undefined` | Predefined color options |
|
|
117
|
+
| `showPreview` | `boolean` | `true` | Show color preview |
|
|
118
|
+
| `title` | `string` | `'Colors'` | Section title |
|
|
119
|
+
|
|
120
|
+
#### Example
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<CustomColorsSection
|
|
124
|
+
colors={{
|
|
125
|
+
primary: '#FF5722',
|
|
126
|
+
secondary: '#2196F3',
|
|
127
|
+
accent: '#FFC107',
|
|
128
|
+
background: '#FFFFFF',
|
|
129
|
+
surface: '#F5F5F5',
|
|
130
|
+
}}
|
|
131
|
+
onColorsChange={(newColors) => {
|
|
132
|
+
setCustomColors(newColors);
|
|
133
|
+
}}
|
|
134
|
+
availableColors={[
|
|
135
|
+
'#FF5722', '#2196F3', '#4CAF50', '#FF9800',
|
|
136
|
+
'#9C27B0', '#00BCD4', '#8BC34A', '#FFC107'
|
|
137
|
+
]}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### AppearancePreview
|
|
142
|
+
|
|
143
|
+
Component showing live preview of theme changes.
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
import { AppearancePreview } from '@umituz/react-native-settings';
|
|
147
|
+
|
|
148
|
+
function ThemePreview() {
|
|
149
|
+
const { themeMode, customColors } = useAppearance();
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<AppearancePreview
|
|
153
|
+
themeMode={themeMode}
|
|
154
|
+
customColors={customColors}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Props
|
|
161
|
+
|
|
162
|
+
| Prop | Type | Default | Description |
|
|
163
|
+
|------|------|---------|-------------|
|
|
164
|
+
| `themeMode` | `'light' \| 'dark' \| 'auto'` | **Required** | Theme mode |
|
|
165
|
+
| `customColors` | `ColorPalette` | `undefined` | Custom colors |
|
|
166
|
+
| `showSystemTheme` | `boolean` | `true` | Show system theme |
|
|
167
|
+
|
|
168
|
+
### ThemeOption
|
|
169
|
+
|
|
170
|
+
Individual theme option button/card.
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
import { ThemeOption } from '@umituz/react-native-settings';
|
|
174
|
+
|
|
175
|
+
function ThemeOptions() {
|
|
176
|
+
return (
|
|
177
|
+
<View>
|
|
178
|
+
<ThemeOption
|
|
179
|
+
mode="light"
|
|
180
|
+
title="Light"
|
|
181
|
+
icon="sunny-outline"
|
|
182
|
+
selected={themeMode === 'light'}
|
|
183
|
+
onPress={() => setThemeMode('light')}
|
|
184
|
+
/>
|
|
185
|
+
|
|
186
|
+
<ThemeOption
|
|
187
|
+
mode="dark"
|
|
188
|
+
title="Dark"
|
|
189
|
+
icon="moon-outline"
|
|
190
|
+
selected={themeMode === 'dark'}
|
|
191
|
+
onPress={() => setThemeMode('dark')}
|
|
192
|
+
/>
|
|
193
|
+
|
|
194
|
+
<ThemeOption
|
|
195
|
+
mode="auto"
|
|
196
|
+
title="Auto"
|
|
197
|
+
icon="phone-portrait-outline"
|
|
198
|
+
selected={themeMode === 'auto'}
|
|
199
|
+
onPress={() => setThemeMode('auto')}
|
|
200
|
+
/>
|
|
201
|
+
</View>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Props
|
|
207
|
+
|
|
208
|
+
| Prop | Type | Default | Description |
|
|
209
|
+
|------|------|---------|-------------|
|
|
210
|
+
| `mode` | `'light' \| 'dark' \| 'auto'` | **Required** | Theme mode |
|
|
211
|
+
| `title` | `string` | **Required** | Theme title |
|
|
212
|
+
| `icon` | `IconName` | **Required** | Theme icon |
|
|
213
|
+
| `selected` | `boolean` | `false` | Selected state |
|
|
214
|
+
| `onPress` | `() => void` | **Required** | Press handler |
|
|
215
|
+
| `description` | `string` | `undefined` | Theme description |
|
|
216
|
+
|
|
217
|
+
### ColorPicker
|
|
218
|
+
|
|
219
|
+
Color picker component for selecting custom colors.
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { ColorPicker } from '@umituz/react-native-settings';
|
|
223
|
+
|
|
224
|
+
function PrimaryColorPicker() {
|
|
225
|
+
const [color, setColor] = useState('#FF5722');
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<ColorPicker
|
|
229
|
+
label="Primary Color"
|
|
230
|
+
value={color}
|
|
231
|
+
onChange={setColor}
|
|
232
|
+
availableColors={['#FF5722', '#2196F3', '#4CAF50', '#FF9800']}
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Props
|
|
239
|
+
|
|
240
|
+
| Prop | Type | Default | Description |
|
|
241
|
+
|------|------|---------|-------------|
|
|
242
|
+
| `label` | `string` | **Required** | Color label |
|
|
243
|
+
| `value` | `string` | **Required** | Current color (hex) |
|
|
244
|
+
| `onChange` | `(color: string) => void` | **Required** | Change handler |
|
|
245
|
+
| `availableColors` | `string[]` | `undefined` | Predefined colors |
|
|
246
|
+
| `showCustomPicker` | `boolean` | `true` | Show custom color picker |
|
|
247
|
+
| `allowAlpha` | `boolean` | `false` | Allow alpha channel |
|
|
248
|
+
|
|
249
|
+
## Examples
|
|
250
|
+
|
|
251
|
+
### Complete Appearance Screen
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
function AppearanceScreen() {
|
|
255
|
+
const { themeMode, customColors } = useAppearance();
|
|
256
|
+
const { setThemeMode, setCustomColors, resetColors } = useAppearanceActions();
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
<ScrollView>
|
|
260
|
+
<AppearancePreview
|
|
261
|
+
themeMode={themeMode}
|
|
262
|
+
customColors={customColors}
|
|
263
|
+
/>
|
|
264
|
+
|
|
265
|
+
<ThemeModeSection
|
|
266
|
+
themeMode={themeMode}
|
|
267
|
+
onThemeModeChange={setThemeMode}
|
|
268
|
+
showPreview={true}
|
|
269
|
+
/>
|
|
270
|
+
|
|
271
|
+
<CustomColorsSection
|
|
272
|
+
colors={customColors || defaultColors}
|
|
273
|
+
onColorsChange={setCustomColors}
|
|
274
|
+
showPreview={true}
|
|
275
|
+
/>
|
|
276
|
+
|
|
277
|
+
<TouchableOpacity onPress={resetColors}>
|
|
278
|
+
<Text>Reset to Defaults</Text>
|
|
279
|
+
</TouchableOpacity>
|
|
280
|
+
</ScrollView>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Custom Color Palette
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
function CustomThemeBuilder() {
|
|
289
|
+
const [colors, setColors] = useState(defaultColors);
|
|
290
|
+
const { setCustomColors } = useAppearanceActions();
|
|
291
|
+
|
|
292
|
+
const handleColorChange = (key: string, value: string) => {
|
|
293
|
+
setColors(prev => ({ ...prev, [key]: value }));
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<View>
|
|
298
|
+
<ColorPicker
|
|
299
|
+
label="Primary"
|
|
300
|
+
value={colors.primary}
|
|
301
|
+
onChange={(color) => handleColorChange('primary', color)}
|
|
302
|
+
/>
|
|
303
|
+
|
|
304
|
+
<ColorPicker
|
|
305
|
+
label="Secondary"
|
|
306
|
+
value={colors.secondary}
|
|
307
|
+
onChange={(color) => handleColorChange('secondary', color)}
|
|
308
|
+
/>
|
|
309
|
+
|
|
310
|
+
<ColorPicker
|
|
311
|
+
label="Accent"
|
|
312
|
+
value={colors.accent}
|
|
313
|
+
onChange={(color) => handleColorChange('accent', color)}
|
|
314
|
+
/>
|
|
315
|
+
|
|
316
|
+
<Button
|
|
317
|
+
onPress={() => setCustomColors(colors)}
|
|
318
|
+
title="Apply Theme"
|
|
319
|
+
/>
|
|
320
|
+
</View>
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Theme Switcher
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
function QuickThemeSwitcher() {
|
|
329
|
+
const { themeMode, setThemeMode } = useAppearanceActions();
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<View style={styles.container}>
|
|
333
|
+
<TouchableOpacity
|
|
334
|
+
style={[styles.option, themeMode === 'light' && styles.selected]}
|
|
335
|
+
onPress={() => setThemeMode('light')}
|
|
336
|
+
>
|
|
337
|
+
<Ionicons name="sunny" size={24} />
|
|
338
|
+
<Text>Light</Text>
|
|
339
|
+
</TouchableOpacity>
|
|
340
|
+
|
|
341
|
+
<TouchableOpacity
|
|
342
|
+
style={[styles.option, themeMode === 'dark' && styles.selected]}
|
|
343
|
+
onPress={() => setThemeMode('dark')}
|
|
344
|
+
>
|
|
345
|
+
<Ionicons name="moon" size={24} />
|
|
346
|
+
<Text>Dark</Text>
|
|
347
|
+
</TouchableOpacity>
|
|
348
|
+
|
|
349
|
+
<TouchableOpacity
|
|
350
|
+
style={[styles.option, themeMode === 'auto' && styles.selected]}
|
|
351
|
+
onPress={() => setThemeMode('auto')}
|
|
352
|
+
>
|
|
353
|
+
<Ionicons name="phone-portrait" size={24} />
|
|
354
|
+
<Text>Auto</Text>
|
|
355
|
+
</TouchableOpacity>
|
|
356
|
+
</View>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Preset Themes
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
function ThemePresets() {
|
|
365
|
+
const { setCustomColors } = useAppearanceActions();
|
|
366
|
+
|
|
367
|
+
const presets = {
|
|
368
|
+
ocean: {
|
|
369
|
+
primary: '#2196F3',
|
|
370
|
+
secondary: '#00BCD4',
|
|
371
|
+
accent: '#4FC3F7',
|
|
372
|
+
},
|
|
373
|
+
sunset: {
|
|
374
|
+
primary: '#FF5722',
|
|
375
|
+
secondary: '#FF9800',
|
|
376
|
+
accent: '#FFC107',
|
|
377
|
+
},
|
|
378
|
+
forest: {
|
|
379
|
+
primary: '#4CAF50',
|
|
380
|
+
secondary: '#8BC34A',
|
|
381
|
+
accent: '#CDDC39',
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
return (
|
|
386
|
+
<View>
|
|
387
|
+
<Text>Choose a preset theme:</Text>
|
|
388
|
+
|
|
389
|
+
{Object.entries(presets).map(([name, colors]) => (
|
|
390
|
+
<TouchableOpacity
|
|
391
|
+
key={name}
|
|
392
|
+
onPress={() => setCustomColors(colors)}
|
|
393
|
+
>
|
|
394
|
+
<View style={{ flexDirection: 'row' }}>
|
|
395
|
+
<View style={{ backgroundColor: colors.primary, width: 20, height: 20 }} />
|
|
396
|
+
<View style={{ backgroundColor: colors.secondary, width: 20, height: 20 }} />
|
|
397
|
+
<View style={{ backgroundColor: colors.accent, width: 20, height: 20 }} />
|
|
398
|
+
<Text>{name}</Text>
|
|
399
|
+
</View>
|
|
400
|
+
</TouchableOpacity>
|
|
401
|
+
))}
|
|
402
|
+
</View>
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Styling
|
|
408
|
+
|
|
409
|
+
### Theme Styles
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
const styles = StyleSheet.create({
|
|
413
|
+
container: {
|
|
414
|
+
padding: tokens.spacing.lg,
|
|
415
|
+
},
|
|
416
|
+
themeOption: {
|
|
417
|
+
flexDirection: 'row',
|
|
418
|
+
alignItems: 'center',
|
|
419
|
+
padding: tokens.spacing.md,
|
|
420
|
+
backgroundColor: tokens.colors.surface,
|
|
421
|
+
borderRadius: tokens.borderRadius.md,
|
|
422
|
+
marginBottom: tokens.spacing.sm,
|
|
423
|
+
},
|
|
424
|
+
themeOptionSelected: {
|
|
425
|
+
borderWidth: 2,
|
|
426
|
+
borderColor: tokens.colors.primary,
|
|
427
|
+
},
|
|
428
|
+
themeIcon: {
|
|
429
|
+
marginRight: tokens.spacing.md,
|
|
430
|
+
},
|
|
431
|
+
themeTitle: {
|
|
432
|
+
fontSize: tokens.typography.fontSize.base,
|
|
433
|
+
fontWeight: '600',
|
|
434
|
+
color: tokens.colors.textPrimary,
|
|
435
|
+
},
|
|
436
|
+
themeDescription: {
|
|
437
|
+
fontSize: tokens.typography.fontSize.sm,
|
|
438
|
+
color: tokens.colors.textSecondary,
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Color Palettes
|
|
444
|
+
|
|
445
|
+
### Light Theme Default
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
const lightColors: ColorPalette = {
|
|
449
|
+
primary: '#2196F3',
|
|
450
|
+
secondary: '#00BCD4',
|
|
451
|
+
accent: '#FFC107',
|
|
452
|
+
background: '#FFFFFF',
|
|
453
|
+
surface: '#F5F5F5',
|
|
454
|
+
error: '#F44336',
|
|
455
|
+
success: '#4CAF50',
|
|
456
|
+
warning: '#FF9800',
|
|
457
|
+
};
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Dark Theme Default
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
const darkColors: ColorPalette = {
|
|
464
|
+
primary: '#2196F3',
|
|
465
|
+
secondary: '#00BCD4',
|
|
466
|
+
accent: '#FFC107',
|
|
467
|
+
background: '#121212',
|
|
468
|
+
surface: '#1E1E1E',
|
|
469
|
+
error: '#EF5350',
|
|
470
|
+
success: '#66BB6A',
|
|
471
|
+
warning: '#FFA726',
|
|
472
|
+
};
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Best Practices
|
|
476
|
+
|
|
477
|
+
1. **Preview**: Always show theme preview
|
|
478
|
+
2. **System Theme**: Respect system preference in auto mode
|
|
479
|
+
3. **Persistence**: Save theme changes immediately
|
|
480
|
+
4. **Validation**: Validate color hex codes
|
|
481
|
+
5. **Reset**: Provide reset to defaults
|
|
482
|
+
6. **Performance**: Use smooth transitions
|
|
483
|
+
7. **Accessibility**: Ensure sufficient contrast
|
|
484
|
+
|
|
485
|
+
## Related
|
|
486
|
+
|
|
487
|
+
- **Appearance Hooks**: Theme management hooks
|
|
488
|
+
- **Appearance Services**: System theme detection
|
|
489
|
+
- **Appearance Domain**: Appearance domain documentation
|
|
490
|
+
|
|
491
|
+
## License
|
|
492
|
+
|
|
493
|
+
MIT
|
|
@@ -355,48 +355,42 @@ function NavigationBoundary() {
|
|
|
355
355
|
```tsx
|
|
356
356
|
function StyledFallback({ error, resetError }) {
|
|
357
357
|
return (
|
|
358
|
-
<View style={styles.container}>
|
|
359
|
-
<
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
<Text style={styles.message}>
|
|
374
|
-
Something went wrong
|
|
375
|
-
</Text>
|
|
376
|
-
|
|
377
|
-
{__DEV__ && (
|
|
378
|
-
<View style={styles.details}>
|
|
379
|
-
<Text style={styles.errorText}>
|
|
380
|
-
{error.message}
|
|
381
|
-
</Text>
|
|
382
|
-
</View>
|
|
383
|
-
)}
|
|
358
|
+
<View style={[styles.container, { backgroundColor: '#f5f5f5' }]}>
|
|
359
|
+
<View style={styles.content}>
|
|
360
|
+
<Ionicons
|
|
361
|
+
name="warning-outline"
|
|
362
|
+
size={80}
|
|
363
|
+
color="#667eea"
|
|
364
|
+
style={styles.icon}
|
|
365
|
+
/>
|
|
366
|
+
|
|
367
|
+
<Text style={styles.title}>Oops!</Text>
|
|
368
|
+
|
|
369
|
+
<Text style={styles.message}>
|
|
370
|
+
Something went wrong
|
|
371
|
+
</Text>
|
|
384
372
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
</
|
|
391
|
-
|
|
392
|
-
|
|
373
|
+
{__DEV__ && (
|
|
374
|
+
<View style={styles.details}>
|
|
375
|
+
<Text style={styles.errorText}>
|
|
376
|
+
{error.message}
|
|
377
|
+
</Text>
|
|
378
|
+
</View>
|
|
379
|
+
)}
|
|
380
|
+
|
|
381
|
+
<TouchableOpacity
|
|
382
|
+
style={styles.button}
|
|
383
|
+
onPress={resetError}
|
|
384
|
+
>
|
|
385
|
+
<Text style={styles.buttonText}>Try Again</Text>
|
|
386
|
+
</TouchableOpacity>
|
|
387
|
+
</View>
|
|
393
388
|
</View>
|
|
394
389
|
);
|
|
395
390
|
}
|
|
396
391
|
|
|
397
392
|
const styles = StyleSheet.create({
|
|
398
393
|
container: { flex: 1 },
|
|
399
|
-
gradient: { flex: 1 },
|
|
400
394
|
content: {
|
|
401
395
|
flex: 1,
|
|
402
396
|
justifyContent: 'center',
|
|
@@ -407,34 +401,34 @@ const styles = StyleSheet.create({
|
|
|
407
401
|
title: {
|
|
408
402
|
fontSize: 32,
|
|
409
403
|
fontWeight: 'bold',
|
|
410
|
-
color: '
|
|
404
|
+
color: '#333',
|
|
411
405
|
marginBottom: 10,
|
|
412
406
|
},
|
|
413
407
|
message: {
|
|
414
408
|
fontSize: 16,
|
|
415
|
-
color: '
|
|
409
|
+
color: '#666',
|
|
416
410
|
textAlign: 'center',
|
|
417
411
|
marginBottom: 20,
|
|
418
412
|
},
|
|
419
413
|
details: {
|
|
420
|
-
backgroundColor: '
|
|
414
|
+
backgroundColor: '#eee',
|
|
421
415
|
padding: 10,
|
|
422
416
|
borderRadius: 8,
|
|
423
417
|
marginBottom: 20,
|
|
424
418
|
},
|
|
425
419
|
errorText: {
|
|
426
|
-
color: '
|
|
420
|
+
color: '#666',
|
|
427
421
|
fontSize: 12,
|
|
428
422
|
fontFamily: 'monospace',
|
|
429
423
|
},
|
|
430
424
|
button: {
|
|
431
|
-
backgroundColor: '
|
|
425
|
+
backgroundColor: '#667eea',
|
|
432
426
|
paddingHorizontal: 30,
|
|
433
427
|
paddingVertical: 15,
|
|
434
428
|
borderRadius: 25,
|
|
435
429
|
},
|
|
436
430
|
buttonText: {
|
|
437
|
-
color: '
|
|
431
|
+
color: 'white',
|
|
438
432
|
fontWeight: 'bold',
|
|
439
433
|
},
|
|
440
434
|
});
|
|
@@ -8,7 +8,7 @@ A premium, consistent card component for settings items with icons, text, option
|
|
|
8
8
|
- **Customizable**: Icon, title, subtitle, colors, and styles
|
|
9
9
|
- **Interactive**: Press feedback, switch controls, right icons
|
|
10
10
|
- **Accessible**: Full accessibility support with proper labels
|
|
11
|
-
- **Modern**:
|
|
11
|
+
- **Modern**: Sleek design, smooth animations
|
|
12
12
|
- **Design System**: Uses tokens for consistent styling
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
@@ -111,7 +111,7 @@ function CustomColoredItem() {
|
|
|
111
111
|
```
|
|
112
112
|
SettingsItemCard
|
|
113
113
|
├── Icon Container
|
|
114
|
-
│ ├── Icon Background
|
|
114
|
+
│ ├── Icon Background
|
|
115
115
|
│ └── Icon
|
|
116
116
|
├── Content
|
|
117
117
|
│ ├── Title
|
|
@@ -324,7 +324,7 @@ const defaultIconColors = {
|
|
|
324
324
|
title="Favorites"
|
|
325
325
|
/>
|
|
326
326
|
|
|
327
|
-
//
|
|
327
|
+
// Custom color
|
|
328
328
|
<SettingsItemCard
|
|
329
329
|
icon="star"
|
|
330
330
|
iconBgColor="#FFD700"
|