@umituz/react-native-design-system 2.6.61 → 2.6.64
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/AtomicButton.tsx +6 -257
- package/src/atoms/AtomicChip.tsx +4 -224
- package/src/atoms/AtomicIcon.tsx +2 -6
- package/src/atoms/AtomicIcon.types.ts +5 -0
- package/src/atoms/AtomicInput.tsx +34 -154
- package/src/atoms/AtomicPicker.tsx +31 -123
- package/src/atoms/button/AtomicButton.tsx +108 -0
- package/src/atoms/button/configs/buttonSizeConfig.ts +37 -0
- package/src/atoms/button/index.ts +6 -0
- package/src/atoms/button/styles/buttonStyles.ts +36 -0
- package/src/atoms/button/styles/buttonVariantStyles.ts +88 -0
- package/src/atoms/button/types/index.ts +40 -0
- package/src/atoms/chip/AtomicChip.tsx +112 -0
- package/src/atoms/chip/configs/chipColorConfig.ts +47 -0
- package/src/atoms/chip/configs/chipSizeConfig.ts +34 -0
- package/src/atoms/chip/index.ts +6 -0
- package/src/atoms/chip/styles/chipStyles.ts +28 -0
- package/src/atoms/chip/types/index.ts +42 -0
- package/src/atoms/index.ts +6 -4
- package/src/atoms/input/components/InputHelper.tsx +49 -0
- package/src/atoms/input/components/InputIcon.tsx +44 -0
- package/src/atoms/input/components/InputLabel.tsx +20 -0
- package/src/atoms/input/styles/inputStylesHelper.ts +1 -1
- package/src/atoms/input/types.ts +72 -0
- package/src/atoms/picker/hooks/usePickerState.ts +139 -0
- package/src/exports/atoms.ts +69 -0
- package/src/exports/device.ts +58 -0
- package/src/exports/layouts.ts +19 -0
- package/src/exports/molecules.ts +166 -0
- package/src/exports/organisms.ts +9 -0
- package/src/exports/responsive.ts +36 -0
- package/src/exports/safe-area.ts +6 -0
- package/src/exports/theme.ts +47 -0
- package/src/exports/typography.ts +22 -0
- package/src/exports/utilities.ts +6 -0
- package/src/exports/variants.ts +22 -0
- package/src/index.ts +11 -417
- package/src/layouts/ScreenLayout/ScreenLayout.tsx +17 -181
- package/src/layouts/ScreenLayout/components/ContentWrapper.tsx +31 -0
- package/src/layouts/ScreenLayout/components/index.ts +6 -0
- package/src/layouts/ScreenLayout/styles/screenLayoutStyles.ts +47 -0
- package/src/layouts/ScreenLayout/types/index.ts +27 -0
- package/src/molecules/avatar/Avatar.constants.ts +103 -0
- package/src/molecules/avatar/Avatar.types.ts +64 -0
- package/src/molecules/avatar/Avatar.utils.ts +8 -160
- package/src/molecules/calendar/index.ts +4 -9
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +103 -302
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts.bak +116 -0
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.types.ts +64 -0
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.utils.ts +56 -0
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +140 -0
- package/src/molecules/calendar/infrastructure/storage/NavigationActions.ts +118 -0
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +34 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +168 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarNavigation.ts +47 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarView.ts +24 -0
- package/src/molecules/calendar/presentation/hooks/useCalendar.ts +7 -11
- package/src/responsive/compute/computeDeviceInfo.ts +22 -0
- package/src/responsive/compute/computeResponsivePositioning.ts +42 -0
- package/src/responsive/compute/computeResponsiveSizes.ts +48 -0
- package/src/responsive/padding/paddingUtils.ts +65 -0
- package/src/responsive/positioning/positioningUtils.ts +61 -0
- package/src/responsive/responsiveLayout.ts +11 -264
- package/src/responsive/screen/screenLayoutConfig.ts +38 -0
- package/src/responsive/tabbar/tabBarConfig.ts +88 -0
- package/src/responsive/types/responsiveTypes.ts +69 -0
- package/src/responsive/useResponsive.ts +69 -158
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button Variant Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DesignTokens } from '../../../theme';
|
|
6
|
+
import type { ButtonVariant, ButtonVariantStyles } from '../types';
|
|
7
|
+
|
|
8
|
+
export const getVariantStyles = (
|
|
9
|
+
variant: ButtonVariant,
|
|
10
|
+
tokens: DesignTokens,
|
|
11
|
+
): ButtonVariantStyles => {
|
|
12
|
+
const baseStyle = {
|
|
13
|
+
backgroundColor: tokens.colors.primary,
|
|
14
|
+
borderWidth: 0,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const baseTextStyle = {
|
|
18
|
+
color: tokens.colors.textInverse,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
switch (variant) {
|
|
22
|
+
case 'primary':
|
|
23
|
+
return {
|
|
24
|
+
container: {
|
|
25
|
+
...baseStyle,
|
|
26
|
+
backgroundColor: tokens.colors.primary,
|
|
27
|
+
},
|
|
28
|
+
text: {
|
|
29
|
+
...baseTextStyle,
|
|
30
|
+
color: tokens.colors.textInverse,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
case 'secondary':
|
|
35
|
+
return {
|
|
36
|
+
container: {
|
|
37
|
+
...baseStyle,
|
|
38
|
+
backgroundColor: tokens.colors.surfaceSecondary,
|
|
39
|
+
},
|
|
40
|
+
text: {
|
|
41
|
+
...baseTextStyle,
|
|
42
|
+
color: tokens.colors.textPrimary,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
case 'outline':
|
|
47
|
+
return {
|
|
48
|
+
container: {
|
|
49
|
+
backgroundColor: undefined,
|
|
50
|
+
borderWidth: 1,
|
|
51
|
+
borderColor: tokens.colors.border,
|
|
52
|
+
},
|
|
53
|
+
text: {
|
|
54
|
+
...baseTextStyle,
|
|
55
|
+
color: tokens.colors.textPrimary,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
case 'text':
|
|
60
|
+
return {
|
|
61
|
+
container: {
|
|
62
|
+
backgroundColor: undefined,
|
|
63
|
+
},
|
|
64
|
+
text: {
|
|
65
|
+
...baseTextStyle,
|
|
66
|
+
color: tokens.colors.primary,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
case 'danger':
|
|
71
|
+
return {
|
|
72
|
+
container: {
|
|
73
|
+
...baseStyle,
|
|
74
|
+
backgroundColor: tokens.colors.error,
|
|
75
|
+
},
|
|
76
|
+
text: {
|
|
77
|
+
...baseTextStyle,
|
|
78
|
+
color: tokens.colors.textInverse,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
default:
|
|
83
|
+
return {
|
|
84
|
+
container: baseStyle,
|
|
85
|
+
text: baseTextStyle,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomicButton Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { StyleProp } from 'react-native';
|
|
6
|
+
import type { TextStyle, ViewStyle } from 'react-native';
|
|
7
|
+
import type { IconName } from '../../AtomicIcon';
|
|
8
|
+
|
|
9
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'text' | 'danger';
|
|
10
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
11
|
+
|
|
12
|
+
export interface AtomicButtonProps {
|
|
13
|
+
readonly title?: string;
|
|
14
|
+
readonly children?: React.ReactNode;
|
|
15
|
+
readonly onPress: () => void;
|
|
16
|
+
readonly variant?: ButtonVariant;
|
|
17
|
+
readonly size?: ButtonSize;
|
|
18
|
+
readonly disabled?: boolean;
|
|
19
|
+
readonly loading?: boolean;
|
|
20
|
+
readonly icon?: IconName;
|
|
21
|
+
readonly iconPosition?: 'left' | 'right';
|
|
22
|
+
readonly fullWidth?: boolean;
|
|
23
|
+
readonly style?: StyleProp<ViewStyle>;
|
|
24
|
+
readonly textStyle?: StyleProp<TextStyle>;
|
|
25
|
+
readonly activeOpacity?: number;
|
|
26
|
+
readonly testID?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ButtonSizeConfig {
|
|
30
|
+
readonly paddingVertical: number;
|
|
31
|
+
readonly paddingHorizontal: number;
|
|
32
|
+
readonly fontSize: number;
|
|
33
|
+
readonly iconSize: number;
|
|
34
|
+
readonly minHeight: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ButtonVariantStyles {
|
|
38
|
+
readonly container: ViewStyle;
|
|
39
|
+
readonly text: TextStyle;
|
|
40
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomicChip Component
|
|
3
|
+
* Refactored: Extracted configs, styles, and types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { View, ViewStyle, TouchableOpacity } from 'react-native';
|
|
8
|
+
import { AtomicText } from '../AtomicText';
|
|
9
|
+
import { AtomicIcon } from '../AtomicIcon';
|
|
10
|
+
import { useAppDesignTokens } from '../../theme';
|
|
11
|
+
import { getChipSizeConfig } from './configs/chipSizeConfig';
|
|
12
|
+
import { getChipColorConfig } from './configs/chipColorConfig';
|
|
13
|
+
import { getChipBorderStyle, getChipSelectedStyle } from './styles/chipStyles';
|
|
14
|
+
import type { AtomicChipProps } from './types';
|
|
15
|
+
|
|
16
|
+
export const AtomicChip: React.FC<AtomicChipProps> = React.memo(({
|
|
17
|
+
children,
|
|
18
|
+
variant = 'filled',
|
|
19
|
+
size = 'md',
|
|
20
|
+
color = 'primary',
|
|
21
|
+
backgroundColor,
|
|
22
|
+
textColor,
|
|
23
|
+
borderColor,
|
|
24
|
+
leadingIcon,
|
|
25
|
+
trailingIcon,
|
|
26
|
+
clickable = false,
|
|
27
|
+
onPress,
|
|
28
|
+
selected = false,
|
|
29
|
+
disabled = false,
|
|
30
|
+
style,
|
|
31
|
+
testID,
|
|
32
|
+
activeOpacity = 0.7,
|
|
33
|
+
}) => {
|
|
34
|
+
const tokens = useAppDesignTokens();
|
|
35
|
+
|
|
36
|
+
const sizeConfig = getChipSizeConfig(size, tokens);
|
|
37
|
+
const colorConfig = getChipColorConfig(color, variant, tokens);
|
|
38
|
+
const borderStyle = getChipBorderStyle(variant, tokens);
|
|
39
|
+
const selectedStyle = getChipSelectedStyle(selected, tokens);
|
|
40
|
+
|
|
41
|
+
// Apply custom colors if provided
|
|
42
|
+
const finalBackgroundColor = backgroundColor || colorConfig.bg;
|
|
43
|
+
const finalTextColor = textColor || colorConfig.text;
|
|
44
|
+
const finalBorderColor = borderColor || colorConfig.border;
|
|
45
|
+
|
|
46
|
+
// Handle disabled state
|
|
47
|
+
const isDisabled = disabled || (!clickable && !onPress);
|
|
48
|
+
const opacity = isDisabled ? 0.5 : 1;
|
|
49
|
+
|
|
50
|
+
const chipStyle: ViewStyle = {
|
|
51
|
+
flexDirection: 'row',
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
justifyContent: 'center',
|
|
54
|
+
paddingHorizontal: sizeConfig.paddingHorizontal,
|
|
55
|
+
paddingVertical: sizeConfig.paddingVertical,
|
|
56
|
+
backgroundColor: finalBackgroundColor,
|
|
57
|
+
opacity,
|
|
58
|
+
...borderStyle,
|
|
59
|
+
borderColor: finalBorderColor,
|
|
60
|
+
...selectedStyle,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const textStyle = {
|
|
64
|
+
fontSize: sizeConfig.fontSize,
|
|
65
|
+
fontWeight: tokens.typography.medium,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const iconColor = finalTextColor;
|
|
69
|
+
|
|
70
|
+
const content = (
|
|
71
|
+
<View style={[chipStyle, style]} testID={testID}>
|
|
72
|
+
{leadingIcon && (
|
|
73
|
+
<AtomicIcon
|
|
74
|
+
name={leadingIcon}
|
|
75
|
+
size={sizeConfig.iconSize}
|
|
76
|
+
customColor={iconColor}
|
|
77
|
+
style={{ marginRight: tokens.spacing.xs }}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
<AtomicText
|
|
81
|
+
type="labelMedium"
|
|
82
|
+
color={finalTextColor}
|
|
83
|
+
style={textStyle}
|
|
84
|
+
>
|
|
85
|
+
{children}
|
|
86
|
+
</AtomicText>
|
|
87
|
+
{trailingIcon && (
|
|
88
|
+
<AtomicIcon
|
|
89
|
+
name={trailingIcon}
|
|
90
|
+
size={sizeConfig.iconSize}
|
|
91
|
+
customColor={iconColor}
|
|
92
|
+
style={{ marginLeft: tokens.spacing.xs }}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
</View>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (clickable && onPress && !disabled) {
|
|
99
|
+
return (
|
|
100
|
+
<TouchableOpacity onPress={onPress} activeOpacity={activeOpacity}>
|
|
101
|
+
{content}
|
|
102
|
+
</TouchableOpacity>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return content;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
AtomicChip.displayName = 'AtomicChip';
|
|
110
|
+
|
|
111
|
+
// Re-export types for convenience
|
|
112
|
+
export type { AtomicChipProps, ChipVariant, ChipSize, ChipColor } from './types';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip Color Configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DesignTokens } from '../../../theme';
|
|
6
|
+
import type { ChipColor, ChipVariant, ChipColorConfig } from '../types';
|
|
7
|
+
|
|
8
|
+
export const getChipColorConfig = (
|
|
9
|
+
color: ChipColor,
|
|
10
|
+
variant: ChipVariant,
|
|
11
|
+
tokens: DesignTokens,
|
|
12
|
+
): ChipColorConfig => {
|
|
13
|
+
const colorMap: Record<ChipColor, Record<ChipVariant, ChipColorConfig>> = {
|
|
14
|
+
primary: {
|
|
15
|
+
filled: { bg: tokens.colors.primary, text: tokens.colors.onPrimary, border: tokens.colors.primary },
|
|
16
|
+
outlined: { bg: undefined, text: tokens.colors.primary, border: tokens.colors.primary },
|
|
17
|
+
soft: { bg: tokens.colors.primaryContainer, text: tokens.colors.onPrimaryContainer, border: undefined },
|
|
18
|
+
},
|
|
19
|
+
secondary: {
|
|
20
|
+
filled: { bg: tokens.colors.secondary, text: tokens.colors.onSecondary, border: tokens.colors.secondary },
|
|
21
|
+
outlined: { bg: undefined, text: tokens.colors.secondary, border: tokens.colors.secondary },
|
|
22
|
+
soft: { bg: tokens.colors.secondaryContainer, text: tokens.colors.onSecondaryContainer, border: undefined },
|
|
23
|
+
},
|
|
24
|
+
success: {
|
|
25
|
+
filled: { bg: tokens.colors.success, text: tokens.colors.onSuccess, border: tokens.colors.success },
|
|
26
|
+
outlined: { bg: undefined, text: tokens.colors.success, border: tokens.colors.success },
|
|
27
|
+
soft: { bg: tokens.colors.successContainer, text: tokens.colors.onSuccessContainer, border: undefined },
|
|
28
|
+
},
|
|
29
|
+
warning: {
|
|
30
|
+
filled: { bg: tokens.colors.warning, text: tokens.colors.onWarning, border: tokens.colors.warning },
|
|
31
|
+
outlined: { bg: undefined, text: tokens.colors.warning, border: tokens.colors.warning },
|
|
32
|
+
soft: { bg: tokens.colors.warningContainer, text: tokens.colors.onWarningContainer, border: undefined },
|
|
33
|
+
},
|
|
34
|
+
error: {
|
|
35
|
+
filled: { bg: tokens.colors.error, text: tokens.colors.onError, border: tokens.colors.error },
|
|
36
|
+
outlined: { bg: undefined, text: tokens.colors.error, border: tokens.colors.error },
|
|
37
|
+
soft: { bg: tokens.colors.errorContainer, text: tokens.colors.onErrorContainer, border: undefined },
|
|
38
|
+
},
|
|
39
|
+
info: {
|
|
40
|
+
filled: { bg: tokens.colors.info, text: tokens.colors.onInfo, border: tokens.colors.info },
|
|
41
|
+
outlined: { bg: undefined, text: tokens.colors.info, border: tokens.colors.info },
|
|
42
|
+
soft: { bg: tokens.colors.infoContainer, text: tokens.colors.onInfoContainer, border: undefined },
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return colorMap[color][variant];
|
|
47
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip Size Configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DesignTokens } from '../../../theme';
|
|
6
|
+
import type { ChipSize, ChipSizeConfig } from '../types';
|
|
7
|
+
|
|
8
|
+
export const getChipSizeConfig = (
|
|
9
|
+
size: ChipSize,
|
|
10
|
+
tokens: DesignTokens,
|
|
11
|
+
): ChipSizeConfig => {
|
|
12
|
+
const sizeConfigs: Record<ChipSize, ChipSizeConfig> = {
|
|
13
|
+
sm: {
|
|
14
|
+
paddingHorizontal: tokens.spacing.sm,
|
|
15
|
+
paddingVertical: tokens.spacing.xs,
|
|
16
|
+
fontSize: tokens.typography.bodySmall.responsiveFontSize,
|
|
17
|
+
iconSize: 'xs',
|
|
18
|
+
},
|
|
19
|
+
md: {
|
|
20
|
+
paddingHorizontal: tokens.spacing.md,
|
|
21
|
+
paddingVertical: tokens.spacing.sm,
|
|
22
|
+
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
23
|
+
iconSize: 'sm',
|
|
24
|
+
},
|
|
25
|
+
lg: {
|
|
26
|
+
paddingHorizontal: tokens.spacing.md,
|
|
27
|
+
paddingVertical: tokens.spacing.sm,
|
|
28
|
+
fontSize: tokens.typography.bodyLarge.responsiveFontSize,
|
|
29
|
+
iconSize: 'sm',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return sizeConfigs[size];
|
|
34
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DesignTokens } from '../../../theme';
|
|
6
|
+
import type { ChipVariant } from '../types';
|
|
7
|
+
|
|
8
|
+
export const getChipBorderStyle = (
|
|
9
|
+
variant: ChipVariant,
|
|
10
|
+
tokens: DesignTokens,
|
|
11
|
+
) => {
|
|
12
|
+
return {
|
|
13
|
+
borderWidth: variant === 'outlined' ? 1 : 0,
|
|
14
|
+
borderRadius: tokens.borders.radius.xl,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const getChipSelectedStyle = (
|
|
19
|
+
selected: boolean,
|
|
20
|
+
tokens: DesignTokens,
|
|
21
|
+
) => {
|
|
22
|
+
if (!selected) return {};
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
borderWidth: tokens.borders.width.medium,
|
|
26
|
+
borderColor: tokens.colors.primary,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomicChip Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ViewStyle } from 'react-native';
|
|
6
|
+
import type { IconSize } from '../../AtomicIcon';
|
|
7
|
+
|
|
8
|
+
export type ChipVariant = 'filled' | 'outlined' | 'soft';
|
|
9
|
+
export type ChipSize = 'sm' | 'md' | 'lg';
|
|
10
|
+
export type ChipColor = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';
|
|
11
|
+
|
|
12
|
+
export interface AtomicChipProps {
|
|
13
|
+
readonly children: React.ReactNode;
|
|
14
|
+
readonly variant?: ChipVariant;
|
|
15
|
+
readonly size?: ChipSize;
|
|
16
|
+
readonly color?: ChipColor;
|
|
17
|
+
readonly backgroundColor?: string;
|
|
18
|
+
readonly textColor?: string;
|
|
19
|
+
readonly borderColor?: string;
|
|
20
|
+
readonly leadingIcon?: string;
|
|
21
|
+
readonly trailingIcon?: string;
|
|
22
|
+
readonly clickable?: boolean;
|
|
23
|
+
readonly onPress?: () => void;
|
|
24
|
+
readonly selected?: boolean;
|
|
25
|
+
readonly disabled?: boolean;
|
|
26
|
+
readonly style?: ViewStyle;
|
|
27
|
+
readonly testID?: string;
|
|
28
|
+
readonly activeOpacity?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ChipSizeConfig {
|
|
32
|
+
readonly paddingHorizontal: number;
|
|
33
|
+
readonly paddingVertical: number;
|
|
34
|
+
readonly fontSize: number;
|
|
35
|
+
readonly iconSize: IconSize;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ChipColorConfig {
|
|
39
|
+
readonly bg: string | undefined;
|
|
40
|
+
readonly text: string;
|
|
41
|
+
readonly border: string | undefined;
|
|
42
|
+
}
|
package/src/atoms/index.ts
CHANGED
|
@@ -25,11 +25,13 @@ export {
|
|
|
25
25
|
// Input
|
|
26
26
|
export {
|
|
27
27
|
AtomicInput,
|
|
28
|
-
type AtomicInputProps,
|
|
29
|
-
type AtomicInputVariant,
|
|
30
|
-
type AtomicInputState,
|
|
31
|
-
type AtomicInputSize,
|
|
32
28
|
} from './AtomicInput';
|
|
29
|
+
export type {
|
|
30
|
+
AtomicInputProps,
|
|
31
|
+
AtomicInputVariant,
|
|
32
|
+
AtomicInputState,
|
|
33
|
+
AtomicInputSize,
|
|
34
|
+
} from './input/types';
|
|
33
35
|
|
|
34
36
|
// Icon
|
|
35
37
|
export {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { AtomicText } from '../../AtomicText';
|
|
4
|
+
import type { AtomicInputState } from '../../input/types';
|
|
5
|
+
|
|
6
|
+
interface InputHelperProps {
|
|
7
|
+
helperText?: string;
|
|
8
|
+
showCharacterCount?: boolean;
|
|
9
|
+
characterCount?: number;
|
|
10
|
+
maxLength?: number;
|
|
11
|
+
state?: AtomicInputState;
|
|
12
|
+
testID?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const InputHelper: React.FC<InputHelperProps> = ({
|
|
16
|
+
helperText,
|
|
17
|
+
showCharacterCount,
|
|
18
|
+
characterCount = 0,
|
|
19
|
+
maxLength,
|
|
20
|
+
state,
|
|
21
|
+
testID,
|
|
22
|
+
}) => {
|
|
23
|
+
if (!helperText && !showCharacterCount) return null;
|
|
24
|
+
|
|
25
|
+
const color = state === 'error' ? 'error' : 'secondary';
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 4 }}>
|
|
29
|
+
{helperText && (
|
|
30
|
+
<AtomicText
|
|
31
|
+
style={{ flex: 1 }}
|
|
32
|
+
color={color}
|
|
33
|
+
testID={testID ? `${testID}-helper` : undefined}
|
|
34
|
+
>
|
|
35
|
+
{helperText}
|
|
36
|
+
</AtomicText>
|
|
37
|
+
)}
|
|
38
|
+
{showCharacterCount && maxLength && (
|
|
39
|
+
<AtomicText
|
|
40
|
+
style={{ marginLeft: 8 }}
|
|
41
|
+
color="secondary"
|
|
42
|
+
testID={testID ? `${testID}-count` : undefined}
|
|
43
|
+
>
|
|
44
|
+
{characterCount}/{maxLength}
|
|
45
|
+
</AtomicText>
|
|
46
|
+
)}
|
|
47
|
+
</View>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Pressable } from 'react-native';
|
|
3
|
+
import { AtomicIcon } from '../../AtomicIcon';
|
|
4
|
+
|
|
5
|
+
interface InputIconProps {
|
|
6
|
+
name: string;
|
|
7
|
+
size: number;
|
|
8
|
+
color: string;
|
|
9
|
+
position: 'leading' | 'trailing';
|
|
10
|
+
onPress?: () => void;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const InputIcon: React.FC<InputIconProps> = ({
|
|
15
|
+
name,
|
|
16
|
+
size,
|
|
17
|
+
color,
|
|
18
|
+
position,
|
|
19
|
+
onPress,
|
|
20
|
+
testID,
|
|
21
|
+
}) => {
|
|
22
|
+
const positionStyle = position === 'leading' ? styles.leadingIcon : styles.trailingIcon;
|
|
23
|
+
const Wrapper = onPress ? Pressable : View;
|
|
24
|
+
const wrapperProps = onPress ? { onPress, testID } : {};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Wrapper style={positionStyle} {...wrapperProps}>
|
|
28
|
+
<AtomicIcon name={name} customSize={size} customColor={color} />
|
|
29
|
+
</Wrapper>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const styles = {
|
|
34
|
+
leadingIcon: {
|
|
35
|
+
position: 'absolute' as const,
|
|
36
|
+
left: 12,
|
|
37
|
+
zIndex: 1,
|
|
38
|
+
},
|
|
39
|
+
trailingIcon: {
|
|
40
|
+
position: 'absolute' as const,
|
|
41
|
+
right: 12,
|
|
42
|
+
zIndex: 1,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AtomicText } from '../../AtomicText';
|
|
3
|
+
import type { AtomicInputState } from '../../input/types';
|
|
4
|
+
|
|
5
|
+
interface InputLabelProps {
|
|
6
|
+
label?: string;
|
|
7
|
+
state?: AtomicInputState;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const InputLabel: React.FC<InputLabelProps> = ({ label, state }) => {
|
|
11
|
+
if (!label) return null;
|
|
12
|
+
|
|
13
|
+
const color = state === 'error' ? 'error' : state === 'success' ? 'success' : 'secondary';
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<AtomicText type="labelMedium" color={color} style={{ marginBottom: 4 }}>
|
|
17
|
+
{label}
|
|
18
|
+
</AtomicText>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { ViewStyle } from 'react-native';
|
|
9
9
|
import { useAppDesignTokens } from '../../../theme';
|
|
10
|
-
import type { AtomicInputVariant, AtomicInputSize } from '../../
|
|
10
|
+
import type { AtomicInputVariant, AtomicInputSize } from '../../input/types';
|
|
11
11
|
|
|
12
12
|
interface GetVariantStyleParams {
|
|
13
13
|
variant: AtomicInputVariant;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { StyleProp } from 'react-native';
|
|
2
|
+
import type { TextStyle, ViewStyle } from 'react-native';
|
|
3
|
+
import type { IconName } from '../AtomicIcon';
|
|
4
|
+
|
|
5
|
+
export type AtomicInputVariant = 'outlined' | 'filled' | 'flat';
|
|
6
|
+
export type AtomicInputState = 'default' | 'error' | 'success' | 'disabled';
|
|
7
|
+
export type AtomicInputSize = 'sm' | 'md' | 'lg';
|
|
8
|
+
|
|
9
|
+
export interface AtomicInputProps {
|
|
10
|
+
/** Input label */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Current input value */
|
|
13
|
+
value?: string;
|
|
14
|
+
/** Value change callback */
|
|
15
|
+
onChangeText?: (text: string) => void;
|
|
16
|
+
/** Input variant (outlined, filled, flat) */
|
|
17
|
+
variant?: AtomicInputVariant;
|
|
18
|
+
/** Input state (default, error, success, disabled) */
|
|
19
|
+
state?: AtomicInputState;
|
|
20
|
+
/** Input size (sm, md, lg) */
|
|
21
|
+
size?: AtomicInputSize;
|
|
22
|
+
/** Placeholder text */
|
|
23
|
+
placeholder?: string;
|
|
24
|
+
/** Helper text below input */
|
|
25
|
+
helperText?: string;
|
|
26
|
+
/** Leading icon (Ionicons name) */
|
|
27
|
+
leadingIcon?: IconName;
|
|
28
|
+
/** Trailing icon (Ionicons name) */
|
|
29
|
+
trailingIcon?: IconName;
|
|
30
|
+
/** Callback when trailing icon is pressed */
|
|
31
|
+
onTrailingIconPress?: () => void;
|
|
32
|
+
/** Show password toggle for secure inputs */
|
|
33
|
+
showPasswordToggle?: boolean;
|
|
34
|
+
/** Secure text entry (password field) */
|
|
35
|
+
secureTextEntry?: boolean;
|
|
36
|
+
/** Maximum character length */
|
|
37
|
+
maxLength?: number;
|
|
38
|
+
/** Show character counter */
|
|
39
|
+
showCharacterCount?: boolean;
|
|
40
|
+
/** Keyboard type */
|
|
41
|
+
keyboardType?: 'default' | 'email-address' | 'numeric' | 'phone-pad' | 'url' | 'number-pad' | 'decimal-pad' | 'web-search' | 'twitter' | 'numeric' | 'visible-password';
|
|
42
|
+
/** Return key type */
|
|
43
|
+
returnKeyType?: 'done' | 'go' | 'next' | 'search' | 'send';
|
|
44
|
+
/** Callback when submit button is pressed */
|
|
45
|
+
onSubmitEditing?: () => void;
|
|
46
|
+
/** Blur on submit */
|
|
47
|
+
blurOnSubmit?: boolean;
|
|
48
|
+
/** Auto focus */
|
|
49
|
+
autoFocus?: boolean;
|
|
50
|
+
/** Auto-capitalize */
|
|
51
|
+
autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters';
|
|
52
|
+
/** Auto-correct */
|
|
53
|
+
autoCorrect?: boolean;
|
|
54
|
+
/** Disabled state */
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** Container style */
|
|
57
|
+
style?: StyleProp<ViewStyle>;
|
|
58
|
+
/** Input text style */
|
|
59
|
+
inputStyle?: StyleProp<TextStyle>;
|
|
60
|
+
/** Test ID for E2E testing */
|
|
61
|
+
testID?: string;
|
|
62
|
+
/** Blur callback */
|
|
63
|
+
onBlur?: () => void;
|
|
64
|
+
/** Focus callback */
|
|
65
|
+
onFocus?: () => void;
|
|
66
|
+
/** Multiline input support */
|
|
67
|
+
multiline?: boolean;
|
|
68
|
+
/** Number of lines for multiline input */
|
|
69
|
+
numberOfLines?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type { AtomicInputProps as InputProps };
|