@umituz/react-native-design-system 1.5.36 → 1.5.38
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 +2 -2
- package/package.json +7 -5
- package/src/index.ts +29 -221
- package/src/presentation/organisms/AppHeader.tsx +3 -5
- package/src/presentation/tokens/commonStyles.ts +1 -1
- package/src/presentation/atoms/AtomicAvatar.tsx +0 -157
- package/src/presentation/atoms/AtomicAvatarGroup.tsx +0 -169
- package/src/presentation/atoms/AtomicBadge.tsx +0 -232
- package/src/presentation/atoms/AtomicButton.tsx +0 -236
- package/src/presentation/atoms/AtomicCard.tsx +0 -107
- package/src/presentation/atoms/AtomicChip.tsx +0 -223
- package/src/presentation/atoms/AtomicDatePicker.tsx +0 -347
- package/src/presentation/atoms/AtomicDivider.tsx +0 -114
- package/src/presentation/atoms/AtomicFab.tsx +0 -98
- package/src/presentation/atoms/AtomicFilter.tsx +0 -154
- package/src/presentation/atoms/AtomicFormError.tsx +0 -105
- package/src/presentation/atoms/AtomicIcon.tsx +0 -40
- package/src/presentation/atoms/AtomicImage.tsx +0 -149
- package/src/presentation/atoms/AtomicInput.tsx +0 -363
- package/src/presentation/atoms/AtomicNumberInput.tsx +0 -182
- package/src/presentation/atoms/AtomicPicker.tsx +0 -458
- package/src/presentation/atoms/AtomicProgress.tsx +0 -139
- package/src/presentation/atoms/AtomicSearchBar.tsx +0 -114
- package/src/presentation/atoms/AtomicSort.tsx +0 -145
- package/src/presentation/atoms/AtomicSwitch.tsx +0 -166
- package/src/presentation/atoms/AtomicText.tsx +0 -55
- package/src/presentation/atoms/AtomicTextArea.tsx +0 -313
- package/src/presentation/atoms/AtomicTouchable.tsx +0 -209
- package/src/presentation/atoms/fab/styles/fabStyles.ts +0 -69
- package/src/presentation/atoms/fab/types/index.ts +0 -82
- package/src/presentation/atoms/filter/styles/filterStyles.ts +0 -32
- package/src/presentation/atoms/filter/types/index.ts +0 -89
- package/src/presentation/atoms/index.ts +0 -366
- package/src/presentation/atoms/input/hooks/useInputState.ts +0 -15
- package/src/presentation/atoms/input/styles/inputStyles.ts +0 -66
- package/src/presentation/atoms/input/types/index.ts +0 -25
- package/src/presentation/atoms/picker/styles/pickerStyles.ts +0 -207
- package/src/presentation/atoms/picker/types/index.ts +0 -40
- package/src/presentation/atoms/touchable/styles/touchableStyles.ts +0 -62
- package/src/presentation/atoms/touchable/types/index.ts +0 -155
- package/src/presentation/hooks/useResponsive.ts +0 -180
- package/src/presentation/molecules/AtomicConfirmationModal.tsx +0 -243
- package/src/presentation/molecules/EmptyState.tsx +0 -130
- package/src/presentation/molecules/FormField.tsx +0 -128
- package/src/presentation/molecules/GridContainer.tsx +0 -124
- package/src/presentation/molecules/IconContainer.tsx +0 -94
- package/src/presentation/molecules/ListItem.tsx +0 -36
- package/src/presentation/molecules/ScreenHeader.tsx +0 -140
- package/src/presentation/molecules/SearchBar.tsx +0 -85
- package/src/presentation/molecules/SectionCard.tsx +0 -74
- package/src/presentation/molecules/SectionContainer.tsx +0 -106
- package/src/presentation/molecules/SectionHeader.tsx +0 -125
- package/src/presentation/molecules/confirmation-modal/styles/confirmationModalStyles.ts +0 -133
- package/src/presentation/molecules/confirmation-modal/types/index.ts +0 -105
- package/src/presentation/molecules/index.ts +0 -41
- package/src/presentation/molecules/listitem/styles/listItemStyles.ts +0 -19
- package/src/presentation/molecules/listitem/types/index.ts +0 -17
- package/src/presentation/organisms/FormContainer.tsx +0 -180
- package/src/presentation/organisms/ScreenLayout.tsx +0 -171
- package/src/presentation/organisms/index.ts +0 -25
- package/src/presentation/utils/platformConstants.ts +0 -124
- package/src/presentation/utils/responsive.ts +0 -516
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EmptyState Molecule - Universal Empty State Display
|
|
3
|
-
*
|
|
4
|
-
* Displays icon, title, and subtitle for empty data scenarios
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: MOLECULE
|
|
8
|
-
* Composition: Icon + AtomicText + Layout
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - Empty lists
|
|
12
|
-
* - Empty grids
|
|
13
|
-
* - No search results
|
|
14
|
-
* - No data states
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React from 'react';
|
|
18
|
-
import { View, StyleSheet, ViewStyle, TextStyle } from 'react-native';
|
|
19
|
-
import { AtomicText, AtomicIcon } from '../atoms';
|
|
20
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
21
|
-
|
|
22
|
-
// =============================================================================
|
|
23
|
-
// TYPE DEFINITIONS
|
|
24
|
-
// =============================================================================
|
|
25
|
-
|
|
26
|
-
export interface EmptyStateProps {
|
|
27
|
-
/** Material icon name */
|
|
28
|
-
icon: string;
|
|
29
|
-
/** Icon size (default: xl) */
|
|
30
|
-
iconSize?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
|
|
31
|
-
/** Main heading text */
|
|
32
|
-
title: string;
|
|
33
|
-
/** Descriptive subtitle text */
|
|
34
|
-
subtitle?: string;
|
|
35
|
-
/** Custom icon color (default: textTertiary) */
|
|
36
|
-
iconColor?: string;
|
|
37
|
-
/** Custom title color (default: textPrimary) */
|
|
38
|
-
titleColor?: string;
|
|
39
|
-
/** Custom subtitle color (default: textSecondary) */
|
|
40
|
-
subtitleColor?: string;
|
|
41
|
-
/** Container style override */
|
|
42
|
-
style?: ViewStyle;
|
|
43
|
-
/** Title style override */
|
|
44
|
-
titleStyle?: TextStyle;
|
|
45
|
-
/** Subtitle style override */
|
|
46
|
-
subtitleStyle?: TextStyle;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// =============================================================================
|
|
50
|
-
// COMPONENT IMPLEMENTATION
|
|
51
|
-
// =============================================================================
|
|
52
|
-
|
|
53
|
-
export const EmptyState: React.FC<EmptyStateProps> = ({
|
|
54
|
-
icon,
|
|
55
|
-
iconSize = 'xl',
|
|
56
|
-
title,
|
|
57
|
-
subtitle,
|
|
58
|
-
iconColor,
|
|
59
|
-
titleColor,
|
|
60
|
-
subtitleColor,
|
|
61
|
-
style,
|
|
62
|
-
titleStyle,
|
|
63
|
-
subtitleStyle,
|
|
64
|
-
}) => {
|
|
65
|
-
const tokens = useAppDesignTokens();
|
|
66
|
-
const styles = getStyles(tokens);
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<View style={[styles.container, style]}>
|
|
70
|
-
<AtomicIcon
|
|
71
|
-
name={icon}
|
|
72
|
-
size={iconSize}
|
|
73
|
-
customColor={iconColor || tokens.colors.textSecondary}
|
|
74
|
-
/>
|
|
75
|
-
<AtomicText
|
|
76
|
-
type="headlineMedium"
|
|
77
|
-
color={titleColor || tokens.colors.textPrimary}
|
|
78
|
-
style={StyleSheet.flatten([
|
|
79
|
-
styles.title,
|
|
80
|
-
titleStyle,
|
|
81
|
-
])}
|
|
82
|
-
>
|
|
83
|
-
{title}
|
|
84
|
-
</AtomicText>
|
|
85
|
-
{subtitle && (
|
|
86
|
-
<AtomicText
|
|
87
|
-
type="bodyMedium"
|
|
88
|
-
color={subtitleColor || tokens.colors.textSecondary}
|
|
89
|
-
style={StyleSheet.flatten([
|
|
90
|
-
styles.subtitle,
|
|
91
|
-
subtitleStyle,
|
|
92
|
-
])}
|
|
93
|
-
>
|
|
94
|
-
{subtitle}
|
|
95
|
-
</AtomicText>
|
|
96
|
-
)}
|
|
97
|
-
</View>
|
|
98
|
-
);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// =============================================================================
|
|
102
|
-
// STYLES
|
|
103
|
-
// =============================================================================
|
|
104
|
-
|
|
105
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
106
|
-
StyleSheet.create({
|
|
107
|
-
container: {
|
|
108
|
-
flex: 1,
|
|
109
|
-
justifyContent: 'center',
|
|
110
|
-
alignItems: 'center',
|
|
111
|
-
paddingVertical: tokens.spacing.xl,
|
|
112
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
113
|
-
},
|
|
114
|
-
title: {
|
|
115
|
-
fontSize: tokens.typography.headingMedium.fontSize,
|
|
116
|
-
fontWeight: tokens.typography.headingMedium.fontWeight,
|
|
117
|
-
marginTop: tokens.spacing.md,
|
|
118
|
-
textAlign: 'center',
|
|
119
|
-
},
|
|
120
|
-
subtitle: {
|
|
121
|
-
fontSize: tokens.typography.bodySmall.fontSize,
|
|
122
|
-
marginTop: tokens.spacing.xs,
|
|
123
|
-
textAlign: 'center',
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// =============================================================================
|
|
128
|
-
// EXPORTS
|
|
129
|
-
// =============================================================================
|
|
130
|
-
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FormField Molecule - Complete Form Input with Label and Error
|
|
3
|
-
*
|
|
4
|
-
* Combines AtomicText (label/error) + AtomicInput (field)
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: MOLECULE
|
|
8
|
-
* Composition: AtomicText + AtomicInput
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import React from 'react';
|
|
12
|
-
import { View, ViewStyle } from 'react-native';
|
|
13
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
14
|
-
import { AtomicText } from '../atoms/AtomicText';
|
|
15
|
-
import { AtomicInput, AtomicInputProps } from '../atoms/AtomicInput';
|
|
16
|
-
|
|
17
|
-
// =============================================================================
|
|
18
|
-
// TYPE DEFINITIONS
|
|
19
|
-
// =============================================================================
|
|
20
|
-
|
|
21
|
-
export interface FormFieldProps extends Omit<AtomicInputProps, 'state' | 'label'> {
|
|
22
|
-
label?: string;
|
|
23
|
-
error?: string;
|
|
24
|
-
helperText?: string;
|
|
25
|
-
required?: boolean;
|
|
26
|
-
containerStyle?: ViewStyle;
|
|
27
|
-
style?: ViewStyle; // Alias for containerStyle (for convenience)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// =============================================================================
|
|
31
|
-
// COMPONENT IMPLEMENTATION
|
|
32
|
-
// =============================================================================
|
|
33
|
-
|
|
34
|
-
export const FormField: React.FC<FormFieldProps> = ({
|
|
35
|
-
label,
|
|
36
|
-
error,
|
|
37
|
-
helperText,
|
|
38
|
-
required = false,
|
|
39
|
-
containerStyle,
|
|
40
|
-
style, // Accept both style and containerStyle
|
|
41
|
-
...inputProps
|
|
42
|
-
}) => {
|
|
43
|
-
const tokens = useAppDesignTokens();
|
|
44
|
-
const inputState = error ? 'error' : 'default';
|
|
45
|
-
|
|
46
|
-
const styles = getStyles(tokens);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<View style={[styles.container, containerStyle || style]}>
|
|
50
|
-
{/* Label */}
|
|
51
|
-
{label && (
|
|
52
|
-
<View style={styles.labelContainer}>
|
|
53
|
-
<AtomicText type="labelMedium" color="primary" style={styles.label}>
|
|
54
|
-
{label}
|
|
55
|
-
</AtomicText>
|
|
56
|
-
{required && (
|
|
57
|
-
<AtomicText type="labelMedium" color="error">
|
|
58
|
-
{' *'}
|
|
59
|
-
</AtomicText>
|
|
60
|
-
)}
|
|
61
|
-
</View>
|
|
62
|
-
)}
|
|
63
|
-
|
|
64
|
-
{/* Input Field */}
|
|
65
|
-
<AtomicInput
|
|
66
|
-
{...inputProps}
|
|
67
|
-
label={label || ''}
|
|
68
|
-
state={inputState}
|
|
69
|
-
/>
|
|
70
|
-
|
|
71
|
-
{/* Error Message */}
|
|
72
|
-
{error && (
|
|
73
|
-
<AtomicText
|
|
74
|
-
type="bodySmall"
|
|
75
|
-
|
|
76
|
-
color="error"
|
|
77
|
-
style={styles.errorText}
|
|
78
|
-
>
|
|
79
|
-
{error}
|
|
80
|
-
</AtomicText>
|
|
81
|
-
)}
|
|
82
|
-
|
|
83
|
-
{/* Helper Text */}
|
|
84
|
-
{!error && helperText && (
|
|
85
|
-
<AtomicText
|
|
86
|
-
type="bodySmall"
|
|
87
|
-
|
|
88
|
-
color="secondary"
|
|
89
|
-
style={styles.helperText}
|
|
90
|
-
>
|
|
91
|
-
{helperText}
|
|
92
|
-
</AtomicText>
|
|
93
|
-
)}
|
|
94
|
-
</View>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// =============================================================================
|
|
99
|
-
// STYLES
|
|
100
|
-
// =============================================================================
|
|
101
|
-
|
|
102
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) => ({
|
|
103
|
-
container: {
|
|
104
|
-
marginBottom: tokens.spacing.md,
|
|
105
|
-
} as ViewStyle,
|
|
106
|
-
labelContainer: {
|
|
107
|
-
flexDirection: 'row',
|
|
108
|
-
marginBottom: tokens.spacing.sm,
|
|
109
|
-
} as ViewStyle,
|
|
110
|
-
label: {
|
|
111
|
-
fontWeight: tokens.typography.labelMedium.fontWeight,
|
|
112
|
-
color: tokens.colors.textPrimary,
|
|
113
|
-
} as ViewStyle,
|
|
114
|
-
inputError: {
|
|
115
|
-
borderColor: tokens.colors.error,
|
|
116
|
-
} as ViewStyle,
|
|
117
|
-
errorText: {
|
|
118
|
-
marginTop: tokens.spacing.xs,
|
|
119
|
-
} as ViewStyle,
|
|
120
|
-
helperText: {
|
|
121
|
-
marginTop: tokens.spacing.xs,
|
|
122
|
-
} as ViewStyle,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// =============================================================================
|
|
126
|
-
// EXPORTS
|
|
127
|
-
// =============================================================================
|
|
128
|
-
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GridContainer Molecule - Responsive Grid Layout
|
|
3
|
-
*
|
|
4
|
-
* Provides flexible grid layout with configurable columns and gap
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: MOLECULE
|
|
8
|
-
* Composition: View + Responsive Layout
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - Stats grids (2 columns)
|
|
12
|
-
* - Action grids (2 columns)
|
|
13
|
-
* - Product grids (2-3 columns)
|
|
14
|
-
* - Gallery grids (3-4 columns)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React from 'react';
|
|
18
|
-
import { View, StyleSheet, ViewStyle, DimensionValue } from 'react-native';
|
|
19
|
-
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// TYPE DEFINITIONS
|
|
22
|
-
// =============================================================================
|
|
23
|
-
|
|
24
|
-
export interface GridContainerProps {
|
|
25
|
-
/** Number of columns (default: 2) */
|
|
26
|
-
columns?: 2 | 3 | 4;
|
|
27
|
-
/** Gap between items in pixels (default: 8) */
|
|
28
|
-
gap?: number;
|
|
29
|
-
/** Container style override */
|
|
30
|
-
style?: ViewStyle;
|
|
31
|
-
/** Grid items to render */
|
|
32
|
-
children: React.ReactNode;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface GridItemProps {
|
|
36
|
-
/** Item content */
|
|
37
|
-
children: React.ReactNode;
|
|
38
|
-
/** Item style override */
|
|
39
|
-
style?: ViewStyle;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// =============================================================================
|
|
43
|
-
// COMPONENT IMPLEMENTATION
|
|
44
|
-
// =============================================================================
|
|
45
|
-
|
|
46
|
-
const GridContainerComponent: React.FC<GridContainerProps> = ({
|
|
47
|
-
columns = 2,
|
|
48
|
-
gap = 8,
|
|
49
|
-
style,
|
|
50
|
-
children,
|
|
51
|
-
}) => {
|
|
52
|
-
const styles = getStyles(gap);
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<View style={[styles.container, style]}>
|
|
56
|
-
{React.Children.map(children, (child) => {
|
|
57
|
-
if (React.isValidElement<GridItemProps>(child)) {
|
|
58
|
-
const childStyle = child.props.style;
|
|
59
|
-
const itemStyle = getItemStyle(columns, gap);
|
|
60
|
-
return React.cloneElement(child, {
|
|
61
|
-
style: StyleSheet.flatten([itemStyle, childStyle]),
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
return child;
|
|
65
|
-
})}
|
|
66
|
-
</View>
|
|
67
|
-
);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// =============================================================================
|
|
71
|
-
// GRID ITEM COMPONENT
|
|
72
|
-
// =============================================================================
|
|
73
|
-
|
|
74
|
-
export const GridItem: React.FC<GridItemProps> = ({ children, style }) => {
|
|
75
|
-
return <View style={style}>{children}</View>;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// Export GridContainer with Item property
|
|
79
|
-
export const GridContainer = GridContainerComponent as typeof GridContainerComponent & {
|
|
80
|
-
Item: typeof GridItem;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Attach GridItem to GridContainer for convenient usage
|
|
84
|
-
GridContainer.Item = GridItem;
|
|
85
|
-
|
|
86
|
-
// =============================================================================
|
|
87
|
-
// HELPERS
|
|
88
|
-
// =============================================================================
|
|
89
|
-
|
|
90
|
-
const getItemStyle = (columns: number, gap: number): ViewStyle => {
|
|
91
|
-
// Calculate width: (100% - total gap space) / columns
|
|
92
|
-
// For 2 columns with 8px gap: (100% - 8px) / 2 = ~48%
|
|
93
|
-
// For 3 columns with 8px gap: (100% - 16px) / 3 = ~31.33%
|
|
94
|
-
|
|
95
|
-
const widthMap: Record<number, DimensionValue> = {
|
|
96
|
-
2: '48%' as DimensionValue,
|
|
97
|
-
3: '31.33%' as DimensionValue,
|
|
98
|
-
4: '23%' as DimensionValue,
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
width: widthMap[columns] || ('48%' as DimensionValue),
|
|
103
|
-
marginHorizontal: gap / 2,
|
|
104
|
-
marginBottom: gap * 1.5,
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// =============================================================================
|
|
109
|
-
// STYLES
|
|
110
|
-
// =============================================================================
|
|
111
|
-
|
|
112
|
-
const getStyles = (gap: number) =>
|
|
113
|
-
StyleSheet.create({
|
|
114
|
-
container: {
|
|
115
|
-
flexDirection: 'row' as const,
|
|
116
|
-
flexWrap: 'wrap' as const,
|
|
117
|
-
marginHorizontal: -(gap / 2),
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// =============================================================================
|
|
122
|
-
// EXPORTS
|
|
123
|
-
// =============================================================================
|
|
124
|
-
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IconContainer Molecule Component
|
|
3
|
-
*
|
|
4
|
-
* Standardized icon container with consistent sizing and styling.
|
|
5
|
-
* Used throughout app for icon displays in lists, cards, and settings.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Consistent sizing system
|
|
9
|
-
* - Optional background circle
|
|
10
|
-
* - Optional gradient background
|
|
11
|
-
* - Theme-aware colors
|
|
12
|
-
* - Accessibility support
|
|
13
|
-
*
|
|
14
|
-
* Atomic Design: Molecule (View + Icon)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React from 'react';
|
|
18
|
-
import { View, StyleSheet } from 'react-native';
|
|
19
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
20
|
-
import { LinearGradient } from 'expo-linear-gradient';
|
|
21
|
-
|
|
22
|
-
interface IconContainerProps {
|
|
23
|
-
icon: React.ReactNode;
|
|
24
|
-
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
25
|
-
backgroundColor?: string;
|
|
26
|
-
gradient?: string[];
|
|
27
|
-
withBorder?: boolean;
|
|
28
|
-
borderColor?: string;
|
|
29
|
-
style?: object;
|
|
30
|
-
testID?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const getSizeMap = (tokens: ReturnType<typeof useAppDesignTokens>) => ({
|
|
34
|
-
sm: tokens.iconSizes.sm,
|
|
35
|
-
md: tokens.iconSizes.md,
|
|
36
|
-
lg: tokens.iconSizes.lg,
|
|
37
|
-
xl: tokens.iconSizes.xl,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
export const IconContainer: React.FC<IconContainerProps> = ({
|
|
41
|
-
icon,
|
|
42
|
-
size = 'md',
|
|
43
|
-
backgroundColor,
|
|
44
|
-
gradient,
|
|
45
|
-
withBorder = false,
|
|
46
|
-
borderColor,
|
|
47
|
-
style,
|
|
48
|
-
testID,
|
|
49
|
-
}) => {
|
|
50
|
-
const tokens = useAppDesignTokens();
|
|
51
|
-
const sizeMap = getSizeMap(tokens);
|
|
52
|
-
const containerSize = sizeMap[size];
|
|
53
|
-
const borderRadius = containerSize / 2;
|
|
54
|
-
|
|
55
|
-
const containerStyle = [
|
|
56
|
-
styles.container,
|
|
57
|
-
{
|
|
58
|
-
width: containerSize,
|
|
59
|
-
height: containerSize,
|
|
60
|
-
borderRadius,
|
|
61
|
-
backgroundColor: backgroundColor || (gradient ? undefined : tokens.colors.surfaceVariant),
|
|
62
|
-
},
|
|
63
|
-
withBorder && {
|
|
64
|
-
borderWidth: 1,
|
|
65
|
-
borderColor: borderColor || tokens.colors.border,
|
|
66
|
-
},
|
|
67
|
-
style,
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
if (gradient) {
|
|
71
|
-
return (
|
|
72
|
-
<LinearGradient
|
|
73
|
-
colors={gradient as unknown as readonly [string, string, ...string[]]}
|
|
74
|
-
style={containerStyle}
|
|
75
|
-
testID={testID}
|
|
76
|
-
>
|
|
77
|
-
{icon}
|
|
78
|
-
</LinearGradient>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<View style={containerStyle} testID={testID}>
|
|
84
|
-
{icon}
|
|
85
|
-
</View>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const styles = StyleSheet.create({
|
|
90
|
-
container: {
|
|
91
|
-
alignItems: 'center',
|
|
92
|
-
justifyContent: 'center',
|
|
93
|
-
},
|
|
94
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
4
|
-
import { AtomicText } from '../atoms/AtomicText';
|
|
5
|
-
import { AtomicIcon } from '../atoms/AtomicIcon';
|
|
6
|
-
import { ListItemProps } from './listitem/types';
|
|
7
|
-
import { getListItemStyles } from './listitem/styles/listItemStyles';
|
|
8
|
-
|
|
9
|
-
export type { ListItemProps };
|
|
10
|
-
|
|
11
|
-
export const ListItem: React.FC<ListItemProps> = ({
|
|
12
|
-
title, subtitle, leftIcon, rightIcon = 'forward', onPress, disabled = false, style,
|
|
13
|
-
}) => {
|
|
14
|
-
const tokens = useAppDesignTokens();
|
|
15
|
-
const listItemStyles = getListItemStyles(tokens);
|
|
16
|
-
const Component: React.ComponentType<any> = onPress ? TouchableOpacity : View;
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<Component style={[listItemStyles.container, disabled ? listItemStyles.disabled : undefined, style]} onPress={onPress} disabled={disabled} activeOpacity={0.7}>
|
|
20
|
-
{leftIcon && (
|
|
21
|
-
<View style={listItemStyles.iconContainer}>
|
|
22
|
-
<AtomicIcon name={leftIcon} color={disabled ? 'surfaceVariant' : 'primary'} />
|
|
23
|
-
</View>
|
|
24
|
-
)}
|
|
25
|
-
<View style={listItemStyles.content}>
|
|
26
|
-
<AtomicText type="bodyLarge" color={disabled ? 'surfaceVariant' : 'onSurface'} numberOfLines={1}>{title}</AtomicText>
|
|
27
|
-
{subtitle && <AtomicText type="bodySmall" color="surfaceVariant" numberOfLines={2} style={listItemStyles.subtitle}>{subtitle}</AtomicText>}
|
|
28
|
-
</View>
|
|
29
|
-
{rightIcon && onPress && (
|
|
30
|
-
<View style={listItemStyles.iconContainer}>
|
|
31
|
-
<AtomicIcon name={rightIcon} color="surfaceVariant" />
|
|
32
|
-
</View>
|
|
33
|
-
)}
|
|
34
|
-
</Component>
|
|
35
|
-
);
|
|
36
|
-
};
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScreenHeader Component - {{APP_NAME}}
|
|
3
|
-
*
|
|
4
|
-
* Reusable screen header with consistent back button placement
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Top-left back button (arrow-back icon)
|
|
9
|
-
* - Centered title text
|
|
10
|
-
* - Optional right action button
|
|
11
|
-
* - Consistent spacing and layout
|
|
12
|
-
* - Works with all 100+ generated apps
|
|
13
|
-
*
|
|
14
|
-
* CRITICAL: Back button MUST ALWAYS be top-left (never bottom, never center)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React from 'react';
|
|
18
|
-
import { View, StyleSheet, TouchableOpacity, ViewStyle } from 'react-native';
|
|
19
|
-
import { useNavigation } from '@react-navigation/native';
|
|
20
|
-
import { AtomicIcon } from '../atoms/AtomicIcon';
|
|
21
|
-
import { AtomicText } from '../atoms/AtomicText';
|
|
22
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
23
|
-
|
|
24
|
-
export interface ScreenHeaderProps {
|
|
25
|
-
/** Screen title (centered) */
|
|
26
|
-
title: string;
|
|
27
|
-
|
|
28
|
-
/** Optional right action button */
|
|
29
|
-
rightAction?: React.ReactNode;
|
|
30
|
-
|
|
31
|
-
/** Custom back button action (default: navigation.goBack()) */
|
|
32
|
-
onBackPress?: () => void;
|
|
33
|
-
|
|
34
|
-
/** Hide back button (rare cases only) */
|
|
35
|
-
hideBackButton?: boolean;
|
|
36
|
-
|
|
37
|
-
/** Additional header style */
|
|
38
|
-
style?: ViewStyle;
|
|
39
|
-
|
|
40
|
-
/** Test ID for E2E testing */
|
|
41
|
-
testID?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* ScreenHeader Component
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* // Basic usage (most common)
|
|
49
|
-
* <ScreenHeader title="Settings" />
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* // With right action
|
|
53
|
-
* <ScreenHeader
|
|
54
|
-
* title="Edit Profile"
|
|
55
|
-
* rightAction={<TouchableOpacity onPress={handleSave}><Text>Save</Text></TouchableOpacity>}
|
|
56
|
-
* />
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* // Custom back action
|
|
60
|
-
* <ScreenHeader
|
|
61
|
-
* title="Unsaved Changes"
|
|
62
|
-
* onBackPress={handleUnsavedChanges}
|
|
63
|
-
* />
|
|
64
|
-
*/
|
|
65
|
-
export const ScreenHeader: React.FC<ScreenHeaderProps> = ({
|
|
66
|
-
title,
|
|
67
|
-
rightAction,
|
|
68
|
-
onBackPress,
|
|
69
|
-
hideBackButton = false,
|
|
70
|
-
style,
|
|
71
|
-
testID = 'screen-header',
|
|
72
|
-
}) => {
|
|
73
|
-
const navigation = useNavigation();
|
|
74
|
-
const tokens = useAppDesignTokens();
|
|
75
|
-
|
|
76
|
-
const handleBackPress = () => {
|
|
77
|
-
if (onBackPress) {
|
|
78
|
-
onBackPress();
|
|
79
|
-
} else {
|
|
80
|
-
navigation.goBack();
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<View
|
|
86
|
-
style={[
|
|
87
|
-
{
|
|
88
|
-
flexDirection: 'row',
|
|
89
|
-
alignItems: 'center',
|
|
90
|
-
justifyContent: 'space-between',
|
|
91
|
-
paddingHorizontal: tokens.spacing.screenPadding,
|
|
92
|
-
paddingVertical: tokens.spacing.md,
|
|
93
|
-
borderBottomWidth: 0.5,
|
|
94
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
95
|
-
borderBottomColor: tokens.colors.border,
|
|
96
|
-
},
|
|
97
|
-
style
|
|
98
|
-
]}
|
|
99
|
-
testID={testID}
|
|
100
|
-
>
|
|
101
|
-
{/* Left: Back Button (ALWAYS top-left when visible) */}
|
|
102
|
-
<View style={{ width: 40, alignItems: 'flex-start' }}>
|
|
103
|
-
{!hideBackButton && (
|
|
104
|
-
<TouchableOpacity
|
|
105
|
-
onPress={handleBackPress}
|
|
106
|
-
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
107
|
-
testID={`${testID}-back-button`}
|
|
108
|
-
>
|
|
109
|
-
<AtomicIcon name="arrow-back" color="primary" />
|
|
110
|
-
</TouchableOpacity>
|
|
111
|
-
)}
|
|
112
|
-
</View>
|
|
113
|
-
|
|
114
|
-
{/* Center: Title */}
|
|
115
|
-
<View style={{ flex: 1, alignItems: 'center', paddingHorizontal: tokens.spacing.sm }}>
|
|
116
|
-
<AtomicText
|
|
117
|
-
type="headlineMedium"
|
|
118
|
-
style={[
|
|
119
|
-
{
|
|
120
|
-
fontWeight: tokens.typography.bold,
|
|
121
|
-
textAlign: 'center',
|
|
122
|
-
color: tokens.colors.textPrimary,
|
|
123
|
-
}
|
|
124
|
-
]}
|
|
125
|
-
numberOfLines={1}
|
|
126
|
-
testID={`${testID}-title`}
|
|
127
|
-
>
|
|
128
|
-
{title}
|
|
129
|
-
</AtomicText>
|
|
130
|
-
</View>
|
|
131
|
-
|
|
132
|
-
{/* Right: Optional Action or Placeholder */}
|
|
133
|
-
<View style={{ width: 40, alignItems: 'flex-start' }}>
|
|
134
|
-
{rightAction || <View style={{ width: 40 }} />}
|
|
135
|
-
</View>
|
|
136
|
-
</View>
|
|
137
|
-
);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
export default ScreenHeader;
|