@umituz/react-native-design-system 1.5.32 → 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 +3 -2
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.34",
|
|
4
4
|
"description": "Universal design system for React Native apps - Domain-Driven Design architecture with Material Design 3 components",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -65,12 +65,14 @@
|
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@eslint/js": "^9.0.0",
|
|
67
67
|
"@expo/vector-icons": ">=14.0.0",
|
|
68
|
+
"@gorhom/bottom-sheet": "^5.0.0",
|
|
68
69
|
"@react-native-community/datetimepicker": "^8.5.0",
|
|
69
70
|
"@react-navigation/native": "^6.0.0",
|
|
70
71
|
"@types/react": "^18.2.45",
|
|
71
72
|
"@types/react-native": "^0.73.0",
|
|
72
73
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
73
74
|
"@typescript-eslint/parser": "^7.0.0",
|
|
75
|
+
"@umituz/react-native-bottom-sheet": "*",
|
|
74
76
|
"@umituz/react-native-icon": "^1.0.1",
|
|
75
77
|
"eslint": "^9.0.0",
|
|
76
78
|
"eslint-plugin-react": "^7.33.0",
|
|
@@ -79,6 +81,7 @@
|
|
|
79
81
|
"lucide-react-native": ">=0.468.0",
|
|
80
82
|
"react": ">=18.2.0 || ^19.0.0",
|
|
81
83
|
"react-native": ">=0.74.0",
|
|
84
|
+
"react-native-gesture-handler": "^2.16.0",
|
|
82
85
|
"react-native-reanimated": "~3.10.1",
|
|
83
86
|
"react-native-safe-area-context": "^5.6.2",
|
|
84
87
|
"react-native-svg": "^15.0.0",
|
|
@@ -49,6 +49,7 @@ import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/dat
|
|
|
49
49
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
50
50
|
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
51
51
|
import { AtomicIcon, type AtomicIconColor } from './AtomicIcon';
|
|
52
|
+
// @ts-ignore - Peer dependency, types may not be available during typecheck
|
|
52
53
|
import { BottomSheetModal, useBottomSheetModal } from '@umituz/react-native-bottom-sheet';
|
|
53
54
|
import { AtomicButton } from './AtomicButton';
|
|
54
55
|
|
|
@@ -205,7 +206,7 @@ export const AtomicDatePicker: React.FC<AtomicDatePickerProps> = ({
|
|
|
205
206
|
accessibilityState={{ disabled }}
|
|
206
207
|
>
|
|
207
208
|
<AtomicIcon
|
|
208
|
-
name="
|
|
209
|
+
name="Calendar"
|
|
209
210
|
color={getIconColor()}
|
|
210
211
|
size="md"
|
|
211
212
|
/>
|
|
@@ -250,7 +251,7 @@ export const AtomicDatePicker: React.FC<AtomicDatePickerProps> = ({
|
|
|
250
251
|
/>
|
|
251
252
|
<View style={styles.buttonContainer}>
|
|
252
253
|
<AtomicButton
|
|
253
|
-
|
|
254
|
+
title="Done"
|
|
254
255
|
onPress={handleDone}
|
|
255
256
|
variant="primary"
|
|
256
257
|
style={styles.doneButton}
|
|
@@ -131,7 +131,14 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
131
131
|
},
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
-
const config = sizeConfig[size];
|
|
134
|
+
const config = sizeConfig[size] ?? sizeConfig.md;
|
|
135
|
+
|
|
136
|
+
// Ensure config is always defined with safe fallbacks
|
|
137
|
+
const fontSize = config?.fontSize ?? tokens.typography.bodyMedium?.fontSize ?? 16;
|
|
138
|
+
const iconSize = config?.iconSize ?? 20;
|
|
139
|
+
const paddingVertical = config?.paddingVertical ?? tokens.spacing?.sm ?? 8;
|
|
140
|
+
const paddingHorizontal = config?.paddingHorizontal ?? tokens.spacing?.md ?? 12;
|
|
141
|
+
const minHeight = config?.minHeight ?? 48;
|
|
135
142
|
|
|
136
143
|
// Get variant styles
|
|
137
144
|
const getVariantStyle = (): ViewStyle => {
|
|
@@ -192,10 +199,10 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
192
199
|
styles.container,
|
|
193
200
|
getVariantStyle(),
|
|
194
201
|
{
|
|
195
|
-
paddingTop:
|
|
196
|
-
paddingBottom:
|
|
197
|
-
paddingHorizontal:
|
|
198
|
-
minHeight:
|
|
202
|
+
paddingTop: paddingVertical,
|
|
203
|
+
paddingBottom: paddingVertical,
|
|
204
|
+
paddingHorizontal: paddingHorizontal,
|
|
205
|
+
minHeight: minHeight,
|
|
199
206
|
justifyContent: 'center',
|
|
200
207
|
opacity: isDisabled ? 0.5 : 1,
|
|
201
208
|
},
|
|
@@ -205,13 +212,13 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
205
212
|
const textInputStyle: StyleProp<TextStyle> = [
|
|
206
213
|
styles.input,
|
|
207
214
|
{
|
|
208
|
-
fontSize:
|
|
209
|
-
lineHeight:
|
|
215
|
+
fontSize: fontSize,
|
|
216
|
+
lineHeight: fontSize * 1.2, // Tighter lineHeight to prevent text clipping
|
|
210
217
|
color: getTextColor(),
|
|
211
218
|
paddingVertical: 0, // Remove vertical padding to prevent clipping
|
|
212
219
|
},
|
|
213
|
-
leadingIcon ? { paddingLeft:
|
|
214
|
-
(trailingIcon || showPasswordToggle) ? { paddingRight:
|
|
220
|
+
leadingIcon ? { paddingLeft: iconSize + 8 } : undefined,
|
|
221
|
+
(trailingIcon || showPasswordToggle) ? { paddingRight: iconSize + 8 } : undefined,
|
|
215
222
|
inputStyle,
|
|
216
223
|
];
|
|
217
224
|
|
|
@@ -232,7 +239,7 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
232
239
|
<View style={styles.leadingIcon}>
|
|
233
240
|
<AtomicIcon
|
|
234
241
|
name={leadingIcon}
|
|
235
|
-
customSize={
|
|
242
|
+
customSize={iconSize}
|
|
236
243
|
customColor={iconColor}
|
|
237
244
|
/>
|
|
238
245
|
</View>
|
|
@@ -268,7 +275,7 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
268
275
|
>
|
|
269
276
|
<AtomicIcon
|
|
270
277
|
name={isPasswordVisible ? "EyeOff" : "Eye"}
|
|
271
|
-
customSize={
|
|
278
|
+
customSize={iconSize}
|
|
272
279
|
customColor={iconColor}
|
|
273
280
|
/>
|
|
274
281
|
</Pressable>
|
|
@@ -282,7 +289,7 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
|
|
|
282
289
|
>
|
|
283
290
|
<AtomicIcon
|
|
284
291
|
name={trailingIcon}
|
|
285
|
-
customSize={
|
|
292
|
+
customSize={iconSize}
|
|
286
293
|
customColor={iconColor}
|
|
287
294
|
/>
|
|
288
295
|
</Pressable>
|
package/src/index.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @umituz/react-native-design-system - Public API
|
|
3
|
-
*
|
|
4
|
-
* Universal UI component library for React Native apps
|
|
5
|
-
* Domain-Driven Design (DDD) Architecture
|
|
6
|
-
*
|
|
7
|
-
* This is the SINGLE SOURCE OF TRUTH for all UI components.
|
|
8
|
-
* ALL imports from the design system MUST go through this file.
|
|
9
|
-
*
|
|
10
|
-
* Architecture:
|
|
11
|
-
* - presentation/atoms: Primitive UI components (AtomicButton, AtomicText, etc.)
|
|
12
|
-
* - presentation/molecules: Composite components (SearchBar, ListItem, etc.)
|
|
13
|
-
* - presentation/organisms: Complex patterns (ScreenLayout, AppHeader, FormContainer)
|
|
14
|
-
* - presentation/tokens: Design tokens (colors, typography, spacing, etc.)
|
|
15
|
-
* - presentation/utils: Utility functions and helpers
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
* import { AtomicButton, AtomicFilter, AtomicTouchable, SearchBar, STATIC_TOKENS } from '@umituz/react-native-design-system';
|
|
19
|
-
*/
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// ATOMS - Primitive UI Components
|
|
22
|
-
// =============================================================================
|
|
23
|
-
export { AtomicButton, } from './presentation/atoms/AtomicButton';
|
|
24
|
-
export { AtomicText, } from './presentation/atoms/AtomicText';
|
|
25
|
-
export { AtomicCard, } from './presentation/atoms/AtomicCard';
|
|
26
|
-
export { AtomicInput, } from './presentation/atoms/AtomicInput';
|
|
27
|
-
export { AtomicNumberInput, } from './presentation/atoms/AtomicNumberInput';
|
|
28
|
-
export { AtomicSwitch, } from './presentation/atoms/AtomicSwitch';
|
|
29
|
-
export { AtomicIcon, } from './presentation/atoms/AtomicIcon';
|
|
30
|
-
export { AtomicFormError, } from './presentation/atoms/AtomicFormError';
|
|
31
|
-
export { AtomicDatePicker, } from './presentation/atoms/AtomicDatePicker';
|
|
32
|
-
export { AtomicPicker, } from './presentation/atoms/AtomicPicker';
|
|
33
|
-
export { AtomicTextArea, } from './presentation/atoms/AtomicTextArea';
|
|
34
|
-
export { AtomicBadge, } from './presentation/atoms/AtomicBadge';
|
|
35
|
-
export { AtomicProgress, } from './presentation/atoms/AtomicProgress';
|
|
36
|
-
export { AtomicDivider, } from './presentation/atoms/AtomicDivider';
|
|
37
|
-
export { AtomicFab, getFabVariants, } from './presentation/atoms/AtomicFab';
|
|
38
|
-
export { AtomicFilter, getFilterContainerStyle, getClearAllContainerStyle, getScrollContentContainerStyle, } from './presentation/atoms/AtomicFilter';
|
|
39
|
-
export { AtomicTouchable, TouchablePresets, getOpacityValue, normalizeHitSlop, } from './presentation/atoms/AtomicTouchable';
|
|
40
|
-
export { AtomicSearchBar, } from './presentation/atoms/AtomicSearchBar';
|
|
41
|
-
export { AtomicSort, } from './presentation/atoms/AtomicSort';
|
|
42
|
-
// =============================================================================
|
|
43
|
-
// MOLECULES - Composite Components
|
|
44
|
-
// =============================================================================
|
|
45
|
-
export { FormField, } from './presentation/molecules/FormField';
|
|
46
|
-
export { ListItem, } from './presentation/molecules/ListItem';
|
|
47
|
-
export { SearchBar, } from './presentation/molecules/SearchBar';
|
|
48
|
-
// SettingItem moved to @domains/settings/presentation/components/SettingItem
|
|
49
|
-
// LanguageSwitcher moved to @umituz/react-native-localization
|
|
50
|
-
// Import directly: import { SettingItem } from '@domains/settings/presentation/components/SettingItem';
|
|
51
|
-
export { SectionCard, } from './presentation/molecules/SectionCard';
|
|
52
|
-
export { IconContainer, } from './presentation/molecules/IconContainer';
|
|
53
|
-
export { SectionHeader, } from './presentation/molecules/SectionHeader';
|
|
54
|
-
export { EmptyState, } from './presentation/molecules/EmptyState';
|
|
55
|
-
export { GridContainer, } from './presentation/molecules/GridContainer';
|
|
56
|
-
export { SectionContainer, } from './presentation/molecules/SectionContainer';
|
|
57
|
-
export { ScreenHeader, } from './presentation/molecules/ScreenHeader';
|
|
58
|
-
export { AtomicConfirmationModal, useConfirmationModal, } from './presentation/molecules/AtomicConfirmationModal';
|
|
59
|
-
// =============================================================================
|
|
60
|
-
// ORGANISMS - Complex Patterns
|
|
61
|
-
// =============================================================================
|
|
62
|
-
export { ScreenLayout, } from './presentation/organisms/ScreenLayout';
|
|
63
|
-
export { AppHeader, } from './presentation/organisms/AppHeader';
|
|
64
|
-
export { FormContainer, } from './presentation/organisms/FormContainer';
|
|
65
|
-
// Note: FeedbackModal moved to @domains/feedback
|
|
66
|
-
// Import from feedback domain: import { FeedbackModal } from '@domains/feedback';
|
|
67
|
-
// =============================================================================
|
|
68
|
-
// THEME-RELATED EXPORTS - Re-exported from @umituz/react-native-theme
|
|
69
|
-
// =============================================================================
|
|
70
|
-
// All tokens, colors, and theme utilities come from @umituz/react-native-theme
|
|
71
|
-
// Design system does NOT define any tokens - it only uses them from theme package
|
|
72
|
-
export {
|
|
73
|
-
// Token factory
|
|
74
|
-
createDesignTokens, STATIC_DESIGN_TOKENS, BASE_TOKENS, STATIC_TOKENS,
|
|
75
|
-
// Color utilities
|
|
76
|
-
withAlpha, lightColors, darkColors, getColorPalette, } from '@umituz/react-native-theme';
|
|
77
|
-
// Hook for dynamic theme-aware tokens (re-exported from theme package)
|
|
78
|
-
export { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
79
|
-
export { useCommonStyles, } from './presentation/tokens/commonStyles';
|
|
80
|
-
// =============================================================================
|
|
81
|
-
// UTILITIES - Helper Functions
|
|
82
|
-
// =============================================================================
|
|
83
|
-
export { IOS_HIG, ANDROID_MATERIAL, PLATFORM_CONSTANTS, isValidTouchTarget, getMinTouchTarget, } from './presentation/utils/platformConstants';
|
|
84
|
-
// =============================================================================
|
|
85
|
-
// RESPONSIVE UTILITIES - Centralized Responsive Management
|
|
86
|
-
// =============================================================================
|
|
87
|
-
export { useResponsive, useResponsiveSizes, useDeviceType, } from './presentation/hooks/useResponsive';
|
|
88
|
-
export { getScreenDimensions, isSmallPhone, isTablet, getResponsiveLogoSize, getResponsiveInputHeight, getResponsiveHorizontalPadding, getResponsiveBottomPosition, getResponsiveFABPosition, getResponsiveModalMaxHeight, getResponsiveMinModalHeight, getResponsiveIconContainerSize, getResponsiveGridColumns, getResponsiveMaxWidth, getResponsiveFontSize, isLandscape, getKeyboardBehavior, getDeviceType, getMinTouchTargetSize, getSpacingMultiplier, getOnboardingIconMarginTop, getOnboardingIconMarginBottom, getOnboardingTitleMarginBottom, getOnboardingTextPadding, getOnboardingDescriptionMarginTop, DeviceType, } from './presentation/utils/responsive';
|
|
89
|
-
// =============================================================================
|
|
90
|
-
// THEME MANAGEMENT - Global Theme Store
|
|
91
|
-
// =============================================================================
|
|
92
|
-
// Theme management moved to @umituz/react-native-theme
|
|
93
|
-
export { useDesignSystemTheme, } from '@umituz/react-native-theme';
|
|
94
|
-
// =============================================================================
|
|
95
|
-
// ICONS DOMAIN - Universal Icon System
|
|
96
|
-
// =============================================================================
|
|
97
|
-
// Icon components have been moved to @umituz/react-native-icon package.
|
|
98
|
-
// Import directly: import { Icon, IconName, IconSize, IconColor } from '@umituz/react-native-icon';
|
|
99
|
-
// Re-export for backward compatibility (deprecated - use @umituz/react-native-icon directly)
|
|
100
|
-
export { Icon, } from '@umituz/react-native-icon';
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicAvatar - Universal Avatar Component
|
|
3
|
-
*
|
|
4
|
-
* Displays user profile images with fallback to initials
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: ATOM
|
|
8
|
-
* Purpose: User profile image display
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - User profile pictures
|
|
12
|
-
* - Contact avatars
|
|
13
|
-
* - Group member avatars
|
|
14
|
-
* - Default user placeholders
|
|
15
|
-
*/
|
|
16
|
-
import React from 'react';
|
|
17
|
-
import { View, StyleSheet } from 'react-native';
|
|
18
|
-
import { AtomicImage } from './AtomicImage';
|
|
19
|
-
import { AtomicText } from './AtomicText';
|
|
20
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
21
|
-
// =============================================================================
|
|
22
|
-
// COMPONENT IMPLEMENTATION
|
|
23
|
-
// =============================================================================
|
|
24
|
-
export const AtomicAvatar = ({ source, name, size = 'md', customSize, backgroundColor, textColor, borderRadius, borderWidth = 0, borderColor, style, imageStyle, testID, }) => {
|
|
25
|
-
const tokens = useAppDesignTokens();
|
|
26
|
-
const avatarSize = customSize || tokens.avatarSizes[size];
|
|
27
|
-
const avatarRadius = borderRadius ?? avatarSize / 2;
|
|
28
|
-
// Generate initials from name
|
|
29
|
-
const getInitials = (name) => {
|
|
30
|
-
return name
|
|
31
|
-
.split(' ')
|
|
32
|
-
.map(word => word.charAt(0))
|
|
33
|
-
.join('')
|
|
34
|
-
.toUpperCase()
|
|
35
|
-
.slice(0, 2);
|
|
36
|
-
};
|
|
37
|
-
// Default colors
|
|
38
|
-
const defaultBackgroundColor = backgroundColor || tokens.colors.primary;
|
|
39
|
-
const defaultTextColor = textColor || tokens.colors.onPrimary;
|
|
40
|
-
const defaultBorderColor = borderColor || tokens.colors.border;
|
|
41
|
-
const avatarStyle = {
|
|
42
|
-
width: avatarSize,
|
|
43
|
-
height: avatarSize,
|
|
44
|
-
borderRadius: avatarRadius,
|
|
45
|
-
backgroundColor: defaultBackgroundColor,
|
|
46
|
-
borderWidth,
|
|
47
|
-
borderColor: defaultBorderColor,
|
|
48
|
-
alignItems: 'center',
|
|
49
|
-
justifyContent: 'center',
|
|
50
|
-
overflow: 'hidden',
|
|
51
|
-
};
|
|
52
|
-
const imageStyleFinal = {
|
|
53
|
-
width: avatarSize,
|
|
54
|
-
height: avatarSize,
|
|
55
|
-
borderRadius: avatarRadius,
|
|
56
|
-
};
|
|
57
|
-
// Font size based on avatar size
|
|
58
|
-
const getFontSize = (size) => {
|
|
59
|
-
if (size <= 32)
|
|
60
|
-
return 12;
|
|
61
|
-
if (size <= 48)
|
|
62
|
-
return 16;
|
|
63
|
-
if (size <= 64)
|
|
64
|
-
return 20;
|
|
65
|
-
return 24;
|
|
66
|
-
};
|
|
67
|
-
return (<View style={[avatarStyle, style]} testID={testID}>
|
|
68
|
-
{source ? (<AtomicImage source={source} style={StyleSheet.flatten([imageStyleFinal, imageStyle])} resizeMode="cover"/>) : name ? (<AtomicText type="labelLarge" color={defaultTextColor} style={{
|
|
69
|
-
fontSize: getFontSize(avatarSize),
|
|
70
|
-
fontWeight: tokens.typography.semibold,
|
|
71
|
-
}}>
|
|
72
|
-
{getInitials(name)}
|
|
73
|
-
</AtomicText>) : (<AtomicText type="labelLarge" color={defaultTextColor} style={{
|
|
74
|
-
fontSize: getFontSize(avatarSize),
|
|
75
|
-
fontWeight: tokens.typography.semibold,
|
|
76
|
-
}}>
|
|
77
|
-
?
|
|
78
|
-
</AtomicText>)}
|
|
79
|
-
</View>);
|
|
80
|
-
};
|
|
81
|
-
// =============================================================================
|
|
82
|
-
// EXPORTS
|
|
83
|
-
// =============================================================================
|
|
84
|
-
export default AtomicAvatar;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicAvatarGroup - Universal Avatar Group Component
|
|
3
|
-
*
|
|
4
|
-
* Displays multiple avatars in a group with overlap and overflow handling
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: ATOM
|
|
8
|
-
* Purpose: Multiple avatar display with group behavior
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - Team member avatars
|
|
12
|
-
* - Group chat participants
|
|
13
|
-
* - Project collaborators
|
|
14
|
-
* - Event attendees
|
|
15
|
-
* - Social connections
|
|
16
|
-
*/
|
|
17
|
-
import React from 'react';
|
|
18
|
-
import { View } from 'react-native';
|
|
19
|
-
import { AtomicAvatar } from './AtomicAvatar';
|
|
20
|
-
import { AtomicText } from './AtomicText';
|
|
21
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
22
|
-
// =============================================================================
|
|
23
|
-
// COMPONENT IMPLEMENTATION
|
|
24
|
-
// =============================================================================
|
|
25
|
-
export const AtomicAvatarGroup = ({ avatars, maxVisible = 3, size = 'md', customSize, spacing = -8, showOverflow = true, overflowBackgroundColor, overflowTextColor, borderWidth = 2, borderColor, style, testID, }) => {
|
|
26
|
-
const tokens = useAppDesignTokens();
|
|
27
|
-
// Calculate visible avatars and overflow count
|
|
28
|
-
const visibleAvatars = avatars.slice(0, maxVisible);
|
|
29
|
-
const overflowCount = avatars.length - maxVisible;
|
|
30
|
-
// Size mapping for overflow text
|
|
31
|
-
const sizeMap = {
|
|
32
|
-
xs: 10,
|
|
33
|
-
sm: 12,
|
|
34
|
-
md: 14,
|
|
35
|
-
lg: 16,
|
|
36
|
-
xl: 18,
|
|
37
|
-
xxl: 20,
|
|
38
|
-
};
|
|
39
|
-
const textSize = sizeMap[size];
|
|
40
|
-
// Default colors for overflow
|
|
41
|
-
const defaultOverflowBackground = overflowBackgroundColor || tokens.colors.surfaceVariant;
|
|
42
|
-
const defaultOverflowText = overflowTextColor || tokens.colors.textPrimary;
|
|
43
|
-
const containerStyle = {
|
|
44
|
-
flexDirection: 'row',
|
|
45
|
-
alignItems: 'center',
|
|
46
|
-
};
|
|
47
|
-
const avatarStyle = {
|
|
48
|
-
marginLeft: spacing,
|
|
49
|
-
borderWidth,
|
|
50
|
-
borderColor: borderColor || tokens.colors.surface,
|
|
51
|
-
};
|
|
52
|
-
return (<View style={[containerStyle, style]} testID={testID}>
|
|
53
|
-
{visibleAvatars.map((avatar, index) => (<AtomicAvatar key={avatar.id} source={avatar.source} name={avatar.name} size={size} customSize={customSize} backgroundColor={avatar.backgroundColor} textColor={avatar.textColor} borderWidth={borderWidth} borderColor={borderColor} style={[
|
|
54
|
-
avatarStyle,
|
|
55
|
-
...(index === 0 ? [{ marginLeft: 0 }] : []), // First avatar has no left margin
|
|
56
|
-
]}/>))}
|
|
57
|
-
{showOverflow && overflowCount > 0 && (<View style={[
|
|
58
|
-
{
|
|
59
|
-
alignItems: 'center',
|
|
60
|
-
justifyContent: 'center',
|
|
61
|
-
width: customSize || 40,
|
|
62
|
-
height: customSize || 40,
|
|
63
|
-
borderRadius: (customSize || 40) / 2,
|
|
64
|
-
backgroundColor: defaultOverflowBackground,
|
|
65
|
-
borderWidth,
|
|
66
|
-
borderColor: borderColor || tokens.colors.surface,
|
|
67
|
-
marginLeft: spacing,
|
|
68
|
-
},
|
|
69
|
-
]}>
|
|
70
|
-
<AtomicText type="labelMedium" color={defaultOverflowText} style={{
|
|
71
|
-
fontWeight: tokens.typography.semibold,
|
|
72
|
-
fontSize: textSize,
|
|
73
|
-
}}>
|
|
74
|
-
+{overflowCount}
|
|
75
|
-
</AtomicText>
|
|
76
|
-
</View>)}
|
|
77
|
-
</View>);
|
|
78
|
-
};
|
|
79
|
-
// =============================================================================
|
|
80
|
-
// EXPORTS
|
|
81
|
-
// =============================================================================
|
|
82
|
-
export default AtomicAvatarGroup;
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicBadge - Universal Badge Component
|
|
3
|
-
*
|
|
4
|
-
* Provides consistent badge/notification count display
|
|
5
|
-
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
6
|
-
*
|
|
7
|
-
* Atomic Design Level: ATOM
|
|
8
|
-
* Purpose: Display counts, notifications, status indicators
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - Notification counts
|
|
12
|
-
* - Cart item counts
|
|
13
|
-
* - Status indicators
|
|
14
|
-
* - Achievement badges
|
|
15
|
-
*/
|
|
16
|
-
import React from 'react';
|
|
17
|
-
import { View, StyleSheet } from 'react-native';
|
|
18
|
-
import { AtomicText } from './AtomicText';
|
|
19
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// SIZE CONFIGURATION
|
|
22
|
-
// =============================================================================
|
|
23
|
-
const getSizeConfig = (tokens) => ({
|
|
24
|
-
xs: {
|
|
25
|
-
minHeight: tokens.spacing.sm,
|
|
26
|
-
paddingHorizontal: tokens.spacing.xs,
|
|
27
|
-
fontSize: tokens.typography.labelSmall.fontSize,
|
|
28
|
-
borderRadius: tokens.borders.radius.sm,
|
|
29
|
-
},
|
|
30
|
-
sm: {
|
|
31
|
-
minHeight: tokens.spacing.md,
|
|
32
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
33
|
-
fontSize: tokens.typography.bodySmall.fontSize,
|
|
34
|
-
borderRadius: tokens.borders.radius.md,
|
|
35
|
-
},
|
|
36
|
-
md: {
|
|
37
|
-
minHeight: tokens.spacing.lg,
|
|
38
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
39
|
-
fontSize: tokens.typography.bodyMedium.fontSize,
|
|
40
|
-
borderRadius: tokens.borders.radius.md,
|
|
41
|
-
},
|
|
42
|
-
lg: {
|
|
43
|
-
minHeight: tokens.spacing.xl,
|
|
44
|
-
paddingHorizontal: tokens.spacing.md,
|
|
45
|
-
fontSize: tokens.typography.bodyLarge.fontSize,
|
|
46
|
-
borderRadius: tokens.borders.radius.lg,
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
// =============================================================================
|
|
50
|
-
// COMPONENT IMPLEMENTATION
|
|
51
|
-
// =============================================================================
|
|
52
|
-
export const AtomicBadge = ({ children, size = 'md', variant = 'primary', shape = 'circle', max, showZero = false, style, textStyle, minWidth, maxWidth, }) => {
|
|
53
|
-
const tokens = useAppDesignTokens();
|
|
54
|
-
const styles = getStyles(tokens);
|
|
55
|
-
const sizeConfig = getSizeConfig(tokens)[size];
|
|
56
|
-
const colors = getVariantColors(tokens, variant);
|
|
57
|
-
const borderRadius = getBorderRadius(shape, sizeConfig.borderRadius, tokens);
|
|
58
|
-
// Handle max value display
|
|
59
|
-
const displayValue = React.useMemo(() => {
|
|
60
|
-
if (typeof children === 'number') {
|
|
61
|
-
if (max && children > max) {
|
|
62
|
-
return `${max}+`;
|
|
63
|
-
}
|
|
64
|
-
return children.toString();
|
|
65
|
-
}
|
|
66
|
-
return children;
|
|
67
|
-
}, [children, max]);
|
|
68
|
-
// Don't render if count is 0 and showZero is false
|
|
69
|
-
if (typeof children === 'number' && children === 0 && !showZero) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
const containerStyle = [
|
|
73
|
-
styles.container,
|
|
74
|
-
{
|
|
75
|
-
minHeight: sizeConfig.minHeight,
|
|
76
|
-
paddingHorizontal: sizeConfig.paddingHorizontal,
|
|
77
|
-
borderRadius,
|
|
78
|
-
backgroundColor: colors.background,
|
|
79
|
-
minWidth: minWidth || sizeConfig.minHeight,
|
|
80
|
-
maxWidth,
|
|
81
|
-
},
|
|
82
|
-
style,
|
|
83
|
-
];
|
|
84
|
-
const textStyleFinal = StyleSheet.flatten([
|
|
85
|
-
styles.text,
|
|
86
|
-
{
|
|
87
|
-
fontSize: sizeConfig.fontSize,
|
|
88
|
-
},
|
|
89
|
-
textStyle,
|
|
90
|
-
]);
|
|
91
|
-
return (<View style={containerStyle}>
|
|
92
|
-
<AtomicText type="bodySmall" color={colors.text} style={textStyleFinal} numberOfLines={1}>
|
|
93
|
-
{displayValue}
|
|
94
|
-
</AtomicText>
|
|
95
|
-
</View>);
|
|
96
|
-
};
|
|
97
|
-
// =============================================================================
|
|
98
|
-
// HELPER FUNCTIONS
|
|
99
|
-
// =============================================================================
|
|
100
|
-
const getVariantColors = (tokens, variant) => {
|
|
101
|
-
switch (variant) {
|
|
102
|
-
case 'primary':
|
|
103
|
-
return {
|
|
104
|
-
background: tokens.colors.primary,
|
|
105
|
-
text: tokens.colors.textInverse,
|
|
106
|
-
};
|
|
107
|
-
case 'secondary':
|
|
108
|
-
return {
|
|
109
|
-
background: tokens.colors.secondary,
|
|
110
|
-
text: tokens.colors.textInverse,
|
|
111
|
-
};
|
|
112
|
-
case 'success':
|
|
113
|
-
return {
|
|
114
|
-
background: tokens.colors.success,
|
|
115
|
-
text: tokens.colors.textInverse,
|
|
116
|
-
};
|
|
117
|
-
case 'warning':
|
|
118
|
-
return {
|
|
119
|
-
background: tokens.colors.warning,
|
|
120
|
-
text: tokens.colors.textInverse,
|
|
121
|
-
};
|
|
122
|
-
case 'error':
|
|
123
|
-
return {
|
|
124
|
-
background: tokens.colors.error,
|
|
125
|
-
text: tokens.colors.textInverse,
|
|
126
|
-
};
|
|
127
|
-
case 'info':
|
|
128
|
-
return {
|
|
129
|
-
background: tokens.colors.info,
|
|
130
|
-
text: tokens.colors.textInverse,
|
|
131
|
-
};
|
|
132
|
-
default:
|
|
133
|
-
return {
|
|
134
|
-
background: tokens.colors.primary,
|
|
135
|
-
text: tokens.colors.textInverse,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
const getBorderRadius = (shape, defaultRadius, tokens) => {
|
|
140
|
-
switch (shape) {
|
|
141
|
-
case 'circle':
|
|
142
|
-
return tokens.borders.radius.full; // Very large radius for circle
|
|
143
|
-
case 'square':
|
|
144
|
-
return tokens.borders.radius.sm;
|
|
145
|
-
case 'rounded':
|
|
146
|
-
default:
|
|
147
|
-
return defaultRadius;
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
// =============================================================================
|
|
151
|
-
// STYLES
|
|
152
|
-
// =============================================================================
|
|
153
|
-
const getStyles = (tokens) => StyleSheet.create({
|
|
154
|
-
container: {
|
|
155
|
-
justifyContent: 'center',
|
|
156
|
-
alignItems: 'center',
|
|
157
|
-
alignSelf: 'flex-start',
|
|
158
|
-
},
|
|
159
|
-
text: {
|
|
160
|
-
fontWeight: tokens.typography.semibold,
|
|
161
|
-
textAlign: 'center',
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
// =============================================================================
|
|
165
|
-
// EXPORTS
|
|
166
|
-
// =============================================================================
|
|
167
|
-
export default AtomicBadge;
|