@umituz/react-native-design-system 4.28.15 → 4.28.17
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/datepicker/components/DatePickerModal.tsx +5 -2
- package/src/media/infrastructure/utils/file-media-utils.ts +5 -0
- package/src/molecules/List/List.tsx +23 -19
- package/src/molecules/alerts/AlertBanner.tsx +62 -42
- package/src/molecules/alerts/AlertInline.tsx +13 -11
- package/src/molecules/alerts/AlertToast.tsx +67 -47
- package/src/molecules/emoji/index.ts +5 -2
- package/src/molecules/filter-group/FilterGroup.tsx +3 -3
- package/src/molecules/navigation/components/NavigationHeader.tsx +7 -7
- package/src/organisms/FormContainer.tsx +26 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "4.28.
|
|
3
|
+
"version": "4.28.17",
|
|
4
4
|
"description": "Universal design system for React Native apps with safe navigation hooks - updated SKILL.md with navigation documentation",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
View,
|
|
11
11
|
Modal,
|
|
12
12
|
TouchableOpacity,
|
|
13
|
-
StyleSheet,
|
|
14
13
|
Platform,
|
|
15
14
|
} from 'react-native';
|
|
16
15
|
import { useSafeAreaInsets } from '../../../safe-area';
|
|
@@ -103,6 +102,10 @@ export const DatePickerModal: React.FC<DatePickerModalProps> = ({
|
|
|
103
102
|
},
|
|
104
103
|
}), [overlayOpacity, tokens, insets.bottom]);
|
|
105
104
|
|
|
105
|
+
const pickerStyle = useMemo(() => ({
|
|
106
|
+
alignSelf: 'center' as const,
|
|
107
|
+
}), []);
|
|
108
|
+
|
|
106
109
|
if (Platform.OS !== 'ios' || !DateTimePicker) {
|
|
107
110
|
return null;
|
|
108
111
|
}
|
|
@@ -145,7 +148,7 @@ export const DatePickerModal: React.FC<DatePickerModalProps> = ({
|
|
|
145
148
|
minimumDate={minimumDate}
|
|
146
149
|
maximumDate={maximumDate}
|
|
147
150
|
display="spinner"
|
|
148
|
-
style={
|
|
151
|
+
style={pickerStyle}
|
|
149
152
|
testID={testID ? `${testID}-picker` : undefined}
|
|
150
153
|
/>
|
|
151
154
|
</View>
|
|
@@ -12,6 +12,11 @@ interface FileWithType {
|
|
|
12
12
|
|
|
13
13
|
export async function getMediaDuration(file: FileWithType): Promise<number | undefined> {
|
|
14
14
|
if (file.type.startsWith("audio/") || file.type.startsWith("video/")) {
|
|
15
|
+
// Stub implementation - returns a random duration for demo purposes
|
|
16
|
+
// In production, this should extract actual media duration using AVFoundation or MediaMetadataRetriever
|
|
17
|
+
if (__DEV__) {
|
|
18
|
+
console.warn('[getMediaDuration] Using stub implementation with random duration');
|
|
19
|
+
}
|
|
15
20
|
return Math.floor(Math.random() * 60) + 10;
|
|
16
21
|
}
|
|
17
22
|
return undefined;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Uses design system responsive utilities
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React from 'react';
|
|
8
|
+
import React, { useMemo } from 'react';
|
|
9
9
|
import { FlatList, RefreshControl, type FlatListProps, type ListRenderItem } from 'react-native';
|
|
10
10
|
import { useAppDesignTokens } from '../../theme';
|
|
11
11
|
|
|
@@ -55,29 +55,33 @@ export const List = <T,>({
|
|
|
55
55
|
}: ListProps<T>) => {
|
|
56
56
|
const tokens = useAppDesignTokens();
|
|
57
57
|
|
|
58
|
+
const contentContainerStyle = useMemo(() => (
|
|
59
|
+
contentPadding
|
|
60
|
+
? {
|
|
61
|
+
paddingHorizontal: tokens.spacing.screenPadding,
|
|
62
|
+
paddingBottom: tokens.spacing.lg,
|
|
63
|
+
}
|
|
64
|
+
: undefined
|
|
65
|
+
), [contentPadding, tokens.spacing.screenPadding, tokens.spacing.lg]);
|
|
66
|
+
|
|
67
|
+
const refreshControlElement = useMemo(() => (
|
|
68
|
+
onRefresh ? (
|
|
69
|
+
<RefreshControl
|
|
70
|
+
refreshing={refreshing}
|
|
71
|
+
onRefresh={onRefresh}
|
|
72
|
+
tintColor={tokens.colors.primary}
|
|
73
|
+
colors={[tokens.colors.primary]}
|
|
74
|
+
/>
|
|
75
|
+
) : undefined
|
|
76
|
+
), [onRefresh, refreshing, tokens.colors.primary]);
|
|
77
|
+
|
|
58
78
|
return (
|
|
59
79
|
<FlatList
|
|
60
80
|
data={data}
|
|
61
81
|
renderItem={renderItem}
|
|
62
82
|
keyExtractor={keyExtractor}
|
|
63
|
-
refreshControl={
|
|
64
|
-
|
|
65
|
-
<RefreshControl
|
|
66
|
-
refreshing={refreshing}
|
|
67
|
-
onRefresh={onRefresh}
|
|
68
|
-
tintColor={tokens.colors.primary}
|
|
69
|
-
colors={[tokens.colors.primary]}
|
|
70
|
-
/>
|
|
71
|
-
) : undefined
|
|
72
|
-
}
|
|
73
|
-
contentContainerStyle={
|
|
74
|
-
contentPadding
|
|
75
|
-
? {
|
|
76
|
-
paddingHorizontal: tokens.spacing.screenPadding,
|
|
77
|
-
paddingBottom: tokens.spacing.lg,
|
|
78
|
-
}
|
|
79
|
-
: undefined
|
|
80
|
-
}
|
|
83
|
+
refreshControl={refreshControlElement}
|
|
84
|
+
contentContainerStyle={contentContainerStyle}
|
|
81
85
|
showsVerticalScrollIndicator={false}
|
|
82
86
|
keyboardShouldPersistTaps="handled"
|
|
83
87
|
{...rest}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Auto-dismisses after duration (default 3 seconds).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React from 'react';
|
|
9
|
+
import React, { useMemo, useCallback } from 'react';
|
|
10
10
|
import { StyleSheet, View, Pressable } from 'react-native';
|
|
11
11
|
import { useSafeAreaInsets } from '../../safe-area';
|
|
12
12
|
import { AtomicText, useIconName } from '../../atoms';
|
|
@@ -33,17 +33,36 @@ export function AlertBanner({ alert }: AlertBannerProps) {
|
|
|
33
33
|
const textColor = getAlertTextColor(tokens);
|
|
34
34
|
const isTop = alert.position === AlertPosition.TOP;
|
|
35
35
|
|
|
36
|
+
const containerStyle = useMemo(() => [
|
|
37
|
+
styles.container,
|
|
38
|
+
{
|
|
39
|
+
backgroundColor,
|
|
40
|
+
paddingTop: isTop ? insets.top + tokens.spacing.sm : tokens.spacing.sm,
|
|
41
|
+
paddingBottom: isTop ? tokens.spacing.sm : insets.bottom + tokens.spacing.sm,
|
|
42
|
+
paddingHorizontal: tokens.spacing.md,
|
|
43
|
+
},
|
|
44
|
+
], [backgroundColor, insets.bottom, insets.top, isTop, tokens.spacing.md, tokens.spacing.sm]);
|
|
45
|
+
|
|
46
|
+
const closeButtonStyle = useMemo(() => [
|
|
47
|
+
styles.closeButton,
|
|
48
|
+
{ marginLeft: tokens.spacing.sm }
|
|
49
|
+
], [tokens.spacing.sm]);
|
|
50
|
+
|
|
51
|
+
const actionsContainerStyle = useMemo(() => [
|
|
52
|
+
styles.actionsContainer,
|
|
53
|
+
{ marginTop: tokens.spacing.sm }
|
|
54
|
+
], [tokens.spacing.sm]);
|
|
55
|
+
|
|
56
|
+
const handleActionPress = useCallback(async (action: typeof alert.actions[0]) => {
|
|
57
|
+
await action.onPress();
|
|
58
|
+
if (action.closeOnPress ?? true) {
|
|
59
|
+
handleDismiss();
|
|
60
|
+
}
|
|
61
|
+
}, [handleDismiss]);
|
|
62
|
+
|
|
36
63
|
return (
|
|
37
64
|
<View
|
|
38
|
-
style={
|
|
39
|
-
styles.container,
|
|
40
|
-
{
|
|
41
|
-
backgroundColor,
|
|
42
|
-
paddingTop: isTop ? insets.top + tokens.spacing.sm : tokens.spacing.sm,
|
|
43
|
-
paddingBottom: isTop ? tokens.spacing.sm : insets.bottom + tokens.spacing.sm,
|
|
44
|
-
paddingHorizontal: tokens.spacing.md,
|
|
45
|
-
},
|
|
46
|
-
]}
|
|
65
|
+
style={containerStyle}
|
|
47
66
|
testID={alert.testID}
|
|
48
67
|
>
|
|
49
68
|
<View style={styles.content}>
|
|
@@ -69,7 +88,7 @@ export function AlertBanner({ alert }: AlertBannerProps) {
|
|
|
69
88
|
{alert.dismissible && (
|
|
70
89
|
<Pressable
|
|
71
90
|
onPress={handleDismiss}
|
|
72
|
-
style={
|
|
91
|
+
style={closeButtonStyle}
|
|
73
92
|
hitSlop={8}
|
|
74
93
|
>
|
|
75
94
|
<AlertIcon name={closeIcon} color={textColor} />
|
|
@@ -78,38 +97,39 @@ export function AlertBanner({ alert }: AlertBannerProps) {
|
|
|
78
97
|
</View>
|
|
79
98
|
|
|
80
99
|
{alert.actions && alert.actions.length > 0 && (
|
|
81
|
-
<View style={
|
|
82
|
-
{alert.actions.map((action) =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
style
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
style={[
|
|
105
|
-
styles.actionText,
|
|
106
|
-
{ color: getActionTextColor(action.style, tokens) },
|
|
107
|
-
]}
|
|
100
|
+
<View style={actionsContainerStyle}>
|
|
101
|
+
{alert.actions.map((action) => {
|
|
102
|
+
const actionButtonStyle = useMemo(() => [
|
|
103
|
+
styles.actionButton,
|
|
104
|
+
{
|
|
105
|
+
paddingVertical: tokens.spacing.xs,
|
|
106
|
+
paddingHorizontal: tokens.spacing.sm,
|
|
107
|
+
marginRight: tokens.spacing.xs,
|
|
108
|
+
borderRadius: tokens.borders.radius.sm,
|
|
109
|
+
},
|
|
110
|
+
getActionButtonStyle(action.style, tokens),
|
|
111
|
+
], [action.style, tokens]);
|
|
112
|
+
|
|
113
|
+
const actionTextStyle = useMemo(() => [
|
|
114
|
+
styles.actionText,
|
|
115
|
+
{ color: getActionTextColor(action.style, tokens) }
|
|
116
|
+
], [action.style, tokens]);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Pressable
|
|
120
|
+
key={action.id}
|
|
121
|
+
onPress={() => handleActionPress(action)}
|
|
122
|
+
style={actionButtonStyle}
|
|
108
123
|
>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
<AtomicText
|
|
125
|
+
type="bodySmall"
|
|
126
|
+
style={actionTextStyle}
|
|
127
|
+
>
|
|
128
|
+
{action.label}
|
|
129
|
+
</AtomicText>
|
|
130
|
+
</Pressable>
|
|
131
|
+
);
|
|
132
|
+
})}
|
|
113
133
|
</View>
|
|
114
134
|
)}
|
|
115
135
|
</View>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AlertInline Component
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import React from 'react';
|
|
5
|
+
import React, { useMemo } from 'react';
|
|
6
6
|
import { StyleSheet, View } from 'react-native';
|
|
7
7
|
import { useAppDesignTokens } from '../../theme';
|
|
8
8
|
import { Alert } from './AlertTypes';
|
|
@@ -16,17 +16,19 @@ interface AlertInlineProps {
|
|
|
16
16
|
export const AlertInline: React.FC<AlertInlineProps> = ({ alert }) => {
|
|
17
17
|
const tokens = useAppDesignTokens();
|
|
18
18
|
|
|
19
|
+
const containerStyle = useMemo(() => [
|
|
20
|
+
styles.container,
|
|
21
|
+
{
|
|
22
|
+
borderColor: getAlertBorderColor(alert.type, tokens),
|
|
23
|
+
backgroundColor: getAlertBackgroundColorInline(alert.type, tokens),
|
|
24
|
+
borderRadius: tokens.borders.radius.sm,
|
|
25
|
+
padding: tokens.spacing.md,
|
|
26
|
+
marginVertical: tokens.spacing.sm,
|
|
27
|
+
}
|
|
28
|
+
], [alert.type, tokens]);
|
|
29
|
+
|
|
19
30
|
return (
|
|
20
|
-
<View style={
|
|
21
|
-
styles.container,
|
|
22
|
-
{
|
|
23
|
-
borderColor: getAlertBorderColor(alert.type, tokens),
|
|
24
|
-
backgroundColor: getAlertBackgroundColorInline(alert.type, tokens),
|
|
25
|
-
borderRadius: tokens.borders.radius.sm,
|
|
26
|
-
padding: tokens.spacing.md,
|
|
27
|
-
marginVertical: tokens.spacing.sm,
|
|
28
|
-
}
|
|
29
|
-
]}>
|
|
31
|
+
<View style={containerStyle}>
|
|
30
32
|
<AlertContent
|
|
31
33
|
title={alert.title}
|
|
32
34
|
message={alert.message}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Floats on top of content.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React from 'react';
|
|
8
|
+
import React, { useMemo, useCallback } from 'react';
|
|
9
9
|
import { StyleSheet, View, Pressable } from 'react-native';
|
|
10
10
|
import { AtomicText, useIconName } from '../../atoms';
|
|
11
11
|
import { useAppDesignTokens } from '../../theme';
|
|
@@ -34,16 +34,39 @@ export function AlertToast({ alert }: AlertToastProps) {
|
|
|
34
34
|
const backgroundColor = getAlertBackgroundColor(alert.type, tokens);
|
|
35
35
|
const textColor = getAlertTextColor(tokens);
|
|
36
36
|
|
|
37
|
+
const containerStyle = useMemo(() => [
|
|
38
|
+
styles.container,
|
|
39
|
+
{
|
|
40
|
+
backgroundColor,
|
|
41
|
+
padding: tokens.spacing.md,
|
|
42
|
+
borderRadius: tokens.borders.radius.md,
|
|
43
|
+
},
|
|
44
|
+
], [backgroundColor, tokens.borders.radius.md, tokens.spacing.md]);
|
|
45
|
+
|
|
46
|
+
const closeButtonStyle = useMemo(() => [
|
|
47
|
+
styles.closeButton,
|
|
48
|
+
{ marginLeft: tokens.spacing.sm }
|
|
49
|
+
], [tokens.spacing.sm]);
|
|
50
|
+
|
|
51
|
+
const actionsContainerStyle = useMemo(() => [
|
|
52
|
+
styles.actionsContainer,
|
|
53
|
+
{ marginTop: tokens.spacing.sm }
|
|
54
|
+
], [tokens.spacing.sm]);
|
|
55
|
+
|
|
56
|
+
const handleActionPress = useCallback(async (action: typeof alert.actions[0]) => {
|
|
57
|
+
try {
|
|
58
|
+
await action.onPress();
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (__DEV__) console.error('[AlertToast] action.onPress failed', e);
|
|
61
|
+
}
|
|
62
|
+
if (action.closeOnPress ?? true) {
|
|
63
|
+
handleDismiss();
|
|
64
|
+
}
|
|
65
|
+
}, [handleDismiss]);
|
|
66
|
+
|
|
37
67
|
return (
|
|
38
68
|
<View
|
|
39
|
-
style={
|
|
40
|
-
styles.container,
|
|
41
|
-
{
|
|
42
|
-
backgroundColor,
|
|
43
|
-
padding: tokens.spacing.md,
|
|
44
|
-
borderRadius: tokens.borders.radius.md,
|
|
45
|
-
},
|
|
46
|
-
]}
|
|
69
|
+
style={containerStyle}
|
|
47
70
|
testID={alert.testID}
|
|
48
71
|
>
|
|
49
72
|
<Pressable
|
|
@@ -72,7 +95,7 @@ export function AlertToast({ alert }: AlertToastProps) {
|
|
|
72
95
|
{alert.dismissible && (
|
|
73
96
|
<Pressable
|
|
74
97
|
onPress={handleDismiss}
|
|
75
|
-
style={
|
|
98
|
+
style={closeButtonStyle}
|
|
76
99
|
hitSlop={8}
|
|
77
100
|
>
|
|
78
101
|
<AlertIcon name={closeIcon} color={textColor} />
|
|
@@ -81,44 +104,41 @@ export function AlertToast({ alert }: AlertToastProps) {
|
|
|
81
104
|
</View>
|
|
82
105
|
|
|
83
106
|
{alert.actions && alert.actions.length > 0 && (
|
|
84
|
-
<View style={
|
|
85
|
-
{alert.actions.map((action) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
]}
|
|
110
|
-
>
|
|
111
|
-
<AtomicText
|
|
112
|
-
type="bodySmall"
|
|
113
|
-
style={[
|
|
114
|
-
styles.actionText,
|
|
115
|
-
{ color: getActionTextColor(action.style, tokens) },
|
|
116
|
-
]}
|
|
107
|
+
<View style={actionsContainerStyle}>
|
|
108
|
+
{alert.actions.map((action) => {
|
|
109
|
+
const actionButtonStyle = useMemo(() => [
|
|
110
|
+
styles.actionButton,
|
|
111
|
+
{
|
|
112
|
+
paddingVertical: tokens.spacing.xs,
|
|
113
|
+
paddingHorizontal: tokens.spacing.sm,
|
|
114
|
+
marginRight: tokens.spacing.xs,
|
|
115
|
+
borderRadius: tokens.borders.radius.sm,
|
|
116
|
+
},
|
|
117
|
+
getActionButtonStyle(action.style, tokens),
|
|
118
|
+
], [action.style, tokens]);
|
|
119
|
+
|
|
120
|
+
const actionTextStyle = useMemo(() => [
|
|
121
|
+
styles.actionText,
|
|
122
|
+
{ color: getActionTextColor(action.style, tokens) }
|
|
123
|
+
], [action.style, tokens]);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<Pressable
|
|
127
|
+
key={action.id}
|
|
128
|
+
onPress={() => handleActionPress(action)}
|
|
129
|
+
accessibilityRole="button"
|
|
130
|
+
accessibilityLabel={action.label}
|
|
131
|
+
style={actionButtonStyle}
|
|
117
132
|
>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
<AtomicText
|
|
134
|
+
type="bodySmall"
|
|
135
|
+
style={actionTextStyle}
|
|
136
|
+
>
|
|
137
|
+
{action.label}
|
|
138
|
+
</AtomicText>
|
|
139
|
+
</Pressable>
|
|
140
|
+
);
|
|
141
|
+
})}
|
|
122
142
|
</View>
|
|
123
143
|
)}
|
|
124
144
|
</Pressable>
|
|
@@ -166,8 +166,11 @@ export type {
|
|
|
166
166
|
export { EmojiCategory, EmojiUtils } from './domain/entities/Emoji';
|
|
167
167
|
|
|
168
168
|
// Presentation Components
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
// NOTE: EmojiPicker requires rn-emoji-keyboard (optional peer dependency)
|
|
170
|
+
// Import it directly when needed:
|
|
171
|
+
// import { EmojiPicker } from '@umituz/react-native-design-system/src/molecules/emoji/presentation/components/EmojiPicker';
|
|
172
|
+
// export { EmojiPicker } from './presentation/components/EmojiPicker';
|
|
173
|
+
// export type { EmojiPickerProps } from './presentation/components/EmojiPicker';
|
|
171
174
|
|
|
172
175
|
// Presentation Hooks
|
|
173
176
|
export { useEmojiPicker } from './presentation/hooks/useEmojiPicker';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import React, { useMemo, useCallback } from 'react';
|
|
3
|
-
import { ScrollView
|
|
3
|
+
import { ScrollView } from 'react-native';
|
|
4
4
|
import { AtomicChip } from '../../atoms/chip/AtomicChip';
|
|
5
5
|
import { useAppDesignTokens } from '../../theme';
|
|
6
6
|
import type { FilterGroupProps } from './types';
|
|
@@ -16,14 +16,14 @@ export const FilterGroup = React.memo(function FilterGroup<T = string>({
|
|
|
16
16
|
}: FilterGroupProps<T>) {
|
|
17
17
|
const tokens = useAppDesignTokens();
|
|
18
18
|
|
|
19
|
-
const styles = useMemo(() =>
|
|
19
|
+
const styles = useMemo(() => ({
|
|
20
20
|
container: {
|
|
21
21
|
flexGrow: 0,
|
|
22
22
|
},
|
|
23
23
|
content: {
|
|
24
24
|
paddingHorizontal: tokens.spacing.md,
|
|
25
25
|
gap: tokens.spacing.md,
|
|
26
|
-
alignItems: 'center',
|
|
26
|
+
alignItems: 'center' as const,
|
|
27
27
|
},
|
|
28
28
|
item: {
|
|
29
29
|
},
|
|
@@ -25,14 +25,14 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
|
|
|
25
25
|
const arrowLeftIcon = useIconName('arrowLeft');
|
|
26
26
|
const spacingMultiplier = tokens.spacingMultiplier;
|
|
27
27
|
|
|
28
|
-
const styles = useMemo(() =>
|
|
28
|
+
const styles = useMemo(() => ({
|
|
29
29
|
container: {
|
|
30
30
|
paddingTop: insets.top,
|
|
31
31
|
paddingHorizontal: tokens.spacing.md,
|
|
32
32
|
paddingBottom: tokens.spacing.sm,
|
|
33
33
|
backgroundColor: tokens.colors.backgroundPrimary,
|
|
34
|
-
flexDirection: 'row',
|
|
35
|
-
alignItems: 'center',
|
|
34
|
+
flexDirection: 'row' as const,
|
|
35
|
+
alignItems: 'center' as const,
|
|
36
36
|
borderBottomWidth: 1,
|
|
37
37
|
borderBottomColor: tokens.colors.outlineVariant,
|
|
38
38
|
zIndex: 100,
|
|
@@ -42,16 +42,16 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
|
|
|
42
42
|
width: calculateResponsiveSize(NAVIGATION.backButton.width, spacingMultiplier),
|
|
43
43
|
height: calculateResponsiveSize(NAVIGATION.backButton.height, spacingMultiplier),
|
|
44
44
|
borderRadius: tokens.borders.radius.full,
|
|
45
|
-
alignItems: 'center',
|
|
46
|
-
justifyContent: 'center',
|
|
45
|
+
alignItems: 'center' as const,
|
|
46
|
+
justifyContent: 'center' as const,
|
|
47
47
|
backgroundColor: tokens.colors.surfaceVariant,
|
|
48
48
|
},
|
|
49
49
|
title: {
|
|
50
50
|
flex: 1,
|
|
51
|
-
textAlign: centerTitle ? 'center' : 'left',
|
|
51
|
+
textAlign: (centerTitle ? 'center' : 'left') as 'center' | 'left',
|
|
52
52
|
},
|
|
53
53
|
sideElement: {
|
|
54
|
-
width: centerTitle ? calculateResponsiveSize(40, spacingMultiplier) : 'auto',
|
|
54
|
+
width: centerTitle ? calculateResponsiveSize(40, spacingMultiplier) : 'auto' as const,
|
|
55
55
|
}
|
|
56
56
|
}), [tokens, insets, centerTitle, spacingMultiplier]);
|
|
57
57
|
|
|
@@ -47,7 +47,6 @@ import React, { useMemo } from 'react';
|
|
|
47
47
|
import {
|
|
48
48
|
ScrollView,
|
|
49
49
|
View,
|
|
50
|
-
StyleSheet,
|
|
51
50
|
StyleProp,
|
|
52
51
|
ViewStyle,
|
|
53
52
|
} from 'react-native';
|
|
@@ -110,33 +109,32 @@ export const FormContainer: React.FC<FormContainerProps> = ({
|
|
|
110
109
|
|
|
111
110
|
// Create styles for form container (memoized to avoid re-creation on every render)
|
|
112
111
|
const styles = useMemo(
|
|
113
|
-
() =>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}),
|
|
112
|
+
() => ({
|
|
113
|
+
container: {
|
|
114
|
+
flex: 1,
|
|
115
|
+
backgroundColor: tokens.colors.backgroundPrimary,
|
|
116
|
+
},
|
|
117
|
+
surface: {
|
|
118
|
+
flex: 1,
|
|
119
|
+
backgroundColor: tokens.colors.surface,
|
|
120
|
+
borderWidth: showBorder ? 1 : 0,
|
|
121
|
+
borderColor: tokens.colors.border,
|
|
122
|
+
borderRadius: tokens.borders.radius.md,
|
|
123
|
+
},
|
|
124
|
+
scrollView: {
|
|
125
|
+
flex: 1,
|
|
126
|
+
},
|
|
127
|
+
contentContainer: {
|
|
128
|
+
flexGrow: 1,
|
|
129
|
+
padding: tokens.spacing.lg,
|
|
130
|
+
paddingTop: tokens.spacing.xl,
|
|
131
|
+
paddingBottom: formBottomPadding + insets.bottom,
|
|
132
|
+
maxWidth: formContentWidth,
|
|
133
|
+
alignSelf: 'center' as const,
|
|
134
|
+
width: '100%',
|
|
135
|
+
gap: formElementSpacing,
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
140
138
|
[tokens, showBorder, formBottomPadding, insets.bottom, formContentWidth, formElementSpacing],
|
|
141
139
|
);
|
|
142
140
|
|