@umituz/react-native-design-system 1.15.0 → 2.0.1

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 (88) hide show
  1. package/package.json +26 -19
  2. package/src/atoms/AtomicAvatar.tsx +161 -0
  3. package/src/atoms/AtomicButton.tsx +241 -0
  4. package/src/atoms/AtomicCard.tsx +84 -0
  5. package/src/atoms/AtomicChip.tsx +226 -0
  6. package/src/atoms/AtomicDatePicker.tsx +255 -0
  7. package/src/atoms/AtomicFab.tsx +99 -0
  8. package/src/atoms/AtomicIcon.tsx +149 -0
  9. package/src/atoms/AtomicInput.tsx +308 -0
  10. package/src/atoms/AtomicPicker.tsx +310 -0
  11. package/src/atoms/AtomicProgress.tsx +149 -0
  12. package/src/atoms/AtomicText.tsx +55 -0
  13. package/src/atoms/__tests__/AtomicButton.test.tsx +107 -0
  14. package/src/atoms/__tests__/AtomicIcon.test.tsx +110 -0
  15. package/src/atoms/__tests__/AtomicInput.test.tsx +195 -0
  16. package/src/atoms/datepicker/components/DatePickerButton.tsx +112 -0
  17. package/src/atoms/datepicker/components/DatePickerModal.tsx +143 -0
  18. package/src/atoms/fab/styles/fabStyles.ts +98 -0
  19. package/src/atoms/fab/types/index.ts +88 -0
  20. package/src/atoms/index.ts +70 -0
  21. package/src/atoms/input/hooks/useInputState.ts +63 -0
  22. package/src/atoms/input/styles/inputStylesHelper.ts +120 -0
  23. package/src/atoms/picker/components/PickerChips.tsx +57 -0
  24. package/src/atoms/picker/components/PickerModal.tsx +214 -0
  25. package/src/atoms/picker/styles/pickerStyles.ts +223 -0
  26. package/src/atoms/picker/types/index.ts +42 -0
  27. package/src/index.ts +133 -52
  28. package/src/molecules/ConfirmationModal.tsx +42 -0
  29. package/src/molecules/ConfirmationModalContent.tsx +87 -0
  30. package/src/molecules/ConfirmationModalMain.tsx +91 -0
  31. package/src/molecules/FormField.tsx +155 -0
  32. package/src/molecules/IconContainer.tsx +79 -0
  33. package/src/molecules/ListItem.tsx +35 -0
  34. package/src/molecules/ScreenHeader.tsx +171 -0
  35. package/src/molecules/SearchBar.tsx +198 -0
  36. package/src/molecules/confirmation-modal/components.tsx +94 -0
  37. package/src/molecules/confirmation-modal/index.ts +7 -0
  38. package/src/molecules/confirmation-modal/styles/confirmationModalStyles.ts +133 -0
  39. package/src/molecules/confirmation-modal/types/index.ts +41 -0
  40. package/src/molecules/confirmation-modal/useConfirmationModal.ts +50 -0
  41. package/src/molecules/index.ts +19 -0
  42. package/src/molecules/listitem/index.ts +6 -0
  43. package/src/molecules/listitem/styles/listItemStyles.ts +37 -0
  44. package/src/molecules/listitem/types/index.ts +21 -0
  45. package/src/organisms/AppHeader.tsx +136 -0
  46. package/src/organisms/FormContainer.tsx +169 -0
  47. package/src/organisms/ScreenLayout.tsx +183 -0
  48. package/src/organisms/index.ts +31 -0
  49. package/src/responsive/config.ts +139 -0
  50. package/src/responsive/deviceDetection.ts +155 -0
  51. package/src/responsive/gridUtils.ts +79 -0
  52. package/src/responsive/index.ts +52 -0
  53. package/src/responsive/platformConstants.ts +98 -0
  54. package/src/responsive/responsive.ts +61 -0
  55. package/src/responsive/responsiveLayout.ts +137 -0
  56. package/src/responsive/responsiveSizing.ts +134 -0
  57. package/src/responsive/useResponsive.ts +140 -0
  58. package/src/responsive/validation.ts +158 -0
  59. package/src/theme/core/BaseTokens.ts +42 -0
  60. package/src/theme/core/ColorPalette.ts +29 -0
  61. package/src/theme/core/CustomColors.ts +122 -0
  62. package/src/theme/core/NavigationTheme.ts +72 -0
  63. package/src/theme/core/TokenFactory.ts +103 -0
  64. package/src/theme/core/colors/ColorUtils.ts +53 -0
  65. package/src/theme/core/colors/DarkColors.ts +146 -0
  66. package/src/theme/core/colors/LightColors.ts +146 -0
  67. package/src/theme/core/constants/DesignConstants.ts +31 -0
  68. package/src/theme/core/themes.ts +118 -0
  69. package/src/theme/core/tokens/BaseTokens.ts +144 -0
  70. package/src/theme/core/tokens/Borders.ts +43 -0
  71. package/src/theme/core/tokens/Sizes.ts +51 -0
  72. package/src/theme/core/tokens/Spacing.ts +38 -0
  73. package/src/theme/core/tokens/Typography.ts +143 -0
  74. package/src/theme/hooks/useAppDesignTokens.ts +45 -0
  75. package/src/theme/hooks/useCommonStyles.ts +248 -0
  76. package/src/theme/hooks/useThemedStyles.ts +68 -0
  77. package/src/theme/index.ts +94 -0
  78. package/src/theme/infrastructure/globalThemeStore.ts +69 -0
  79. package/src/theme/infrastructure/storage/ThemeStorage.ts +93 -0
  80. package/src/theme/infrastructure/stores/themeStore.ts +109 -0
  81. package/src/typography/__tests__/colorValidationUtils.test.ts +180 -0
  82. package/src/typography/__tests__/textColorUtils.test.ts +185 -0
  83. package/src/typography/__tests__/textStyleUtils.test.ts +168 -0
  84. package/src/typography/domain/entities/TypographyTypes.ts +88 -0
  85. package/src/typography/index.ts +53 -0
  86. package/src/typography/presentation/utils/colorValidationUtils.ts +133 -0
  87. package/src/typography/presentation/utils/textColorUtils.ts +205 -0
  88. package/src/typography/presentation/utils/textStyleUtils.ts +159 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * AtomicPicker Styles
