@umituz/react-native-design-system 1.5.33 → 1.5.35

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.
Files changed (67) hide show
  1. package/package.json +4 -1
  2. package/src/presentation/atoms/AtomicDatePicker.tsx +7 -3
  3. package/src/presentation/atoms/AtomicInput.tsx +19 -12
  4. package/src/index.js +0 -100
  5. package/src/presentation/atoms/AtomicAvatar.js +0 -84
  6. package/src/presentation/atoms/AtomicAvatarGroup.js +0 -82
  7. package/src/presentation/atoms/AtomicBadge.js +0 -167
  8. package/src/presentation/atoms/AtomicButton.js +0 -171
  9. package/src/presentation/atoms/AtomicCard.js +0 -69
  10. package/src/presentation/atoms/AtomicChip.js +0 -130
  11. package/src/presentation/atoms/AtomicDatePicker.js +0 -245
  12. package/src/presentation/atoms/AtomicDivider.js +0 -57
  13. package/src/presentation/atoms/AtomicFab.js +0 -67
  14. package/src/presentation/atoms/AtomicFilter.js +0 -103
  15. package/src/presentation/atoms/AtomicFormError.js +0 -63
  16. package/src/presentation/atoms/AtomicIcon.js +0 -29
  17. package/src/presentation/atoms/AtomicImage.js +0 -91
  18. package/src/presentation/atoms/AtomicInput.js +0 -201
  19. package/src/presentation/atoms/AtomicNumberInput.js +0 -124
  20. package/src/presentation/atoms/AtomicPicker.js +0 -298
  21. package/src/presentation/atoms/AtomicProgress.js +0 -79
  22. package/src/presentation/atoms/AtomicSearchBar.js +0 -45
  23. package/src/presentation/atoms/AtomicSort.js +0 -76
  24. package/src/presentation/atoms/AtomicSwitch.js +0 -103
  25. package/src/presentation/atoms/AtomicText.js +0 -22
  26. package/src/presentation/atoms/AtomicTextArea.js +0 -195
  27. package/src/presentation/atoms/AtomicTouchable.js +0 -137
  28. package/src/presentation/atoms/fab/styles/fabStyles.js +0 -62
  29. package/src/presentation/atoms/fab/types/index.js +0 -1
  30. package/src/presentation/atoms/filter/styles/filterStyles.js +0 -28
  31. package/src/presentation/atoms/filter/types/index.js +0 -1
  32. package/src/presentation/atoms/index.js +0 -145
  33. package/src/presentation/atoms/input/hooks/useInputState.js +0 -12
  34. package/src/presentation/atoms/input/styles/inputStyles.js +0 -58
  35. package/src/presentation/atoms/input/types/index.js +0 -1
  36. package/src/presentation/atoms/picker/styles/pickerStyles.js +0 -176
  37. package/src/presentation/atoms/picker/types/index.js +0 -1
  38. package/src/presentation/atoms/touchable/styles/touchableStyles.js +0 -53
  39. package/src/presentation/atoms/touchable/types/index.js +0 -1
  40. package/src/presentation/hooks/useResponsive.js +0 -81
  41. package/src/presentation/molecules/AtomicConfirmationModal.js +0 -153
  42. package/src/presentation/molecules/EmptyState.js +0 -67
  43. package/src/presentation/molecules/FormField.js +0 -75
  44. package/src/presentation/molecules/GridContainer.js +0 -76
  45. package/src/presentation/molecules/IconContainer.js +0 -59
  46. package/src/presentation/molecules/ListItem.js +0 -23
  47. package/src/presentation/molecules/ScreenHeader.js +0 -93
  48. package/src/presentation/molecules/SearchBar.js +0 -46
  49. package/src/presentation/molecules/SectionCard.js +0 -46
  50. package/src/presentation/molecules/SectionContainer.js +0 -63
  51. package/src/presentation/molecules/SectionHeader.js +0 -72
  52. package/src/presentation/molecules/confirmation-modal/styles/confirmationModalStyles.js +0 -114
  53. package/src/presentation/molecules/confirmation-modal/types/index.js +0 -6
  54. package/src/presentation/molecules/index.js +0 -16
  55. package/src/presentation/molecules/listitem/styles/listItemStyles.js +0 -14
  56. package/src/presentation/molecules/listitem/types/index.js +0 -1
  57. package/src/presentation/organisms/AppHeader.js +0 -77
  58. package/src/presentation/organisms/FormContainer.js +0 -126
  59. package/src/presentation/organisms/ScreenLayout.js +0 -68
  60. package/src/presentation/organisms/index.js +0 -13
  61. package/src/presentation/tokens/commonStyles.js +0 -219
  62. package/src/presentation/utils/platformConstants.js +0 -113
  63. package/src/presentation/utils/responsive.js +0 -451
  64. package/src/presentation/utils/variants/compound.js +0 -15
  65. package/src/presentation/utils/variants/core.js +0 -22
  66. package/src/presentation/utils/variants/helpers.js +0 -9
  67. package/src/presentation/utils/variants.js +0 -3
