@umituz/react-native-design-system 1.5.33 → 1.5.34
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 +4 -1
- package/src/presentation/atoms/AtomicDatePicker.tsx +2 -1
- package/src/presentation/atoms/AtomicInput.tsx +19 -12
- package/src/index.js +0 -100
- package/src/presentation/atoms/AtomicAvatar.js +0 -84
- package/src/presentation/atoms/AtomicAvatarGroup.js +0 -82
- package/src/presentation/atoms/AtomicBadge.js +0 -167
- package/src/presentation/atoms/AtomicButton.js +0 -171
- package/src/presentation/atoms/AtomicCard.js +0 -69
- package/src/presentation/atoms/AtomicChip.js +0 -130
- package/src/presentation/atoms/AtomicDatePicker.js +0 -245
- package/src/presentation/atoms/AtomicDivider.js +0 -57
- package/src/presentation/atoms/AtomicFab.js +0 -67
- package/src/presentation/atoms/AtomicFilter.js +0 -103
- package/src/presentation/atoms/AtomicFormError.js +0 -63
- package/src/presentation/atoms/AtomicIcon.js +0 -29
- package/src/presentation/atoms/AtomicImage.js +0 -91
- package/src/presentation/atoms/AtomicInput.js +0 -201
- package/src/presentation/atoms/AtomicNumberInput.js +0 -124
- package/src/presentation/atoms/AtomicPicker.js +0 -298
- package/src/presentation/atoms/AtomicProgress.js +0 -79
- package/src/presentation/atoms/AtomicSearchBar.js +0 -45
- package/src/presentation/atoms/AtomicSort.js +0 -76
- package/src/presentation/atoms/AtomicSwitch.js +0 -103
- package/src/presentation/atoms/AtomicText.js +0 -22
- package/src/presentation/atoms/AtomicTextArea.js +0 -195
- package/src/presentation/atoms/AtomicTouchable.js +0 -137
- package/src/presentation/atoms/fab/styles/fabStyles.js +0 -62
- package/src/presentation/atoms/fab/types/index.js +0 -1
- package/src/presentation/atoms/filter/styles/filterStyles.js +0 -28
- package/src/presentation/atoms/filter/types/index.js +0 -1
- package/src/presentation/atoms/index.js +0 -145
- package/src/presentation/atoms/input/hooks/useInputState.js +0 -12
- package/src/presentation/atoms/input/styles/inputStyles.js +0 -58
- package/src/presentation/atoms/input/types/index.js +0 -1
- package/src/presentation/atoms/picker/styles/pickerStyles.js +0 -176
- package/src/presentation/atoms/picker/types/index.js +0 -1
- package/src/presentation/atoms/touchable/styles/touchableStyles.js +0 -53
- package/src/presentation/atoms/touchable/types/index.js +0 -1
- package/src/presentation/hooks/useResponsive.js +0 -81
- package/src/presentation/molecules/AtomicConfirmationModal.js +0 -153
- package/src/presentation/molecules/EmptyState.js +0 -67
- package/src/presentation/molecules/FormField.js +0 -75
- package/src/presentation/molecules/GridContainer.js +0 -76
- package/src/presentation/molecules/IconContainer.js +0 -59
- package/src/presentation/molecules/ListItem.js +0 -23
- package/src/presentation/molecules/ScreenHeader.js +0 -93
- package/src/presentation/molecules/SearchBar.js +0 -46
- package/src/presentation/molecules/SectionCard.js +0 -46
- package/src/presentation/molecules/SectionContainer.js +0 -63
- package/src/presentation/molecules/SectionHeader.js +0 -72
- package/src/presentation/molecules/confirmation-modal/styles/confirmationModalStyles.js +0 -114
- package/src/presentation/molecules/confirmation-modal/types/index.js +0 -6
- package/src/presentation/molecules/index.js +0 -16
- package/src/presentation/molecules/listitem/styles/listItemStyles.js +0 -14
- package/src/presentation/molecules/listitem/types/index.js +0 -1
- package/src/presentation/organisms/AppHeader.js +0 -77
- package/src/presentation/organisms/FormContainer.js +0 -126
- package/src/presentation/organisms/ScreenLayout.js +0 -68
- package/src/presentation/organisms/index.js +0 -13
- package/src/presentation/tokens/commonStyles.js +0 -219
- package/src/presentation/utils/platformConstants.js +0 -113
- package/src/presentation/utils/responsive.js +0 -451
- package/src/presentation/utils/variants/compound.js +0 -15
- package/src/presentation/utils/variants/core.js +0 -22
- package/src/presentation/utils/variants/helpers.js +0 -9
- package/src/presentation/utils/variants.js +0 -3
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicTextArea Component
|
|
3
|
-
*
|
|
4
|
-
* A multiline text input component with pure React Native implementation
|
|
5
|
-
* for longer text entry with consistent styling.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Pure React Native TextInput with multiline
|
|
9
|
-
* - Outlined/filled/flat variants
|
|
10
|
-
* - Error, success, disabled states
|
|
11
|
-
* - Character counter with max length
|
|
12
|
-
* - Helper text for guidance or errors
|
|
13
|
-
* - Configurable rows for height
|
|
14
|
-
* - Theme-aware styling
|
|
15
|
-
* - Full accessibility support
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
* ```tsx
|
|
19
|
-
* const [description, setDescription] = useState('');
|
|
20
|
-
*
|
|
21
|
-
* <AtomicTextArea
|
|
22
|
-
* value={description}
|
|
23
|
-
* onChangeText={setDescription}
|
|
24
|
-
* label="Description"
|
|
25
|
-
* placeholder="Enter description..."
|
|
26
|
-
* maxLength={500}
|
|
27
|
-
* showCharacterCount
|
|
28
|
-
* rows={6}
|
|
29
|
-
* helperText="Provide a detailed description"
|
|
30
|
-
* />
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
import React, { useState } from 'react';
|
|
34
|
-
import { View, TextInput, StyleSheet } from 'react-native';
|
|
35
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
36
|
-
import { AtomicText } from './AtomicText';
|
|
37
|
-
/**
|
|
38
|
-
* AtomicTextArea - Pure React Native Multiline Text Input
|
|
39
|
-
*/
|
|
40
|
-
export const AtomicTextArea = ({ variant = 'outlined', state = 'default', size = 'md', label, value = '', onChangeText, placeholder, helperText, maxLength, showCharacterCount = false, rows = 4, minHeight, autoCapitalize = 'sentences', autoCorrect = true, disabled = false, style, inputStyle, testID, onBlur, onFocus, }) => {
|
|
41
|
-
const tokens = useAppDesignTokens();
|
|
42
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
43
|
-
const isDisabled = state === 'disabled' || disabled;
|
|
44
|
-
const characterCount = value?.toString().length || 0;
|
|
45
|
-
const hasError = state === 'error';
|
|
46
|
-
const hasSuccess = state === 'success';
|
|
47
|
-
// Size configuration
|
|
48
|
-
const sizeConfig = {
|
|
49
|
-
sm: {
|
|
50
|
-
paddingVertical: tokens.spacing.xs,
|
|
51
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
52
|
-
fontSize: tokens.typography.bodySmall.fontSize,
|
|
53
|
-
lineHeight: 20,
|
|
54
|
-
},
|
|
55
|
-
md: {
|
|
56
|
-
paddingVertical: tokens.spacing.sm,
|
|
57
|
-
paddingHorizontal: tokens.spacing.md,
|
|
58
|
-
fontSize: tokens.typography.bodyMedium.fontSize,
|
|
59
|
-
lineHeight: 24,
|
|
60
|
-
},
|
|
61
|
-
lg: {
|
|
62
|
-
paddingVertical: tokens.spacing.md,
|
|
63
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
64
|
-
fontSize: tokens.typography.bodyLarge.fontSize,
|
|
65
|
-
lineHeight: 28,
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
const config = sizeConfig[size];
|
|
69
|
-
// Calculate height based on rows
|
|
70
|
-
const getTextAreaHeight = () => {
|
|
71
|
-
if (minHeight)
|
|
72
|
-
return minHeight;
|
|
73
|
-
const paddingVertical = config.paddingVertical * 2;
|
|
74
|
-
return (rows * config.lineHeight) + paddingVertical;
|
|
75
|
-
};
|
|
76
|
-
// Get variant styles
|
|
77
|
-
const getVariantStyle = () => {
|
|
78
|
-
const baseStyle = {
|
|
79
|
-
backgroundColor: tokens.colors.surface,
|
|
80
|
-
borderRadius: tokens.borders.radius.md,
|
|
81
|
-
};
|
|
82
|
-
let borderColor = tokens.colors.border;
|
|
83
|
-
if (isFocused)
|
|
84
|
-
borderColor = tokens.colors.primary;
|
|
85
|
-
if (hasError)
|
|
86
|
-
borderColor = tokens.colors.error;
|
|
87
|
-
if (hasSuccess)
|
|
88
|
-
borderColor = tokens.colors.success;
|
|
89
|
-
if (isDisabled)
|
|
90
|
-
borderColor = tokens.colors.borderDisabled;
|
|
91
|
-
switch (variant) {
|
|
92
|
-
case 'outlined':
|
|
93
|
-
return {
|
|
94
|
-
...baseStyle,
|
|
95
|
-
borderWidth: isFocused ? 2 : 1,
|
|
96
|
-
borderColor,
|
|
97
|
-
};
|
|
98
|
-
case 'filled':
|
|
99
|
-
return {
|
|
100
|
-
...baseStyle,
|
|
101
|
-
backgroundColor: tokens.colors.surfaceSecondary,
|
|
102
|
-
borderWidth: 0,
|
|
103
|
-
borderBottomWidth: isFocused ? 2 : 1,
|
|
104
|
-
borderBottomColor: borderColor,
|
|
105
|
-
};
|
|
106
|
-
case 'flat':
|
|
107
|
-
return {
|
|
108
|
-
...baseStyle,
|
|
109
|
-
backgroundColor: 'transparent',
|
|
110
|
-
borderWidth: 0,
|
|
111
|
-
borderBottomWidth: 1,
|
|
112
|
-
borderBottomColor: borderColor,
|
|
113
|
-
borderRadius: 0,
|
|
114
|
-
};
|
|
115
|
-
default:
|
|
116
|
-
return baseStyle;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
// Get text color based on state
|
|
120
|
-
const getTextColor = () => {
|
|
121
|
-
if (isDisabled)
|
|
122
|
-
return tokens.colors.textDisabled;
|
|
123
|
-
if (hasError)
|
|
124
|
-
return tokens.colors.error;
|
|
125
|
-
if (hasSuccess)
|
|
126
|
-
return tokens.colors.success;
|
|
127
|
-
return tokens.colors.textPrimary;
|
|
128
|
-
};
|
|
129
|
-
const containerStyle = [
|
|
130
|
-
styles.container,
|
|
131
|
-
getVariantStyle(),
|
|
132
|
-
{
|
|
133
|
-
paddingVertical: config.paddingVertical,
|
|
134
|
-
paddingHorizontal: config.paddingHorizontal,
|
|
135
|
-
height: getTextAreaHeight(),
|
|
136
|
-
opacity: isDisabled ? 0.5 : 1,
|
|
137
|
-
},
|
|
138
|
-
style,
|
|
139
|
-
];
|
|
140
|
-
const textInputStyle = [
|
|
141
|
-
styles.input,
|
|
142
|
-
{
|
|
143
|
-
fontSize: config.fontSize,
|
|
144
|
-
lineHeight: config.lineHeight,
|
|
145
|
-
color: getTextColor(),
|
|
146
|
-
},
|
|
147
|
-
inputStyle,
|
|
148
|
-
];
|
|
149
|
-
return (<View testID={testID}>
|
|
150
|
-
{label && (<AtomicText type="labelMedium" color={hasError ? 'error' : hasSuccess ? 'success' : 'secondary'} style={styles.label}>
|
|
151
|
-
{label}
|
|
152
|
-
</AtomicText>)}
|
|
153
|
-
|
|
154
|
-
<View style={containerStyle}>
|
|
155
|
-
<TextInput value={value} onChangeText={onChangeText} placeholder={placeholder} placeholderTextColor={tokens.colors.textSecondary} maxLength={maxLength} autoCapitalize={autoCapitalize} autoCorrect={autoCorrect} editable={!isDisabled} multiline={true} numberOfLines={rows} textAlignVertical="top" style={textInputStyle} onBlur={() => {
|
|
156
|
-
setIsFocused(false);
|
|
157
|
-
onBlur?.();
|
|
158
|
-
}} onFocus={() => {
|
|
159
|
-
setIsFocused(true);
|
|
160
|
-
onFocus?.();
|
|
161
|
-
}} testID={testID ? `${testID}-input` : undefined}/>
|
|
162
|
-
</View>
|
|
163
|
-
|
|
164
|
-
{(helperText || showCharacterCount) && (<View style={styles.helperRow}>
|
|
165
|
-
{helperText && (<AtomicText type="bodySmall" color={hasError ? 'error' : 'secondary'} style={styles.helperText} testID={testID ? `${testID}-helper` : undefined}>
|
|
166
|
-
{helperText}
|
|
167
|
-
</AtomicText>)}
|
|
168
|
-
{showCharacterCount && maxLength && (<AtomicText type="bodySmall" color="secondary" style={styles.characterCount} testID={testID ? `${testID}-count` : undefined}>
|
|
169
|
-
{characterCount}/{maxLength}
|
|
170
|
-
</AtomicText>)}
|
|
171
|
-
</View>)}
|
|
172
|
-
</View>);
|
|
173
|
-
};
|
|
174
|
-
const styles = StyleSheet.create({
|
|
175
|
-
container: {
|
|
176
|
-
justifyContent: 'flex-start',
|
|
177
|
-
},
|
|
178
|
-
input: {
|
|
179
|
-
flex: 1,
|
|
180
|
-
},
|
|
181
|
-
label: {
|
|
182
|
-
marginBottom: 4,
|
|
183
|
-
},
|
|
184
|
-
helperRow: {
|
|
185
|
-
flexDirection: 'row',
|
|
186
|
-
justifyContent: 'space-between',
|
|
187
|
-
marginTop: 4,
|
|
188
|
-
},
|
|
189
|
-
helperText: {
|
|
190
|
-
flex: 1,
|
|
191
|
-
},
|
|
192
|
-
characterCount: {
|
|
193
|
-
marginLeft: 8,
|
|
194
|
-
},
|
|
195
|
-
});
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Pressable } from 'react-native';
|
|
3
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
4
|
-
import { getOpacityValue, getTouchableContainerStyle, getDisabledStyle, normalizeHitSlop, } from './touchable/styles/touchableStyles';
|
|
5
|
-
export { getOpacityValue, getTouchableContainerStyle, getDisabledStyle, normalizeHitSlop, } from './touchable/styles/touchableStyles';
|
|
6
|
-
/**
|
|
7
|
-
* AtomicTouchable - Unified Touchable Component
|
|
8
|
-
*
|
|
9
|
-
* A modern, accessible touchable wrapper using React Native's Pressable API.
|
|
10
|
-
* Provides consistent behavior across iOS, Android, and Web.
|
|
11
|
-
*
|
|
12
|
-
* Features:
|
|
13
|
-
* - Multiple feedback variants (opacity, highlight, ripple, none)
|
|
14
|
-
* - Configurable feedback strength (subtle, normal, strong)
|
|
15
|
-
* - Disabled state with visual feedback
|
|
16
|
-
* - Hit slop customization for small touch targets
|
|
17
|
-
* - Minimum 48x48 touch target (iOS HIG compliance)
|
|
18
|
-
* - Full accessibility support
|
|
19
|
-
* - Theme-aware ripple colors
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* // Basic usage with opacity feedback
|
|
24
|
-
* <AtomicTouchable onPress={handlePress}>
|
|
25
|
-
* <AtomicText>Press Me</AtomicText>
|
|
26
|
-
* </AtomicTouchable>
|
|
27
|
-
*
|
|
28
|
-
* // With custom hit slop (extends touch area)
|
|
29
|
-
* <AtomicTouchable
|
|
30
|
-
* onPress={handlePress}
|
|
31
|
-
* hitSlop={8}
|
|
32
|
-
* feedback="ripple"
|
|
33
|
-
* >
|
|
34
|
-
* <AtomicIcon name="X" size="sm" />
|
|
35
|
-
* </AtomicTouchable>
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export const AtomicTouchable = ({ children, onPress, onPressIn, onPressOut, onLongPress, feedback = 'opacity', strength = 'normal', disabled = false, hitSlop, style, pressedStyle, disabledStyle, accessibilityLabel, accessibilityHint, accessibilityRole = 'button', testID, delayLongPress = 500, rippleColor, rippleRadius = 0, }) => {
|
|
39
|
-
const tokens = useAppDesignTokens();
|
|
40
|
-
// Determine if touchable should be disabled
|
|
41
|
-
const isDisabled = disabled;
|
|
42
|
-
// Get opacity value based on strength
|
|
43
|
-
const opacityValue = getOpacityValue(strength);
|
|
44
|
-
// Normalize hit slop
|
|
45
|
-
const normalizedHitSlop = normalizeHitSlop(hitSlop);
|
|
46
|
-
// Default ripple color (theme primary with alpha)
|
|
47
|
-
const defaultRippleColor = tokens.colors.primary + '40'; // 40 = 25% opacity in hex
|
|
48
|
-
/**
|
|
49
|
-
* Get style based on pressed state
|
|
50
|
-
*/
|
|
51
|
-
const getPressedStyle = ({ pressed }) => {
|
|
52
|
-
const baseStyle = [
|
|
53
|
-
getTouchableContainerStyle(),
|
|
54
|
-
style,
|
|
55
|
-
];
|
|
56
|
-
if (isDisabled) {
|
|
57
|
-
return [...baseStyle, getDisabledStyle(), disabledStyle];
|
|
58
|
-
}
|
|
59
|
-
if (pressed) {
|
|
60
|
-
// Apply feedback based on variant
|
|
61
|
-
switch (feedback) {
|
|
62
|
-
case 'opacity':
|
|
63
|
-
return [...baseStyle, { opacity: opacityValue }, pressedStyle];
|
|
64
|
-
case 'highlight':
|
|
65
|
-
return [
|
|
66
|
-
...baseStyle,
|
|
67
|
-
{ backgroundColor: tokens.colors.surfaceVariant },
|
|
68
|
-
pressedStyle,
|
|
69
|
-
];
|
|
70
|
-
case 'none':
|
|
71
|
-
return [...baseStyle, pressedStyle];
|
|
72
|
-
case 'ripple':
|
|
73
|
-
// Ripple is handled by android_ripple prop
|
|
74
|
-
return [...baseStyle, pressedStyle];
|
|
75
|
-
default:
|
|
76
|
-
return [...baseStyle, pressedStyle];
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return baseStyle;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Android ripple configuration
|
|
83
|
-
* Used when feedback='ripple'
|
|
84
|
-
* Pressable automatically ignores this prop on iOS/Web
|
|
85
|
-
*/
|
|
86
|
-
const androidRippleConfig = feedback === 'ripple'
|
|
87
|
-
? {
|
|
88
|
-
color: rippleColor || defaultRippleColor,
|
|
89
|
-
borderless: false,
|
|
90
|
-
radius: rippleRadius,
|
|
91
|
-
}
|
|
92
|
-
: undefined;
|
|
93
|
-
return (<Pressable onPress={isDisabled ? undefined : onPress} onPressIn={isDisabled ? undefined : onPressIn} onPressOut={isDisabled ? undefined : onPressOut} onLongPress={isDisabled ? undefined : onLongPress} delayLongPress={delayLongPress} disabled={isDisabled} hitSlop={normalizedHitSlop} style={getPressedStyle} android_ripple={androidRippleConfig} accessibilityLabel={accessibilityLabel} accessibilityHint={accessibilityHint} accessibilityRole={accessibilityRole} accessibilityState={{
|
|
94
|
-
disabled: isDisabled,
|
|
95
|
-
}} testID={testID}>
|
|
96
|
-
{children}
|
|
97
|
-
</Pressable>);
|
|
98
|
-
};
|
|
99
|
-
/**
|
|
100
|
-
* Preset touchable configurations for common use cases
|
|
101
|
-
*/
|
|
102
|
-
export const TouchablePresets = {
|
|
103
|
-
/**
|
|
104
|
-
* iOS-style opacity feedback (default)
|
|
105
|
-
*/
|
|
106
|
-
ios: {
|
|
107
|
-
feedback: 'opacity',
|
|
108
|
-
strength: 'normal',
|
|
109
|
-
},
|
|
110
|
-
/**
|
|
111
|
-
* Android-style ripple feedback
|
|
112
|
-
*/
|
|
113
|
-
android: {
|
|
114
|
-
feedback: 'ripple',
|
|
115
|
-
strength: 'normal',
|
|
116
|
-
},
|
|
117
|
-
/**
|
|
118
|
-
* Subtle feedback for secondary actions
|
|
119
|
-
*/
|
|
120
|
-
subtle: {
|
|
121
|
-
feedback: 'opacity',
|
|
122
|
-
strength: 'subtle',
|
|
123
|
-
},
|
|
124
|
-
/**
|
|
125
|
-
* Strong feedback for primary actions
|
|
126
|
-
*/
|
|
127
|
-
strong: {
|
|
128
|
-
feedback: 'opacity',
|
|
129
|
-
strength: 'strong',
|
|
130
|
-
},
|
|
131
|
-
/**
|
|
132
|
-
* No visual feedback (use sparingly)
|
|
133
|
-
*/
|
|
134
|
-
none: {
|
|
135
|
-
feedback: 'none',
|
|
136
|
-
},
|
|
137
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Material Design 3 FAB size configurations
|
|
3
|
-
*/
|
|
4
|
-
export const FAB_SIZES = {
|
|
5
|
-
sm: {
|
|
6
|
-
width: 40,
|
|
7
|
-
height: 40,
|
|
8
|
-
borderRadius: 20, // Perfect circle
|
|
9
|
-
},
|
|
10
|
-
md: {
|
|
11
|
-
width: 56,
|
|
12
|
-
height: 56,
|
|
13
|
-
borderRadius: 28, // Perfect circle (Material Design 3 standard)
|
|
14
|
-
},
|
|
15
|
-
lg: {
|
|
16
|
-
width: 72,
|
|
17
|
-
height: 72,
|
|
18
|
-
borderRadius: 36, // Perfect circle
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Get FAB variant styles based on design tokens
|
|
23
|
-
* Note: Icon colors are handled via customColor in AtomicIcon
|
|
24
|
-
*/
|
|
25
|
-
export const getFabVariants = (tokens) => ({
|
|
26
|
-
primary: {
|
|
27
|
-
backgroundColor: tokens.colors.primary,
|
|
28
|
-
iconColor: tokens.colors.onPrimary,
|
|
29
|
-
},
|
|
30
|
-
secondary: {
|
|
31
|
-
backgroundColor: tokens.colors.secondary,
|
|
32
|
-
iconColor: tokens.colors.onSecondary,
|
|
33
|
-
},
|
|
34
|
-
surface: {
|
|
35
|
-
backgroundColor: tokens.colors.surface,
|
|
36
|
-
iconColor: tokens.colors.onSurface,
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
/**
|
|
40
|
-
* Get icon size based on FAB size
|
|
41
|
-
* Returns AtomicIconSize type ('sm', 'md', 'lg')
|
|
42
|
-
*/
|
|
43
|
-
export const getFabIconSize = (size) => {
|
|
44
|
-
switch (size) {
|
|
45
|
-
case 'sm':
|
|
46
|
-
return 'sm';
|
|
47
|
-
case 'md':
|
|
48
|
-
return 'md';
|
|
49
|
-
case 'lg':
|
|
50
|
-
return 'lg';
|
|
51
|
-
default:
|
|
52
|
-
return 'md';
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Get FAB border for depth (shadows removed per CLAUDE.md)
|
|
57
|
-
* Subtle border provides visual elevation without shadow issues
|
|
58
|
-
*/
|
|
59
|
-
export const getFabBorder = (tokens) => ({
|
|
60
|
-
borderWidth: 1,
|
|
61
|
-
borderColor: tokens.colors.outline,
|
|
62
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Filter container styles
|
|
3
|
-
* Horizontal scrollable filter chip list
|
|
4
|
-
*/
|
|
5
|
-
export const getFilterContainerStyle = () => ({
|
|
6
|
-
flexDirection: 'row',
|
|
7
|
-
paddingHorizontal: 16,
|
|
8
|
-
paddingVertical: 12,
|
|
9
|
-
gap: 8, // Space between chips
|
|
10
|
-
});
|
|
11
|
-
/**
|
|
12
|
-
* Clear all button container styles
|
|
13
|
-
*/
|
|
14
|
-
export const getClearAllContainerStyle = () => ({
|
|
15
|
-
marginLeft: 8,
|
|
16
|
-
paddingHorizontal: 12,
|
|
17
|
-
paddingVertical: 6,
|
|
18
|
-
borderRadius: 16,
|
|
19
|
-
justifyContent: 'center',
|
|
20
|
-
alignItems: 'center',
|
|
21
|
-
});
|
|
22
|
-
/**
|
|
23
|
-
* ScrollView content container style
|
|
24
|
-
*/
|
|
25
|
-
export const getScrollContentContainerStyle = () => ({
|
|
26
|
-
alignItems: 'center',
|
|
27
|
-
gap: 8,
|
|
28
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Atomic Components Export Index
|
|
3
|
-
*
|
|
4
|
-
* Centralized export file for all atomic design components
|
|
5
|
-
* Following atomic design principles with React Native implementation
|
|
6
|
-
*
|
|
7
|
-
* Generated for {{APP_NAME}} - {{CATEGORY}} category
|
|
8
|
-
* Theme: {{THEME_NAME}}
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* ```typescript
|
|
12
|
-
* import { AtomicButton, AtomicText, AtomicCard } from '@domains/design-system';
|
|
13
|
-
*
|
|
14
|
-
* // Or individual imports
|
|
15
|
-
* import { AtomicButton } from '@domains/design-system';
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
// STEP 1: Import all components first (required for default export)
|
|
19
|
-
import { AtomicButton, } from './AtomicButton';
|
|
20
|
-
import { AtomicText, } from './AtomicText';
|
|
21
|
-
import { AtomicCard, } from './AtomicCard';
|
|
22
|
-
import { AtomicInput, } from './AtomicInput';
|
|
23
|
-
import { AtomicIcon, } from './AtomicIcon';
|
|
24
|
-
import { AtomicImage, } from './AtomicImage';
|
|
25
|
-
import { AtomicSwitch, } from './AtomicSwitch';
|
|
26
|
-
import { AtomicBadge, } from './AtomicBadge';
|
|
27
|
-
import { AtomicFormError, } from './AtomicFormError';
|
|
28
|
-
import { AtomicAvatar, } from './AtomicAvatar';
|
|
29
|
-
import { AtomicChip, } from './AtomicChip';
|
|
30
|
-
import { AtomicDivider, } from './AtomicDivider';
|
|
31
|
-
import { AtomicProgress, } from './AtomicProgress';
|
|
32
|
-
import { AtomicAvatarGroup, } from './AtomicAvatarGroup';
|
|
33
|
-
import { AtomicFab, getFabVariants, } from './AtomicFab';
|
|
34
|
-
import { AtomicFilter, getFilterContainerStyle, getClearAllContainerStyle, getScrollContentContainerStyle, } from './AtomicFilter';
|
|
35
|
-
import { AtomicTouchable, TouchablePresets, getOpacityValue, normalizeHitSlop, } from './AtomicTouchable';
|
|
36
|
-
// STEP 2: Re-export all components (for named imports)
|
|
37
|
-
export { AtomicButton, };
|
|
38
|
-
// Helper types extracted from ButtonVariantConfig
|
|
39
|
-
export { AtomicText, };
|
|
40
|
-
export { AtomicCard, };
|
|
41
|
-
export { AtomicInput, };
|
|
42
|
-
export { AtomicIcon, };
|
|
43
|
-
export { AtomicImage, };
|
|
44
|
-
export { AtomicSwitch, };
|
|
45
|
-
export { AtomicBadge, };
|
|
46
|
-
export { AtomicFormError, };
|
|
47
|
-
export { AtomicAvatar, };
|
|
48
|
-
export { AtomicChip, };
|
|
49
|
-
export { AtomicDivider, };
|
|
50
|
-
export { AtomicProgress, };
|
|
51
|
-
export { AtomicAvatarGroup, };
|
|
52
|
-
export { AtomicFab, getFabVariants, };
|
|
53
|
-
export { AtomicFilter, getFilterContainerStyle, getClearAllContainerStyle, getScrollContentContainerStyle, };
|
|
54
|
-
export { AtomicTouchable, TouchablePresets, getOpacityValue, normalizeHitSlop, };
|
|
55
|
-
/**
|
|
56
|
-
* Atomic component utilities
|
|
57
|
-
*/
|
|
58
|
-
export const AtomicUtils = {
|
|
59
|
-
/**
|
|
60
|
-
* Get recommended component combinations for common UI patterns
|
|
61
|
-
*/
|
|
62
|
-
getRecommendedCombinations: () => ({
|
|
63
|
-
// Card with header
|
|
64
|
-
cardWithHeader: {
|
|
65
|
-
card: { variant: 'elevated', padding: 'lg' },
|
|
66
|
-
title: { variant: 'titleLarge', color: 'primary' },
|
|
67
|
-
description: { variant: 'bodyMedium', color: 'secondary' },
|
|
68
|
-
},
|
|
69
|
-
// Form field
|
|
70
|
-
formField: {
|
|
71
|
-
input: { variant: 'outlined', size: 'md' },
|
|
72
|
-
label: { variant: 'labelMedium', color: 'primary' },
|
|
73
|
-
helper: { variant: 'bodySmall', color: 'secondary' },
|
|
74
|
-
},
|
|
75
|
-
// Action button
|
|
76
|
-
primaryAction: {
|
|
77
|
-
button: { variant: 'primary', size: 'lg' },
|
|
78
|
-
text: { variant: 'labelLarge', color: 'onPrimary' },
|
|
79
|
-
icon: { size: 'md', color: 'onPrimary' },
|
|
80
|
-
},
|
|
81
|
-
// Secondary action
|
|
82
|
-
secondaryAction: {
|
|
83
|
-
button: { variant: 'outline', size: 'md' },
|
|
84
|
-
text: { variant: 'labelMedium', color: 'primary' },
|
|
85
|
-
icon: { size: 'sm', color: 'primary' },
|
|
86
|
-
},
|
|
87
|
-
}),
|
|
88
|
-
/**
|
|
89
|
-
* Validate component prop combinations
|
|
90
|
-
*/
|
|
91
|
-
validatePropCombination: (componentType, props) => {
|
|
92
|
-
// Add validation logic here for prop combinations
|
|
93
|
-
// This helps catch design system violations early
|
|
94
|
-
return true;
|
|
95
|
-
},
|
|
96
|
-
/**
|
|
97
|
-
* Get accessibility guidelines for component combinations
|
|
98
|
-
*/
|
|
99
|
-
getAccessibilityGuidelines: () => ({
|
|
100
|
-
button: {
|
|
101
|
-
minimumTouchTarget: 48,
|
|
102
|
-
requiresAccessibilityLabel: true,
|
|
103
|
-
supportsAccessibilityHint: true,
|
|
104
|
-
},
|
|
105
|
-
input: {
|
|
106
|
-
requiresLabel: true,
|
|
107
|
-
supportsHelperText: true,
|
|
108
|
-
requiresAccessibilityLabel: true,
|
|
109
|
-
},
|
|
110
|
-
card: {
|
|
111
|
-
supportsAccessibilityRole: true,
|
|
112
|
-
canBeAccessibilityContainer: true,
|
|
113
|
-
},
|
|
114
|
-
text: {
|
|
115
|
-
supportsAccessibilityLabel: true,
|
|
116
|
-
respectsSystemTextSize: true,
|
|
117
|
-
},
|
|
118
|
-
icon: {
|
|
119
|
-
requiresAccessibilityLabel: true,
|
|
120
|
-
supportsAccessibilityHint: false,
|
|
121
|
-
},
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
// STEP 3: Default export (now all components are available in scope)
|
|
125
|
-
const defaultExport = {
|
|
126
|
-
AtomicButton,
|
|
127
|
-
AtomicText,
|
|
128
|
-
AtomicCard,
|
|
129
|
-
AtomicInput,
|
|
130
|
-
AtomicIcon,
|
|
131
|
-
AtomicImage,
|
|
132
|
-
AtomicSwitch,
|
|
133
|
-
AtomicBadge,
|
|
134
|
-
AtomicFormError,
|
|
135
|
-
AtomicAvatar,
|
|
136
|
-
AtomicChip,
|
|
137
|
-
AtomicDivider,
|
|
138
|
-
AtomicProgress,
|
|
139
|
-
AtomicAvatarGroup,
|
|
140
|
-
AtomicFab,
|
|
141
|
-
AtomicFilter,
|
|
142
|
-
AtomicTouchable,
|
|
143
|
-
AtomicUtils,
|
|
144
|
-
};
|
|
145
|
-
export default defaultExport;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
export const useInputState = (secureTextEntry = false) => {
|
|
3
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
4
|
-
const [isPasswordVisible, setIsPasswordVisible] = useState(!secureTextEntry);
|
|
5
|
-
const togglePasswordVisibility = () => setIsPasswordVisible(!isPasswordVisible);
|
|
6
|
-
return {
|
|
7
|
-
isFocused,
|
|
8
|
-
setIsFocused,
|
|
9
|
-
isPasswordVisible,
|
|
10
|
-
togglePasswordVisibility,
|
|
11
|
-
};
|
|
12
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export const getContainerVariantStyles = (tokens) => ({
|
|
2
|
-
outlined: {
|
|
3
|
-
borderWidth: 1,
|
|
4
|
-
borderRadius: 12,
|
|
5
|
-
borderColor: tokens.colors.outline,
|
|
6
|
-
},
|
|
7
|
-
filled: {
|
|
8
|
-
backgroundColor: tokens.colors.surfaceVariant,
|
|
9
|
-
borderRadius: 12,
|
|
10
|
-
borderBottomWidth: 2,
|
|
11
|
-
borderBottomColor: tokens.colors.outline,
|
|
12
|
-
},
|
|
13
|
-
underlined: {
|
|
14
|
-
borderBottomWidth: 1,
|
|
15
|
-
borderBottomColor: tokens.colors.outline,
|
|
16
|
-
backgroundColor: 'transparent',
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
export const containerSizeStyles = {
|
|
20
|
-
sm: { height: 40, paddingHorizontal: 12, paddingVertical: 8 },
|
|
21
|
-
md: { height: 56, paddingHorizontal: 16, paddingVertical: 16 },
|
|
22
|
-
lg: { height: 64, paddingHorizontal: 24, paddingVertical: 20 },
|
|
23
|
-
};
|
|
24
|
-
export const getInputSizeStyles = (tokens) => ({
|
|
25
|
-
sm: { fontSize: tokens.typography.bodyMedium.fontSize },
|
|
26
|
-
md: { fontSize: tokens.typography.bodyLarge.fontSize },
|
|
27
|
-
lg: { fontSize: tokens.typography.bodyLarge.fontSize },
|
|
28
|
-
});
|
|
29
|
-
export const getLabelSizeStyles = (tokens) => ({
|
|
30
|
-
sm: { fontSize: tokens.typography.bodySmall.fontSize },
|
|
31
|
-
md: { fontSize: tokens.typography.bodyMedium.fontSize },
|
|
32
|
-
lg: { fontSize: tokens.typography.bodyLarge.fontSize },
|
|
33
|
-
});
|
|
34
|
-
export const getStateStyles = (tokens) => ({
|
|
35
|
-
default: {},
|
|
36
|
-
error: { borderColor: tokens.colors.error },
|
|
37
|
-
success: { borderColor: tokens.colors.success },
|
|
38
|
-
disabled: {
|
|
39
|
-
backgroundColor: tokens.colors.surfaceDisabled,
|
|
40
|
-
borderColor: tokens.colors.outlineDisabled,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
export const getFocusStyles = (tokens) => ({
|
|
44
|
-
outlined: { borderColor: tokens.colors.primary, borderWidth: 2 },
|
|
45
|
-
filled: { borderBottomColor: tokens.colors.primary, borderBottomWidth: 2 },
|
|
46
|
-
underlined: { borderBottomColor: tokens.colors.primary, borderBottomWidth: 2 },
|
|
47
|
-
});
|
|
48
|
-
export const getStateColor = (tokens, state, isFocused, isDisabled) => {
|
|
49
|
-
if (isDisabled)
|
|
50
|
-
return tokens.colors.onSurfaceDisabled;
|
|
51
|
-
if (state === 'error')
|
|
52
|
-
return tokens.colors.error;
|
|
53
|
-
if (state === 'success')
|
|
54
|
-
return tokens.colors.success;
|
|
55
|
-
if (isFocused)
|
|
56
|
-
return tokens.colors.primary;
|
|
57
|
-
return tokens.colors.surfaceVariant;
|
|
58
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|