cpk-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/components/modals/AlertDialog/AlertDialog.js +80 -0
- package/components/modals/AlertDialog/AlertDialog.stories.tsx +80 -0
- package/components/modals/AlertDialog/AlertDialog.tsx +194 -0
- package/components/modals/Snackbar/Snackbar.js +94 -0
- package/components/modals/Snackbar/Snackbar.stories.tsx +98 -0
- package/components/modals/Snackbar/Snackbar.tsx +174 -0
- package/components/modals/Snackbar/const.js +5 -0
- package/components/modals/Snackbar/const.ts +4 -0
- package/components/uis/Accordion/Accordion.js +11 -0
- package/components/uis/Accordion/Accordion.stories.tsx +38 -0
- package/components/uis/Accordion/Accordion.test.tsx +128 -0
- package/components/uis/Accordion/Accordion.tsx +58 -0
- package/components/uis/Accordion/AccordionItem.js +102 -0
- package/components/uis/Accordion/AccordionItem.tsx +213 -0
- package/components/uis/Button/Button.js +161 -0
- package/components/uis/Button/Button.stories.tsx +81 -0
- package/components/uis/Button/Button.test.tsx +560 -0
- package/components/uis/Button/Button.tsx +335 -0
- package/components/uis/Checkbox/Checkbox.js +70 -0
- package/components/uis/Checkbox/Checkbox.stories.tsx +46 -0
- package/components/uis/Checkbox/Checkbox.test.tsx +139 -0
- package/components/uis/Checkbox/Checkbox.tsx +150 -0
- package/components/uis/Icon/Icon.js +3780 -0
- package/components/uis/Icon/Icon.stories.tsx +45 -0
- package/components/uis/Icon/Icon.test.tsx +19 -0
- package/components/uis/Icon/Icon.tsx +3800 -0
- package/components/uis/Icon/Pretendard-Bold.otf +0 -0
- package/components/uis/Icon/Pretendard-Regular.otf +0 -0
- package/components/uis/Icon/Pretendard-Thin.otf +0 -0
- package/components/uis/Icon/cpk.ttf +0 -0
- package/components/uis/Icon/selection.json +1 -0
- package/components/uis/IconButton/IconButton.js +120 -0
- package/components/uis/IconButton/IconButton.test.tsx +165 -0
- package/components/uis/IconButton/IconButton.tsx +252 -0
- package/components/uis/LoadingIndicator/LoadingIndicator.js +24 -0
- package/components/uis/LoadingIndicator/LoadingIndicator.tsx +79 -0
- package/components/uis/Rating/Rating.js +53 -0
- package/components/uis/Rating/Rating.test.tsx +72 -0
- package/components/uis/Rating/Rating.tsx +155 -0
- package/components/uis/StatusbarBrightness/StatusBarBrightness.js +13 -0
- package/components/uis/StatusbarBrightness/StatusBarBrightness.test.tsx +41 -0
- package/components/uis/StatusbarBrightness/StatusBarBrightness.tsx +17 -0
- package/components/uis/Styled/StyledComponents.js +130 -0
- package/components/uis/Styled/StyledComponents.tsx +200 -0
- package/components/uis/SwitchToggle/SwitchToggle.js +126 -0
- package/components/uis/SwitchToggle/SwitchToggle.test.tsx +70 -0
- package/components/uis/SwitchToggle/SwitchToggle.tsx +224 -0
- package/components/uis/Typography/Typography.js +90 -0
- package/components/uis/Typography/Typography.test.tsx +58 -0
- package/components/uis/Typography/Typography.tsx +132 -0
- package/hooks/useDebouncedColorScheme.js +21 -0
- package/hooks/useDebouncedColorScheme.tsx +30 -0
- package/index.js +16 -0
- package/index.tsx +18 -0
- package/package.json +35 -0
- package/providers/ThemeProvider.js +106 -0
- package/providers/ThemeProvider.tsx +180 -0
- package/providers/index.js +62 -0
- package/providers/index.tsx +125 -0
- package/react-native.config.cjs +5 -0
- package/utils/colors.js +124 -0
- package/utils/colors.ts +127 -0
- package/utils/createCtx.js +15 -0
- package/utils/createCtx.tsx +26 -0
- package/utils/guards.js +44 -0
- package/utils/guards.ts +93 -0
- package/utils/theme.js +5 -0
- package/utils/theme.ts +33 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {fireEvent, render} from '@testing-library/react-native';
|
|
3
|
+
|
|
4
|
+
import type {RatingProps} from './Rating';
|
|
5
|
+
import {Rating} from './Rating';
|
|
6
|
+
import {createComponent} from '../../../../test/testUtils';
|
|
7
|
+
|
|
8
|
+
const Component = (props?: RatingProps): JSX.Element =>
|
|
9
|
+
createComponent(<Rating {...props} />);
|
|
10
|
+
|
|
11
|
+
describe('Rating', () => {
|
|
12
|
+
test('renders five stars', () => {
|
|
13
|
+
const {getAllByTestId} = render(
|
|
14
|
+
Component({
|
|
15
|
+
testID: 'star',
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
18
|
+
const stars = getAllByTestId('star');
|
|
19
|
+
expect(stars).toHaveLength(5);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('renders half stars when allowHalfRating is true', () => {
|
|
23
|
+
const {getAllByTestId} = render(
|
|
24
|
+
Component({
|
|
25
|
+
testID: 'half-star',
|
|
26
|
+
allowHalfRating: true,
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
const halfStars = getAllByTestId('half-star');
|
|
30
|
+
expect(halfStars).toHaveLength(5);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('renders `dooboo` iconType', () => {
|
|
34
|
+
const {getAllByTestId} = render(
|
|
35
|
+
Component({
|
|
36
|
+
testID: 'star',
|
|
37
|
+
iconType: 'dooboo',
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
40
|
+
const stars = getAllByTestId('star');
|
|
41
|
+
expect(stars).toHaveLength(5);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('calls onRatingUpdate when a star is clicked', () => {
|
|
45
|
+
const handleRatingUpdate = jest.fn();
|
|
46
|
+
const {getAllByRole} = render(
|
|
47
|
+
Component({
|
|
48
|
+
onRatingUpdate: handleRatingUpdate,
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
const thirdStar = getAllByRole('button')[0];
|
|
52
|
+
|
|
53
|
+
fireEvent.press(thirdStar);
|
|
54
|
+
|
|
55
|
+
expect(handleRatingUpdate).toHaveBeenCalledWith(0.5);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('calls onRatingUpdate when a half star is clicked', () => {
|
|
59
|
+
const handleRatingUpdate = jest.fn();
|
|
60
|
+
const {getAllByRole} = render(
|
|
61
|
+
Component({
|
|
62
|
+
onRatingUpdate: handleRatingUpdate,
|
|
63
|
+
allowHalfRating: true,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
const thirdHalfStar = getAllByRole('button')[1];
|
|
67
|
+
|
|
68
|
+
fireEvent.press(thirdHalfStar);
|
|
69
|
+
|
|
70
|
+
expect(handleRatingUpdate).toHaveBeenCalledWith(1);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// React import is needed for expo-web
|
|
2
|
+
import React, {useState} from 'react';
|
|
3
|
+
import type {StyleProp, ViewStyle} from 'react-native';
|
|
4
|
+
import {Pressable, View} from 'react-native';
|
|
5
|
+
import styled, {css} from '@emotion/native';
|
|
6
|
+
|
|
7
|
+
import type {IconName} from '../Icon/Icon';
|
|
8
|
+
import {Icon} from '../Icon/Icon';
|
|
9
|
+
|
|
10
|
+
const Container = styled.View`
|
|
11
|
+
flex-direction: row;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
const StarContainer = styled.View`
|
|
15
|
+
padding: 1px;
|
|
16
|
+
|
|
17
|
+
flex-direction: row;
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
type Styles = {
|
|
21
|
+
starContainer: StyleProp<ViewStyle>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type RatingProps = {
|
|
25
|
+
testID?: string;
|
|
26
|
+
styles?: Styles;
|
|
27
|
+
style?: StyleProp<ViewStyle>;
|
|
28
|
+
size?: number;
|
|
29
|
+
iconType?: 'star' | 'dooboo';
|
|
30
|
+
initialRating?: number;
|
|
31
|
+
direction?: 'horizontal' | 'vertical';
|
|
32
|
+
allowHalfRating?: boolean;
|
|
33
|
+
onRatingUpdate?: (score: number) => void;
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
color?: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function Rating({
|
|
39
|
+
testID,
|
|
40
|
+
style,
|
|
41
|
+
styles,
|
|
42
|
+
initialRating = 0,
|
|
43
|
+
size = 24,
|
|
44
|
+
iconType = 'star',
|
|
45
|
+
onRatingUpdate,
|
|
46
|
+
direction = 'horizontal',
|
|
47
|
+
allowHalfRating = true,
|
|
48
|
+
disabled = false,
|
|
49
|
+
color,
|
|
50
|
+
}: RatingProps): JSX.Element {
|
|
51
|
+
const [rating, setRating] = useState(initialRating);
|
|
52
|
+
const iconPrefix = iconType === 'star' ? 'Star' : 'QuestBox';
|
|
53
|
+
|
|
54
|
+
const handlePress = (newRating: number, halfPressed?: boolean): void => {
|
|
55
|
+
const convertedRating = newRating + (!halfPressed ? 0.5 : 0);
|
|
56
|
+
|
|
57
|
+
setRating(convertedRating);
|
|
58
|
+
|
|
59
|
+
if (onRatingUpdate) {
|
|
60
|
+
onRatingUpdate(convertedRating);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const renderStarIcon = ({
|
|
65
|
+
key,
|
|
66
|
+
position,
|
|
67
|
+
}: {
|
|
68
|
+
key: string;
|
|
69
|
+
position: number;
|
|
70
|
+
}): JSX.Element => {
|
|
71
|
+
const filled = rating >= position + (allowHalfRating ? 0.5 : 0);
|
|
72
|
+
const iconName: IconName = filled ? `${iconPrefix}Fill` : `${iconPrefix}`;
|
|
73
|
+
const halfFilled =
|
|
74
|
+
rating >= position && rating < position + (allowHalfRating ? 0.5 : 0);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<StarContainer
|
|
78
|
+
key={key}
|
|
79
|
+
style={[
|
|
80
|
+
css`
|
|
81
|
+
width: ${size + 'px'};
|
|
82
|
+
`,
|
|
83
|
+
styles?.starContainer,
|
|
84
|
+
]}
|
|
85
|
+
testID={testID}
|
|
86
|
+
>
|
|
87
|
+
{halfFilled && allowHalfRating ? (
|
|
88
|
+
<View style={{position: 'absolute'}}>
|
|
89
|
+
<Icon
|
|
90
|
+
color={color}
|
|
91
|
+
name={`${iconPrefix}` as IconName}
|
|
92
|
+
size={size}
|
|
93
|
+
style={{position: 'absolute'}}
|
|
94
|
+
/>
|
|
95
|
+
<Icon
|
|
96
|
+
color={color}
|
|
97
|
+
name={`${iconPrefix}HalfFill` as IconName}
|
|
98
|
+
size={size}
|
|
99
|
+
/>
|
|
100
|
+
</View>
|
|
101
|
+
) : (
|
|
102
|
+
<Icon
|
|
103
|
+
color={color}
|
|
104
|
+
name={iconName}
|
|
105
|
+
size={size}
|
|
106
|
+
style={{position: 'absolute'}}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
<Pressable
|
|
110
|
+
accessibilityRole="button"
|
|
111
|
+
disabled={disabled}
|
|
112
|
+
onPress={() => handlePress(position, true)}
|
|
113
|
+
>
|
|
114
|
+
<View
|
|
115
|
+
style={{
|
|
116
|
+
width: size / 2,
|
|
117
|
+
height: size,
|
|
118
|
+
backgroundColor: 'transparent',
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
121
|
+
</Pressable>
|
|
122
|
+
<Pressable
|
|
123
|
+
accessibilityRole="button"
|
|
124
|
+
disabled={disabled}
|
|
125
|
+
onPress={() => handlePress(position)}
|
|
126
|
+
>
|
|
127
|
+
<View
|
|
128
|
+
style={{
|
|
129
|
+
width: size / 2,
|
|
130
|
+
height: size,
|
|
131
|
+
backgroundColor: 'transparent',
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
</Pressable>
|
|
135
|
+
</StarContainer>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<Container
|
|
141
|
+
style={[
|
|
142
|
+
css`
|
|
143
|
+
flex-direction: ${direction === 'horizontal' ? 'row' : 'column'};
|
|
144
|
+
`,
|
|
145
|
+
style,
|
|
146
|
+
]}
|
|
147
|
+
>
|
|
148
|
+
{[...Array(5)].map((_, index) => {
|
|
149
|
+
const position = index + (allowHalfRating ? 0.5 : 1);
|
|
150
|
+
|
|
151
|
+
return renderStarIcon({key: `${_}-${index}`, position});
|
|
152
|
+
})}
|
|
153
|
+
</Container>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { StatusBar } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../../providers/ThemeProvider';
|
|
4
|
+
function StatusBarBrightness({ type }) {
|
|
5
|
+
const { themeType } = useTheme();
|
|
6
|
+
const statusColor = type
|
|
7
|
+
? type
|
|
8
|
+
: themeType === 'light'
|
|
9
|
+
? 'dark-content'
|
|
10
|
+
: 'light-content';
|
|
11
|
+
return _jsx(StatusBar, { barStyle: statusColor });
|
|
12
|
+
}
|
|
13
|
+
export default StatusBarBrightness;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
import type {RenderAPI} from '@testing-library/react-native';
|
|
4
|
+
import {render} from '@testing-library/react-native';
|
|
5
|
+
|
|
6
|
+
import {createComponent} from '../../../../test/testUtils';
|
|
7
|
+
import StatusBarBrightness from './StatusBarBrightness';
|
|
8
|
+
import {ThemeProvider} from '../../../providers/ThemeProvider';
|
|
9
|
+
|
|
10
|
+
let testingLib: RenderAPI;
|
|
11
|
+
|
|
12
|
+
const Component = (): JSX.Element =>
|
|
13
|
+
createComponent(
|
|
14
|
+
<View>
|
|
15
|
+
<StatusBarBrightness />
|
|
16
|
+
</View>,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
describe('[StatusBarBrightness]', () => {
|
|
20
|
+
it('should render without crashing', () => {
|
|
21
|
+
testingLib = render(Component());
|
|
22
|
+
|
|
23
|
+
const json = testingLib.toJSON();
|
|
24
|
+
|
|
25
|
+
expect(json).toBeTruthy();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should render [dark] mode', () => {
|
|
29
|
+
testingLib = render(
|
|
30
|
+
<ThemeProvider initialThemeType="dark">
|
|
31
|
+
<View>
|
|
32
|
+
<StatusBarBrightness />
|
|
33
|
+
</View>
|
|
34
|
+
</ThemeProvider>,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const json = testingLib.toJSON();
|
|
38
|
+
|
|
39
|
+
expect(json).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type {StatusBarStyle} from 'react-native';
|
|
2
|
+
import {StatusBar} from 'react-native';
|
|
3
|
+
import {useTheme} from '../../../providers/ThemeProvider';
|
|
4
|
+
|
|
5
|
+
function StatusBarBrightness({type}: {type?: StatusBarStyle}): JSX.Element {
|
|
6
|
+
const {themeType} = useTheme();
|
|
7
|
+
|
|
8
|
+
const statusColor: StatusBarStyle = type
|
|
9
|
+
? type
|
|
10
|
+
: themeType === 'light'
|
|
11
|
+
? 'dark-content'
|
|
12
|
+
: 'light-content';
|
|
13
|
+
|
|
14
|
+
return <StatusBar barStyle={statusColor} />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default StatusBarBrightness;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Animated } from 'react-native';
|
|
2
|
+
import styled from '@emotion/native';
|
|
3
|
+
import { isEmptyObject } from '../../../utils/theme';
|
|
4
|
+
import { light } from '../../../utils/colors';
|
|
5
|
+
// 기본 theme 설정 함수
|
|
6
|
+
const resolveTheme = (theme) => isEmptyObject(theme) ? light : theme;
|
|
7
|
+
// ButtonWrapper Component
|
|
8
|
+
export const ButtonWrapper = styled.View `
|
|
9
|
+
border-width: ${({ outlined }) => (outlined ? '1px' : undefined)};
|
|
10
|
+
background-color: ${({ theme, type, outlined, loading, disabled }) => {
|
|
11
|
+
theme = resolveTheme(theme);
|
|
12
|
+
if (loading) {
|
|
13
|
+
return outlined ? undefined : theme.button[type].bg;
|
|
14
|
+
}
|
|
15
|
+
if (disabled) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return outlined ? theme.bg.basic : theme.button[type ?? 'primary'].bg;
|
|
19
|
+
}};
|
|
20
|
+
border-color: ${({ theme, type, disabled }) => {
|
|
21
|
+
theme = resolveTheme(theme);
|
|
22
|
+
if (disabled) {
|
|
23
|
+
return theme.bg.basic;
|
|
24
|
+
}
|
|
25
|
+
return theme.button[type].bg;
|
|
26
|
+
}};
|
|
27
|
+
`;
|
|
28
|
+
// ButtonText Component
|
|
29
|
+
export const ButtonText = styled.Text `
|
|
30
|
+
font-family: Pretendard;
|
|
31
|
+
color: ${({ theme, outlined, type, disabled }) => {
|
|
32
|
+
theme = resolveTheme(theme);
|
|
33
|
+
if (outlined) {
|
|
34
|
+
return theme.text.basic;
|
|
35
|
+
}
|
|
36
|
+
if (disabled) {
|
|
37
|
+
return theme.text.disabled;
|
|
38
|
+
}
|
|
39
|
+
return theme.button[type].text;
|
|
40
|
+
}};
|
|
41
|
+
`;
|
|
42
|
+
// CheckboxWrapperOutlined Component
|
|
43
|
+
export const CheckboxWrapperOutlined = styled(Animated.View) `
|
|
44
|
+
border-width: 1px;
|
|
45
|
+
border-color: ${({ theme, type, disabled }) => {
|
|
46
|
+
theme = resolveTheme(theme);
|
|
47
|
+
if (disabled) {
|
|
48
|
+
return theme.bg.disabled;
|
|
49
|
+
}
|
|
50
|
+
return type === 'light'
|
|
51
|
+
? theme.role.primary
|
|
52
|
+
: theme.button[type ?? 'primary'].bg;
|
|
53
|
+
}};
|
|
54
|
+
`;
|
|
55
|
+
// CheckboxWrapper Component
|
|
56
|
+
export const CheckboxWrapper = styled(Animated.View) `
|
|
57
|
+
background-color: ${({ theme, checked, type, disabled }) => {
|
|
58
|
+
theme = resolveTheme(theme);
|
|
59
|
+
if (disabled) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
if (!checked) {
|
|
63
|
+
return theme.bg.disabled;
|
|
64
|
+
}
|
|
65
|
+
return type === 'light'
|
|
66
|
+
? theme.role.primary
|
|
67
|
+
: theme.button[type ?? 'primary'].bg;
|
|
68
|
+
}};
|
|
69
|
+
`;
|
|
70
|
+
// RadioButtonWrapper Component
|
|
71
|
+
export const RadioButtonWrapper = styled.View `
|
|
72
|
+
border-width: 1px;
|
|
73
|
+
border-color: ${({ theme, type, selected, disabled }) => {
|
|
74
|
+
theme = resolveTheme(theme);
|
|
75
|
+
if (disabled) {
|
|
76
|
+
return theme.bg.disabled;
|
|
77
|
+
}
|
|
78
|
+
if (!selected) {
|
|
79
|
+
return theme.text.basic;
|
|
80
|
+
}
|
|
81
|
+
return type === 'light'
|
|
82
|
+
? theme.role.primary
|
|
83
|
+
: theme.button[type ?? 'primary'].bg;
|
|
84
|
+
}};
|
|
85
|
+
`;
|
|
86
|
+
// RadioWrapper Component
|
|
87
|
+
export const RadioWrapper = styled(Animated.View) `
|
|
88
|
+
background-color: ${({ theme, selected, type, disabled }) => {
|
|
89
|
+
theme = resolveTheme(theme);
|
|
90
|
+
if (disabled) {
|
|
91
|
+
return theme.bg.disabled;
|
|
92
|
+
}
|
|
93
|
+
if (!selected) {
|
|
94
|
+
return theme.role.primary;
|
|
95
|
+
}
|
|
96
|
+
return theme.button[type ?? 'primary'].bg;
|
|
97
|
+
}};
|
|
98
|
+
`;
|
|
99
|
+
// ColoredText Component
|
|
100
|
+
export const ColoredText = styled.Text `
|
|
101
|
+
font-family: Pretendard;
|
|
102
|
+
color: ${({ theme, selected, type, disabled }) => {
|
|
103
|
+
theme = resolveTheme(theme);
|
|
104
|
+
if (disabled) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
if (!selected) {
|
|
108
|
+
return theme.text.basic;
|
|
109
|
+
}
|
|
110
|
+
return type === 'light'
|
|
111
|
+
? theme.role.primary
|
|
112
|
+
: theme.button[type ?? 'primary'].bg;
|
|
113
|
+
}};
|
|
114
|
+
`;
|
|
115
|
+
// SnackbarWrapper Component
|
|
116
|
+
export const SnackbarWrapper = styled(Animated.View) `
|
|
117
|
+
background-color: ${({ theme, type }) => {
|
|
118
|
+
theme = resolveTheme(theme);
|
|
119
|
+
return !type ? theme.bg.disabled : theme.button[type ?? 'light'].bg;
|
|
120
|
+
}};
|
|
121
|
+
flex-direction: row;
|
|
122
|
+
text-align: left;
|
|
123
|
+
align-items: center;
|
|
124
|
+
align-self: center;
|
|
125
|
+
position: absolute;
|
|
126
|
+
font-size: 16px;
|
|
127
|
+
padding: 10px 20px;
|
|
128
|
+
bottom: 20px;
|
|
129
|
+
border-radius: 20px;
|
|
130
|
+
`;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {Animated} from 'react-native';
|
|
2
|
+
import styled from '@emotion/native';
|
|
3
|
+
import {CpkTheme, isEmptyObject} from '../../../utils/theme';
|
|
4
|
+
import {light} from '../../../utils/colors';
|
|
5
|
+
|
|
6
|
+
export type ButtonType =
|
|
7
|
+
| 'primary'
|
|
8
|
+
| 'secondary'
|
|
9
|
+
| 'success'
|
|
10
|
+
| 'danger'
|
|
11
|
+
| 'warning'
|
|
12
|
+
| 'info'
|
|
13
|
+
| 'light';
|
|
14
|
+
|
|
15
|
+
export type SnackbarType =
|
|
16
|
+
| 'primary'
|
|
17
|
+
| 'secondary'
|
|
18
|
+
| 'success'
|
|
19
|
+
| 'warning'
|
|
20
|
+
| 'info'
|
|
21
|
+
| 'danger';
|
|
22
|
+
|
|
23
|
+
// 기본 theme 설정 함수
|
|
24
|
+
const resolveTheme = (theme?: CpkTheme) =>
|
|
25
|
+
isEmptyObject(theme) ? light : theme!;
|
|
26
|
+
|
|
27
|
+
// ButtonWrapper Component
|
|
28
|
+
export const ButtonWrapper = styled.View<{
|
|
29
|
+
type?: ButtonType;
|
|
30
|
+
outlined?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
loading?: boolean;
|
|
33
|
+
}>`
|
|
34
|
+
border-width: ${({outlined}) => (outlined ? '1px' : undefined)};
|
|
35
|
+
background-color: ${({theme, type, outlined, loading, disabled}) => {
|
|
36
|
+
theme = resolveTheme(theme);
|
|
37
|
+
|
|
38
|
+
if (loading) {
|
|
39
|
+
return outlined ? undefined : theme.button[type!].bg;
|
|
40
|
+
}
|
|
41
|
+
if (disabled) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return outlined ? theme.bg.basic : theme.button[type ?? 'primary'].bg;
|
|
45
|
+
}};
|
|
46
|
+
border-color: ${({theme, type, disabled}) => {
|
|
47
|
+
theme = resolveTheme(theme);
|
|
48
|
+
|
|
49
|
+
if (disabled) {
|
|
50
|
+
return theme.bg.basic;
|
|
51
|
+
}
|
|
52
|
+
return theme.button[type!].bg;
|
|
53
|
+
}};
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
// ButtonText Component
|
|
57
|
+
export const ButtonText = styled.Text<{
|
|
58
|
+
outlined?: boolean;
|
|
59
|
+
type?: ButtonType | SnackbarType;
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
loading?: boolean;
|
|
62
|
+
theme?: CpkTheme;
|
|
63
|
+
}>`
|
|
64
|
+
font-family: Pretendard;
|
|
65
|
+
color: ${({theme, outlined, type, disabled}) => {
|
|
66
|
+
theme = resolveTheme(theme);
|
|
67
|
+
|
|
68
|
+
if (outlined) {
|
|
69
|
+
return theme.text.basic;
|
|
70
|
+
}
|
|
71
|
+
if (disabled) {
|
|
72
|
+
return theme.text.disabled;
|
|
73
|
+
}
|
|
74
|
+
return theme.button[type!].text;
|
|
75
|
+
}};
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
// CheckboxWrapperOutlined Component
|
|
79
|
+
export const CheckboxWrapperOutlined = styled(Animated.View)<{
|
|
80
|
+
type: ButtonType;
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
checked?: boolean;
|
|
83
|
+
}>`
|
|
84
|
+
border-width: 1px;
|
|
85
|
+
border-color: ${({theme, type, disabled}) => {
|
|
86
|
+
theme = resolveTheme(theme);
|
|
87
|
+
|
|
88
|
+
if (disabled) {
|
|
89
|
+
return theme.bg.disabled;
|
|
90
|
+
}
|
|
91
|
+
return type === 'light'
|
|
92
|
+
? theme.role.primary
|
|
93
|
+
: theme.button[type ?? 'primary'].bg;
|
|
94
|
+
}};
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
// CheckboxWrapper Component
|
|
98
|
+
export const CheckboxWrapper = styled(Animated.View)<{
|
|
99
|
+
type: ButtonType;
|
|
100
|
+
disabled?: boolean;
|
|
101
|
+
checked?: boolean;
|
|
102
|
+
}>`
|
|
103
|
+
background-color: ${({theme, checked, type, disabled}) => {
|
|
104
|
+
theme = resolveTheme(theme);
|
|
105
|
+
|
|
106
|
+
if (disabled) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
if (!checked) {
|
|
110
|
+
return theme.bg.disabled;
|
|
111
|
+
}
|
|
112
|
+
return type === 'light'
|
|
113
|
+
? theme.role.primary
|
|
114
|
+
: theme.button[type ?? 'primary'].bg;
|
|
115
|
+
}};
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
// RadioButtonWrapper Component
|
|
119
|
+
export const RadioButtonWrapper = styled.View<{
|
|
120
|
+
type: ButtonType;
|
|
121
|
+
selected?: boolean;
|
|
122
|
+
disabled?: boolean;
|
|
123
|
+
}>`
|
|
124
|
+
border-width: 1px;
|
|
125
|
+
border-color: ${({theme, type, selected, disabled}) => {
|
|
126
|
+
theme = resolveTheme(theme);
|
|
127
|
+
|
|
128
|
+
if (disabled) {
|
|
129
|
+
return theme.bg.disabled;
|
|
130
|
+
}
|
|
131
|
+
if (!selected) {
|
|
132
|
+
return theme.text.basic;
|
|
133
|
+
}
|
|
134
|
+
return type === 'light'
|
|
135
|
+
? theme.role.primary
|
|
136
|
+
: theme.button[type ?? 'primary'].bg;
|
|
137
|
+
}};
|
|
138
|
+
`;
|
|
139
|
+
|
|
140
|
+
// RadioWrapper Component
|
|
141
|
+
export const RadioWrapper = styled(Animated.View)<{
|
|
142
|
+
type: ButtonType;
|
|
143
|
+
disabled?: boolean;
|
|
144
|
+
selected?: boolean;
|
|
145
|
+
}>`
|
|
146
|
+
background-color: ${({theme, selected, type, disabled}) => {
|
|
147
|
+
theme = resolveTheme(theme);
|
|
148
|
+
|
|
149
|
+
if (disabled) {
|
|
150
|
+
return theme.bg.disabled;
|
|
151
|
+
}
|
|
152
|
+
if (!selected) {
|
|
153
|
+
return theme.role.primary;
|
|
154
|
+
}
|
|
155
|
+
return theme.button[type ?? 'primary'].bg;
|
|
156
|
+
}};
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
// ColoredText Component
|
|
160
|
+
export const ColoredText = styled.Text<{
|
|
161
|
+
type: ButtonType;
|
|
162
|
+
disabled?: boolean;
|
|
163
|
+
selected?: boolean;
|
|
164
|
+
}>`
|
|
165
|
+
font-family: Pretendard;
|
|
166
|
+
color: ${({theme, selected, type, disabled}) => {
|
|
167
|
+
theme = resolveTheme(theme);
|
|
168
|
+
|
|
169
|
+
if (disabled) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
if (!selected) {
|
|
173
|
+
return theme.text.basic;
|
|
174
|
+
}
|
|
175
|
+
return type === 'light'
|
|
176
|
+
? theme.role.primary
|
|
177
|
+
: theme.button[type ?? 'primary'].bg;
|
|
178
|
+
}};
|
|
179
|
+
`;
|
|
180
|
+
|
|
181
|
+
// SnackbarWrapper Component
|
|
182
|
+
export const SnackbarWrapper = styled(Animated.View)<{
|
|
183
|
+
type?: SnackbarType;
|
|
184
|
+
checked?: boolean;
|
|
185
|
+
}>`
|
|
186
|
+
background-color: ${({theme, type}) => {
|
|
187
|
+
theme = resolveTheme(theme);
|
|
188
|
+
|
|
189
|
+
return !type ? theme.bg.disabled : theme.button[type ?? 'light'].bg;
|
|
190
|
+
}};
|
|
191
|
+
flex-direction: row;
|
|
192
|
+
text-align: left;
|
|
193
|
+
align-items: center;
|
|
194
|
+
align-self: center;
|
|
195
|
+
position: absolute;
|
|
196
|
+
font-size: 16px;
|
|
197
|
+
padding: 10px 20px;
|
|
198
|
+
bottom: 20px;
|
|
199
|
+
border-radius: 20px;
|
|
200
|
+
`;
|