@@ -1,171 +0,0 @@
1
- import React from 'react';
2
- import { StyleSheet, TouchableOpacity, View } from 'react-native';
3
- import { AtomicText } from './AtomicText';
4
- import { Icon } from '@umituz/react-native-icon';
5
- import { useAppDesignTokens } from '@umituz/react-native-theme';
6
- export const AtomicButton = ({ title, children, onPress, variant = 'primary', size = 'md', disabled = false, icon, fullWidth = false, style, textStyle, testID, }) => {
7
- const tokens = useAppDesignTokens();
8
- const handlePress = () => {
9
- if (!disabled) {
10
- onPress();
11
- }
12
- };
13
- // Size configurations
14
- const sizeConfig = {
15
- sm: {
16
- paddingVertical: tokens.spacing.xs,
17
- paddingHorizontal: tokens.spacing.sm,
18
- fontSize: tokens.typography.bodySmall.fontSize,
19
- iconSize: 16,
20
- minHeight: 32,
21
- },
22
- md: {
23
- paddingVertical: tokens.spacing.sm,
24
- paddingHorizontal: tokens.spacing.md,
25
- fontSize: tokens.typography.bodyMedium.fontSize,
26
- iconSize: 20,
27
- minHeight: 44,
28
- },
29
- lg: {
30
- paddingVertical: tokens.spacing.md,
31
- paddingHorizontal: tokens.spacing.lg,
32
- fontSize: tokens.typography.bodyLarge.fontSize,
33
- iconSize: 24,
34
- minHeight: 52,
35
- },
36
- };
37
- const config = sizeConfig[size];
38
- // Variant styles
39
- const getVariantStyles = () => {
40
- const baseStyle = {
41
- backgroundColor: tokens.colors.primary,
42
- borderWidth: 0,
43
- };
44
- const baseTextStyle = {
45
- color: tokens.colors.textInverse,
46
- };
47
- switch (variant) {
48
- case 'primary':
49
- return {
50
- container: {
51
- ...baseStyle,
52
- backgroundColor: tokens.colors.primary,
53
- },
54
- text: {
55
- ...baseTextStyle,
56
- color: tokens.colors.textInverse,
57
- },
58
- };
59
- case 'secondary':
60
- return {
61
- container: {
62
- ...baseStyle,
63
- backgroundColor: tokens.colors.surfaceSecondary,
64
- },
65
- text: {
66
- ...baseTextStyle,
67
- color: tokens.colors.textPrimary,
68
- },
69
- };
70
- case 'outline':
71
- return {
72
- container: {
73
- ...baseStyle,
74
- backgroundColor: 'transparent',
75
- borderWidth: 1,
76
- borderColor: tokens.colors.border,
77
- },
78
- text: {
79
- ...baseTextStyle,
80
- color: tokens.colors.textPrimary,
81
- },
82
- };
83
- case 'text':
84
- return {
85
- container: {
86
- ...baseStyle,
87
- backgroundColor: 'transparent',
88
- },
89
- text: {
90
- ...baseTextStyle,
91
- color: tokens.colors.primary,
92
- },
93
- };
94
- case 'danger':
95
- return {
96
- container: {
97
- ...baseStyle,
98
- backgroundColor: tokens.colors.error,
99
- },
100
- text: {
101
- ...baseTextStyle,
102
- color: tokens.colors.textInverse,
103
- },
104
- };
105
- default:
106
- return {
107
- container: baseStyle,
108
- text: baseTextStyle,
109
- };
110
- }
111
- };
112
- const variantStyles = getVariantStyles();
113
- const containerStyle = [
114
- styles.button,
115
- {
116
- paddingVertical: config.paddingVertical,
117
- paddingHorizontal: config.paddingHorizontal,
118
- minHeight: config.minHeight,
119
- borderRadius: tokens.borders.radius.md,
120
- },
121
- variantStyles.container,
122
- fullWidth ? styles.fullWidth : undefined,
123
- disabled ? styles.disabled : undefined,
124
- style,
125
- ];
126
- const buttonTextStyle = [
127
- {
128
- fontSize: config.fontSize,
129
- fontWeight: '600',
130
- },
131
- variantStyles.text,
132
- disabled ? styles.disabledText : undefined,
133
- textStyle,
134
- ];
135
- const buttonText = title || children;
136
- const showIcon = icon;
137
- const iconColor = variantStyles.text.color;
138
- return (<TouchableOpacity style={containerStyle} onPress={handlePress} activeOpacity={0.8} disabled={disabled} testID={testID}>
139
- <View style={styles.content}>
140
- {showIcon ? (<Icon name={icon} customSize={config.iconSize} customColor={typeof iconColor === 'string' ? iconColor : undefined} style={styles.icon}/>) : null}
141
-
142
- <AtomicText style={buttonTextStyle}>
143
- {buttonText}
144
- </AtomicText>
145
- </View>
146
- </TouchableOpacity>);
147
- };
148
- const styles = StyleSheet.create({
149
- button: {
150
- alignItems: 'center',
151
- justifyContent: 'center',
152
- flexDirection: 'row',
153
- },
154
- content: {
155
- flexDirection: 'row',
156
- alignItems: 'center',
157
- justifyContent: 'center',
158
- },
159
- fullWidth: {
160
- width: '100%',
161
- },
162
- disabled: {
163
- opacity: 0.5,
164
- },
165
- disabledText: {
166
- opacity: 0.7,
167
- },
168
- icon: {
169
- marginRight: 8,
170
- },
171
- });
@@ -1,69 +0,0 @@
1
- import React from 'react';
2
- import { View, Pressable } from 'react-native';
3
- import { useAppDesignTokens } from '@umituz/react-native-theme';
4
- export const AtomicCard = ({ variant = 'elevated', padding = 'md', onPress, disabled = false, style, children, testID, }) => {
5
- const tokens = useAppDesignTokens();
6
- const handlePress = () => {
7
- if (onPress && !disabled) {
8
- onPress();
9
- }
10
- };
11
- // Map padding to token values
12
- const getPaddingValue = () => {
13
- const paddingMap = {
14
- none: 0,
15
- sm: tokens.spacing.sm,
16
- md: tokens.spacing.md,
17
- lg: tokens.spacing.lg,
18
- xl: tokens.spacing.xl,
19
- };
20
- return paddingMap[padding];
21
- };
22
- // Get variant styles
23
- const getVariantStyle = () => {
24
- const baseStyle = {
25
- backgroundColor: tokens.colors.surface,
26
- borderRadius: tokens.borders.radius.md,
27
- };
28
- switch (variant) {
29
- case 'elevated':
30
- return {
31
- ...baseStyle,
32
- borderWidth: 1,
33
- borderColor: tokens.colors.border,
34
- };
35
- case 'outlined':
36
- return {
37
- ...baseStyle,
38
- borderWidth: 1,
39
- borderColor: tokens.colors.border,
40
- };
41
- case 'flat':
42
- return {
43
- ...baseStyle,
44
- borderWidth: 0,
45
- };
46
- default:
47
- return baseStyle;
48
- }
49
- };
50
- const cardStyle = [
51
- getVariantStyle(),
52
- {
53
- padding: getPaddingValue(),
54
- opacity: disabled ? 0.5 : 1,
55
- },
56
- style,
57
- ];
58
- const cardContent = (<View style={cardStyle} testID={testID}>
59
- {children}
60
- </View>);
61
- // If onPress provided, wrap with pressable
62
- if (onPress && !disabled) {
63
- return (<Pressable onPress={handlePress}>
64
- {cardContent}
65
- </Pressable>);
66
- }
67
- // Otherwise just return static card
68
- return cardContent;
69
- };
@@ -1,130 +0,0 @@
1
- /**
2
- * AtomicChip - Universal Chip/Tag Component
3
- *
4
- * Displays small tags, labels, or status indicators
5
- * Theme: {{THEME_NAME}} ({{CATEGORY}} category)
6
- *
7
- * Atomic Design Level: ATOM
8
- * Purpose: Tag and label display
9
- *
10
- * Usage:
11
- * - Category tags
12
- * - Status indicators
13
- * - Filter chips
14
- * - Skill labels
15
- * - Badge displays
16
- */
17
- import React from 'react';
18
- import { View, TouchableOpacity } from 'react-native';
19
- import { AtomicText } from './AtomicText';
20
- import { AtomicIcon } from './AtomicIcon';
21
- import { useAppDesignTokens } from '@umituz/react-native-theme';
22
- // =============================================================================
23
- // COMPONENT IMPLEMENTATION
24
- // =============================================================================
25
- export const AtomicChip = ({ children, variant = 'filled', size = 'md', color = 'primary', backgroundColor, textColor, borderColor, leadingIcon, trailingIcon, clickable = false, onPress, selected = false, disabled = false, style, testID, }) => {
26
- const tokens = useAppDesignTokens();
27
- // Size mapping
28
- const sizeMap = {
29
- sm: {
30
- paddingHorizontal: tokens.spacing.sm,
31
- paddingVertical: tokens.spacing.xs,
32
- fontSize: tokens.typography.bodySmall.fontSize,
33
- iconSize: 'xs'
34
- },
35
- md: {
36
- paddingHorizontal: tokens.spacing.md,
37
- paddingVertical: tokens.spacing.sm,
38
- fontSize: tokens.typography.bodyMedium.fontSize,
39
- iconSize: 'sm'
40
- },
41
- lg: {
42
- paddingHorizontal: tokens.spacing.md,
43
- paddingVertical: tokens.spacing.sm,
44
- fontSize: tokens.typography.bodyLarge.fontSize,
45
- iconSize: 'sm'
46
- },
47
- };
48
- const sizeConfig = sizeMap[size];
49
- // Color mapping
50
- const colorMap = {
51
- primary: {
52
- filled: { bg: tokens.colors.primary, text: tokens.colors.onPrimary, border: tokens.colors.primary },
53
- outlined: { bg: 'transparent', text: tokens.colors.primary, border: tokens.colors.primary },
54
- soft: { bg: tokens.colors.primaryContainer, text: tokens.colors.onPrimaryContainer, border: 'transparent' },
55
- },
56
- secondary: {
57
- filled: { bg: tokens.colors.secondary, text: tokens.colors.onSecondary, border: tokens.colors.secondary },
58
- outlined: { bg: 'transparent', text: tokens.colors.secondary, border: tokens.colors.secondary },
59
- soft: { bg: tokens.colors.secondaryContainer, text: tokens.colors.onSecondaryContainer, border: 'transparent' },
60
- },
61
- success: {
62
- filled: { bg: tokens.colors.success, text: tokens.colors.onSuccess, border: tokens.colors.success },
63
- outlined: { bg: 'transparent', text: tokens.colors.success, border: tokens.colors.success },
64
- soft: { bg: tokens.colors.successContainer, text: tokens.colors.onSuccessContainer, border: 'transparent' },
65
- },
66
- warning: {
67
- filled: { bg: tokens.colors.warning, text: tokens.colors.onWarning, border: tokens.colors.warning },
68
- outlined: { bg: 'transparent', text: tokens.colors.warning, border: tokens.colors.warning },
69
- soft: { bg: tokens.colors.warningContainer, text: tokens.colors.onWarningContainer, border: 'transparent' },
70
- },
71
- error: {
72
- filled: { bg: tokens.colors.error, text: tokens.colors.onError, border: tokens.colors.error },
73
- outlined: { bg: 'transparent', text: tokens.colors.error, border: tokens.colors.error },
74
- soft: { bg: tokens.colors.errorContainer, text: tokens.colors.onErrorContainer, border: 'transparent' },
75
- },
76
- info: {
77
- filled: { bg: tokens.colors.info, text: tokens.colors.onInfo, border: tokens.colors.info },
78
- outlined: { bg: 'transparent', text: tokens.colors.info, border: tokens.colors.info },
79
- soft: { bg: tokens.colors.infoContainer, text: tokens.colors.onInfoContainer, border: 'transparent' },
80
- },
81
- };
82
- const colorConfig = colorMap[color][variant];
83
- // Apply custom colors if provided
84
- const finalBackgroundColor = backgroundColor || colorConfig.bg;
85
- const finalTextColor = textColor || colorConfig.text;
86
- const finalBorderColor = borderColor || colorConfig.border;
87
- // Handle disabled state
88
- const isDisabled = disabled || (!clickable && !onPress);
89
- const opacity = isDisabled ? 0.5 : 1;
90
- // Handle selected state
91
- const selectedStyle = selected ? {
92
- borderWidth: tokens.borders.width.medium,
93
- borderColor: tokens.colors.primary,
94
- } : {};
95
- const chipStyle = {
96
- flexDirection: 'row',
97
- alignItems: 'center',
98
- justifyContent: 'center',
99
- paddingHorizontal: sizeConfig.paddingHorizontal,
100
- paddingVertical: sizeConfig.paddingVertical,
101
- backgroundColor: finalBackgroundColor,
102
- borderRadius: tokens.borders.radius.xl,
103
- borderWidth: variant === 'outlined' ? 1 : 0,
104
- borderColor: finalBorderColor,
105
- opacity,
106
- ...selectedStyle,
107
- };
108
- const textStyle = {
109
- fontSize: sizeConfig.fontSize,
110
- fontWeight: tokens.typography.medium,
111
- };
112
- const iconColor = finalTextColor;
113
- const content = (<View style={[chipStyle, style]} testID={testID}>
114
- {leadingIcon && (<AtomicIcon name={leadingIcon} size={sizeConfig.iconSize} customColor={iconColor} style={{ marginRight: tokens.spacing.xs }}/>)}
115
- <AtomicText type="labelMedium" color={finalTextColor} style={textStyle}>
116
- {children}
117
- </AtomicText>
118
- {trailingIcon && (<AtomicIcon name={trailingIcon} size={sizeConfig.iconSize} customColor={iconColor} style={{ marginLeft: tokens.spacing.xs }}/>)}
119
- </View>);
120
- if (clickable && onPress && !disabled) {
121
- return (<TouchableOpacity onPress={onPress} activeOpacity={0.7}>
122
- {content}
123
- </TouchableOpacity>);
124
- }
125
- return content;
126
- };
127
- // =============================================================================
128
- // EXPORTS
129
- // =============================================================================
130
- export default AtomicChip;
@@ -1,245 +0,0 @@
1
- /**
2
- * AtomicDatePicker Component
3
- *
4
- * A reusable date picker component that wraps the native date picker
5
- * with consistent styling and behavior across platforms.
6
- *
7
- * Features:
8
- * - Platform-specific native pickers (iOS wheel, Android dialog)
9
- * - Consistent styling with design tokens
10
- * - Locale-aware date/time formatting (native Date methods)
11
- * - Timezone-aware (respects device timezone)
12
- * - Automatic language integration (native locale support)
13
- * - Optional label and error states
14
- * - Minimum and maximum date constraints
15
- * - Disabled state support
16
- * - Theme-aware styling
17
- * - Proper keyboard avoidance on iOS
18
- *
19
- * Usage:
20
- * ```tsx
21
- * const [selectedDate, setSelectedDate] = useState(new Date());
22
- *
23
- * <AtomicDatePicker
24
- * value={selectedDate}
25
- * onChange={setSelectedDate}
26
- * label="Birth Date"
27
- * minimumDate={new Date(1900, 0, 1)}
28
- * maximumDate={new Date()}
29
- * />
30
- * ```
31
- *
32
- * Platform Behavior:
33
- * - iOS: Opens modal with spinner wheel, requires "Done" button
34
- * - Android: Opens native dialog, auto-closes on selection
35
- *
36
- * @module AtomicDatePicker
37
- */
38
- import React, { useState } from 'react';
39
- import { View, Text, TouchableOpacity, StyleSheet, Modal, useWindowDimensions, } from 'react-native';
40
- import DateTimePicker from '@react-native-community/datetimepicker';
41
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
42
- import { useAppDesignTokens } from '@umituz/react-native-theme';
43
- import { useResponsive } from '../hooks/useResponsive';
44
- import { AtomicIcon } from './AtomicIcon';
45
- /**
46
- * AtomicDatePicker - Universal date/time picker component
47
- *
48
- * Wraps @react-native-community/datetimepicker with:
49
- * - Theme integration
50
- * - Platform-specific modal handling
51
- * - Error states
52
- * - Disabled states
53
- * - Responsive sizing
54
- */
55
- export const AtomicDatePicker = ({ value, onChange, label, error, disabled = false, minimumDate, maximumDate, mode = 'date', placeholder = 'Select date', testID, }) => {
56
- const tokens = useAppDesignTokens();
57
- const { height } = useWindowDimensions();
58
- const insets = useSafeAreaInsets();
59
- const { isTabletDevice } = useResponsive();
60
- const [show, setShow] = useState(false);
61
- /**
62
- * Handle date/time change
63
- * Universal handler that works across all platforms
64
- * Note: event.type can be 'set', 'dismissed', or 'neutralButtonPressed'
65
- */
66
- const handleChange = (event, selectedDate) => {
67
- // Close picker when user confirms or dismisses
68
- // iOS: Stays open until "Done" button (handled separately)
69
- // Android/Web: Auto-closes on selection
70
- if (event.type === 'set' || event.type === 'dismissed') {
71
- setShow(false);
72
- }
73
- // Update value only if date was selected (not dismissed)
74
- if (event.type === 'set' && selectedDate) {
75
- onChange(selectedDate);
76
- }
77
- };
78
- /**
79
- * Format date based on mode
80
- * Uses native Date formatting (locale-aware)
81
- */
82
- const formatDate = (date) => {
83
- if (mode === 'time') {
84
- // Format time only
85
- return date.toLocaleTimeString([], {
86
- hour: '2-digit',
87
- minute: '2-digit'
88
- });
89
- }
90
- if (mode === 'datetime') {
91
- // Format date + time
92
- const dateStr = date.toLocaleDateString([], {
93
- year: 'numeric',
94
- month: 'short',
95
- day: 'numeric',
96
- });
97
- const timeStr = date.toLocaleTimeString([], {
98
- hour: '2-digit',
99
- minute: '2-digit'
100
- });
101
- return `${dateStr} ${timeStr}`;
102
- }
103
- // Format date only
104
- return date.toLocaleDateString([], {
105
- year: 'numeric',
106
- month: 'long',
107
- day: 'numeric',
108
- });
109
- };
110
- /**
111
- * Determine icon color based on state
112
- */
113
- const getIconColor = () => {
114
- if (disabled)
115
- return 'secondary';
116
- if (error)
117
- return 'error';
118
- return 'primary';
119
- };
120
- const styles = getStyles(tokens, height, insets);
121
- return (<View style={styles.container} testID={testID}>
122
- {label && (<Text style={styles.label} testID={testID ? `${testID}-label` : undefined}>
123
- {label}
124
- </Text>)}
125
-
126
- <TouchableOpacity style={[
127
- styles.button,
128
- error ? styles.buttonError : undefined,
129
- disabled ? styles.buttonDisabled : undefined,
130
- ]} onPress={() => !disabled && setShow(true)} disabled={disabled} testID={testID ? `${testID}-button` : undefined} accessibilityLabel={label || placeholder} accessibilityRole="button" accessibilityState={{ disabled }}>
131
- <AtomicIcon name="calendar" color={getIconColor()} size="md"/>
132
- <Text style={[
133
- styles.text,
134
- disabled ? styles.textDisabled : undefined,
135
- error ? styles.textError : undefined,
136
- ]}>
137
- {value ? formatDate(value) : placeholder}
138
- </Text>
139
- </TouchableOpacity>
140
-
141
- {error && (<Text style={styles.errorText} testID={testID ? `${testID}-error` : undefined}>
142
- {error}
143
- </Text>)}
144
-
145
- {/* Universal DatePicker - Works across iOS, Android, Web */}
146
- {show && (<Modal transparent animationType={isTabletDevice ? 'fade' : 'slide'} visible={show} onRequestClose={() => setShow(false)}>
147
- <TouchableOpacity style={styles.modalOverlay} activeOpacity={1} onPress={() => setShow(false)} accessibilityLabel="Close date picker" accessibilityRole="button">
148
- <View style={styles.pickerContainer} onStartShouldSetResponder={() => true}>
149
- <DateTimePicker value={value || new Date()} mode={mode} display="spinner" onChange={handleChange} minimumDate={minimumDate} maximumDate={maximumDate} testID={testID ? `${testID}-picker` : undefined}/>
150
- <View style={styles.buttonContainer}>
151
- <TouchableOpacity style={styles.doneButton} onPress={() => setShow(false)} testID={testID ? `${testID}-done` : undefined} accessibilityLabel="Done" accessibilityRole="button">
152
- <Text style={styles.doneText}>Done</Text>
153
- </TouchableOpacity>
154
- </View>
155
- </View>
156
- </TouchableOpacity>
157
- </Modal>)}
158
- </View>);
159
- };
160
- /**
161
- * Get component styles based on design tokens
162
- */
163
- const getStyles = (tokens, height, insets) => {
164
- // Responsive button sizing based on device height
165
- const buttonMinWidth = height <= 667 ? Math.min(height * 0.25, 150) : 200;
166
- return StyleSheet.create({
167
- container: {
168
- marginBottom: tokens.spacing.md,
169
- },
170
- label: {
171
- fontSize: tokens.typography.bodyMedium.fontSize,
172
- fontWeight: tokens.typography.semibold,
173
- color: tokens.colors.textPrimary,
174
- marginBottom: tokens.spacing.sm,
175
- },
176
- button: {
177
- flexDirection: 'row',
178
- alignItems: 'center',
179
- backgroundColor: tokens.colors.surface,
180
- borderWidth: 1,
181
- borderColor: tokens.colors.border,
182
- borderRadius: tokens.borders.radius.lg,
183
- paddingHorizontal: tokens.spacing.md,
184
- paddingVertical: tokens.spacing.md,
185
- gap: tokens.spacing.sm,
186
- minHeight: 48, // Apple HIG minimum touch target
187
- },
188
- buttonError: {
189
- borderColor: tokens.colors.error,
190
- borderWidth: tokens.borders.width.medium,
191
- },
192
- buttonDisabled: {
193
- backgroundColor: tokens.colors.surfaceDisabled,
194
- opacity: tokens.opacity.disabled,
195
- },
196
- text: {
197
- flex: 1,
198
- fontSize: tokens.typography.bodyLarge.fontSize,
199
- color: tokens.colors.textPrimary,
200
- },
201
- textDisabled: {
202
- color: tokens.colors.textDisabled,
203
- },
204
- textError: {
205
- color: tokens.colors.error,
206
- },
207
- errorText: {
208
- fontSize: tokens.typography.bodySmall.fontSize,
209
- color: tokens.colors.error,
210
- marginTop: tokens.spacing.xs,
211
- marginLeft: tokens.spacing.xs,
212
- },
213
- modalOverlay: {
214
- flex: 1,
215
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
216
- justifyContent: 'flex-start',
217
- },
218
- pickerContainer: {
219
- backgroundColor: tokens.colors.surface,
220
- borderTopLeftRadius: tokens.borders.radius.xl,
221
- borderTopRightRadius: tokens.borders.radius.xl,
222
- paddingTop: tokens.spacing.lg,
223
- paddingBottom: Math.max(insets.bottom + tokens.spacing.md, tokens.spacing.xl),
224
- },
225
- buttonContainer: {
226
- alignItems: 'center',
227
- marginTop: tokens.spacing.md,
228
- paddingHorizontal: tokens.spacing.lg,
229
- },
230
- doneButton: {
231
- backgroundColor: tokens.colors.primary,
232
- paddingHorizontal: tokens.spacing.xl,
233
- paddingVertical: tokens.spacing.sm,
234
- borderRadius: tokens.borders.radius.lg,
235
- minWidth: buttonMinWidth,
236
- alignItems: 'center',
237
- minHeight: 44, // Apple HIG minimum touch target
238
- },
239
- doneText: {
240
- color: tokens.colors.onPrimary,
241
- fontSize: tokens.typography.bodyLarge.fontSize,
242
- fontWeight: tokens.typography.semibold,
243
- },
244
- });
245
- };
@@ -1,57 +0,0 @@
1
- /**
2
- * AtomicDivider - Universal Divider Component
3
- *
4
- * Displays horizontal or vertical dividers for content separation
5
- * Theme: {{THEME_NAME}} ({{CATEGORY}} category)
6
- *
7
- * Atomic Design Level: ATOM
8
- * Purpose: Content separation and visual hierarchy
9
- *
10
- * Usage:
11
- * - Section separators
12
- * - List item dividers
13
- * - Card separators
14
- * - Menu dividers
15
- * - Form field separators
16
- */
17
- import React from 'react';
18
- import { View } from 'react-native';
19
- import { useAppDesignTokens } from '@umituz/react-native-theme';
20
- // =============================================================================
21
- // COMPONENT IMPLEMENTATION
22
- // =============================================================================
23
- export const AtomicDivider = ({ orientation = 'horizontal', thickness = 'thin', color, length, margin, marginTop, marginBottom, marginLeft, marginRight, style, testID, }) => {
24
- const tokens = useAppDesignTokens();
25
- // Thickness mapping
26
- const thicknessMap = {
27
- thin: 1,
28
- medium: 2,
29
- thick: 4,
30
- };
31
- const dividerThickness = thicknessMap[thickness];
32
- const dividerColor = color || tokens.colors.border;
33
- // Compute final length values with proper type handling
34
- const finalLength = length !== undefined ? length : (orientation === 'horizontal' ? '100%' : 20);
35
- // Base styles for all dividers
36
- const baseStyle = {
37
- backgroundColor: dividerColor,
38
- margin: margin,
39
- marginTop: marginTop,
40
- marginBottom: marginBottom,
41
- marginLeft: marginLeft,
42
- marginRight: marginRight,
43
- };
44
- // Orientation-specific styles with explicit type casting
45
- const orientationStyle = (orientation === 'horizontal' ? {
46
- width: finalLength,
47
- height: dividerThickness,
48
- } : {
49
- width: dividerThickness,
50
- height: finalLength,
51
- });
52
- return (<View style={[baseStyle, orientationStyle, style]} testID={testID}/>);
53
- };
54
- // =============================================================================
55
- // EXPORTS
56
- // =============================================================================
57
- export default AtomicDivider;