3
+ */
4
+ import type { ViewStyle, TextStyle } from 'react-native';
5
+ import type { DesignTokens } from '../../../theme';
6
+
7
+ export type PickerSize = 'sm' | 'md' | 'lg';
8
+
9
+ export interface PickerContainerStyles {
10
+ base: ViewStyle;
11
+ size: Record<PickerSize, ViewStyle>;
12
+ state: {
13
+ error: ViewStyle;
14
+ disabled: ViewStyle;
15
+ };
16
+ }
17
+
18
+ export interface PickerLabelStyles {
19
+ base: TextStyle;
20
+ size: Record<PickerSize, TextStyle>;
21
+ }
22
+
23
+ export interface PickerValueStyles {
24
+ base: TextStyle;
25
+ size: Record<PickerSize, TextStyle>;
26
+ }
27
+
28
+ export interface PickerPlaceholderStyles {
29
+ base: TextStyle;
30
+ size: Record<PickerSize, TextStyle>;
31
+ }
32
+
33
+ export const getPickerContainerStyles = (tokens: DesignTokens): PickerContainerStyles => ({
34
+ base: {
35
+ flexDirection: 'row',
36
+ alignItems: 'center',
37
+ justifyContent: 'space-between',
38
+ borderWidth: 1,
39
+ borderColor: tokens.colors.outline,
40
+ backgroundColor: tokens.colors.surface,
41
+ borderRadius: tokens.borders.radius.md,
42
+ },
43
+ size: {
44
+ sm: {
45
+ paddingHorizontal: tokens.spacing.sm,
46
+ paddingVertical: tokens.spacing.xs,
47
+ minHeight: 36,
48
+ },
49
+ md: {
50
+ paddingHorizontal: tokens.spacing.md,
51
+ paddingVertical: tokens.spacing.sm,
52
+ minHeight: 48,
53
+ },
54
+ lg: {
55
+ paddingHorizontal: tokens.spacing.lg,
56
+ paddingVertical: tokens.spacing.md,
57
+ minHeight: 56,
58
+ },
59
+ },
60
+ state: {
61
+ error: {
62
+ borderColor: tokens.colors.error,
63
+ },
64
+ disabled: {
65
+ opacity: tokens.opacity.disabled,
66
+ },
67
+ },
68
+ });
69
+
70
+ export const getPickerLabelStyles = (tokens: DesignTokens): PickerLabelStyles => ({
71
+ base: {
72
+ color: tokens.colors.textPrimary,
73
+ marginBottom: tokens.spacing.xs,
74
+ },
75
+ size: {
76
+ sm: { fontSize: tokens.typography.bodySmall.fontSize },
77
+ md: { fontSize: tokens.typography.bodyMedium.fontSize },
78
+ lg: { fontSize: tokens.typography.bodyLarge.fontSize },
79
+ },
80
+ });
81
+
82
+ export const getPickerValueStyles = (tokens: DesignTokens): PickerValueStyles => ({
83
+ base: {
84
+ color: tokens.colors.textPrimary,
85
+ flex: 1,
86
+ },
87
+ size: {
88
+ sm: { fontSize: tokens.typography.bodySmall.fontSize },
89
+ md: { fontSize: tokens.typography.bodyMedium.fontSize },
90
+ lg: { fontSize: tokens.typography.bodyLarge.fontSize },
91
+ },
92
+ });
93
+
94
+ export const getPickerPlaceholderStyles = (tokens: DesignTokens): PickerPlaceholderStyles => ({
95
+ base: {
96
+ color: tokens.colors.textTertiary,
97
+ flex: 1,
98
+ },
99
+ size: {
100
+ sm: { fontSize: tokens.typography.bodySmall.fontSize },
101
+ md: { fontSize: tokens.typography.bodyMedium.fontSize },
102
+ lg: { fontSize: tokens.typography.bodyLarge.fontSize },
103
+ },
104
+ });
105
+
106
+ export const getPickerErrorStyles = (tokens: DesignTokens): TextStyle => ({
107
+ color: tokens.colors.error,
108
+ fontSize: tokens.typography.bodySmall.fontSize,
109
+ marginTop: tokens.spacing.xs,
110
+ });
111
+
112
+ // Modal styles
113
+ export const getModalOverlayStyles = (tokens: DesignTokens): ViewStyle => ({
114
+ flex: 1,
115
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
116
+ justifyContent: 'flex-end',
117
+ });
118
+
119
+ export const getModalContainerStyles = (tokens: DesignTokens, bottomInset: number): ViewStyle => ({
120
+ backgroundColor: tokens.colors.surface,
121
+ borderTopLeftRadius: tokens.borders.radius.lg,
122
+ borderTopRightRadius: tokens.borders.radius.lg,
123
+ maxHeight: '80%',
124
+ paddingBottom: bottomInset,
125
+ });
126
+
127
+ export const getModalHeaderStyles = (tokens: DesignTokens): ViewStyle => ({
128
+ flexDirection: 'row',
129
+ justifyContent: 'space-between',
130
+ alignItems: 'center',
131
+ paddingHorizontal: tokens.spacing.md,
132
+ paddingVertical: tokens.spacing.md,
133
+ borderBottomWidth: 1,
134
+ borderBottomColor: tokens.colors.outline,
135
+ });
136
+
137
+ export const getModalTitleStyles = (tokens: DesignTokens): TextStyle => ({
138
+ fontSize: tokens.typography.titleLarge.fontSize,
139
+ fontWeight: '600',
140
+ color: tokens.colors.onSurface,
141
+ });
142
+
143
+ export const getSearchContainerStyles = (tokens: DesignTokens): ViewStyle => ({
144
+ flexDirection: 'row',
145
+ alignItems: 'center',
146
+ backgroundColor: tokens.colors.surfaceVariant,
147
+ borderRadius: tokens.borders.radius.md,
148
+ marginHorizontal: tokens.spacing.md,
149
+ marginVertical: tokens.spacing.sm,
150
+ paddingHorizontal: tokens.spacing.md,
151
+ paddingVertical: tokens.spacing.sm,
152
+ gap: tokens.spacing.sm,
153
+ });
154
+
155
+ export const getSearchInputStyles = (tokens: DesignTokens): TextStyle => ({
156
+ flex: 1,
157
+ fontSize: tokens.typography.bodyMedium.fontSize,
158
+ color: tokens.colors.onSurface,
159
+ paddingVertical: 0,
160
+ });
161
+
162
+ export const getOptionContainerStyles = (
163
+ tokens: DesignTokens,
164
+ selected: boolean,
165
+ disabled: boolean
166
+ ): ViewStyle => ({
167
+ flexDirection: 'row',
168
+ alignItems: 'center',
169
+ paddingHorizontal: tokens.spacing.md,
170
+ paddingVertical: tokens.spacing.md,
171
+ gap: tokens.spacing.md,
172
+ backgroundColor: selected ? tokens.colors.surfaceVariant : 'transparent',
173
+ opacity: disabled ? tokens.opacity.disabled : 1,
174
+ });
175
+
176
+ export const getOptionTextStyles = (tokens: DesignTokens, selected: boolean): TextStyle => ({
177
+ fontSize: tokens.typography.bodyLarge.fontSize,
178
+ color: selected ? tokens.colors.primary : tokens.colors.onSurface,
179
+ fontWeight: selected ? '600' : '400',
180
+ });
181
+
182
+ export const getOptionDescriptionStyles = (tokens: DesignTokens): TextStyle => ({
183
+ fontSize: tokens.typography.bodySmall.fontSize,
184
+ color: tokens.colors.textSecondary,
185
+ marginTop: tokens.spacing.xs,
186
+ });
187
+
188
+ export const getEmptyStateStyles = (tokens: DesignTokens): ViewStyle => ({
189
+ flex: 1,
190
+ justifyContent: 'center',
191
+ alignItems: 'center',
192
+ paddingVertical: tokens.spacing.xl,
193
+ gap: tokens.spacing.md,
194
+ });
195
+
196
+ export const getEmptyStateTextStyles = (tokens: DesignTokens): TextStyle => ({
197
+ fontSize: tokens.typography.bodyMedium.fontSize,
198
+ color: tokens.colors.textSecondary,
199
+ textAlign: 'center',
200
+ });
201
+
202
+ // Chip styles
203
+ export const getChipContainerStyles = (tokens: DesignTokens): ViewStyle => ({
204
+ flexDirection: 'row',
205
+ flexWrap: 'wrap',
206
+ gap: tokens.spacing.xs,
207
+ marginTop: tokens.spacing.sm,
208
+ });
209
+
210
+ export const getChipStyles = (tokens: DesignTokens): ViewStyle => ({
211
+ flexDirection: 'row',
212
+ alignItems: 'center',
213
+ backgroundColor: tokens.colors.surfaceVariant,
214
+ borderRadius: tokens.borders.radius.full,
215
+ paddingHorizontal: tokens.spacing.sm,
216
+ paddingVertical: tokens.spacing.xs,
217
+ gap: tokens.spacing.xs,
218
+ });
219
+
220
+ export const getChipTextStyles = (tokens: DesignTokens): TextStyle => ({
221
+ fontSize: tokens.typography.bodySmall.fontSize,
222
+ color: tokens.colors.onSurface,
223
+ });
@@ -0,0 +1,42 @@
1
+ import { ViewStyle, TextStyle } from 'react-native';
2
+ import { IconColor } from '../../AtomicIcon';
3
+
4
+ /**
5
+ * Picker option item
6
+ *
7
+ * icon: Any MaterialIcons name
8
+ * @see https://fonts.google.com/icons
9
+ */
10
+ export interface PickerOption {
11
+ label: string;
12
+ value: string;
13
+ icon?: string; // MaterialIcons name
14
+ disabled?: boolean;
15
+ description?: string;
16
+ testID?: string;
17
+ }
18
+
19
+ export type PickerSize = 'sm' | 'md' | 'lg';
20
+
21
+ export interface AtomicPickerProps {
22
+ value: string | string[];
23
+ onChange: (value: string | string[]) => void;
24
+ options: PickerOption[];
25
+ label?: string;
26
+ placeholder?: string;
27
+ error?: string;
28
+ disabled?: boolean;
29
+ multiple?: boolean;
30
+ searchable?: boolean;
31
+ clearable?: boolean;
32
+ autoClose?: boolean;
33
+ color?: IconColor;
34
+ size?: PickerSize;
35
+ modalTitle?: string;
36
+ emptyMessage?: string;
37
+ clearAccessibilityLabel?: string;
38
+ closeAccessibilityLabel?: string;
39
+ style?: ViewStyle | ViewStyle[];
40
+ labelStyle?: TextStyle | TextStyle[];
41
+ testID?: string;
42
+ }
package/src/index.ts CHANGED
@@ -1,29 +1,115 @@
1
1
  /**
2
2
  * @umituz/react-native-design-system
3
3
  * Universal design system for React Native apps
4
+ *
5
+ * Consolidated package including:
6
+ * - Atoms (primitive UI components)
7
+ * - Molecules (composite components)
8
+ * - Organisms (complex UI patterns)
9
+ * - Theme (design tokens, colors)
10
+ * - Typography (text styles)
11
+ * - Responsive (screen utilities)
4
12
  */
