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.
Files changed (69) hide show
  1. package/README.md +27 -0
  2. package/components/modals/AlertDialog/AlertDialog.js +80 -0
  3. package/components/modals/AlertDialog/AlertDialog.stories.tsx +80 -0
  4. package/components/modals/AlertDialog/AlertDialog.tsx +194 -0
  5. package/components/modals/Snackbar/Snackbar.js +94 -0
  6. package/components/modals/Snackbar/Snackbar.stories.tsx +98 -0
  7. package/components/modals/Snackbar/Snackbar.tsx +174 -0
  8. package/components/modals/Snackbar/const.js +5 -0
  9. package/components/modals/Snackbar/const.ts +4 -0
  10. package/components/uis/Accordion/Accordion.js +11 -0
  11. package/components/uis/Accordion/Accordion.stories.tsx +38 -0
  12. package/components/uis/Accordion/Accordion.test.tsx +128 -0
  13. package/components/uis/Accordion/Accordion.tsx +58 -0
  14. package/components/uis/Accordion/AccordionItem.js +102 -0
  15. package/components/uis/Accordion/AccordionItem.tsx +213 -0
  16. package/components/uis/Button/Button.js +161 -0
  17. package/components/uis/Button/Button.stories.tsx +81 -0
  18. package/components/uis/Button/Button.test.tsx +560 -0
  19. package/components/uis/Button/Button.tsx +335 -0
  20. package/components/uis/Checkbox/Checkbox.js +70 -0
  21. package/components/uis/Checkbox/Checkbox.stories.tsx +46 -0
  22. package/components/uis/Checkbox/Checkbox.test.tsx +139 -0
  23. package/components/uis/Checkbox/Checkbox.tsx +150 -0
  24. package/components/uis/Icon/Icon.js +3780 -0
  25. package/components/uis/Icon/Icon.stories.tsx +45 -0
  26. package/components/uis/Icon/Icon.test.tsx +19 -0
  27. package/components/uis/Icon/Icon.tsx +3800 -0
  28. package/components/uis/Icon/Pretendard-Bold.otf +0 -0
  29. package/components/uis/Icon/Pretendard-Regular.otf +0 -0
  30. package/components/uis/Icon/Pretendard-Thin.otf +0 -0
  31. package/components/uis/Icon/cpk.ttf +0 -0
  32. package/components/uis/Icon/selection.json +1 -0
  33. package/components/uis/IconButton/IconButton.js +120 -0
  34. package/components/uis/IconButton/IconButton.test.tsx +165 -0
  35. package/components/uis/IconButton/IconButton.tsx +252 -0
  36. package/components/uis/LoadingIndicator/LoadingIndicator.js +24 -0
  37. package/components/uis/LoadingIndicator/LoadingIndicator.tsx +79 -0
  38. package/components/uis/Rating/Rating.js +53 -0
  39. package/components/uis/Rating/Rating.test.tsx +72 -0
  40. package/components/uis/Rating/Rating.tsx +155 -0
  41. package/components/uis/StatusbarBrightness/StatusBarBrightness.js +13 -0
  42. package/components/uis/StatusbarBrightness/StatusBarBrightness.test.tsx +41 -0
  43. package/components/uis/StatusbarBrightness/StatusBarBrightness.tsx +17 -0
  44. package/components/uis/Styled/StyledComponents.js +130 -0
  45. package/components/uis/Styled/StyledComponents.tsx +200 -0
  46. package/components/uis/SwitchToggle/SwitchToggle.js +126 -0
  47. package/components/uis/SwitchToggle/SwitchToggle.test.tsx +70 -0
  48. package/components/uis/SwitchToggle/SwitchToggle.tsx +224 -0
  49. package/components/uis/Typography/Typography.js +90 -0
  50. package/components/uis/Typography/Typography.test.tsx +58 -0
  51. package/components/uis/Typography/Typography.tsx +132 -0
  52. package/hooks/useDebouncedColorScheme.js +21 -0
  53. package/hooks/useDebouncedColorScheme.tsx +30 -0
  54. package/index.js +16 -0
  55. package/index.tsx +18 -0
  56. package/package.json +35 -0
  57. package/providers/ThemeProvider.js +106 -0
  58. package/providers/ThemeProvider.tsx +180 -0
  59. package/providers/index.js +62 -0
  60. package/providers/index.tsx +125 -0
  61. package/react-native.config.cjs +5 -0
  62. package/utils/colors.js +124 -0
  63. package/utils/colors.ts +127 -0
  64. package/utils/createCtx.js +15 -0
  65. package/utils/createCtx.tsx +26 -0
  66. package/utils/guards.js +44 -0
  67. package/utils/guards.ts +93 -0
  68. package/utils/theme.js +5 -0
  69. package/utils/theme.ts +33 -0
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef } from 'react';
3
+ import { Platform, TouchableHighlight, View } from 'react-native';
4
+ import { useHover } from 'react-native-web-hooks';
5
+ import { css } from '@emotion/native';
6
+ import { Icon } from '../Icon/Icon';
7
+ import { LoadingIndicator } from '../LoadingIndicator/LoadingIndicator';
8
+ import { getTheme } from '../../../utils/theme';
9
+ import { useTheme } from '../../../providers/ThemeProvider';
10
+ export const ButtonStyles = ({ theme, type = 'solid', color = 'primary', loading, disabled, }) => {
11
+ theme = getTheme(theme);
12
+ let backgroundColor = theme.button[color].bg;
13
+ let borderColor = theme.button[color].bg;
14
+ let iconColor = theme.button[color].bg;
15
+ if (disabled) {
16
+ backgroundColor = theme.button.disabled.bg;
17
+ borderColor = theme.button.disabled.text;
18
+ iconColor = theme.button.disabled.text;
19
+ }
20
+ if (['text', 'outlined'].includes(type)) {
21
+ backgroundColor = theme.bg.basic;
22
+ }
23
+ if (type === 'solid' || color === 'light') {
24
+ iconColor = theme.button[color].text;
25
+ }
26
+ return {
27
+ backgroundColor,
28
+ borderColor,
29
+ borderWidth: type === 'outlined' ? 1 : 0,
30
+ iconColor,
31
+ disabledBackgroundColor: type === 'solid' && !loading ? theme.button.disabled.bg : theme.bg.basic,
32
+ disabledBorderColor: theme.bg.disabled,
33
+ disabledTextColor: theme.button.disabled.text,
34
+ };
35
+ };
36
+ export function IconButton({ testID, type = 'solid', color = 'primary', size = 'medium', disabled, loading = false, loadingElement, icon, iconElement, style, styles, onPress, activeOpacity = 0.95, touchableHighlightProps, }) {
37
+ const ref = useRef(null);
38
+ const hovered = useHover(ref);
39
+ const { theme } = useTheme();
40
+ const { backgroundColor, borderColor, borderWidth, iconColor, disabledBackgroundColor, disabledBorderColor, } = ButtonStyles({
41
+ theme,
42
+ type,
43
+ color,
44
+ loading,
45
+ disabled,
46
+ });
47
+ const iconSize = size === 'large'
48
+ ? 32
49
+ : size === 'medium'
50
+ ? 24
51
+ : size === 'small'
52
+ ? 16
53
+ : size;
54
+ const borderWidthStr = `${borderWidth + 'px'}`;
55
+ const borderRadiusStr = `99px`;
56
+ const compositeStyles = {
57
+ container: [
58
+ css `
59
+ background-color: ${backgroundColor};
60
+ border-color: ${borderColor};
61
+ border-width: ${borderWidthStr};
62
+ padding: 12px;
63
+ `,
64
+ styles?.container,
65
+ ],
66
+ icon: [
67
+ css `
68
+ color: ${iconColor};
69
+ `,
70
+ styles?.icon,
71
+ ],
72
+ disabled: [
73
+ css `
74
+ background-color: ${disabledBackgroundColor};
75
+ border-color: ${disabledBorderColor};
76
+ `,
77
+ styles?.disabled,
78
+ ],
79
+ hovered: [
80
+ {
81
+ shadowColor: theme.text.basic,
82
+ shadowOpacity: 0.24,
83
+ shadowRadius: 16,
84
+ elevation: 10,
85
+ },
86
+ styles?.hovered,
87
+ ],
88
+ };
89
+ return (_jsx(View, { style: [
90
+ css `
91
+ flex-direction: row;
92
+ border-radius: ${borderRadiusStr};
93
+ `,
94
+ style,
95
+ ], children: _jsx(TouchableHighlight, { activeOpacity: activeOpacity, delayPressIn: 50, disabled: disabled || loading, onPress: onPress, ref: Platform.select({
96
+ web: ref,
97
+ default: undefined,
98
+ }), style: css `
99
+ border-radius: ${borderRadiusStr};
100
+ `, testID: testID, underlayColor: theme.role.underlay, ...touchableHighlightProps, children: _jsx(View, { style: [
101
+ css `
102
+ padding: 4px;
103
+ border-radius: ${borderRadiusStr};
104
+
105
+ flex-direction: row;
106
+ justify-content: center;
107
+ align-items: center;
108
+ `,
109
+ compositeStyles.container,
110
+ hovered && !disabled && compositeStyles.hovered,
111
+ disabled && compositeStyles.disabled,
112
+ ], testID: loading ? 'loading-view' : 'button-container', children: loading
113
+ ? loadingElement || (_jsx(LoadingIndicator, { color: theme.text.disabled, size: "small", style: css `
114
+ justify-content: center;
115
+ align-items: center;
116
+ height: ${iconSize + 'px'};
117
+ width: ${iconSize + 'px'};
118
+ ` }))
119
+ : iconElement || (_jsx(Icon, { color: iconColor, name: icon || 'QuestBoxFill', size: iconSize, style: compositeStyles?.icon })) }) }) }));
120
+ }
@@ -0,0 +1,165 @@
1
+ import React from 'react';
2
+ import type {RenderAPI} from '@testing-library/react-native';
3
+ import {render} from '@testing-library/react-native';
4
+
5
+ import {createComponent} from '../../../../test/testUtils';
6
+ import type {IconButtonProps} from './IconButton';
7
+ import {IconButton} from './IconButton';
8
+
9
+ let testingLib: RenderAPI;
10
+
11
+ jest.mock('react-native-web-hooks', () => ({
12
+ useHover: () => true,
13
+ }));
14
+
15
+ const Component = (props?: IconButtonProps): JSX.Element =>
16
+ createComponent(<IconButton {...props} />);
17
+
18
+ describe('[IconButton]', () => {
19
+ it('should render without crashing', () => {
20
+ testingLib = render(Component());
21
+
22
+ const json = testingLib.toJSON();
23
+
24
+ expect(json).toBeTruthy();
25
+ });
26
+
27
+ it('should render `outlined` button', () => {
28
+ testingLib = render(
29
+ Component({
30
+ type: 'outlined',
31
+ }),
32
+ );
33
+
34
+ const json = testingLib.toJSON();
35
+
36
+ expect(json).toBeTruthy();
37
+ });
38
+
39
+ describe('loading', () => {
40
+ it('should render `loading` button', () => {
41
+ testingLib = render(
42
+ Component({
43
+ loading: true,
44
+ }),
45
+ );
46
+
47
+ const json = testingLib.toJSON();
48
+
49
+ expect(json).toBeTruthy();
50
+ });
51
+
52
+ it('should render `disabled` button', () => {
53
+ testingLib = render(
54
+ Component({
55
+ loading: true,
56
+ disabled: true,
57
+ }),
58
+ );
59
+
60
+ const json = testingLib.toJSON();
61
+
62
+ expect(json).toBeTruthy();
63
+ });
64
+ });
65
+
66
+ describe('size', () => {
67
+ it('should renders large size', () => {
68
+ testingLib = render(
69
+ Component({
70
+ size: 'large',
71
+ }),
72
+ );
73
+
74
+ const json = testingLib.toJSON();
75
+
76
+ expect(json).toBeTruthy();
77
+ });
78
+
79
+ it('should renders small size', () => {
80
+ testingLib = render(
81
+ Component({
82
+ size: 'small',
83
+ }),
84
+ );
85
+
86
+ const json = testingLib.toJSON();
87
+
88
+ expect(json).toBeTruthy();
89
+ });
90
+ });
91
+
92
+ describe('type', () => {
93
+ it('should render color==="info"', () => {
94
+ testingLib = render(
95
+ Component({
96
+ color: 'info',
97
+ }),
98
+ );
99
+
100
+ const json = testingLib.toJSON();
101
+
102
+ expect(json).toBeTruthy();
103
+ });
104
+
105
+ it('should renders primary color', () => {
106
+ testingLib = render(
107
+ Component({
108
+ color: 'primary',
109
+ }),
110
+ );
111
+
112
+ const json = testingLib.toJSON();
113
+
114
+ expect(json).toBeTruthy();
115
+ });
116
+
117
+ it('should renders secondary color', () => {
118
+ testingLib = render(
119
+ Component({
120
+ color: 'secondary',
121
+ }),
122
+ );
123
+
124
+ const json = testingLib.toJSON();
125
+
126
+ expect(json).toBeTruthy();
127
+ });
128
+
129
+ it('should renders danger color', () => {
130
+ testingLib = render(
131
+ Component({
132
+ color: 'danger',
133
+ }),
134
+ );
135
+
136
+ const json = testingLib.toJSON();
137
+
138
+ expect(json).toBeTruthy();
139
+ });
140
+
141
+ it('should renders warning color', () => {
142
+ testingLib = render(
143
+ Component({
144
+ color: 'warning',
145
+ }),
146
+ );
147
+
148
+ const json = testingLib.toJSON();
149
+
150
+ expect(json).toBeTruthy();
151
+ });
152
+ });
153
+
154
+ it('should render `disabled` button', () => {
155
+ testingLib = render(
156
+ Component({
157
+ disabled: true,
158
+ }),
159
+ );
160
+
161
+ const json = testingLib.toJSON();
162
+
163
+ expect(json).toBeTruthy();
164
+ });
165
+ });
@@ -0,0 +1,252 @@
1
+ import React, {useRef} from 'react';
2
+ import type {StyleProp, TouchableHighlightProps, ViewStyle} from 'react-native';
3
+ import {Platform, TouchableHighlight, View} from 'react-native';
4
+ import {useHover} from 'react-native-web-hooks';
5
+ import {css} from '@emotion/native';
6
+
7
+ import type {IconName} from '../Icon/Icon';
8
+ import {Icon} from '../Icon/Icon';
9
+ import {LoadingIndicator} from '../LoadingIndicator/LoadingIndicator';
10
+ import {CpkTheme, getTheme} from '../../../utils/theme';
11
+ import {useTheme} from '../../../providers/ThemeProvider';
12
+
13
+ type Styles = {
14
+ container?: StyleProp<ViewStyle>;
15
+ icon?: StyleProp<ViewStyle>;
16
+ disabled?: StyleProp<ViewStyle>;
17
+ hovered?: StyleProp<ViewStyle>;
18
+ };
19
+
20
+ type ButtonType = 'text' | 'solid' | 'outlined';
21
+
22
+ type ButtonColorType =
23
+ | 'primary'
24
+ | 'secondary'
25
+ | 'success'
26
+ | 'danger'
27
+ | 'warning'
28
+ | 'info'
29
+ | 'light';
30
+
31
+ type ButtonSizeType = 'small' | 'medium' | 'large' | number;
32
+
33
+ export const ButtonStyles = ({
34
+ theme,
35
+ type = 'solid',
36
+ color = 'primary',
37
+ loading,
38
+ disabled,
39
+ }: {
40
+ theme?: CpkTheme;
41
+ type?: ButtonType;
42
+ color?: ButtonColorType;
43
+ disabled?: boolean;
44
+ loading?: boolean;
45
+ }): {
46
+ padding?: number;
47
+ backgroundColor?: string;
48
+ borderColor?: string;
49
+ borderWidth?: number;
50
+ iconColor?: string;
51
+ disabledBackgroundColor: string;
52
+ disabledBorderColor: string;
53
+ disabledTextColor: string;
54
+ } => {
55
+ theme = getTheme(theme);
56
+
57
+ let backgroundColor = theme.button[color].bg;
58
+ let borderColor = theme.button[color].bg;
59
+ let iconColor = theme.button[color].bg;
60
+
61
+ if (disabled) {
62
+ backgroundColor = theme.button.disabled.bg;
63
+ borderColor = theme.button.disabled.text;
64
+ iconColor = theme.button.disabled.text;
65
+ }
66
+
67
+ if (['text', 'outlined'].includes(type)) {
68
+ backgroundColor = theme.bg.basic;
69
+ }
70
+
71
+ if (type === 'solid' || color === 'light') {
72
+ iconColor = theme.button[color].text;
73
+ }
74
+
75
+ return {
76
+ backgroundColor,
77
+ borderColor,
78
+ borderWidth: type === 'outlined' ? 1 : 0,
79
+ iconColor,
80
+ disabledBackgroundColor:
81
+ type === 'solid' && !loading ? theme.button.disabled.bg : theme.bg.basic,
82
+ disabledBorderColor: theme.bg.disabled,
83
+ disabledTextColor: theme.button.disabled.text,
84
+ };
85
+ };
86
+
87
+ export type IconButtonProps = {
88
+ testID?: string;
89
+ type?: ButtonType;
90
+ color?: ButtonColorType;
91
+ size?: ButtonSizeType | number;
92
+ disabled?: boolean;
93
+ loading?: boolean;
94
+ loadingElement?: JSX.Element;
95
+ icon?: IconName;
96
+ iconElement?: JSX.Element;
97
+ style?: StyleProp<Omit<ViewStyle, 'borderRadius' | 'padding'>>;
98
+ styles?: Styles;
99
+ onPress?: TouchableHighlightProps['onPress'];
100
+ activeOpacity?: number;
101
+ touchableHighlightProps?: Omit<TouchableHighlightProps, 'onPress' | 'style'>;
102
+ };
103
+
104
+ export function IconButton({
105
+ testID,
106
+ type = 'solid',
107
+ color = 'primary',
108
+ size = 'medium',
109
+ disabled,
110
+ loading = false,
111
+ loadingElement,
112
+ icon,
113
+ iconElement,
114
+ style,
115
+ styles,
116
+ onPress,
117
+ activeOpacity = 0.95,
118
+ touchableHighlightProps,
119
+ }: IconButtonProps): JSX.Element {
120
+ const ref = useRef<React.ElementRef<typeof TouchableHighlight>>(null);
121
+ const hovered = useHover(ref);
122
+ const {theme} = useTheme();
123
+
124
+ const {
125
+ backgroundColor,
126
+ borderColor,
127
+ borderWidth,
128
+ iconColor,
129
+ disabledBackgroundColor,
130
+ disabledBorderColor,
131
+ } = ButtonStyles({
132
+ theme,
133
+ type,
134
+ color,
135
+ loading,
136
+ disabled,
137
+ });
138
+
139
+ const iconSize =
140
+ size === 'large'
141
+ ? 32
142
+ : size === 'medium'
143
+ ? 24
144
+ : size === 'small'
145
+ ? 16
146
+ : size;
147
+
148
+ const borderWidthStr = `${borderWidth + 'px'}`;
149
+ const borderRadiusStr = `99px`;
150
+
151
+ const compositeStyles: Styles = {
152
+ container: [
153
+ css`
154
+ background-color: ${backgroundColor};
155
+ border-color: ${borderColor};
156
+ border-width: ${borderWidthStr};
157
+ padding: 12px;
158
+ `,
159
+ styles?.container,
160
+ ],
161
+ icon: [
162
+ css`
163
+ color: ${iconColor};
164
+ `,
165
+ styles?.icon,
166
+ ],
167
+ disabled: [
168
+ css`
169
+ background-color: ${disabledBackgroundColor};
170
+ border-color: ${disabledBorderColor};
171
+ `,
172
+ styles?.disabled,
173
+ ],
174
+ hovered: [
175
+ {
176
+ shadowColor: theme.text.basic,
177
+ shadowOpacity: 0.24,
178
+ shadowRadius: 16,
179
+ elevation: 10,
180
+ },
181
+ styles?.hovered,
182
+ ],
183
+ };
184
+
185
+ return (
186
+ <View
187
+ style={[
188
+ css`
189
+ flex-direction: row;
190
+ border-radius: ${borderRadiusStr};
191
+ `,
192
+ style,
193
+ ]}
194
+ >
195
+ <TouchableHighlight
196
+ activeOpacity={activeOpacity}
197
+ delayPressIn={50}
198
+ disabled={disabled || loading}
199
+ onPress={onPress}
200
+ ref={Platform.select({
201
+ web: ref,
202
+ default: undefined,
203
+ })}
204
+ style={css`
205
+ border-radius: ${borderRadiusStr};
206
+ `}
207
+ testID={testID}
208
+ underlayColor={theme.role.underlay}
209
+ {...touchableHighlightProps}
210
+ >
211
+ <View
212
+ style={[
213
+ css`
214
+ padding: 4px;
215
+ border-radius: ${borderRadiusStr};
216
+
217
+ flex-direction: row;
218
+ justify-content: center;
219
+ align-items: center;
220
+ `,
221
+ compositeStyles.container,
222
+ hovered && !disabled && compositeStyles.hovered,
223
+ disabled && compositeStyles.disabled,
224
+ ]}
225
+ testID={loading ? 'loading-view' : 'button-container'}
226
+ >
227
+ {loading
228
+ ? loadingElement || (
229
+ <LoadingIndicator
230
+ color={theme.text.disabled}
231
+ size="small"
232
+ style={css`
233
+ justify-content: center;
234
+ align-items: center;
235
+ height: ${iconSize + 'px'};
236
+ width: ${iconSize + 'px'};
237
+ `}
238
+ />
239
+ )
240
+ : iconElement || (
241
+ <Icon
242
+ color={iconColor}
243
+ name={icon || 'QuestBoxFill'}
244
+ size={iconSize}
245
+ style={compositeStyles?.icon}
246
+ />
247
+ )}
248
+ </View>
249
+ </TouchableHighlight>
250
+ </View>
251
+ );
252
+ }
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ActivityIndicator, Image } from "react-native";
3
+ import styled from "@emotion/native";
4
+ import { useTheme } from "../../../providers/ThemeProvider";
5
+ const Container = styled.View ``;
6
+ export function LoadingIndicator({ customElement, style, styles, size = "large", color, imgSource, }) {
7
+ const { theme } = useTheme();
8
+ const handleImgSourceType = (src) => {
9
+ if (typeof src === "string") {
10
+ return {
11
+ uri: src,
12
+ };
13
+ }
14
+ return src;
15
+ };
16
+ return (_jsx(Container, { style: style, children: customElement ? (typeof customElement === "function" ? (customElement()) : (customElement)) : !imgSource ? (_jsx(ActivityIndicator, { color: color || theme.role.secondary, size: size, style: styles?.activityIndicator })) : (_jsx(Image, { source: handleImgSourceType(imgSource), style: [
17
+ size === "large"
18
+ ? { width: 50, height: 50 }
19
+ : size === "small"
20
+ ? { width: 30, height: 30 }
21
+ : undefined,
22
+ styles?.image,
23
+ ] })) }));
24
+ }
@@ -0,0 +1,79 @@
1
+ import React from "react";
2
+ import type {
3
+ ImageSourcePropType,
4
+ ImageStyle,
5
+ StyleProp,
6
+ ViewStyle,
7
+ } from "react-native";
8
+ import { ActivityIndicator, Image } from "react-native";
9
+ import styled from "@emotion/native";
10
+ import { useTheme } from "../../../providers/ThemeProvider";
11
+
12
+ type Styles = {
13
+ activityIndicator?: ViewStyle;
14
+ image?: ImageStyle;
15
+ };
16
+
17
+ type Props = {
18
+ style?: StyleProp<ViewStyle>;
19
+ styles?: Styles;
20
+ color?: string;
21
+ size?: ActivityIndicator["props"]["size"];
22
+ imgSource?: string | ImageSourcePropType;
23
+ customElement?: JSX.Element | (() => JSX.Element);
24
+ };
25
+
26
+ const Container = styled.View``;
27
+
28
+ export function LoadingIndicator({
29
+ customElement,
30
+ style,
31
+ styles,
32
+ size = "large",
33
+ color,
34
+ imgSource,
35
+ }: Props): JSX.Element {
36
+ const { theme } = useTheme();
37
+
38
+ const handleImgSourceType = (
39
+ src: string | ImageSourcePropType
40
+ ): ImageSourcePropType => {
41
+ if (typeof src === "string") {
42
+ return {
43
+ uri: src,
44
+ };
45
+ }
46
+
47
+ return src;
48
+ };
49
+
50
+ return (
51
+ <Container style={style}>
52
+ {customElement ? (
53
+ typeof customElement === "function" ? (
54
+ customElement()
55
+ ) : (
56
+ customElement
57
+ )
58
+ ) : !imgSource ? (
59
+ <ActivityIndicator
60
+ color={color || theme.role.secondary}
61
+ size={size}
62
+ style={styles?.activityIndicator}
63
+ />
64
+ ) : (
65
+ <Image
66
+ source={handleImgSourceType(imgSource)}
67
+ style={[
68
+ size === "large"
69
+ ? { width: 50, height: 50 }
70
+ : size === "small"
71
+ ? { width: 30, height: 30 }
72
+ : undefined,
73
+ styles?.image,
74
+ ]}
75
+ />
76
+ )}
77
+ </Container>
78
+ );
79
+ }
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // React import is needed for expo-web
3
+ import { useState } from 'react';
4
+ import { Pressable, View } from 'react-native';
5
+ import styled, { css } from '@emotion/native';
6
+ import { Icon } from '../Icon/Icon';
7
+ const Container = styled.View `
8
+ flex-direction: row;
9
+ `;
10
+ const StarContainer = styled.View `
11
+ padding: 1px;
12
+
13
+ flex-direction: row;
14
+ `;
15
+ export function Rating({ testID, style, styles, initialRating = 0, size = 24, iconType = 'star', onRatingUpdate, direction = 'horizontal', allowHalfRating = true, disabled = false, color, }) {
16
+ const [rating, setRating] = useState(initialRating);
17
+ const iconPrefix = iconType === 'star' ? 'Star' : 'QuestBox';
18
+ const handlePress = (newRating, halfPressed) => {
19
+ const convertedRating = newRating + (!halfPressed ? 0.5 : 0);
20
+ setRating(convertedRating);
21
+ if (onRatingUpdate) {
22
+ onRatingUpdate(convertedRating);
23
+ }
24
+ };
25
+ const renderStarIcon = ({ key, position, }) => {
26
+ const filled = rating >= position + (allowHalfRating ? 0.5 : 0);
27
+ const iconName = filled ? `${iconPrefix}Fill` : `${iconPrefix}`;
28
+ const halfFilled = rating >= position && rating < position + (allowHalfRating ? 0.5 : 0);
29
+ return (_jsxs(StarContainer, { style: [
30
+ css `
31
+ width: ${size + 'px'};
32
+ `,
33
+ styles?.starContainer,
34
+ ], testID: testID, children: [halfFilled && allowHalfRating ? (_jsxs(View, { style: { position: 'absolute' }, children: [_jsx(Icon, { color: color, name: `${iconPrefix}`, size: size, style: { position: 'absolute' } }), _jsx(Icon, { color: color, name: `${iconPrefix}HalfFill`, size: size })] })) : (_jsx(Icon, { color: color, name: iconName, size: size, style: { position: 'absolute' } })), _jsx(Pressable, { accessibilityRole: "button", disabled: disabled, onPress: () => handlePress(position, true), children: _jsx(View, { style: {
35
+ width: size / 2,
36
+ height: size,
37
+ backgroundColor: 'transparent',
38
+ } }) }), _jsx(Pressable, { accessibilityRole: "button", disabled: disabled, onPress: () => handlePress(position), children: _jsx(View, { style: {
39
+ width: size / 2,
40
+ height: size,
41
+ backgroundColor: 'transparent',
42
+ } }) })] }, key));
43
+ };
44
+ return (_jsx(Container, { style: [
45
+ css `
46
+ flex-direction: ${direction === 'horizontal' ? 'row' : 'column'};
47
+ `,
48
+ style,
49
+ ], children: [...Array(5)].map((_, index) => {
50
+ const position = index + (allowHalfRating ? 0.5 : 1);
51
+ return renderStarIcon({ key: `${_}-${index}`, position });
52
+ }) }));
53
+ }