@umituz/react-native-design-system 2.6.66 → 2.6.67
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 +1 -1
- package/src/atoms/picker/styles/pickerModalStyles.ts +36 -0
- package/src/atoms/picker/styles/pickerOptionStyles.ts +32 -0
- package/src/atoms/picker/styles/pickerSearchStyles.ts +25 -0
- package/src/atoms/picker/styles/pickerStateStyles.ts +42 -0
- package/src/atoms/picker/styles/pickerStyles.ts +78 -184
- package/src/molecules/calendar/presentation/components/AtomicCalendar.tsx +19 -160
- package/src/molecules/calendar/presentation/components/CalendarDayCell.tsx +101 -0
- package/src/molecules/calendar/presentation/components/CalendarWeekdayHeader.tsx +28 -0
- package/src/molecules/calendar/presentation/components/calendarStyles.ts +56 -0
- package/src/theme/hooks/commonStyles/formStyles.ts +17 -0
- package/src/theme/hooks/commonStyles/layoutStyles.ts +38 -0
- package/src/theme/hooks/commonStyles/paddingStyles.ts +20 -0
- package/src/theme/hooks/commonStyles/screenContainerStyles.ts +22 -0
- package/src/theme/hooks/commonStyles/scrollContainerStyles.ts +28 -0
- package/src/theme/hooks/commonStyles/sectionStyles.ts +17 -0
- package/src/theme/hooks/commonStyles/textStyles.ts +36 -0
- package/src/theme/hooks/useCommonStyles.ts +15 -219
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.67",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picker Modal Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../../theme';
|
|
7
|
+
|
|
8
|
+
export const getModalOverlayStyles = (): ViewStyle => ({
|
|
9
|
+
flex: 1,
|
|
10
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
11
|
+
justifyContent: 'flex-end',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const getModalContainerStyles = (tokens: DesignTokens, bottomInset: number): ViewStyle => ({
|
|
15
|
+
backgroundColor: tokens.colors.surface,
|
|
16
|
+
borderTopLeftRadius: tokens.borders.radius.lg,
|
|
17
|
+
borderTopRightRadius: tokens.borders.radius.lg,
|
|
18
|
+
maxHeight: '80%',
|
|
19
|
+
paddingBottom: bottomInset,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const getModalHeaderStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
23
|
+
flexDirection: 'row',
|
|
24
|
+
justifyContent: 'space-between',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
paddingHorizontal: tokens.spacing.md,
|
|
27
|
+
paddingVertical: tokens.spacing.md,
|
|
28
|
+
borderBottomWidth: 1,
|
|
29
|
+
borderBottomColor: tokens.colors.outline,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const getModalTitleStyles = (tokens: DesignTokens): TextStyle => ({
|
|
33
|
+
fontSize: tokens.typography.titleLarge.responsiveFontSize,
|
|
34
|
+
fontWeight: '600',
|
|
35
|
+
color: tokens.colors.onSurface,
|
|
36
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picker Option Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../../theme';
|
|
7
|
+
|
|
8
|
+
export const getOptionContainerStyles = (
|
|
9
|
+
tokens: DesignTokens,
|
|
10
|
+
selected: boolean,
|
|
11
|
+
disabled: boolean
|
|
12
|
+
): ViewStyle => ({
|
|
13
|
+
flexDirection: 'row',
|
|
14
|
+
alignItems: 'center',
|
|
15
|
+
paddingHorizontal: tokens.spacing.md,
|
|
16
|
+
paddingVertical: tokens.spacing.md,
|
|
17
|
+
gap: tokens.spacing.md,
|
|
18
|
+
backgroundColor: selected ? tokens.colors.surfaceVariant : 'transparent',
|
|
19
|
+
opacity: disabled ? tokens.opacity.disabled : 1,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const getOptionTextStyles = (tokens: DesignTokens, selected: boolean): TextStyle => ({
|
|
23
|
+
fontSize: tokens.typography.bodyLarge.responsiveFontSize,
|
|
24
|
+
color: selected ? tokens.colors.primary : tokens.colors.onSurface,
|
|
25
|
+
fontWeight: selected ? '600' : '400',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const getOptionDescriptionStyles = (tokens: DesignTokens): TextStyle => ({
|
|
29
|
+
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
30
|
+
color: tokens.colors.textSecondary,
|
|
31
|
+
marginTop: tokens.spacing.xs,
|
|
32
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picker Search Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../../theme';
|
|
7
|
+
|
|
8
|
+
export const getSearchContainerStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
9
|
+
flexDirection: 'row',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
backgroundColor: tokens.colors.surfaceVariant,
|
|
12
|
+
borderRadius: tokens.borders.radius.md,
|
|
13
|
+
marginHorizontal: tokens.spacing.md,
|
|
14
|
+
marginVertical: tokens.spacing.sm,
|
|
15
|
+
paddingHorizontal: tokens.spacing.md,
|
|
16
|
+
paddingVertical: tokens.spacing.sm,
|
|
17
|
+
gap: tokens.spacing.sm,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const getSearchInputStyles = (tokens: DesignTokens): TextStyle => ({
|
|
21
|
+
flex: 1,
|
|
22
|
+
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
23
|
+
color: tokens.colors.onSurface,
|
|
24
|
+
paddingVertical: 0,
|
|
25
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picker Empty State & Chip Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../../theme';
|
|
7
|
+
|
|
8
|
+
export const getEmptyStateStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
9
|
+
flex: 1,
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
paddingVertical: tokens.spacing.xl,
|
|
13
|
+
gap: tokens.spacing.md,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const getEmptyStateTextStyles = (tokens: DesignTokens): TextStyle => ({
|
|
17
|
+
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
18
|
+
color: tokens.colors.textSecondary,
|
|
19
|
+
textAlign: 'center',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const getChipContainerStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
23
|
+
flexDirection: 'row',
|
|
24
|
+
flexWrap: 'wrap',
|
|
25
|
+
gap: tokens.spacing.xs,
|
|
26
|
+
marginTop: tokens.spacing.sm,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const getChipStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
30
|
+
flexDirection: 'row',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
backgroundColor: tokens.colors.surfaceVariant,
|
|
33
|
+
borderRadius: tokens.borders.radius.full,
|
|
34
|
+
paddingHorizontal: tokens.spacing.sm,
|
|
35
|
+
paddingVertical: tokens.spacing.xs,
|
|
36
|
+
gap: tokens.spacing.xs,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const getChipTextStyles = (tokens: DesignTokens): TextStyle => ({
|
|
40
|
+
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
41
|
+
color: tokens.colors.onSurface,
|
|
42
|
+
});
|
|
@@ -7,217 +7,111 @@ import type { DesignTokens } from '../../../theme';
|
|
|
7
7
|
export type PickerSize = 'sm' | 'md' | 'lg';
|
|
8
8
|
|
|
9
9
|
export interface PickerContainerStyles {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
base: ViewStyle;
|
|
11
|
+
size: Record<PickerSize, ViewStyle>;
|
|
12
|
+
state: {
|
|
13
|
+
error: ViewStyle;
|
|
14
|
+
disabled: ViewStyle;
|
|
15
|
+
};
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export interface PickerLabelStyles {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
base: TextStyle;
|
|
20
|
+
size: Record<PickerSize, TextStyle>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface PickerValueStyles {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
base: TextStyle;
|
|
25
|
+
size: Record<PickerSize, TextStyle>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export interface PickerPlaceholderStyles {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
base: TextStyle;
|
|
30
|
+
size: Record<PickerSize, TextStyle>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export const getPickerContainerStyles = (tokens: DesignTokens): PickerContainerStyles => ({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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 * tokens.spacingMultiplier,
|
|
42
48
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
minHeight: 36 * tokens.spacingMultiplier,
|
|
48
|
-
},
|
|
49
|
-
md: {
|
|
50
|
-
paddingHorizontal: tokens.spacing.md,
|
|
51
|
-
paddingVertical: tokens.spacing.sm,
|
|
52
|
-
minHeight: 48 * tokens.spacingMultiplier,
|
|
53
|
-
},
|
|
54
|
-
lg: {
|
|
55
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
56
|
-
paddingVertical: tokens.spacing.md,
|
|
57
|
-
minHeight: 56 * tokens.spacingMultiplier,
|
|
58
|
-
},
|
|
49
|
+
md: {
|
|
50
|
+
paddingHorizontal: tokens.spacing.md,
|
|
51
|
+
paddingVertical: tokens.spacing.sm,
|
|
52
|
+
minHeight: 48 * tokens.spacingMultiplier,
|
|
59
53
|
},
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
disabled: {
|
|
65
|
-
opacity: tokens.opacity.disabled,
|
|
66
|
-
},
|
|
54
|
+
lg: {
|
|
55
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
56
|
+
paddingVertical: tokens.spacing.md,
|
|
57
|
+
minHeight: 56 * tokens.spacingMultiplier,
|
|
67
58
|
},
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
color: tokens.colors.textPrimary,
|
|
73
|
-
marginBottom: tokens.spacing.xs,
|
|
59
|
+
},
|
|
60
|
+
state: {
|
|
61
|
+
error: {
|
|
62
|
+
borderColor: tokens.colors.error,
|
|
74
63
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
md: { fontSize: tokens.typography.bodyMedium.responsiveFontSize },
|
|
78
|
-
lg: { fontSize: tokens.typography.bodyLarge.responsiveFontSize },
|
|
64
|
+
disabled: {
|
|
65
|
+
opacity: tokens.opacity.disabled,
|
|
79
66
|
},
|
|
67
|
+
},
|
|
80
68
|
});
|
|
81
69
|
|
|
82
|
-
export const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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.responsiveFontSize },
|
|
101
|
-
md: { fontSize: tokens.typography.bodyMedium.responsiveFontSize },
|
|
102
|
-
lg: { fontSize: tokens.typography.bodyLarge.responsiveFontSize },
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
export const getPickerErrorStyles = (tokens: DesignTokens): TextStyle => ({
|
|
107
|
-
color: tokens.colors.error,
|
|
108
|
-
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
109
|
-
marginTop: tokens.spacing.xs,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Modal styles
|
|
113
|
-
export const getModalOverlayStyles = (): 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.responsiveFontSize,
|
|
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,
|
|
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.responsiveFontSize },
|
|
77
|
+
md: { fontSize: tokens.typography.bodyMedium.responsiveFontSize },
|
|
78
|
+
lg: { fontSize: tokens.typography.bodyLarge.responsiveFontSize },
|
|
79
|
+
},
|
|
153
80
|
});
|
|
154
81
|
|
|
155
|
-
export const
|
|
82
|
+
export const getPickerValueStyles = (tokens: DesignTokens): PickerValueStyles => ({
|
|
83
|
+
base: {
|
|
84
|
+
color: tokens.colors.textPrimary,
|
|
156
85
|
flex: 1,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
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,
|
|
86
|
+
},
|
|
87
|
+
size: {
|
|
88
|
+
sm: { fontSize: tokens.typography.bodySmall.responsiveFontSize },
|
|
89
|
+
md: { fontSize: tokens.typography.bodyMedium.responsiveFontSize },
|
|
90
|
+
lg: { fontSize: tokens.typography.bodyLarge.responsiveFontSize },
|
|
91
|
+
},
|
|
174
92
|
});
|
|
175
93
|
|
|
176
|
-
export const
|
|
177
|
-
|
|
178
|
-
color:
|
|
179
|
-
fontWeight: selected ? '600' : '400',
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
export const getOptionDescriptionStyles = (tokens: DesignTokens): TextStyle => ({
|
|
183
|
-
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
184
|
-
color: tokens.colors.textSecondary,
|
|
185
|
-
marginTop: tokens.spacing.xs,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
export const getEmptyStateStyles = (tokens: DesignTokens): ViewStyle => ({
|
|
94
|
+
export const getPickerPlaceholderStyles = (tokens: DesignTokens): PickerPlaceholderStyles => ({
|
|
95
|
+
base: {
|
|
96
|
+
color: tokens.colors.textTertiary,
|
|
189
97
|
flex: 1,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export const getEmptyStateTextStyles = (tokens: DesignTokens): TextStyle => ({
|
|
197
|
-
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
198
|
-
color: tokens.colors.textSecondary,
|
|
199
|
-
textAlign: 'center',
|
|
98
|
+
},
|
|
99
|
+
size: {
|
|
100
|
+
sm: { fontSize: tokens.typography.bodySmall.responsiveFontSize },
|
|
101
|
+
md: { fontSize: tokens.typography.bodyMedium.responsiveFontSize },
|
|
102
|
+
lg: { fontSize: tokens.typography.bodyLarge.responsiveFontSize },
|
|
103
|
+
},
|
|
200
104
|
});
|
|
201
105
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
gap: tokens.spacing.xs,
|
|
207
|
-
marginTop: tokens.spacing.sm,
|
|
106
|
+
export const getPickerErrorStyles = (tokens: DesignTokens): TextStyle => ({
|
|
107
|
+
color: tokens.colors.error,
|
|
108
|
+
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
109
|
+
marginTop: tokens.spacing.xs,
|
|
208
110
|
});
|
|
209
111
|
|
|
210
|
-
export
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
216
|
-
paddingVertical: tokens.spacing.xs,
|
|
217
|
-
gap: tokens.spacing.xs,
|
|
218
|
-
});
|
|
112
|
+
// Re-export modal, search, option, and chip styles
|
|
113
|
+
export * from './pickerModalStyles';
|
|
114
|
+
export * from './pickerSearchStyles';
|
|
115
|
+
export * from './pickerOptionStyles';
|
|
116
|
+
export * from './pickerStateStyles';
|
|
219
117
|
|
|
220
|
-
export const getChipTextStyles = (tokens: DesignTokens): TextStyle => ({
|
|
221
|
-
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
222
|
-
color: tokens.colors.onSurface,
|
|
223
|
-
});
|
|
@@ -31,10 +31,13 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import React from 'react';
|
|
34
|
-
import { View,
|
|
35
|
-
import { useAppDesignTokens
|
|
34
|
+
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
|
35
|
+
import { useAppDesignTokens } from '../../../../index';
|
|
36
36
|
import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
|
|
37
37
|
import { CalendarService } from '../../infrastructure/services/CalendarService';
|
|
38
|
+
import { calendarStyles } from './calendarStyles';
|
|
39
|
+
import { CalendarWeekdayHeader } from './CalendarWeekdayHeader';
|
|
40
|
+
import { CalendarDayCell } from './CalendarDayCell';
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
43
|
* AtomicCalendar Props
|
|
@@ -104,176 +107,32 @@ export const AtomicCalendar: React.FC<AtomicCalendarProps> = ({
|
|
|
104
107
|
testID,
|
|
105
108
|
}) => {
|
|
106
109
|
const tokens = useAppDesignTokens();
|
|
107
|
-
|
|
108
|
-
// Get weekday names (localized)
|
|
109
110
|
const weekdayNames = CalendarService.getWeekdayNames();
|
|
110
111
|
|
|
111
112
|
return (
|
|
112
|
-
<View style={[
|
|
113
|
-
{
|
|
114
|
-
{showWeekdayHeaders && (
|
|
115
|
-
<View style={styles.weekdayHeader}>
|
|
116
|
-
{weekdayNames.map((day, index) => (
|
|
117
|
-
<View key={index} style={styles.weekdayCell}>
|
|
118
|
-
<AtomicText
|
|
119
|
-
type="bodySmall"
|
|
120
|
-
color="secondary"
|
|
121
|
-
style={styles.weekdayText}
|
|
122
|
-
>
|
|
123
|
-
{day}
|
|
124
|
-
</AtomicText>
|
|
125
|
-
</View>
|
|
126
|
-
))}
|
|
127
|
-
</View>
|
|
128
|
-
)}
|
|
113
|
+
<View style={[calendarStyles.container, { backgroundColor: tokens.colors.surface }, style]} testID={testID}>
|
|
114
|
+
{showWeekdayHeaders && <CalendarWeekdayHeader weekdayNames={weekdayNames} />}
|
|
129
115
|
|
|
130
|
-
{
|
|
131
|
-
<View style={styles.grid}>
|
|
116
|
+
<View style={calendarStyles.grid}>
|
|
132
117
|
{days.map((day, index) => {
|
|
133
118
|
const isSelected = CalendarService.isSameDay(day.date, selectedDate);
|
|
134
|
-
const eventCount = day.events.length;
|
|
135
|
-
const visibleEvents = day.events.slice(0, maxEventIndicators);
|
|
136
|
-
const hiddenEventCount = Math.max(0, eventCount - maxEventIndicators);
|
|
137
119
|
|
|
138
120
|
return (
|
|
139
|
-
<
|
|
121
|
+
<CalendarDayCell
|
|
140
122
|
key={index}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
: tokens.colors.border,
|
|
152
|
-
borderWidth: isSelected ? 2 : day.isToday ? 2 : 1,
|
|
153
|
-
opacity: day.isDisabled ? 0.4 : 1,
|
|
154
|
-
},
|
|
155
|
-
dayStyle,
|
|
156
|
-
]}
|
|
157
|
-
onPress={() => !day.isDisabled && onDateSelect(day.date)}
|
|
158
|
-
disabled={day.isDisabled}
|
|
159
|
-
testID={testID ? `${testID}-day-${index}` : undefined}
|
|
160
|
-
accessibilityLabel={`${day.date.toLocaleDateString()}, ${eventCount} events`}
|
|
161
|
-
accessibilityRole="button"
|
|
162
|
-
accessibilityState={{ disabled: day.isDisabled, selected: isSelected }}
|
|
163
|
-
>
|
|
164
|
-
{/* Day Number */}
|
|
165
|
-
<AtomicText
|
|
166
|
-
type="bodyMedium"
|
|
167
|
-
color={
|
|
168
|
-
isSelected
|
|
169
|
-
? 'inverse'
|
|
170
|
-
: day.isCurrentMonth
|
|
171
|
-
? 'primary'
|
|
172
|
-
: 'secondary'
|
|
173
|
-
}
|
|
174
|
-
style={[
|
|
175
|
-
styles.dayText,
|
|
176
|
-
day.isToday && !isSelected && { fontWeight: 'bold' },
|
|
177
|
-
]}
|
|
178
|
-
>
|
|
179
|
-
{day.date.getDate()}
|
|
180
|
-
</AtomicText>
|
|
181
|
-
|
|
182
|
-
{/* Event Indicators */}
|
|
183
|
-
<View style={styles.eventIndicators}>
|
|
184
|
-
{/* Today indicator (if today and has no events) */}
|
|
185
|
-
{day.isToday && eventCount === 0 && (
|
|
186
|
-
<View
|
|
187
|
-
style={[
|
|
188
|
-
styles.eventDot,
|
|
189
|
-
{ backgroundColor: tokens.colors.success },
|
|
190
|
-
]}
|
|
191
|
-
/>
|
|
192
|
-
)}
|
|
193
|
-
|
|
194
|
-
{/* Event dots */}
|
|
195
|
-
{visibleEvents.map((event, eventIndex) => (
|
|
196
|
-
<View
|
|
197
|
-
key={eventIndex}
|
|
198
|
-
style={[
|
|
199
|
-
styles.eventDot,
|
|
200
|
-
{
|
|
201
|
-
backgroundColor: event.color
|
|
202
|
-
? event.color
|
|
203
|
-
: event.isCompleted
|
|
204
|
-
? tokens.colors.success
|
|
205
|
-
: tokens.colors.primary,
|
|
206
|
-
},
|
|
207
|
-
]}
|
|
208
|
-
/>
|
|
209
|
-
))}
|
|
210
|
-
|
|
211
|
-
{/* More events count */}
|
|
212
|
-
{showEventCount && hiddenEventCount > 0 && (
|
|
213
|
-
<AtomicText
|
|
214
|
-
type="bodySmall"
|
|
215
|
-
color="secondary"
|
|
216
|
-
style={styles.moreEventsText}
|
|
217
|
-
>
|
|
218
|
-
+{hiddenEventCount}
|
|
219
|
-
</AtomicText>
|
|
220
|
-
)}
|
|
221
|
-
</View>
|
|
222
|
-
</TouchableOpacity>
|
|
123
|
+
day={day}
|
|
124
|
+
index={index}
|
|
125
|
+
isSelected={isSelected}
|
|
126
|
+
selectedDate={selectedDate}
|
|
127
|
+
onDateSelect={onDateSelect}
|
|
128
|
+
maxEventIndicators={maxEventIndicators}
|
|
129
|
+
showEventCount={showEventCount}
|
|
130
|
+
dayStyle={dayStyle}
|
|
131
|
+
testID={testID}
|
|
132
|
+
/>
|
|
223
133
|
);
|
|
224
134
|
})}
|
|
225
135
|
</View>
|
|
226
136
|
</View>
|
|
227
137
|
);
|
|
228
138
|
};
|
|
229
|
-
|
|
230
|
-
const styles = StyleSheet.create({
|
|
231
|
-
container: {
|
|
232
|
-
borderRadius: 12,
|
|
233
|
-
padding: 16,
|
|
234
|
-
},
|
|
235
|
-
weekdayHeader: {
|
|
236
|
-
flexDirection: 'row',
|
|
237
|
-
marginBottom: 12,
|
|
238
|
-
},
|
|
239
|
-
weekdayCell: {
|
|
240
|
-
flex: 1,
|
|
241
|
-
alignItems: 'center',
|
|
242
|
-
},
|
|
243
|
-
weekdayText: {
|
|
244
|
-
textAlign: 'center',
|
|
245
|
-
},
|
|
246
|
-
grid: {
|
|
247
|
-
flexDirection: 'row',
|
|
248
|
-
flexWrap: 'wrap',
|
|
249
|
-
},
|
|
250
|
-
dayCell: {
|
|
251
|
-
width: `${100 / 7}%`,
|
|
252
|
-
aspectRatio: 1,
|
|
253
|
-
justifyContent: 'center',
|
|
254
|
-
alignItems: 'center',
|
|
255
|
-
borderRadius: 8,
|
|
256
|
-
marginBottom: 4,
|
|
257
|
-
padding: 4,
|
|
258
|
-
},
|
|
259
|
-
dayText: {
|
|
260
|
-
textAlign: 'center',
|
|
261
|
-
},
|
|
262
|
-
eventIndicators: {
|
|
263
|
-
flexDirection: 'row',
|
|
264
|
-
alignItems: 'center',
|
|
265
|
-
justifyContent: 'center',
|
|
266
|
-
marginTop: 4,
|
|
267
|
-
gap: 2,
|
|
268
|
-
flexWrap: 'wrap',
|
|
269
|
-
},
|
|
270
|
-
eventDot: {
|
|
271
|
-
width: 4,
|
|
272
|
-
height: 4,
|
|
273
|
-
borderRadius: 2,
|
|
274
|
-
},
|
|
275
|
-
moreEventsText: {
|
|
276
|
-
fontSize: 8,
|
|
277
|
-
marginLeft: 2,
|
|
278
|
-
},
|
|
279
|
-
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Day Cell Component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { TouchableOpacity, View, StyleProp, ViewStyle } from 'react-native';
|
|
7
|
+
import { AtomicText, useAppDesignTokens } from '../../../../index';
|
|
8
|
+
import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
|
|
9
|
+
import { CalendarService } from '../../infrastructure/services/CalendarService';
|
|
10
|
+
import { calendarStyles } from './calendarStyles';
|
|
11
|
+
|
|
12
|
+
interface CalendarDayCellProps {
|
|
13
|
+
day: CalendarDay;
|
|
14
|
+
index: number;
|
|
15
|
+
isSelected: boolean;
|
|
16
|
+
selectedDate: Date;
|
|
17
|
+
onDateSelect: (date: Date) => void;
|
|
18
|
+
maxEventIndicators: number;
|
|
19
|
+
showEventCount: boolean;
|
|
20
|
+
dayStyle?: StyleProp<ViewStyle>;
|
|
21
|
+
testID?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const CalendarDayCell: React.FC<CalendarDayCellProps> = ({
|
|
25
|
+
day,
|
|
26
|
+
index,
|
|
27
|
+
isSelected,
|
|
28
|
+
selectedDate,
|
|
29
|
+
onDateSelect,
|
|
30
|
+
maxEventIndicators,
|
|
31
|
+
showEventCount,
|
|
32
|
+
dayStyle,
|
|
33
|
+
testID,
|
|
34
|
+
}) => {
|
|
35
|
+
const tokens = useAppDesignTokens();
|
|
36
|
+
const eventCount = day.events.length;
|
|
37
|
+
const visibleEvents = day.events.slice(0, maxEventIndicators);
|
|
38
|
+
const hiddenEventCount = Math.max(0, eventCount - maxEventIndicators);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<TouchableOpacity
|
|
42
|
+
key={index}
|
|
43
|
+
style={[
|
|
44
|
+
calendarStyles.dayCell,
|
|
45
|
+
{
|
|
46
|
+
backgroundColor: isSelected ? tokens.colors.primary : 'transparent',
|
|
47
|
+
borderColor: isSelected
|
|
48
|
+
? tokens.colors.primary
|
|
49
|
+
: day.isToday
|
|
50
|
+
? tokens.colors.primary
|
|
51
|
+
: tokens.colors.border,
|
|
52
|
+
borderWidth: isSelected ? 2 : day.isToday ? 2 : 1,
|
|
53
|
+
opacity: day.isDisabled ? 0.4 : 1,
|
|
54
|
+
},
|
|
55
|
+
dayStyle,
|
|
56
|
+
]}
|
|
57
|
+
onPress={() => !day.isDisabled && onDateSelect(day.date)}
|
|
58
|
+
disabled={day.isDisabled}
|
|
59
|
+
testID={testID ? `${testID}-day-${index}` : undefined}
|
|
60
|
+
accessibilityLabel={`${day.date.toLocaleDateString()}, ${eventCount} events`}
|
|
61
|
+
accessibilityRole="button"
|
|
62
|
+
accessibilityState={{ disabled: day.isDisabled, selected: isSelected }}
|
|
63
|
+
>
|
|
64
|
+
<AtomicText
|
|
65
|
+
type="bodyMedium"
|
|
66
|
+
color={isSelected ? 'inverse' : day.isCurrentMonth ? 'primary' : 'secondary'}
|
|
67
|
+
style={[calendarStyles.dayText, day.isToday && !isSelected && { fontWeight: 'bold' }]}
|
|
68
|
+
>
|
|
69
|
+
{day.date.getDate()}
|
|
70
|
+
</AtomicText>
|
|
71
|
+
|
|
72
|
+
<View style={calendarStyles.eventIndicators}>
|
|
73
|
+
{day.isToday && eventCount === 0 && (
|
|
74
|
+
<View style={[calendarStyles.eventDot, { backgroundColor: tokens.colors.success }]} />
|
|
75
|
+
)}
|
|
76
|
+
|
|
77
|
+
{visibleEvents.map((event, eventIndex) => (
|
|
78
|
+
<View
|
|
79
|
+
key={eventIndex}
|
|
80
|
+
style={[
|
|
81
|
+
calendarStyles.eventDot,
|
|
82
|
+
{
|
|
83
|
+
backgroundColor: event.color
|
|
84
|
+
? event.color
|
|
85
|
+
: event.isCompleted
|
|
86
|
+
? tokens.colors.success
|
|
87
|
+
: tokens.colors.primary,
|
|
88
|
+
},
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
))}
|
|
92
|
+
|
|
93
|
+
{showEventCount && hiddenEventCount > 0 && (
|
|
94
|
+
<AtomicText type="bodySmall" color="secondary" style={calendarStyles.moreEventsText}>
|
|
95
|
+
+{hiddenEventCount}
|
|
96
|
+
</AtomicText>
|
|
97
|
+
)}
|
|
98
|
+
</View>
|
|
99
|
+
</TouchableOpacity>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Weekday Header Component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { View } from 'react-native';
|
|
7
|
+
import { AtomicText } from '../../../../index';
|
|
8
|
+
import { calendarStyles } from './calendarStyles';
|
|
9
|
+
|
|
10
|
+
interface CalendarWeekdayHeaderProps {
|
|
11
|
+
weekdayNames: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const CalendarWeekdayHeader: React.FC<CalendarWeekdayHeaderProps> = ({
|
|
15
|
+
weekdayNames,
|
|
16
|
+
}) => {
|
|
17
|
+
return (
|
|
18
|
+
<View style={calendarStyles.weekdayHeader}>
|
|
19
|
+
{weekdayNames.map((day, index) => (
|
|
20
|
+
<View key={index} style={calendarStyles.weekdayCell}>
|
|
21
|
+
<AtomicText type="bodySmall" color="secondary" style={calendarStyles.weekdayText}>
|
|
22
|
+
{day}
|
|
23
|
+
</AtomicText>
|
|
24
|
+
</View>
|
|
25
|
+
))}
|
|
26
|
+
</View>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Component Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { StyleSheet } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export const calendarStyles = StyleSheet.create({
|
|
8
|
+
container: {
|
|
9
|
+
borderRadius: 12,
|
|
10
|
+
padding: 16,
|
|
11
|
+
},
|
|
12
|
+
weekdayHeader: {
|
|
13
|
+
flexDirection: 'row',
|
|
14
|
+
marginBottom: 12,
|
|
15
|
+
},
|
|
16
|
+
weekdayCell: {
|
|
17
|
+
flex: 1,
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
},
|
|
20
|
+
weekdayText: {
|
|
21
|
+
textAlign: 'center',
|
|
22
|
+
},
|
|
23
|
+
grid: {
|
|
24
|
+
flexDirection: 'row',
|
|
25
|
+
flexWrap: 'wrap',
|
|
26
|
+
},
|
|
27
|
+
dayCell: {
|
|
28
|
+
width: `${100 / 7}%`,
|
|
29
|
+
aspectRatio: 1,
|
|
30
|
+
justifyContent: 'center',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
borderRadius: 8,
|
|
33
|
+
marginBottom: 4,
|
|
34
|
+
padding: 4,
|
|
35
|
+
},
|
|
36
|
+
dayText: {
|
|
37
|
+
textAlign: 'center',
|
|
38
|
+
},
|
|
39
|
+
eventIndicators: {
|
|
40
|
+
flexDirection: 'row',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
justifyContent: 'center',
|
|
43
|
+
marginTop: 4,
|
|
44
|
+
gap: 2,
|
|
45
|
+
flexWrap: 'wrap',
|
|
46
|
+
},
|
|
47
|
+
eventDot: {
|
|
48
|
+
width: 4,
|
|
49
|
+
height: 4,
|
|
50
|
+
borderRadius: 2,
|
|
51
|
+
},
|
|
52
|
+
moreEventsText: {
|
|
53
|
+
fontSize: 8,
|
|
54
|
+
marginLeft: 2,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createFormStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
form: {
|
|
10
|
+
width: '100%',
|
|
11
|
+
} as ViewStyle,
|
|
12
|
+
|
|
13
|
+
formHeader: {
|
|
14
|
+
alignItems: 'center',
|
|
15
|
+
marginBottom: tokens.spacing.xl,
|
|
16
|
+
} as ViewStyle,
|
|
17
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createLayoutStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
centerContainer: {
|
|
10
|
+
flex: 1,
|
|
11
|
+
justifyContent: 'center',
|
|
12
|
+
alignItems: 'center',
|
|
13
|
+
} as ViewStyle,
|
|
14
|
+
|
|
15
|
+
centerContainerPadded: {
|
|
16
|
+
flex: 1,
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
paddingHorizontal: tokens.spacing.xl,
|
|
20
|
+
} as ViewStyle,
|
|
21
|
+
|
|
22
|
+
row: {
|
|
23
|
+
flexDirection: 'row',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
} as ViewStyle,
|
|
26
|
+
|
|
27
|
+
rowBetween: {
|
|
28
|
+
flexDirection: 'row',
|
|
29
|
+
alignItems: 'center',
|
|
30
|
+
justifyContent: 'space-between',
|
|
31
|
+
} as ViewStyle,
|
|
32
|
+
|
|
33
|
+
rowCenter: {
|
|
34
|
+
flexDirection: 'row',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
} as ViewStyle,
|
|
38
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Padding Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createPaddingStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
paddedHorizontal: {
|
|
10
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
11
|
+
} as ViewStyle,
|
|
12
|
+
|
|
13
|
+
paddedVertical: {
|
|
14
|
+
paddingVertical: tokens.spacing.lg,
|
|
15
|
+
} as ViewStyle,
|
|
16
|
+
|
|
17
|
+
padded: {
|
|
18
|
+
padding: tokens.spacing.lg,
|
|
19
|
+
} as ViewStyle,
|
|
20
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Container Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createScreenContainerStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
screenContainer: {
|
|
10
|
+
flex: 1,
|
|
11
|
+
backgroundColor: tokens.colors.backgroundPrimary,
|
|
12
|
+
} as ViewStyle,
|
|
13
|
+
|
|
14
|
+
flexContainer: {
|
|
15
|
+
flex: 1,
|
|
16
|
+
} as ViewStyle,
|
|
17
|
+
|
|
18
|
+
screenContainerSecondary: {
|
|
19
|
+
flex: 1,
|
|
20
|
+
backgroundColor: tokens.colors.backgroundSecondary,
|
|
21
|
+
} as ViewStyle,
|
|
22
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll Container Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createScrollContainerStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
scrollView: {
|
|
10
|
+
flex: 1,
|
|
11
|
+
} as ViewStyle,
|
|
12
|
+
|
|
13
|
+
scrollContent: {
|
|
14
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
15
|
+
paddingBottom: tokens.spacing.xl,
|
|
16
|
+
} as ViewStyle,
|
|
17
|
+
|
|
18
|
+
scrollContentGrow: {
|
|
19
|
+
flexGrow: 1,
|
|
20
|
+
padding: tokens.spacing.lg,
|
|
21
|
+
} as ViewStyle,
|
|
22
|
+
|
|
23
|
+
scrollContentCentered: {
|
|
24
|
+
flexGrow: 1,
|
|
25
|
+
padding: tokens.spacing.lg,
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
} as ViewStyle,
|
|
28
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createSectionStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
section: {
|
|
10
|
+
marginBottom: tokens.spacing.xl,
|
|
11
|
+
} as ViewStyle,
|
|
12
|
+
|
|
13
|
+
sectionPadded: {
|
|
14
|
+
marginBottom: tokens.spacing.xl,
|
|
15
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
16
|
+
} as ViewStyle,
|
|
17
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { TextStyle } from 'react-native';
|
|
6
|
+
import type { DesignTokens } from '../../types/ThemeTypes';
|
|
7
|
+
|
|
8
|
+
export const createTextStyles = (tokens: DesignTokens) => ({
|
|
9
|
+
screenTitle: {
|
|
10
|
+
...tokens.typography.headingLarge,
|
|
11
|
+
color: tokens.colors.textPrimary,
|
|
12
|
+
marginBottom: tokens.spacing.sm,
|
|
13
|
+
} as TextStyle,
|
|
14
|
+
|
|
15
|
+
sectionTitle: {
|
|
16
|
+
...tokens.typography.headingMedium,
|
|
17
|
+
color: tokens.colors.textPrimary,
|
|
18
|
+
marginBottom: tokens.spacing.md,
|
|
19
|
+
} as TextStyle,
|
|
20
|
+
|
|
21
|
+
subtitle: {
|
|
22
|
+
...tokens.typography.bodyMedium,
|
|
23
|
+
color: tokens.colors.textSecondary,
|
|
24
|
+
textAlign: 'center',
|
|
25
|
+
} as TextStyle,
|
|
26
|
+
|
|
27
|
+
bodyText: {
|
|
28
|
+
...tokens.typography.bodyMedium,
|
|
29
|
+
color: tokens.colors.textPrimary,
|
|
30
|
+
} as TextStyle,
|
|
31
|
+
|
|
32
|
+
secondaryText: {
|
|
33
|
+
...tokens.typography.bodySmall,
|
|
34
|
+
color: tokens.colors.textSecondary,
|
|
35
|
+
} as TextStyle,
|
|
36
|
+
});
|
|
@@ -16,8 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { useMemo } from 'react';
|
|
19
|
-
import type { ViewStyle, TextStyle } from 'react-native';
|
|
20
19
|
import { useAppDesignTokens } from './useAppDesignTokens';
|
|
20
|
+
import { createScreenContainerStyles } from './commonStyles/screenContainerStyles';
|
|
21
|
+
import { createScrollContainerStyles } from './commonStyles/scrollContainerStyles';
|
|
22
|
+
import { createLayoutStyles } from './commonStyles/layoutStyles';
|
|
23
|
+
import { createPaddingStyles } from './commonStyles/paddingStyles';
|
|
24
|
+
import { createSectionStyles } from './commonStyles/sectionStyles';
|
|
25
|
+
import { createTextStyles } from './commonStyles/textStyles';
|
|
26
|
+
import { createFormStyles } from './commonStyles/formStyles';
|
|
21
27
|
|
|
22
28
|
/**
|
|
23
29
|
* Hook to get common styles with dynamic theme support
|
|
@@ -25,224 +31,14 @@ import { useAppDesignTokens } from './useAppDesignTokens';
|
|
|
25
31
|
*/
|
|
26
32
|
export const useCommonStyles = () => {
|
|
27
33
|
const tokens = useAppDesignTokens();
|
|
28
|
-
|
|
34
|
+
|
|
29
35
|
return useMemo(() => ({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
screenContainer: {
|
|
38
|
-
flex: 1,
|
|
39
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
40
|
-
} as ViewStyle,
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Basic flex container without background
|
|
44
|
-
* Use when background is set elsewhere or not needed
|
|
45
|
-
*/
|
|
46
|
-
flexContainer: {
|
|
47
|
-
flex: 1,
|
|
48
|
-
} as ViewStyle,
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Screen container with secondary background
|
|
52
|
-
*/
|
|
53
|
-
screenContainerSecondary: {
|
|
54
|
-
flex: 1,
|
|
55
|
-
backgroundColor: tokens.colors.backgroundSecondary,
|
|
56
|
-
} as ViewStyle,
|
|
57
|
-
|
|
58
|
-
// ========================================================================
|
|
59
|
-
// SCROLL CONTAINERS
|
|
60
|
-
// ========================================================================
|
|
61
|
-
/**
|
|
62
|
-
* Standard ScrollView wrapper
|
|
63
|
-
*/
|
|
64
|
-
scrollView: {
|
|
65
|
-
flex: 1,
|
|
66
|
-
} as ViewStyle,
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* ScrollView content container with standard padding
|
|
70
|
-
*/
|
|
71
|
-
scrollContent: {
|
|
72
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
73
|
-
paddingBottom: tokens.spacing.xl,
|
|
74
|
-
} as ViewStyle,
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* ScrollView content that grows to fill available space
|
|
78
|
-
*/
|
|
79
|
-
scrollContentGrow: {
|
|
80
|
-
flexGrow: 1,
|
|
81
|
-
padding: tokens.spacing.lg,
|
|
82
|
-
} as ViewStyle,
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Centered scroll content (for forms, onboarding screens)
|
|
86
|
-
*/
|
|
87
|
-
scrollContentCentered: {
|
|
88
|
-
flexGrow: 1,
|
|
89
|
-
padding: tokens.spacing.lg,
|
|
90
|
-
justifyContent: 'center',
|
|
91
|
-
} as ViewStyle,
|
|
92
|
-
|
|
93
|
-
// ========================================================================
|
|
94
|
-
// LAYOUT UTILITIES
|
|
95
|
-
// ========================================================================
|
|
96
|
-
/**
|
|
97
|
-
* Centered container - both horizontal and vertical
|
|
98
|
-
* Perfect for empty states, splash screens
|
|
99
|
-
*/
|
|
100
|
-
centerContainer: {
|
|
101
|
-
flex: 1,
|
|
102
|
-
justifyContent: 'center',
|
|
103
|
-
alignItems: 'center',
|
|
104
|
-
} as ViewStyle,
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Centered container with padding
|
|
108
|
-
*/
|
|
109
|
-
centerContainerPadded: {
|
|
110
|
-
flex: 1,
|
|
111
|
-
justifyContent: 'center',
|
|
112
|
-
alignItems: 'center',
|
|
113
|
-
paddingHorizontal: tokens.spacing.xl,
|
|
114
|
-
} as ViewStyle,
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Horizontal row layout
|
|
118
|
-
*/
|
|
119
|
-
row: {
|
|
120
|
-
flexDirection: 'row',
|
|
121
|
-
alignItems: 'center',
|
|
122
|
-
} as ViewStyle,
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Horizontal row with space between
|
|
126
|
-
*/
|
|
127
|
-
rowBetween: {
|
|
128
|
-
flexDirection: 'row',
|
|
129
|
-
alignItems: 'center',
|
|
130
|
-
justifyContent: 'space-between',
|
|
131
|
-
} as ViewStyle,
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Horizontal row centered
|
|
135
|
-
*/
|
|
136
|
-
rowCenter: {
|
|
137
|
-
flexDirection: 'row',
|
|
138
|
-
alignItems: 'center',
|
|
139
|
-
justifyContent: 'center',
|
|
140
|
-
} as ViewStyle,
|
|
141
|
-
|
|
142
|
-
// ========================================================================
|
|
143
|
-
// PADDING UTILITIES
|
|
144
|
-
// ========================================================================
|
|
145
|
-
/**
|
|
146
|
-
* Standard horizontal padding
|
|
147
|
-
*/
|
|
148
|
-
paddedHorizontal: {
|
|
149
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
150
|
-
} as ViewStyle,
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Standard vertical padding
|
|
154
|
-
*/
|
|
155
|
-
paddedVertical: {
|
|
156
|
-
paddingVertical: tokens.spacing.lg,
|
|
157
|
-
} as ViewStyle,
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Standard padding all sides
|
|
161
|
-
*/
|
|
162
|
-
padded: {
|
|
163
|
-
padding: tokens.spacing.lg,
|
|
164
|
-
} as ViewStyle,
|
|
165
|
-
|
|
166
|
-
// ========================================================================
|
|
167
|
-
// SECTION STYLES
|
|
168
|
-
// ========================================================================
|
|
169
|
-
/**
|
|
170
|
-
* Standard section container
|
|
171
|
-
*/
|
|
172
|
-
section: {
|
|
173
|
-
marginBottom: tokens.spacing.xl,
|
|
174
|
-
} as ViewStyle,
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Section with padding
|
|
178
|
-
*/
|
|
179
|
-
sectionPadded: {
|
|
180
|
-
marginBottom: tokens.spacing.xl,
|
|
181
|
-
paddingHorizontal: tokens.spacing.lg,
|
|
182
|
-
} as ViewStyle,
|
|
183
|
-
|
|
184
|
-
// ========================================================================
|
|
185
|
-
// TEXT STYLES
|
|
186
|
-
// ========================================================================
|
|
187
|
-
/**
|
|
188
|
-
* Screen title - primary heading
|
|
189
|
-
*/
|
|
190
|
-
screenTitle: {
|
|
191
|
-
...tokens.typography.headingLarge,
|
|
192
|
-
color: tokens.colors.textPrimary,
|
|
193
|
-
marginBottom: tokens.spacing.sm,
|
|
194
|
-
} as TextStyle,
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Section title
|
|
198
|
-
*/
|
|
199
|
-
sectionTitle: {
|
|
200
|
-
...tokens.typography.headingMedium,
|
|
201
|
-
color: tokens.colors.textPrimary,
|
|
202
|
-
marginBottom: tokens.spacing.md,
|
|
203
|
-
} as TextStyle,
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Subtitle/description text
|
|
207
|
-
*/
|
|
208
|
-
subtitle: {
|
|
209
|
-
...tokens.typography.bodyMedium,
|
|
210
|
-
color: tokens.colors.textSecondary,
|
|
211
|
-
textAlign: 'center',
|
|
212
|
-
} as TextStyle,
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Body text
|
|
216
|
-
*/
|
|
217
|
-
bodyText: {
|
|
218
|
-
...tokens.typography.bodyMedium,
|
|
219
|
-
color: tokens.colors.textPrimary,
|
|
220
|
-
} as TextStyle,
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Secondary text (muted)
|
|
224
|
-
*/
|
|
225
|
-
secondaryText: {
|
|
226
|
-
...tokens.typography.bodySmall,
|
|
227
|
-
color: tokens.colors.textSecondary,
|
|
228
|
-
} as TextStyle,
|
|
229
|
-
|
|
230
|
-
// ========================================================================
|
|
231
|
-
// FORM STYLES
|
|
232
|
-
// ========================================================================
|
|
233
|
-
/**
|
|
234
|
-
* Form container
|
|
235
|
-
*/
|
|
236
|
-
form: {
|
|
237
|
-
width: '100%',
|
|
238
|
-
} as ViewStyle,
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Form header section
|
|
242
|
-
*/
|
|
243
|
-
formHeader: {
|
|
244
|
-
alignItems: 'center',
|
|
245
|
-
marginBottom: tokens.spacing.xl,
|
|
246
|
-
} as ViewStyle,
|
|
36
|
+
...createScreenContainerStyles(tokens),
|
|
37
|
+
...createScrollContainerStyles(tokens),
|
|
38
|
+
...createLayoutStyles(tokens),
|
|
39
|
+
...createPaddingStyles(tokens),
|
|
40
|
+
...createSectionStyles(tokens),
|
|
41
|
+
...createTextStyles(tokens),
|
|
42
|
+
...createFormStyles(tokens),
|
|
247
43
|
}), [tokens]);
|
|
248
44
|
};
|