5
13
 
14
+ // =============================================================================
15
+ // THEME EXPORTS
16
+ // =============================================================================
17
+
6
18
  export {
19
+ useAppDesignTokens,
7
20
  useCommonStyles,
8
- } from '@umituz/react-native-design-system-theme';
21
+ useDesignSystemTheme,
22
+ useTheme,
23
+ useThemedStyles,
24
+ useThemedStyleSheet,
25
+ lightColors,
26
+ darkColors,
27
+ getColorPalette,
28
+ withAlpha,
29
+ BASE_TOKENS,
30
+ BASE_TOKENS as STATIC_TOKENS,
31
+ spacing,
32
+ typography,
33
+ borders,
34
+ createDesignTokens,
35
+ lightTheme,
36
+ darkTheme,
37
+ createResponsiveValue,
38
+ ThemeStorage,
39
+ createNavigationTheme,
40
+ applyCustomColors,
41
+ type ColorPalette,
42
+ type ThemeMode,
43
+ type CustomThemeColors,
44
+ type Spacing,
45
+ type Typography,
46
+ type Borders,
47
+ type BaseTokens,
48
+ type IconSizes,
49
+ type Opacity,
50
+ type AvatarSizes,
51
+ type ComponentSizes,
52
+ type DesignTokens,
53
+ type Theme,
54
+ type ExtendedColorPalette,
55
+ type NavigationTheme,
56
+ } from './theme';
9
57
 
