@umituz/react-native-design-system 2.6.65 → 2.6.66
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/AtomicDatePicker.tsx +5 -63
- package/src/atoms/AtomicInput.tsx +3 -14
- package/src/atoms/AtomicPicker.tsx +10 -21
- package/src/atoms/datepicker/hooks/useDatePickerText.ts +64 -0
- package/src/atoms/datepicker/styles/datePickerStyles.ts +27 -0
- package/src/atoms/input/styles/inputStyles.ts +18 -0
- package/src/atoms/picker/components/PickerIcons.tsx +56 -0
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.66",
|
|
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",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* @module AtomicDatePicker
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
import React, { useState
|
|
40
|
+
import React, { useState } from 'react';
|
|
41
41
|
import {
|
|
42
42
|
View,
|
|
43
43
|
StyleSheet,
|
|
@@ -50,6 +50,8 @@ import { useAppDesignTokens } from '../theme';
|
|
|
50
50
|
import { AtomicText } from './AtomicText';
|
|
51
51
|
import { DatePickerModal } from './datepicker/components/DatePickerModal';
|
|
52
52
|
import { DatePickerButton } from './datepicker/components/DatePickerButton';
|
|
53
|
+
import { useDatePickerText } from './datepicker/hooks/useDatePickerText';
|
|
54
|
+
import { getDatePickerStyles } from './datepicker/styles/datePickerStyles';
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* Props for AtomicDatePicker component
|
|
@@ -139,45 +141,8 @@ export const AtomicDatePicker: React.FC<AtomicDatePickerProps> = ({
|
|
|
139
141
|
}
|
|
140
142
|
};
|
|
141
143
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
* Uses native Date formatting (locale-aware)
|
|
145
|
-
*/
|
|
146
|
-
const formatDate = useMemo(() => (date: Date): string => {
|
|
147
|
-
if (mode === 'time') {
|
|
148
|
-
return date.toLocaleTimeString([], {
|
|
149
|
-
hour: '2-digit',
|
|
150
|
-
minute: '2-digit'
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
if (mode === 'datetime') {
|
|
154
|
-
const dateStr = date.toLocaleDateString([], {
|
|
155
|
-
year: 'numeric',
|
|
156
|
-
month: 'short',
|
|
157
|
-
day: 'numeric',
|
|
158
|
-
});
|
|
159
|
-
const timeStr = date.toLocaleTimeString([], {
|
|
160
|
-
hour: '2-digit',
|
|
161
|
-
minute: '2-digit'
|
|
162
|
-
});
|
|
163
|
-
return `${dateStr} ${timeStr}`;
|
|
164
|
-
}
|
|
165
|
-
return date.toLocaleDateString([], {
|
|
166
|
-
year: 'numeric',
|
|
167
|
-
month: 'long',
|
|
168
|
-
day: 'numeric',
|
|
169
|
-
});
|
|
170
|
-
}, [mode]);
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Get display text for the button
|
|
174
|
-
*/
|
|
175
|
-
const displayText = useMemo(() => {
|
|
176
|
-
if (!value) return placeholder;
|
|
177
|
-
return formatDate(value);
|
|
178
|
-
}, [value, placeholder, formatDate]);
|
|
179
|
-
|
|
180
|
-
const styles = getStyles(tokens);
|
|
144
|
+
const { displayText } = useDatePickerText({ value, placeholder, mode });
|
|
145
|
+
const styles = getDatePickerStyles(tokens);
|
|
181
146
|
|
|
182
147
|
return (
|
|
183
148
|
<View style={[styles.container, style]} testID={testID}>
|
|
@@ -229,26 +194,3 @@ export const AtomicDatePicker: React.FC<AtomicDatePickerProps> = ({
|
|
|
229
194
|
</View>
|
|
230
195
|
);
|
|
231
196
|
};
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Get component styles based on design tokens
|
|
235
|
-
*/
|
|
236
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) => {
|
|
237
|
-
return StyleSheet.create({
|
|
238
|
-
container: {
|
|
239
|
-
marginBottom: tokens.spacing.md,
|
|
240
|
-
},
|
|
241
|
-
label: {
|
|
242
|
-
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
243
|
-
fontWeight: tokens.typography.semibold,
|
|
244
|
-
color: tokens.colors.onSurface,
|
|
245
|
-
marginBottom: tokens.spacing.sm,
|
|
246
|
-
},
|
|
247
|
-
errorText: {
|
|
248
|
-
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
249
|
-
color: tokens.colors.error,
|
|
250
|
-
marginTop: tokens.spacing.xs,
|
|
251
|
-
marginLeft: tokens.spacing.xs,
|
|
252
|
-
},
|
|
253
|
-
});
|
|
254
|
-
};
|
|
@@ -3,6 +3,7 @@ import { View, TextInput, StyleSheet, StyleProp, ViewStyle, TextStyle } from 're
|
|
|
3
3
|
import { useAppDesignTokens } from '../theme';
|
|
4
4
|
import { useInputState } from './input/hooks/useInputState';
|
|
5
5
|
import { getSizeConfig, getVariantStyle, getTextColor } from './input/styles/inputStylesHelper';
|
|
6
|
+
import { inputStyles } from './input/styles/inputStyles';
|
|
6
7
|
import type { AtomicInputProps } from './input/types';
|
|
7
8
|
import { InputLabel } from './input/components/InputLabel';
|
|
8
9
|
import { InputIcon } from './input/components/InputIcon';
|
|
@@ -94,7 +95,7 @@ export const AtomicInput = React.forwardRef<TextInput, AtomicInputProps>(({
|
|
|
94
95
|
const iconColor = isDisabled ? tokens.colors.textDisabled : tokens.colors.textSecondary;
|
|
95
96
|
|
|
96
97
|
const containerStyle: StyleProp<ViewStyle> = [
|
|
97
|
-
|
|
98
|
+
inputStyles.container,
|
|
98
99
|
variantStyle,
|
|
99
100
|
{
|
|
100
101
|
paddingTop: sizeConfig.paddingVertical,
|
|
@@ -108,7 +109,7 @@ export const AtomicInput = React.forwardRef<TextInput, AtomicInputProps>(({
|
|
|
108
109
|
];
|
|
109
110
|
|
|
110
111
|
const textInputStyle: StyleProp<TextStyle> = [
|
|
111
|
-
|
|
112
|
+
inputStyles.input,
|
|
112
113
|
{
|
|
113
114
|
fontSize: sizeConfig.fontSize,
|
|
114
115
|
lineHeight: (sizeConfig.fontSize || 16) * 1.2,
|
|
@@ -198,15 +199,3 @@ export const AtomicInput = React.forwardRef<TextInput, AtomicInputProps>(({
|
|
|
198
199
|
</View>
|
|
199
200
|
);
|
|
200
201
|
});
|
|
201
|
-
|
|
202
|
-
const styles = StyleSheet.create({
|
|
203
|
-
container: {
|
|
204
|
-
flexDirection: 'row',
|
|
205
|
-
alignItems: 'center',
|
|
206
|
-
},
|
|
207
|
-
input: {
|
|
208
|
-
flex: 1,
|
|
209
|
-
margin: 0,
|
|
210
|
-
padding: 0,
|
|
211
|
-
},
|
|
212
|
-
});
|
|
@@ -52,6 +52,7 @@ import { AtomicIcon } from './AtomicIcon';
|
|
|
52
52
|
import { AtomicText } from './AtomicText';
|
|
53
53
|
import { PickerModal } from './picker/components/PickerModal';
|
|
54
54
|
import { PickerChips } from './picker/components/PickerChips';
|
|
55
|
+
import { PickerIcons } from './picker/components/PickerIcons';
|
|
55
56
|
import {
|
|
56
57
|
getPickerContainerStyles,
|
|
57
58
|
getPickerLabelStyles,
|
|
@@ -156,27 +157,15 @@ export const AtomicPicker: React.FC<AtomicPickerProps> = ({
|
|
|
156
157
|
</AtomicText>
|
|
157
158
|
|
|
158
159
|
{/* Icons */}
|
|
159
|
-
<
|
|
160
|
-
{
|
|
161
|
-
{
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
>
|
|
169
|
-
<AtomicIcon name="X" size="sm" color="secondary" />
|
|
170
|
-
</TouchableOpacity>
|
|
171
|
-
)}
|
|
172
|
-
|
|
173
|
-
{/* Dropdown Icon */}
|
|
174
|
-
<AtomicIcon
|
|
175
|
-
name={pickerState.modalVisible ? 'ChevronUp' : 'ChevronDown'}
|
|
176
|
-
size="sm"
|
|
177
|
-
color={disabled ? 'surfaceVariant' : 'secondary'}
|
|
178
|
-
/>
|
|
179
|
-
</View>
|
|
160
|
+
<PickerIcons
|
|
161
|
+
clearable={clearable}
|
|
162
|
+
disabled={disabled}
|
|
163
|
+
modalVisible={pickerState.modalVisible}
|
|
164
|
+
selectedOptionsCount={pickerState.selectedOptions.length}
|
|
165
|
+
onClear={pickerState.handleClear}
|
|
166
|
+
clearAccessibilityLabel={clearAccessibilityLabel}
|
|
167
|
+
testID={testID}
|
|
168
|
+
/>
|
|
180
169
|
</TouchableOpacity>
|
|
181
170
|
|
|
182
171
|
{/* Selected Chips (Multi-select) */}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useDatePickerText Hook
|
|
3
|
+
* Handles date formatting and display text for date picker
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMemo } from 'react';
|
|
7
|
+
import type { DatepickerMode } from '../types';
|
|
8
|
+
|
|
9
|
+
interface UseDatePickerTextProps {
|
|
10
|
+
value: Date | null;
|
|
11
|
+
placeholder: string;
|
|
12
|
+
mode: DatepickerMode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface UseDatePickerTextResult {
|
|
16
|
+
displayText: string;
|
|
17
|
+
formatDate: (date: Date) => string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useDatePickerText = ({
|
|
21
|
+
value,
|
|
22
|
+
placeholder,
|
|
23
|
+
mode,
|
|
24
|
+
}: UseDatePickerTextProps): UseDatePickerTextResult => {
|
|
25
|
+
/**
|
|
26
|
+
* Format date based on mode
|
|
27
|
+
* Uses native Date formatting (locale-aware)
|
|
28
|
+
*/
|
|
29
|
+
const formatDate = useMemo(() => (date: Date): string => {
|
|
30
|
+
if (mode === 'time') {
|
|
31
|
+
return date.toLocaleTimeString([], {
|
|
32
|
+
hour: '2-digit',
|
|
33
|
+
minute: '2-digit'
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (mode === 'datetime') {
|
|
37
|
+
const dateStr = date.toLocaleDateString([], {
|
|
38
|
+
year: 'numeric',
|
|
39
|
+
month: 'short',
|
|
40
|
+
day: 'numeric',
|
|
41
|
+
});
|
|
42
|
+
const timeStr = date.toLocaleTimeString([], {
|
|
43
|
+
hour: '2-digit',
|
|
44
|
+
minute: '2-digit'
|
|
45
|
+
});
|
|
46
|
+
return `${dateStr} ${timeStr}`;
|
|
47
|
+
}
|
|
48
|
+
return date.toLocaleDateString([], {
|
|
49
|
+
year: 'numeric',
|
|
50
|
+
month: 'long',
|
|
51
|
+
day: 'numeric',
|
|
52
|
+
});
|
|
53
|
+
}, [mode]);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get display text for the button
|
|
57
|
+
*/
|
|
58
|
+
const displayText = useMemo(() => {
|
|
59
|
+
if (!value) return placeholder;
|
|
60
|
+
return formatDate(value);
|
|
61
|
+
}, [value, placeholder, formatDate]);
|
|
62
|
+
|
|
63
|
+
return { displayText, formatDate };
|
|
64
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DatePicker Styles
|
|
3
|
+
* StyleSheet generator for AtomicDatePicker component
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StyleSheet } from 'react-native';
|
|
7
|
+
import type { DesignTokens } from '../../theme';
|
|
8
|
+
|
|
9
|
+
export const getDatePickerStyles = (tokens: DesignTokens) => {
|
|
10
|
+
return StyleSheet.create({
|
|
11
|
+
container: {
|
|
12
|
+
marginBottom: tokens.spacing.md,
|
|
13
|
+
},
|
|
14
|
+
label: {
|
|
15
|
+
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
16
|
+
fontWeight: tokens.typography.semibold,
|
|
17
|
+
color: tokens.colors.onSurface,
|
|
18
|
+
marginBottom: tokens.spacing.sm,
|
|
19
|
+
},
|
|
20
|
+
errorText: {
|
|
21
|
+
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
22
|
+
color: tokens.colors.error,
|
|
23
|
+
marginTop: tokens.spacing.xs,
|
|
24
|
+
marginLeft: tokens.spacing.xs,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomicInput Styles
|
|
3
|
+
* StyleSheet for AtomicInput component
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StyleSheet } from 'react-native';
|
|
7
|
+
|
|
8
|
+
export const inputStyles = StyleSheet.create({
|
|
9
|
+
container: {
|
|
10
|
+
flexDirection: 'row',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
},
|
|
13
|
+
input: {
|
|
14
|
+
flex: 1,
|
|
15
|
+
margin: 0,
|
|
16
|
+
padding: 0,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picker Icons Component
|
|
3
|
+
* Renders clear button and dropdown icon for AtomicPicker
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
8
|
+
import { useAppDesignTokens } from '../../theme';
|
|
9
|
+
import { AtomicIcon } from '../AtomicIcon';
|
|
10
|
+
import type { PickerOption } from '../picker/types';
|
|
11
|
+
|
|
12
|
+
interface PickerIconsProps {
|
|
13
|
+
clearable: boolean;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
modalVisible: boolean;
|
|
16
|
+
selectedOptionsCount: number;
|
|
17
|
+
onClear: () => void;
|
|
18
|
+
clearAccessibilityLabel?: string;
|
|
19
|
+
testID?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const PickerIcons: React.FC<PickerIconsProps> = ({
|
|
23
|
+
clearable,
|
|
24
|
+
disabled,
|
|
25
|
+
modalVisible,
|
|
26
|
+
selectedOptionsCount,
|
|
27
|
+
onClear,
|
|
28
|
+
clearAccessibilityLabel,
|
|
29
|
+
testID,
|
|
30
|
+
}) => {
|
|
31
|
+
const tokens = useAppDesignTokens();
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: tokens.spacing.xs }}>
|
|
35
|
+
{/* Clear Button */}
|
|
36
|
+
{clearable && selectedOptionsCount > 0 && !disabled && (
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
onPress={onClear}
|
|
39
|
+
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
40
|
+
accessibilityRole="button"
|
|
41
|
+
accessibilityLabel={clearAccessibilityLabel}
|
|
42
|
+
testID={`${testID}-clear`}
|
|
43
|
+
>
|
|
44
|
+
<AtomicIcon name="X" size="sm" color="secondary" />
|
|
45
|
+
</TouchableOpacity>
|
|
46
|
+
)}
|
|
47
|
+
|
|
48
|
+
{/* Dropdown Icon */}
|
|
49
|
+
<AtomicIcon
|
|
50
|
+
name={modalVisible ? 'ChevronUp' : 'ChevronDown'}
|
|
51
|
+
size="sm"
|
|
52
|
+
color={disabled ? 'surfaceVariant' : 'secondary'}
|
|
53
|
+
/>
|
|
54
|
+
</View>
|
|
55
|
+
);
|
|
56
|
+
};
|