@umituz/react-native-design-system 1.14.0 → 2.0.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/package.json +26 -19
- package/src/atoms/AtomicAvatar.tsx +161 -0
- package/src/atoms/AtomicButton.tsx +241 -0
- package/src/atoms/AtomicChip.tsx +226 -0
- package/src/atoms/AtomicDatePicker.tsx +255 -0
- package/src/atoms/AtomicFab.tsx +99 -0
- package/src/atoms/AtomicIcon.tsx +149 -0
- package/src/atoms/AtomicInput.tsx +308 -0
- package/src/atoms/AtomicPicker.tsx +310 -0
- package/src/atoms/AtomicProgress.tsx +149 -0
- package/src/atoms/AtomicText.tsx +55 -0
- package/src/atoms/__tests__/AtomicButton.test.tsx +107 -0
- package/src/atoms/__tests__/AtomicIcon.test.tsx +110 -0
- package/src/atoms/__tests__/AtomicInput.test.tsx +195 -0
- package/src/atoms/datepicker/components/DatePickerButton.tsx +112 -0
- package/src/atoms/datepicker/components/DatePickerModal.tsx +143 -0
- package/src/atoms/fab/styles/fabStyles.ts +98 -0
- package/src/atoms/fab/types/index.ts +88 -0
- package/src/atoms/index.ts +70 -0
- package/src/atoms/input/hooks/useInputState.ts +63 -0
- package/src/atoms/input/styles/inputStylesHelper.ts +120 -0
- package/src/atoms/picker/components/PickerChips.tsx +57 -0
- package/src/atoms/picker/components/PickerModal.tsx +214 -0
- package/src/atoms/picker/styles/pickerStyles.ts +223 -0
- package/src/atoms/picker/types/index.ts +42 -0
- package/src/index.ts +148 -79
- package/src/molecules/ConfirmationModal.tsx +42 -0
- package/src/molecules/ConfirmationModalContent.tsx +87 -0
- package/src/molecules/ConfirmationModalMain.tsx +91 -0
- package/src/molecules/FormField.tsx +155 -0
- package/src/molecules/IconContainer.tsx +79 -0
- package/src/molecules/ListItem.tsx +35 -0
- package/src/molecules/ScreenHeader.tsx +171 -0
- package/src/molecules/SearchBar.tsx +198 -0
- package/src/molecules/confirmation-modal/components.tsx +94 -0
- package/src/molecules/confirmation-modal/index.ts +7 -0
- package/src/molecules/confirmation-modal/styles/confirmationModalStyles.ts +133 -0
- package/src/molecules/confirmation-modal/types/index.ts +41 -0
- package/src/molecules/confirmation-modal/useConfirmationModal.ts +50 -0
- package/src/molecules/index.ts +19 -0
- package/src/molecules/listitem/index.ts +6 -0
- package/src/molecules/listitem/styles/listItemStyles.ts +37 -0
- package/src/molecules/listitem/types/index.ts +21 -0
- package/src/organisms/AppHeader.tsx +136 -0
- package/src/organisms/FormContainer.tsx +169 -0
- package/src/organisms/ScreenLayout.tsx +183 -0
- package/src/organisms/index.ts +31 -0
- package/src/responsive/config.ts +139 -0
- package/src/responsive/deviceDetection.ts +155 -0
- package/src/responsive/gridUtils.ts +79 -0
- package/src/responsive/index.ts +52 -0
- package/src/responsive/platformConstants.ts +98 -0
- package/src/responsive/responsive.ts +61 -0
- package/src/responsive/responsiveLayout.ts +137 -0
- package/src/responsive/responsiveSizing.ts +134 -0
- package/src/responsive/useResponsive.ts +140 -0
- package/src/responsive/validation.ts +158 -0
- package/src/theme/core/BaseTokens.ts +42 -0
- package/src/theme/core/ColorPalette.ts +29 -0
- package/src/theme/core/CustomColors.ts +122 -0
- package/src/theme/core/NavigationTheme.ts +72 -0
- package/src/theme/core/TokenFactory.ts +103 -0
- package/src/theme/core/colors/ColorUtils.ts +53 -0
- package/src/theme/core/colors/DarkColors.ts +146 -0
- package/src/theme/core/colors/LightColors.ts +146 -0
- package/src/theme/core/constants/DesignConstants.ts +31 -0
- package/src/theme/core/themes.ts +118 -0
- package/src/theme/core/tokens/BaseTokens.ts +144 -0
- package/src/theme/core/tokens/Borders.ts +43 -0
- package/src/theme/core/tokens/Sizes.ts +51 -0
- package/src/theme/core/tokens/Spacing.ts +38 -0
- package/src/theme/core/tokens/Typography.ts +143 -0
- package/src/theme/hooks/useAppDesignTokens.ts +45 -0
- package/src/theme/hooks/useCommonStyles.ts +248 -0
- package/src/theme/hooks/useThemedStyles.ts +68 -0
- package/src/theme/index.ts +94 -0
- package/src/theme/infrastructure/globalThemeStore.ts +69 -0
- package/src/theme/infrastructure/storage/ThemeStorage.ts +93 -0
- package/src/theme/infrastructure/stores/themeStore.ts +109 -0
- package/src/typography/__tests__/colorValidationUtils.test.ts +180 -0
- package/src/typography/__tests__/textColorUtils.test.ts +185 -0
- package/src/typography/__tests__/textStyleUtils.test.ts +168 -0
- package/src/typography/domain/entities/TypographyTypes.ts +88 -0
- package/src/typography/index.ts +53 -0
- package/src/typography/presentation/utils/colorValidationUtils.ts +133 -0
- package/src/typography/presentation/utils/textColorUtils.ts +205 -0
- package/src/typography/presentation/utils/textStyleUtils.ts +159 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchBar Molecule - Enhanced Search Input with Clear Button
|
|
3
|
+
*
|
|
4
|
+
* Universal search input with clear functionality and loading state
|
|
5
|
+
* Fully configurable for general purpose use
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import {
|
|
10
|
+
View,
|
|
11
|
+
TextInput,
|
|
12
|
+
TouchableOpacity,
|
|
13
|
+
ActivityIndicator,
|
|
14
|
+
StyleSheet,
|
|
15
|
+
type StyleProp,
|
|
16
|
+
type ViewStyle,
|
|
17
|
+
} from 'react-native';
|
|
18
|
+
import { useAppDesignTokens } from '../theme';
|
|
19
|
+
import { AtomicIcon } from '../atoms';
|
|
20
|
+
|
|
21
|
+
export interface SearchBarProps {
|
|
22
|
+
value: string;
|
|
23
|
+
onChangeText: (text: string) => void;
|
|
24
|
+
onSubmit?: () => void;
|
|
25
|
+
onClear?: () => void;
|
|
26
|
+
placeholder?: string;
|
|
27
|
+
autoFocus?: boolean;
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
style?: StyleProp<ViewStyle>;
|
|
31
|
+
containerStyle?: ViewStyle;
|
|
32
|
+
searchIconName?: string;
|
|
33
|
+
clearIconName?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const useSearchBarLogic = (
|
|
37
|
+
value: string,
|
|
38
|
+
loading: boolean,
|
|
39
|
+
onChangeText: (text: string) => void,
|
|
40
|
+
onClear?: () => void,
|
|
41
|
+
onSubmit?: () => void
|
|
42
|
+
) => {
|
|
43
|
+
const handleClear = React.useCallback(() => {
|
|
44
|
+
onChangeText('');
|
|
45
|
+
onClear?.();
|
|
46
|
+
}, [onChangeText, onClear]);
|
|
47
|
+
|
|
48
|
+
const handleSubmit = React.useCallback(() => {
|
|
49
|
+
onSubmit?.();
|
|
50
|
+
}, [onSubmit]);
|
|
51
|
+
|
|
52
|
+
const showClear = React.useMemo(() =>
|
|
53
|
+
value.length > 0 && !loading, [value, loading]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return { handleClear, handleSubmit, showClear };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const SearchBarInput: React.FC<{
|
|
60
|
+
value: string;
|
|
61
|
+
placeholder?: string;
|
|
62
|
+
autoFocus?: boolean;
|
|
63
|
+
disabled?: boolean;
|
|
64
|
+
style?: StyleProp<ViewStyle>;
|
|
65
|
+
onChangeText: (text: string) => void;
|
|
66
|
+
onSubmitEditing?: () => void;
|
|
67
|
+
tokens: ReturnType<typeof useAppDesignTokens>;
|
|
68
|
+
}> = ({ value, placeholder, autoFocus, disabled, style, onChangeText, onSubmitEditing, tokens }) => {
|
|
69
|
+
const styles = React.useMemo(() => getSearchBarStyles(), []);
|
|
70
|
+
|
|
71
|
+
const inputStyle = React.useMemo(() => [
|
|
72
|
+
styles.input,
|
|
73
|
+
{
|
|
74
|
+
color: tokens.colors.textPrimary,
|
|
75
|
+
...tokens.typography.bodyMedium,
|
|
76
|
+
},
|
|
77
|
+
], [styles.input, tokens.colors.textPrimary, tokens.typography.bodyMedium]);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<TextInput
|
|
81
|
+
value={value}
|
|
82
|
+
onChangeText={onChangeText}
|
|
83
|
+
onSubmitEditing={onSubmitEditing}
|
|
84
|
+
placeholder={placeholder}
|
|
85
|
+
placeholderTextColor={tokens.colors.textSecondary}
|
|
86
|
+
autoFocus={autoFocus}
|
|
87
|
+
editable={!disabled}
|
|
88
|
+
returnKeyType="search"
|
|
89
|
+
autoCapitalize="none"
|
|
90
|
+
autoCorrect={false}
|
|
91
|
+
style={[inputStyle, style]}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const SearchBarIcons: React.FC<{
|
|
97
|
+
searchIconName: string;
|
|
98
|
+
clearIconName: string;
|
|
99
|
+
loading: boolean;
|
|
100
|
+
showClear: boolean;
|
|
101
|
+
onClear: () => void;
|
|
102
|
+
tokens: ReturnType<typeof useAppDesignTokens>;
|
|
103
|
+
}> = ({ searchIconName, clearIconName, loading, showClear, onClear, tokens }) => {
|
|
104
|
+
const styles = React.useMemo(() => getSearchBarStyles(), []);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
<AtomicIcon
|
|
109
|
+
name={searchIconName}
|
|
110
|
+
customSize={20}
|
|
111
|
+
customColor={tokens.colors.textSecondary}
|
|
112
|
+
style={styles.searchIcon}
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
{loading && (
|
|
116
|
+
<ActivityIndicator
|
|
117
|
+
size="small"
|
|
118
|
+
color={tokens.colors.primary}
|
|
119
|
+
style={styles.icon}
|
|
120
|
+
/>
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{showClear && (
|
|
124
|
+
<TouchableOpacity onPress={onClear} style={styles.icon}>
|
|
125
|
+
<AtomicIcon name={clearIconName} customSize={20} customColor={tokens.colors.textSecondary} />
|
|
126
|
+
</TouchableOpacity>
|
|
127
|
+
)}
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const SearchBarComponent: React.FC<SearchBarProps> = ({
|
|
133
|
+
value,
|
|
134
|
+
onChangeText,
|
|
135
|
+
onSubmit,
|
|
136
|
+
onClear,
|
|
137
|
+
placeholder,
|
|
138
|
+
autoFocus = false,
|
|
139
|
+
loading = false,
|
|
140
|
+
disabled = false,
|
|
141
|
+
style,
|
|
142
|
+
containerStyle,
|
|
143
|
+
searchIconName = 'search',
|
|
144
|
+
clearIconName = 'close-circle',
|
|
145
|
+
}) => {
|
|
146
|
+
const tokens = useAppDesignTokens();
|
|
147
|
+
const { handleClear, handleSubmit, showClear } = useSearchBarLogic(
|
|
148
|
+
value, loading, onChangeText, onClear, onSubmit
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<View style={containerStyle}>
|
|
153
|
+
<SearchBarIcons
|
|
154
|
+
searchIconName={searchIconName}
|
|
155
|
+
clearIconName={clearIconName}
|
|
156
|
+
loading={loading}
|
|
157
|
+
showClear={showClear}
|
|
158
|
+
onClear={handleClear}
|
|
159
|
+
tokens={tokens}
|
|
160
|
+
/>
|
|
161
|
+
|
|
162
|
+
<SearchBarInput
|
|
163
|
+
value={value}
|
|
164
|
+
placeholder={placeholder}
|
|
165
|
+
autoFocus={autoFocus}
|
|
166
|
+
disabled={disabled}
|
|
167
|
+
style={style}
|
|
168
|
+
onChangeText={onChangeText}
|
|
169
|
+
onSubmitEditing={handleSubmit}
|
|
170
|
+
tokens={tokens}
|
|
171
|
+
/>
|
|
172
|
+
</View>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const SearchBar = SearchBarComponent;
|
|
177
|
+
|
|
178
|
+
const getSearchBarStyles = () => StyleSheet.create({
|
|
179
|
+
container: {
|
|
180
|
+
flexDirection: 'row',
|
|
181
|
+
alignItems: 'center',
|
|
182
|
+
paddingHorizontal: 12,
|
|
183
|
+
paddingVertical: 8,
|
|
184
|
+
borderRadius: 12,
|
|
185
|
+
minHeight: 44,
|
|
186
|
+
},
|
|
187
|
+
searchIcon: {
|
|
188
|
+
marginRight: 12,
|
|
189
|
+
},
|
|
190
|
+
input: {
|
|
191
|
+
flex: 1,
|
|
192
|
+
paddingVertical: 0,
|
|
193
|
+
},
|
|
194
|
+
icon: {
|
|
195
|
+
marginLeft: 8,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmationModal Subcomponents
|
|
3
|
+
*
|
|
4
|
+
* Smaller components for the confirmation modal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { View, ViewStyle, StyleProp } from 'react-native';
|
|
9
|
+
import { AtomicText, AtomicButton, AtomicIcon } from '../../atoms';
|
|
10
|
+
import type { DesignTokens } from '../../theme';
|
|
11
|
+
import {
|
|
12
|
+
getButtonContainerStyle,
|
|
13
|
+
getButtonStyle,
|
|
14
|
+
} from './styles/confirmationModalStyles';
|
|
15
|
+
|
|
16
|
+
export const ConfirmationModalIcon: React.FC<{
|
|
17
|
+
icon: string;
|
|
18
|
+
iconColor: string;
|
|
19
|
+
testID: string;
|
|
20
|
+
}> = ({ icon, iconColor, testID }) => (
|
|
21
|
+
<AtomicIcon
|
|
22
|
+
name={icon}
|
|
23
|
+
size="xl"
|
|
24
|
+
color={iconColor as 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'surfaceVariant'}
|
|
25
|
+
testID={`${testID}-icon`}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const ConfirmationModalTitle: React.FC<{
|
|
30
|
+
title: string;
|
|
31
|
+
tokens: DesignTokens;
|
|
32
|
+
testID: string;
|
|
33
|
+
}> = ({ title, tokens, testID }) => (
|
|
34
|
+
<AtomicText
|
|
35
|
+
type="titleLarge"
|
|
36
|
+
style={{
|
|
37
|
+
color: tokens.colors.textPrimary,
|
|
38
|
+
textAlign: 'center',
|
|
39
|
+
fontWeight: tokens.typography.bold,
|
|
40
|
+
}}
|
|
41
|
+
testID={`${testID}-title`}
|
|
42
|
+
>
|
|
43
|
+
{title}
|
|
44
|
+
</AtomicText>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const ConfirmationModalMessage: React.FC<{
|
|
48
|
+
message: string;
|
|
49
|
+
tokens: DesignTokens;
|
|
50
|
+
testID: string;
|
|
51
|
+
}> = ({ message, tokens, testID }) => (
|
|
52
|
+
<AtomicText
|
|
53
|
+
type="bodyMedium"
|
|
54
|
+
style={{
|
|
55
|
+
color: tokens.colors.textSecondary,
|
|
56
|
+
textAlign: 'center',
|
|
57
|
+
lineHeight: tokens.typography.bodyMedium.lineHeight,
|
|
58
|
+
}}
|
|
59
|
+
testID={`${testID}-message`}
|
|
60
|
+
>
|
|
61
|
+
{message}
|
|
62
|
+
</AtomicText>
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export const ConfirmationModalButtons: React.FC<{
|
|
66
|
+
confirmText: string;
|
|
67
|
+
cancelText: string;
|
|
68
|
+
onConfirm: () => void;
|
|
69
|
+
onCancel: () => void;
|
|
70
|
+
confirmButtonStyle: StyleProp<ViewStyle>;
|
|
71
|
+
testID: string;
|
|
72
|
+
}> = ({ confirmText, cancelText, onConfirm, onCancel, confirmButtonStyle, testID }) => (
|
|
73
|
+
<View style={getButtonContainerStyle({} as DesignTokens)}>
|
|
74
|
+
<AtomicButton
|
|
75
|
+
variant="outline"
|
|
76
|
+
size="md"
|
|
77
|
+
onPress={onCancel}
|
|
78
|
+
style={getButtonStyle()}
|
|
79
|
+
testID={`${testID}-cancel-button`}
|
|
80
|
+
>
|
|
81
|
+
{cancelText}
|
|
82
|
+
</AtomicButton>
|
|
83
|
+
|
|
84
|
+
<AtomicButton
|
|
85
|
+
variant="primary"
|
|
86
|
+
size="md"
|
|
87
|
+
onPress={onConfirm}
|
|
88
|
+
style={confirmButtonStyle}
|
|
89
|
+
testID={`${testID}-confirm-button`}
|
|
90
|
+
>
|
|
91
|
+
{confirmText}
|
|
92
|
+
</AtomicButton>
|
|
93
|
+
</View>
|
|
94
|
+
);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmationModal Style Utilities
|
|
3
|
+
*
|
|
4
|
+
* Styling functions for confirmation modal component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ViewStyle } from 'react-native';
|
|
8
|
+
import { ConfirmationModalVariant, ConfirmationModalVariantConfig } from '../types/';
|
|
9
|
+
import type { DesignTokens } from '../../../theme';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get variant configuration (icon and color only)
|
|
13
|
+
* Note: Confirm text is handled in component with translations
|
|
14
|
+
*/
|
|
15
|
+
export const getVariantConfig = (
|
|
16
|
+
variant: ConfirmationModalVariant,
|
|
17
|
+
_tokens: DesignTokens
|
|
18
|
+
): Omit<ConfirmationModalVariantConfig, 'confirmText'> => {
|
|
19
|
+
switch (variant) {
|
|
20
|
+
case 'destructive':
|
|
21
|
+
return {
|
|
22
|
+
icon: 'warning',
|
|
23
|
+
iconColor: 'error',
|
|
24
|
+
};
|
|
25
|
+
case 'warning':
|
|
26
|
+
return {
|
|
27
|
+
icon: 'warning',
|
|
28
|
+
iconColor: 'warning',
|
|
29
|
+
};
|
|
30
|
+
case 'success':
|
|
31
|
+
return {
|
|
32
|
+
icon: 'check-circle',
|
|
33
|
+
iconColor: 'success',
|
|
34
|
+
};
|
|
35
|
+
case 'default':
|
|
36
|
+
default:
|
|
37
|
+
return {
|
|
38
|
+
icon: 'help-circle',
|
|
39
|
+
iconColor: 'primary',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get modal overlay style
|
|
46
|
+
*/
|
|
47
|
+
export const getModalOverlayStyle = (_tokens: DesignTokens): ViewStyle => ({
|
|
48
|
+
flex: 1,
|
|
49
|
+
justifyContent: 'center',
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get backdrop style (invisible layer for dismissing)
|
|
56
|
+
*/
|
|
57
|
+
export const getBackdropStyle = (): ViewStyle => ({
|
|
58
|
+
position: 'absolute',
|
|
59
|
+
top: 0,
|
|
60
|
+
left: 0,
|
|
61
|
+
right: 0,
|
|
62
|
+
bottom: 0,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get modal container style
|
|
67
|
+
*/
|
|
68
|
+
export const getModalContainerStyle = (tokens: DesignTokens): ViewStyle => ({
|
|
69
|
+
width: '85%',
|
|
70
|
+
maxWidth: 400,
|
|
71
|
+
backgroundColor: tokens.colors.surface,
|
|
72
|
+
borderRadius: 16,
|
|
73
|
+
padding: 24,
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
borderWidth: 1,
|
|
76
|
+
borderColor: tokens.colors.outline,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get icon container style
|
|
81
|
+
*/
|
|
82
|
+
export const getIconContainerStyle = (_tokens: DesignTokens): ViewStyle => ({
|
|
83
|
+
marginBottom: 16,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get title container style
|
|
88
|
+
*/
|
|
89
|
+
export const getTitleContainerStyle = (_tokens: DesignTokens): ViewStyle => ({
|
|
90
|
+
marginBottom: 8,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get message container style
|
|
95
|
+
*/
|
|
96
|
+
export const getMessageContainerStyle = (_tokens: DesignTokens): ViewStyle => ({
|
|
97
|
+
marginBottom: 24,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get button container style
|
|
102
|
+
*/
|
|
103
|
+
export const getButtonContainerStyle = (_tokens: DesignTokens): ViewStyle => ({
|
|
104
|
+
flexDirection: 'row',
|
|
105
|
+
gap: 12,
|
|
106
|
+
width: '100%',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get button style
|
|
111
|
+
*/
|
|
112
|
+
export const getButtonStyle = (): ViewStyle => ({
|
|
113
|
+
flex: 1,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get confirm button variant based on modal variant
|
|
118
|
+
*/
|
|
119
|
+
export const getConfirmButtonVariant = (
|
|
120
|
+
variant: ConfirmationModalVariant
|
|
121
|
+
): 'primary' | 'secondary' | 'tertiary' | 'outline' | 'ghost' => {
|
|
122
|
+
switch (variant) {
|
|
123
|
+
case 'destructive':
|
|
124
|
+
return 'primary'; // Will use error color
|
|
125
|
+
case 'warning':
|
|
126
|
+
return 'primary'; // Will use warning color
|
|
127
|
+
case 'success':
|
|
128
|
+
return 'primary'; // Will use success color
|
|
129
|
+
case 'default':
|
|
130
|
+
default:
|
|
131
|
+
return 'primary';
|
|
132
|
+
}
|
|
133
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmationModal Types
|
|
3
|
+
*/
|
|
4
|
+
import type { ViewStyle, StyleProp } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export type ConfirmationModalVariant = 'default' | 'destructive' | 'warning' | 'success';
|
|
7
|
+
|
|
8
|
+
export interface ConfirmationModalVariantConfig {
|
|
9
|
+
icon: string;
|
|
10
|
+
iconColor: string;
|
|
11
|
+
confirmText?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ConfirmationModalProps {
|
|
15
|
+
/** Modal visibility */
|
|
16
|
+
visible: boolean;
|
|
17
|
+
/** Modal title */
|
|
18
|
+
title: string;
|
|
19
|
+
/** Modal message */
|
|
20
|
+
message: string;
|
|
21
|
+
/** Confirm button text */
|
|
22
|
+
confirmText?: string;
|
|
23
|
+
/** Cancel button text */
|
|
24
|
+
cancelText?: string;
|
|
25
|
+
/** Confirm callback */
|
|
26
|
+
onConfirm: () => void;
|
|
27
|
+
/** Cancel/Close callback */
|
|
28
|
+
onCancel: () => void;
|
|
29
|
+
/** Modal variant for styling */
|
|
30
|
+
variant?: ConfirmationModalVariant;
|
|
31
|
+
/** Optional icon */
|
|
32
|
+
icon?: string;
|
|
33
|
+
/** Test ID */
|
|
34
|
+
testID?: string;
|
|
35
|
+
/** Show backdrop */
|
|
36
|
+
showBackdrop?: boolean;
|
|
37
|
+
/** Allow backdrop dismiss */
|
|
38
|
+
backdropDismissible?: boolean;
|
|
39
|
+
/** Custom style */
|
|
40
|
+
style?: StyleProp<ViewStyle>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmationModal Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for managing confirmation modal state
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { ConfirmationModalProps, ConfirmationModalVariant } from './types';
|
|
9
|
+
|
|
10
|
+
const useConfirmationModalState = () => {
|
|
11
|
+
const [visible, setVisible] = React.useState(false);
|
|
12
|
+
|
|
13
|
+
const showConfirmation = React.useCallback(() => setVisible(true), []);
|
|
14
|
+
const hideConfirmation = React.useCallback(() => setVisible(false), []);
|
|
15
|
+
|
|
16
|
+
return { visible, showConfirmation, hideConfirmation };
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const useConfirmationModal = (config: {
|
|
20
|
+
title: string;
|
|
21
|
+
message: string;
|
|
22
|
+
variant?: ConfirmationModalVariant;
|
|
23
|
+
confirmText: string;
|
|
24
|
+
cancelText: string;
|
|
25
|
+
onConfirm: () => void;
|
|
26
|
+
}) => {
|
|
27
|
+
const { visible, showConfirmation, hideConfirmation } = useConfirmationModalState();
|
|
28
|
+
|
|
29
|
+
const handleConfirm = React.useCallback(() => {
|
|
30
|
+
config.onConfirm();
|
|
31
|
+
hideConfirmation();
|
|
32
|
+
}, [config, hideConfirmation]);
|
|
33
|
+
|
|
34
|
+
const confirmationProps: ConfirmationModalProps = React.useMemo(() => ({
|
|
35
|
+
visible,
|
|
36
|
+
title: config.title,
|
|
37
|
+
message: config.message,
|
|
38
|
+
variant: config.variant || 'default',
|
|
39
|
+
confirmText: config.confirmText,
|
|
40
|
+
cancelText: config.cancelText,
|
|
41
|
+
onConfirm: handleConfirm,
|
|
42
|
+
onCancel: hideConfirmation,
|
|
43
|
+
}), [visible, config.title, config.message, config.variant, config.confirmText, config.cancelText, handleConfirm, hideConfirmation]);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
showConfirmation,
|
|
47
|
+
hideConfirmation,
|
|
48
|
+
confirmationProps,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Molecules - Composite UI components
|
|
3
|
+
* Built from atoms following atomic design principles
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Component exports
|
|
7
|
+
export { FormField, type FormFieldProps } from './FormField';
|
|
8
|
+
export { ListItem, type ListItemProps } from './ListItem';
|
|
9
|
+
export { SearchBar, type SearchBarProps } from './SearchBar';
|
|
10
|
+
export { IconContainer } from './IconContainer';
|
|
11
|
+
export { ScreenHeader, type ScreenHeaderProps } from './ScreenHeader';
|
|
12
|
+
export { ConfirmationModal } from './ConfirmationModalMain';
|
|
13
|
+
export { useConfirmationModal } from './confirmation-modal/useConfirmationModal';
|
|
14
|
+
|
|
15
|
+
// Type exports
|
|
16
|
+
export type {
|
|
17
|
+
ConfirmationModalProps,
|
|
18
|
+
ConfirmationModalVariant,
|
|
19
|
+
} from './confirmation-modal/types/';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ListItem Styles
|
|
3
|
+
*/
|
|
4
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
5
|
+
import type { DesignTokens } from '../../../theme';
|
|
6
|
+
|
|
7
|
+
export interface ListItemStyles {
|
|
8
|
+
container: ViewStyle;
|
|
9
|
+
disabled: ViewStyle;
|
|
10
|
+
iconContainer: ViewStyle;
|
|
11
|
+
content: ViewStyle;
|
|
12
|
+
subtitle: TextStyle;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const getListItemStyles = (tokens: DesignTokens): ListItemStyles => ({
|
|
16
|
+
container: {
|
|
17
|
+
flexDirection: 'row',
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
paddingVertical: tokens.spacing.md,
|
|
20
|
+
paddingHorizontal: tokens.spacing.md,
|
|
21
|
+
backgroundColor: tokens.colors.surface,
|
|
22
|
+
borderRadius: tokens.borders.radius.md,
|
|
23
|
+
minHeight: 56,
|
|
24
|
+
},
|
|
25
|
+
disabled: {
|
|
26
|
+
opacity: tokens.opacity.disabled,
|
|
27
|
+
},
|
|
28
|
+
iconContainer: {
|
|
29
|
+
marginRight: tokens.spacing.md,
|
|
30
|
+
},
|
|
31
|
+
content: {
|
|
32
|
+
flex: 1,
|
|
33
|
+
},
|
|
34
|
+
subtitle: {
|
|
35
|
+
marginTop: tokens.spacing.xs,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ListItem Types
|
|
3
|
+
*/
|
|
4
|
+
import type { ViewStyle } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export interface ListItemProps {
|
|
7
|
+
/** Main title text */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Optional subtitle text */
|
|
10
|
+
subtitle?: string;
|
|
11
|
+
/** Left icon name */
|
|
12
|
+
leftIcon?: string;
|
|
13
|
+
/** Right icon name */
|
|
14
|
+
rightIcon?: string;
|
|
15
|
+
/** Press handler */
|
|
16
|
+
onPress?: () => void;
|
|
17
|
+
/** Disabled state */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Custom container style */
|
|
20
|
+
style?: ViewStyle;
|
|
21
|
+
}
|