10
- export {
11
- createVariants,
12
- type VariantConfig,
13
- type VariantProps,
14
- } from './presentation/utils/variants/core';
58
+ // =============================================================================
59
+ // TYPOGRAPHY EXPORTS
60
+ // =============================================================================
15
61
 
16
62
  export {
17
- createAdvancedVariants,
18
- type AdvancedVariantConfig,
19
- type CompoundVariant,
20
- } from './presentation/utils/variants/compound';
63
+ getTextColor,
64
+ getTextStyle,
65
+ isTextStyleVariant,
66
+ getAllTextStyleVariants,
67
+ clearTypographyCache,
68
+ clearColorCache,
69
+ isValidHexColor,
70
+ isValidRgbColor,
71
+ isValidHslColor,
72
+ isValidNamedColor,
73
+ isValidColor,
74
+ getColorFormat,
75
+ normalizeColor,
76
+ type TextStyleVariant,
77
+ type ColorVariant,
78
+ } from './typography';
79
+
80
+ // =============================================================================
81
+ // RESPONSIVE EXPORTS
82
+ // =============================================================================
21
83
 
22
84
  export {
23
- conditionalStyle,
24
- responsiveStyle,
25
- combineStyles,
26
- } from './presentation/utils/variants/helpers';
85
+ useResponsive,
86
+ getScreenDimensions,
87
+ isSmallPhone,
88
+ isTablet,
89
+ getResponsiveLogoSize,
90
+ getResponsiveInputHeight,
91
+ getResponsiveHorizontalPadding,
92
+ getResponsiveBottomPosition,
93
+ getResponsiveFABPosition,
94
+ getResponsiveModalMaxHeight,
95
+ getResponsiveMinModalHeight,
96
+ getResponsiveIconContainerSize,
97
+ getResponsiveGridColumns,
98
+ getResponsiveMaxWidth,
99
+ getResponsiveFontSize,
100
+ isLandscape,
101
+ getDeviceType,
102
+ getMinTouchTarget,
103
+ getSpacingMultiplier,
104
+ IOS_HIG,
105
+ PLATFORM_CONSTANTS,
106
+ isValidTouchTarget,
107
+ DeviceType,
108
+ } from './responsive';
109
+
110
+ // =============================================================================
111
+ // ATOMS EXPORTS
112
+ // =============================================================================
27
113
 
28
114
  export {
29
115
  AtomicText,
@@ -62,55 +148,50 @@ export {
62
148
  type PickerOption,
63
149
  type PickerSize,
64
150
  type AtomicDatePickerProps,
65
- } from '@umituz/react-native-design-system-atoms';
151
+ } from './atoms';
66
152
 
67
- export {
68
- ScreenLayout,
69
- } from '@umituz/react-native-design-system-organisms';
153
+ // =============================================================================
154
+ // MOLECULES EXPORTS
155
+ // =============================================================================
70
156
 
71
157
  export {
72
158
  FormField,
73
159
  ListItem,
74
160
  SearchBar,
75
- SectionCard,
76
161
  IconContainer,
77
162
  ScreenHeader,
78
- SectionHeader,
79
- SectionContainer,
80
- GridContainer,
81
163
  ConfirmationModal,
82
164
  useConfirmationModal,
83
- } from '@umituz/react-native-design-system-molecules';
165
+ } from './molecules';
166
+
167
+ // =============================================================================
168
+ // ORGANISMS EXPORTS
169
+ // =============================================================================
84
170
 
85
171
  export {
86
- useResponsive,
87
- getScreenDimensions,
88
- isSmallPhone,
89
- isTablet,
90
- getResponsiveLogoSize,
91
- getResponsiveInputHeight,
92
- getResponsiveHorizontalPadding,
93
- getResponsiveBottomPosition,
94
- getResponsiveFABPosition,
95
- getResponsiveModalMaxHeight,
96
- getResponsiveMinModalHeight,
97
- getResponsiveIconContainerSize,
98
- getResponsiveGridColumns,
99
- getResponsiveMaxWidth,
100
- getResponsiveFontSize,
101
- isLandscape,
102
- getDeviceType,
103
- getMinTouchTarget,
104
- getSpacingMultiplier,
105
- IOS_HIG,
106
- PLATFORM_CONSTANTS,
107
- isValidTouchTarget,
108
- DeviceType,
109
- } from '@umituz/react-native-design-system-responsive';
172
+ ScreenLayout,
173
+ AppHeader,
174
+ FormContainer,
175
+ } from './organisms';
176
+
177
+ // =============================================================================
178
+ // VARIANT UTILITIES
179
+ // =============================================================================
110
180
 
111
181
  export {
112
- useAppDesignTokens,
113
- STATIC_TOKENS,
114
- type DesignTokens,
115
- withAlpha,
116
- } from '@umituz/react-native-design-system-theme';
182
+ createVariants,
183
+ type VariantConfig,
184
+ type VariantProps,
185
+ } from './presentation/utils/variants/core';
186
+
187
+ export {
188
+ createAdvancedVariants,
189
+ type AdvancedVariantConfig,
190
+ type CompoundVariant,
191
+ } from './presentation/utils/variants/compound';
192
+
193
+ export {
194
+ conditionalStyle,
195
+ responsiveStyle,
196
+ combineStyles,
197
+ } from './presentation/utils/variants/helpers';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ConfirmationModal - Universal Confirmation Dialog
3
+ *
4
+ * A reusable confirmation modal for destructive and important actions.
5
+ * Follows Material Design 3 dialog patterns and accessibility guidelines.
6
+ *
7
+ * Features:
8
+ * - Multiple variants (default, destructive, warning, success)
9
+ * - Configurable text and icons
10
+ * - Backdrop dismissal
11
+ * - Full keyboard and screen reader support
12
+ * - Theme-aware styling
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // Destructive confirmation (delete)
17
+ * <ConfirmationModal
18
+ * visible={showDeleteModal}
19
+ * variant="destructive"
20
+ * title="Delete Item?"
21
+ * message="This action cannot be undone. All data will be permanently deleted."
22
+ * confirmText="Delete"
23
+ * cancelText="Cancel"
24
+ * onConfirm={handleDelete}
25
+ * onCancel={() => setShowDeleteModal(false)}
26
+ * />
27
+ *
28
+ * // Generic confirmation
29
+ * <ConfirmationModal
30
+ * visible={showConfirmModal}
31
+ * variant="default"
32
+ * title="Confirm Action"
33
+ * message="Are you sure you want to proceed?"
34
+ * onConfirm={handleConfirm}
35
+ * onCancel={() => setShowConfirmModal(false)}
36
+ * />
37
+ * ```
38
+ */
39
+
40
+ export { ConfirmationModal } from './ConfirmationModalMain';
41
+ export { useConfirmationModal } from './confirmation-modal/useConfirmationModal';
42
+ export type { ConfirmationModalProps, ConfirmationModalVariant } from './confirmation-modal/types';
@@ -0,0 +1,87 @@
1
+ /**
2
+ * ConfirmationModal Content Component
3
+ *
4
+ * Content component for confirmation modal
5
+ */
6
+
7
+ import React from 'react';
8
+ import { View, ViewStyle, StyleProp } from 'react-native';
9
+ import { useAppDesignTokens } from '../theme';
10
+ import { ConfirmationModalVariant } from './confirmation-modal/types/';
11
+ import {
12
+ getVariantConfig,
13
+ getModalContainerStyle,
14
+ getIconContainerStyle,
15
+ getTitleContainerStyle,
16
+ getMessageContainerStyle,
17
+ getButtonStyle,
18
+ } from './confirmation-modal/styles/confirmationModalStyles';
19
+ import {
20
+ ConfirmationModalIcon,
21
+ ConfirmationModalTitle,
22
+ ConfirmationModalMessage,
23
+ ConfirmationModalButtons,
24
+ } from './confirmation-modal/components';
25
+
26
+ const useConfirmButtonStyle = (
27
+ variant: ConfirmationModalVariant,
28
+ tokens: ReturnType<typeof useAppDesignTokens>
29
+ ) => {
30
+ return React.useCallback(() => {
31
+ const baseStyle = getButtonStyle();
32
+ const variantStyles = [];
33
+
34
+ if (variant === 'destructive') variantStyles.push({ backgroundColor: tokens.colors.error });
35
+ if (variant === 'warning') variantStyles.push({ backgroundColor: tokens.colors.warning });
36
+ if (variant === 'success') variantStyles.push({ backgroundColor: tokens.colors.success });
37
+
38
+ return [baseStyle, ...variantStyles];
39
+ }, [variant, tokens.colors]);
40
+ };
41
+
42
+ export const ConfirmationModalContent: React.FC<{
43
+ tokens: ReturnType<typeof useAppDesignTokens>;
44
+ variant: ConfirmationModalVariant;
45
+ title: string;
46
+ message: string;
47
+ confirmText: string;
48
+ cancelText: string;
49
+ icon?: string;
50
+ onConfirm: () => void;
51
+ onCancel: () => void;
52
+ style?: StyleProp<ViewStyle>;
53
+ testID: string;
54
+ }> = ({ tokens, variant, title, message, confirmText, cancelText, icon, onConfirm, onCancel, style, testID }) => {
55
+ const variantConfig = getVariantConfig(variant as 'default' | 'destructive' | 'warning' | 'success', tokens);
56
+ const finalIcon = icon || variantConfig.icon;
57
+ const getConfirmButtonStyle = useConfirmButtonStyle(variant, tokens);
58
+
59
+ return (
60
+ <View style={[getModalContainerStyle(tokens), style]}>
61
+ <View style={getIconContainerStyle(tokens)}>
62
+ <ConfirmationModalIcon
63
+ icon={finalIcon}
64
+ iconColor={variantConfig.iconColor}
65
+ testID={testID}
66
+ />
67
+ </View>
68
+
69
+ <View style={getTitleContainerStyle(tokens)}>
70
+ <ConfirmationModalTitle title={title} tokens={tokens} testID={testID} />
71
+ </View>
72
+
73
+ <View style={getMessageContainerStyle(tokens)}>
74
+ <ConfirmationModalMessage message={message} tokens={tokens} testID={testID} />
75
+ </View>
76
+
77
+ <ConfirmationModalButtons
78
+ confirmText={confirmText}
79
+ cancelText={cancelText}
80
+ onConfirm={onConfirm}
81
+ onCancel={onCancel}
82
+ confirmButtonStyle={getConfirmButtonStyle()}
83
+ testID={testID}
84
+ />
85
+ </View>
86
+ );
87
+ };
@@ -0,0 +1,91 @@
1
+ /**
2
+ * ConfirmationModal Main Component
3
+ *
4
+ * Main confirmation modal component
5
+ */
6
+
7
+ import React from 'react';
8
+ import { View, Modal, TouchableOpacity } from 'react-native';
9
+ import { useAppDesignTokens } from '../theme';
10
+ import { ConfirmationModalProps } from './confirmation-modal/types/';
11
+ import {
12
+ getModalOverlayStyle,
13
+ getBackdropStyle,
14
+ } from './confirmation-modal/styles/confirmationModalStyles';
15
+ import { ConfirmationModalContent } from './ConfirmationModalContent';
16
+
17
+ const useBackdropHandler = (backdropDismissible: boolean, onCancel: () => void) => {
18
+ return React.useCallback(() => {
19
+ if (backdropDismissible) {
20
+ onCancel();
21
+ }
22
+ }, [backdropDismissible, onCancel]);
23
+ };
24
+
25
+ const ConfirmationModalBackdrop: React.FC<{
26
+ showBackdrop: boolean;
27
+ onBackdropPress: () => void;
28
+ testID: string;
29
+ }> = ({ showBackdrop, onBackdropPress, testID }) => {
30
+ if (!showBackdrop) return null;
31
+
32
+ return (
33
+ <TouchableOpacity
34
+ style={getBackdropStyle()}
35
+ activeOpacity={1}
36
+ onPress={onBackdropPress}
37
+ testID={`${testID}-backdrop`}
38
+ />
39
+ );
40
+ };
41
+
42
+ export const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
43
+ visible,
44
+ title,
45
+ message,
46
+ variant = 'default',
47
+ confirmText = 'Confirm',
48
+ cancelText = 'Cancel',
49
+ icon,
50
+ onConfirm,
51
+ onCancel,
52
+ showBackdrop = true,
53
+ backdropDismissible = true,
54
+ style,
55
+ testID = 'atomic-confirmation-modal',
56
+ }) => {
57
+ const tokens = useAppDesignTokens();
58
+ const handleBackdropPress = useBackdropHandler(backdropDismissible, onCancel);
59
+
60
+ return (
61
+ <Modal
62
+ visible={visible}
63
+ transparent
64
+ onRequestClose={onCancel}
65
+ statusBarTranslucent
66
+ testID={testID}
67
+ >
68
+ <View style={getModalOverlayStyle(tokens)}>
69
+ <ConfirmationModalBackdrop
70
+ showBackdrop={showBackdrop}
71
+ onBackdropPress={handleBackdropPress}
72
+ testID={testID}
73
+ />
74
+
75
+ <ConfirmationModalContent
76
+ tokens={tokens}
77
+ variant={variant}
78
+ title={title}
79
+ message={message}
80
+ confirmText={confirmText}
81
+ cancelText={cancelText}
82
+ icon={icon}
83
+ onConfirm={onConfirm}
84
+ onCancel={onCancel}
85
+ style={style}
86
+ testID={testID}
87
+ />
88
+ </View>
89
+ </Modal>
90
+ );
91
+ };