@coldsurf/ocean-road 1.13.2
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/dist/css/global.css +30 -0
- package/dist/index.d.ts +641 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +733 -0
- package/dist/index.js.map +1 -0
- package/dist/native.cjs +94 -0
- package/dist/native.cjs.map +1 -0
- package/dist/native.d.cts +304 -0
- package/dist/native.d.cts.map +1 -0
- package/dist/native.d.ts +304 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +94 -0
- package/dist/native.js.map +1 -0
- package/dist/next.cjs +949 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +270 -0
- package/dist/next.d.cts.map +1 -0
- package/dist/next.d.ts +270 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +949 -0
- package/dist/next.js.map +1 -0
- package/native/index.d.ts +7 -0
- package/next/index.d.ts +7 -0
- package/package.json +126 -0
- package/src/GlobalStyle.tsx +111 -0
- package/src/base/badge/badge.tsx +50 -0
- package/src/base/badge/index.ts +1 -0
- package/src/base/button/button.styled.tsx +123 -0
- package/src/base/button/button.tsx +60 -0
- package/src/base/button/button.types.ts +20 -0
- package/src/base/button/button.utils.ts +36 -0
- package/src/base/button/index.tsx +2 -0
- package/src/base/checkbox/checkbox.styled.ts +52 -0
- package/src/base/checkbox/checkbox.tsx +26 -0
- package/src/base/checkbox/index.ts +1 -0
- package/src/base/icon-button/icon-button.styled.ts +8 -0
- package/src/base/icon-button/icon-button.tsx +15 -0
- package/src/base/icon-button/icon-button.types.ts +3 -0
- package/src/base/icon-button/index.ts +2 -0
- package/src/base/index.ts +11 -0
- package/src/base/label/index.ts +1 -0
- package/src/base/label/label.styled.ts +7 -0
- package/src/base/label/label.tsx +27 -0
- package/src/base/modal/index.ts +1 -0
- package/src/base/modal/modal.tsx +59 -0
- package/src/base/spinner/index.ts +2 -0
- package/src/base/spinner/spinner.styled.ts +25 -0
- package/src/base/spinner/spinner.tsx +36 -0
- package/src/base/spinner/spinner.types.ts +1 -0
- package/src/base/switch/index.ts +1 -0
- package/src/base/switch/switch.styled.tsx +49 -0
- package/src/base/switch/switch.tsx +29 -0
- package/src/base/text/index.ts +1 -0
- package/src/base/text/text.styled.ts +17 -0
- package/src/base/text/text.tsx +37 -0
- package/src/base/text-area/index.ts +2 -0
- package/src/base/text-area/text-area.styled.ts +16 -0
- package/src/base/text-area/text-area.tsx +29 -0
- package/src/base/text-area/text-area.types.ts +11 -0
- package/src/base/text-input/index.ts +2 -0
- package/src/base/text-input/text-input.styled.ts +40 -0
- package/src/base/text-input/text-input.tsx +59 -0
- package/src/base/text-input/text-input.types.ts +15 -0
- package/src/base/toast/index.ts +2 -0
- package/src/base/toast/toast.tsx +60 -0
- package/src/base/toast/toast.types.ts +5 -0
- package/src/constants.ts +1 -0
- package/src/contexts/ColorSchemeProvider.tsx +154 -0
- package/src/css/global.css +30 -0
- package/src/extensions/accordion/accordion.hooks.ts +11 -0
- package/src/extensions/accordion/accordion.tsx +80 -0
- package/src/extensions/accordion/index.ts +1 -0
- package/src/extensions/app-header/app-header.hooks.ts +94 -0
- package/src/extensions/app-header/app-header.tsx +31 -0
- package/src/extensions/app-header/app-header.types.ts +1 -0
- package/src/extensions/app-header/index.ts +8 -0
- package/src/extensions/app-logo/app-logo.tsx +40 -0
- package/src/extensions/app-logo/index.ts +1 -0
- package/src/extensions/app-store-button/app-store-button.tsx +64 -0
- package/src/extensions/app-store-button/index.ts +1 -0
- package/src/extensions/brand-icon/brand-icon.android.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.apple.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.google.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.tsx +22 -0
- package/src/extensions/brand-icon/index.ts +1 -0
- package/src/extensions/color-scheme-toggle/color-scheme-toggle.tsx +76 -0
- package/src/extensions/color-scheme-toggle/index.ts +1 -0
- package/src/extensions/dropdown/dropdown.menu-item.tsx +237 -0
- package/src/extensions/dropdown/dropdown.result-item.tsx +26 -0
- package/src/extensions/dropdown/dropdown.styled.tsx +48 -0
- package/src/extensions/dropdown/dropdown.trigger.tsx +72 -0
- package/src/extensions/dropdown/dropdown.tsx +222 -0
- package/src/extensions/dropdown/dropdown.types.ts +3 -0
- package/src/extensions/dropdown/dropdown.utils.ts +40 -0
- package/src/extensions/dropdown/index.ts +14 -0
- package/src/extensions/error-ui/index.ts +7 -0
- package/src/extensions/error-ui/network-error/index.ts +1 -0
- package/src/extensions/error-ui/network-error/network-error.styled.ts +16 -0
- package/src/extensions/error-ui/network-error/network-error.tsx +14 -0
- package/src/extensions/error-ui/unknown-error/index.ts +1 -0
- package/src/extensions/error-ui/unknown-error/unknown-error.styled.ts +16 -0
- package/src/extensions/error-ui/unknown-error/unknown-error.tsx +14 -0
- package/src/extensions/full-screen-modal/full-screen-modal.tsx +52 -0
- package/src/extensions/full-screen-modal/index.ts +1 -0
- package/src/extensions/grid-card-image/grid-card-image.tsx +11 -0
- package/src/extensions/grid-card-image/index.ts +1 -0
- package/src/extensions/grid-card-image-empty/grid-card-image-empty.tsx +11 -0
- package/src/extensions/grid-card-image-empty/index.ts +1 -0
- package/src/extensions/grid-card-item/grid-card-item.masonry.styled.tsx +95 -0
- package/src/extensions/grid-card-item/grid-card-item.masonry.tsx +63 -0
- package/src/extensions/grid-card-item/grid-card-item.styled.tsx +93 -0
- package/src/extensions/grid-card-item/grid-card-item.subscribe-btn-layout.tsx +30 -0
- package/src/extensions/grid-card-item/grid-card-item.tsx +81 -0
- package/src/extensions/grid-card-item/index.ts +2 -0
- package/src/extensions/grid-card-list/grid-card-list.masonry.styled.tsx +45 -0
- package/src/extensions/grid-card-list/grid-card-list.masonry.tsx +58 -0
- package/src/extensions/grid-card-list/grid-card-list.styled.tsx +40 -0
- package/src/extensions/grid-card-list/grid-card-list.tsx +59 -0
- package/src/extensions/grid-card-list/index.ts +2 -0
- package/src/extensions/grid-card-list-empty/grid-card-list-empty.tsx +38 -0
- package/src/extensions/grid-card-list-empty/index.ts +1 -0
- package/src/extensions/grid-card-list-load-more/grid-card-list-load-more.styled.tsx +15 -0
- package/src/extensions/grid-card-list-load-more/grid-card-list-load-more.tsx +43 -0
- package/src/extensions/grid-card-list-load-more/index.ts +1 -0
- package/src/extensions/index.ts +38 -0
- package/src/extensions/menu-item/index.ts +1 -0
- package/src/extensions/menu-item/menu-item.tsx +87 -0
- package/src/extensions/sns-icon/index.ts +1 -0
- package/src/extensions/sns-icon/sns-icon.facebook.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.instagram.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.tsx +24 -0
- package/src/extensions/sns-icon/sns-icon.x.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.youtube.tsx +11 -0
- package/src/index.ts +8 -0
- package/src/native/button/button.styled.tsx +99 -0
- package/src/native/button/button.tsx +42 -0
- package/src/native/button/index.ts +1 -0
- package/src/native/contexts/color-scheme-context/color-scheme-context.tsx +45 -0
- package/src/native/contexts/color-scheme-context/index.ts +1 -0
- package/src/native/contexts/index.ts +1 -0
- package/src/native/icon-button/icon-button.styled.ts +6 -0
- package/src/native/icon-button/icon-button.tsx +33 -0
- package/src/native/icon-button/icon-button.types.ts +14 -0
- package/src/native/icon-button/icon-button.utils.ts +114 -0
- package/src/native/icon-button/index.ts +1 -0
- package/src/native/index.ts +9 -0
- package/src/native/modal/index.ts +2 -0
- package/src/native/modal/modal.styled.ts +17 -0
- package/src/native/modal/modal.tsx +21 -0
- package/src/native/modal/modal.types.ts +8 -0
- package/src/native/profile-thumbnail/index.ts +1 -0
- package/src/native/profile-thumbnail/profile-thumbnail.tsx +91 -0
- package/src/native/spinner/index.ts +1 -0
- package/src/native/spinner/spinner.tsx +75 -0
- package/src/native/text/index.ts +2 -0
- package/src/native/text/text.tsx +51 -0
- package/src/native/text/text.types.ts +5 -0
- package/src/native/text-input/index.ts +2 -0
- package/src/native/text-input/text-input.tsx +72 -0
- package/src/native/text-input/text-input.types.ts +3 -0
- package/src/native/toast/index.ts +2 -0
- package/src/native/toast/toast.styled.ts +40 -0
- package/src/native/toast/toast.tsx +23 -0
- package/src/native/toast/toast.types.ts +10 -0
- package/src/next/app-footer/app-footer.tsx +250 -0
- package/src/next/app-footer/index.ts +1 -0
- package/src/next/app-header/app-header.fixed-header.tsx +83 -0
- package/src/next/app-header/app-header.full-screen-mobile-accordion-drawer.tsx +131 -0
- package/src/next/app-header/app-header.logo.tsx +50 -0
- package/src/next/app-header/app-header.modal-mobile-accordion-drawer.tsx +69 -0
- package/src/next/app-header/app-header.styled.ts +160 -0
- package/src/next/app-header/app-header.tsx +91 -0
- package/src/next/app-header/index.ts +13 -0
- package/src/next/global-link/global-link.store.ts +41 -0
- package/src/next/global-link/global-link.tsx +52 -0
- package/src/next/global-link/global-link.utils.ts +9 -0
- package/src/next/global-link/index.ts +3 -0
- package/src/next/grid-card-item/grid-card-item.masonry.tsx +23 -0
- package/src/next/grid-card-item/grid-card-item.tsx +23 -0
- package/src/next/grid-card-item/index.ts +2 -0
- package/src/next/index.ts +16 -0
- package/src/next/new-tab-link/index.ts +1 -0
- package/src/next/new-tab-link/new-tab-link.tsx +15 -0
- package/src/next/route-loading/index.ts +1 -0
- package/src/next/route-loading/route-loading.tsx +21 -0
- package/src/tokens/index.ts +2 -0
- package/src/tokens/tokens.ts +8 -0
- package/src/tokens/tokens.types.ts +7 -0
- package/src/utils/breakpoints.ts +9 -0
- package/src/utils/common-styles.ts +23 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/media.ts +23 -0
- package/src/utils/use-prevent-scroll-effect.ts +19 -0
- package/src/utils/with-id.ts +3 -0
- package/src/utils/with-stop-propagation.ts +10 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import color from '@coldsurfers/ocean-road-design-tokens/js/color/variables';
|
|
2
|
+
import { css } from '@emotion/native';
|
|
3
|
+
import type { ButtonTheme } from '../../base/button';
|
|
4
|
+
import type { IconButtonSize } from './icon-button.types';
|
|
5
|
+
|
|
6
|
+
export const sizes = {
|
|
7
|
+
xs: 20,
|
|
8
|
+
sm: 24,
|
|
9
|
+
md: 28,
|
|
10
|
+
lg: 32,
|
|
11
|
+
xl: 36,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const sizesStringify = (size: IconButtonSize) => {
|
|
15
|
+
switch (size) {
|
|
16
|
+
case 'xs':
|
|
17
|
+
return `${sizes.xs}px`;
|
|
18
|
+
case 'sm':
|
|
19
|
+
return `${sizes.sm}px`;
|
|
20
|
+
case 'md':
|
|
21
|
+
return `${sizes.md}px`;
|
|
22
|
+
case 'lg':
|
|
23
|
+
return `${sizes.lg}px`;
|
|
24
|
+
case 'xl':
|
|
25
|
+
return `${sizes.xl}px`;
|
|
26
|
+
default:
|
|
27
|
+
return `${sizes.xs}px`;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const xsStyles = css`
|
|
32
|
+
width: ${sizesStringify('xs')};
|
|
33
|
+
height: ${sizesStringify('xs')};
|
|
34
|
+
border-radius: 10px;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const smStyles = css`
|
|
38
|
+
width: ${sizesStringify('sm')};
|
|
39
|
+
height: ${sizesStringify('sm')};
|
|
40
|
+
border-radius: 12px;
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const mdStyles = css`
|
|
44
|
+
width: ${sizesStringify('md')};
|
|
45
|
+
height: ${sizesStringify('md')};
|
|
46
|
+
border-radius: 14px;
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
const lgStyles = css`
|
|
50
|
+
width: ${sizesStringify('lg')};
|
|
51
|
+
height: ${sizesStringify('lg')};
|
|
52
|
+
border-radius: 16px;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const xlStyles = css`
|
|
56
|
+
width: ${sizesStringify('xl')};
|
|
57
|
+
height: ${sizesStringify('xl')};
|
|
58
|
+
border-radius: 18px;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const getIconButtonSizeStyles = (size: IconButtonSize) => {
|
|
62
|
+
switch (size) {
|
|
63
|
+
case 'xs':
|
|
64
|
+
return xsStyles;
|
|
65
|
+
case 'sm':
|
|
66
|
+
return smStyles;
|
|
67
|
+
case 'md':
|
|
68
|
+
return mdStyles;
|
|
69
|
+
case 'lg':
|
|
70
|
+
return lgStyles;
|
|
71
|
+
case 'xl':
|
|
72
|
+
return xlStyles;
|
|
73
|
+
default:
|
|
74
|
+
return xsStyles;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const transparentStyles = css`
|
|
79
|
+
background-color: transparent;
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const transparentDarkGrayStyles = css`
|
|
83
|
+
background-color: ${color.oc.black.value};
|
|
84
|
+
opacity: 0.5;
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const whiteStyles = css`
|
|
88
|
+
background-color: ${color.oc.white.value};
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const pinkStyles = css`
|
|
92
|
+
background-color: ${color.oc.pink[9].value};
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const indigoStyles = css`
|
|
96
|
+
background-color: ${color.oc.indigo[9].value};
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
export const getIconButtonBackgroundStyles = (theme: ButtonTheme) => {
|
|
100
|
+
switch (theme) {
|
|
101
|
+
case 'transparent':
|
|
102
|
+
return transparentStyles;
|
|
103
|
+
case 'transparentDarkGray':
|
|
104
|
+
return transparentDarkGrayStyles;
|
|
105
|
+
case 'white':
|
|
106
|
+
return whiteStyles;
|
|
107
|
+
case 'pink':
|
|
108
|
+
return pinkStyles;
|
|
109
|
+
case 'indigo':
|
|
110
|
+
return indigoStyles;
|
|
111
|
+
default:
|
|
112
|
+
return indigoStyles;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './icon-button';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './button';
|
|
2
|
+
export * from './contexts';
|
|
3
|
+
export * from './icon-button';
|
|
4
|
+
export * from './modal';
|
|
5
|
+
export * from './profile-thumbnail';
|
|
6
|
+
export * from './spinner';
|
|
7
|
+
export * from './text';
|
|
8
|
+
export * from './text-input';
|
|
9
|
+
export * from './toast';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import styled from '@emotion/native';
|
|
2
|
+
|
|
3
|
+
export const StyledModal = styled.Modal`
|
|
4
|
+
flex: 1;
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
export const StyledModalBackground = styled.Pressable`
|
|
8
|
+
position: absolute;
|
|
9
|
+
z-index: 99;
|
|
10
|
+
top: 0px;
|
|
11
|
+
left: 0px;
|
|
12
|
+
right: 0px;
|
|
13
|
+
bottom: 0px;
|
|
14
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TouchableWithoutFeedback } from 'react-native';
|
|
2
|
+
import { StyledModal, StyledModalBackground } from './modal.styled';
|
|
3
|
+
import type { ModalProps } from './modal.types';
|
|
4
|
+
|
|
5
|
+
export const Modal = ({
|
|
6
|
+
children,
|
|
7
|
+
visible = false,
|
|
8
|
+
transparent = true,
|
|
9
|
+
onPressBackground,
|
|
10
|
+
}: ModalProps) => (
|
|
11
|
+
<StyledModal
|
|
12
|
+
supportedOrientations={['landscape', 'portrait']}
|
|
13
|
+
visible={visible}
|
|
14
|
+
transparent={transparent}
|
|
15
|
+
animationType="slide"
|
|
16
|
+
>
|
|
17
|
+
<StyledModalBackground onPress={onPressBackground}>
|
|
18
|
+
<TouchableWithoutFeedback>{children}</TouchableWithoutFeedback>
|
|
19
|
+
</StyledModalBackground>
|
|
20
|
+
</StyledModal>
|
|
21
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PropsWithChildren } from 'react';
|
|
2
|
+
import type { GestureResponderEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export type ModalProps = PropsWithChildren<{
|
|
5
|
+
visible?: boolean;
|
|
6
|
+
transparent?: boolean;
|
|
7
|
+
onPressBackground?: (event: GestureResponderEvent) => void;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './profile-thumbnail';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { Image, type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native';
|
|
3
|
+
import { colors } from '../../tokens';
|
|
4
|
+
import { useColorScheme } from '../contexts';
|
|
5
|
+
import { Text } from '../text';
|
|
6
|
+
|
|
7
|
+
const PROFILE_THUMBNAIL_SIZE = {
|
|
8
|
+
md: {
|
|
9
|
+
width: 62,
|
|
10
|
+
height: 62,
|
|
11
|
+
},
|
|
12
|
+
sm: {
|
|
13
|
+
width: 42,
|
|
14
|
+
height: 42,
|
|
15
|
+
},
|
|
16
|
+
lg: {
|
|
17
|
+
width: 92,
|
|
18
|
+
height: 92,
|
|
19
|
+
},
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
type ProfileThumbnailProps = {
|
|
23
|
+
size?: 'md' | 'sm' | 'lg';
|
|
24
|
+
type?: 'square' | 'circle';
|
|
25
|
+
emptyBgText: string;
|
|
26
|
+
imageUrl?: string;
|
|
27
|
+
style?: StyleProp<ViewStyle>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ProfileThumbnail = ({
|
|
31
|
+
size = 'md',
|
|
32
|
+
emptyBgText,
|
|
33
|
+
imageUrl,
|
|
34
|
+
type = 'square',
|
|
35
|
+
style,
|
|
36
|
+
}: ProfileThumbnailProps) => {
|
|
37
|
+
const { semantics } = useColorScheme();
|
|
38
|
+
const sizeStyle = useMemo(() => {
|
|
39
|
+
return PROFILE_THUMBNAIL_SIZE[size];
|
|
40
|
+
}, [size]);
|
|
41
|
+
const borderRadiusStyle = useMemo(() => {
|
|
42
|
+
switch (type) {
|
|
43
|
+
case 'circle':
|
|
44
|
+
return {
|
|
45
|
+
borderRadius: sizeStyle.width / 2,
|
|
46
|
+
};
|
|
47
|
+
case 'square':
|
|
48
|
+
return { borderRadius: 4 };
|
|
49
|
+
default:
|
|
50
|
+
return {
|
|
51
|
+
borderRadius: 4,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}, [sizeStyle.width, type]);
|
|
55
|
+
return (
|
|
56
|
+
<View
|
|
57
|
+
style={[
|
|
58
|
+
styles.wrapper,
|
|
59
|
+
sizeStyle,
|
|
60
|
+
borderRadiusStyle,
|
|
61
|
+
{
|
|
62
|
+
backgroundColor: semantics.background[4],
|
|
63
|
+
},
|
|
64
|
+
style,
|
|
65
|
+
]}
|
|
66
|
+
>
|
|
67
|
+
{emptyBgText ? (
|
|
68
|
+
<Text weight="bold" style={styles.bgText}>
|
|
69
|
+
{emptyBgText}
|
|
70
|
+
</Text>
|
|
71
|
+
) : null}
|
|
72
|
+
{imageUrl && <Image source={{ uri: imageUrl }} style={[styles.image, borderRadiusStyle]} />}
|
|
73
|
+
</View>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const styles = StyleSheet.create({
|
|
78
|
+
wrapper: {
|
|
79
|
+
alignItems: 'center',
|
|
80
|
+
justifyContent: 'center',
|
|
81
|
+
},
|
|
82
|
+
bgText: {
|
|
83
|
+
color: colors.oc.white.value,
|
|
84
|
+
position: 'absolute',
|
|
85
|
+
fontSize: 14,
|
|
86
|
+
},
|
|
87
|
+
image: {
|
|
88
|
+
width: '100%',
|
|
89
|
+
height: '100%',
|
|
90
|
+
},
|
|
91
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './spinner';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import styled from '@emotion/native';
|
|
2
|
+
import { LoaderCircle } from 'lucide-react-native';
|
|
3
|
+
import { useEffect, useMemo } from 'react';
|
|
4
|
+
import { type ColorValue, type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native';
|
|
5
|
+
import Reanimated, {
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
withRepeat,
|
|
9
|
+
withTiming,
|
|
10
|
+
} from 'react-native-reanimated';
|
|
11
|
+
import { colors } from '../../tokens';
|
|
12
|
+
|
|
13
|
+
const AnimatedLoaderIcon = Reanimated.createAnimatedComponent(LoaderCircle);
|
|
14
|
+
|
|
15
|
+
const LoaderIcon = styled(AnimatedLoaderIcon)`
|
|
16
|
+
color: ${colors.oc.cyan[5].value};
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
positionCenter?: boolean;
|
|
21
|
+
size?: number | 'small' | 'large' | 'medium';
|
|
22
|
+
color?: ColorValue;
|
|
23
|
+
style?: StyleProp<ViewStyle>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Spinner = ({ positionCenter = false, size = 'large', color, style }: Props) => {
|
|
27
|
+
const rotation = useSharedValue(0); // Shared value for rotation
|
|
28
|
+
|
|
29
|
+
// Animated style for rotation
|
|
30
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
31
|
+
return {
|
|
32
|
+
transform: [{ rotate: `${rotation.value}deg` }],
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const sizeNumber = useMemo(() => {
|
|
37
|
+
switch (size) {
|
|
38
|
+
case 'large':
|
|
39
|
+
return 42;
|
|
40
|
+
case 'small':
|
|
41
|
+
return 20;
|
|
42
|
+
case 'medium':
|
|
43
|
+
return 32;
|
|
44
|
+
default:
|
|
45
|
+
return 42;
|
|
46
|
+
}
|
|
47
|
+
}, [size]);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
// Start the rotation animation
|
|
51
|
+
rotation.value = withRepeat(
|
|
52
|
+
withTiming(360, { duration: 600 }), // Full rotation in 2000ms
|
|
53
|
+
-1, // Infinite repeat
|
|
54
|
+
false // Reverse the direction after each cycle
|
|
55
|
+
);
|
|
56
|
+
}, [rotation]);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<View style={[positionCenter && styles.positionCenter, style]}>
|
|
60
|
+
<View style={styles.animationWrapper}>
|
|
61
|
+
<LoaderIcon size={sizeNumber} color={color} style={animatedStyle} />
|
|
62
|
+
</View>
|
|
63
|
+
</View>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const styles = StyleSheet.create({
|
|
68
|
+
positionCenter: {
|
|
69
|
+
...StyleSheet.absoluteFillObject,
|
|
70
|
+
backgroundColor: 'transparent',
|
|
71
|
+
justifyContent: 'center',
|
|
72
|
+
alignItems: 'center',
|
|
73
|
+
},
|
|
74
|
+
animationWrapper: { justifyContent: 'center', alignItems: 'center' },
|
|
75
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Text as RNText, StyleSheet } from 'react-native';
|
|
2
|
+
import { colors } from '../../tokens';
|
|
3
|
+
import type { TextProps } from './text.types';
|
|
4
|
+
|
|
5
|
+
export const Text = ({ children, weight = 'regular', style, ...others }: TextProps) => {
|
|
6
|
+
const fontFamilySet = {
|
|
7
|
+
thin: styles.thin,
|
|
8
|
+
light: styles.light,
|
|
9
|
+
regular: styles.regular,
|
|
10
|
+
medium: styles.medium,
|
|
11
|
+
bold: styles.bold,
|
|
12
|
+
extraBold: styles.extraBold,
|
|
13
|
+
};
|
|
14
|
+
const flattenedStyle = StyleSheet.flatten(style);
|
|
15
|
+
const lineHeight = (flattenedStyle?.fontSize ?? 0) * 1.205;
|
|
16
|
+
return (
|
|
17
|
+
<RNText
|
|
18
|
+
{...others}
|
|
19
|
+
style={[
|
|
20
|
+
fontFamilySet[weight],
|
|
21
|
+
styles.defaultColor,
|
|
22
|
+
{ lineHeight: lineHeight, letterSpacing: 0.24, includeFontPadding: false },
|
|
23
|
+
style,
|
|
24
|
+
]}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</RNText>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const styles = StyleSheet.create({
|
|
32
|
+
thin: {
|
|
33
|
+
fontFamily: 'Pretendard-Thin',
|
|
34
|
+
},
|
|
35
|
+
light: {
|
|
36
|
+
fontFamily: 'Pretendard-Light',
|
|
37
|
+
},
|
|
38
|
+
regular: {
|
|
39
|
+
fontFamily: 'Pretendard-Regular',
|
|
40
|
+
},
|
|
41
|
+
medium: {
|
|
42
|
+
fontFamily: 'Pretendard-Medium',
|
|
43
|
+
},
|
|
44
|
+
bold: {
|
|
45
|
+
fontFamily: 'Pretendard-Bold',
|
|
46
|
+
},
|
|
47
|
+
extraBold: {
|
|
48
|
+
fontFamily: 'Pretendard-ExtraBold',
|
|
49
|
+
},
|
|
50
|
+
defaultColor: { color: colors.oc.black.value },
|
|
51
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import color from '@coldsurfers/ocean-road-design-tokens/js/color/variables';
|
|
2
|
+
import { forwardRef, memo, useCallback, useState } from 'react';
|
|
3
|
+
import { TextInput as RNTextInput, StyleSheet } from 'react-native';
|
|
4
|
+
import { colors } from '../../tokens';
|
|
5
|
+
import { useColorScheme } from '../contexts';
|
|
6
|
+
import type { TextInputProps } from './text-input.types';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_FONT_SIZE = 12;
|
|
9
|
+
|
|
10
|
+
const _TextInput = forwardRef<RNTextInput, TextInputProps>(({ style, ...otherProps }, ref) => {
|
|
11
|
+
const { semantics, colorScheme } = useColorScheme();
|
|
12
|
+
const [focused, setFocused] = useState<boolean>(false);
|
|
13
|
+
const flattenedStyle = StyleSheet.flatten(style);
|
|
14
|
+
const lineHeight = (flattenedStyle?.fontSize ?? DEFAULT_FONT_SIZE) * 1.275;
|
|
15
|
+
const onFocus = useCallback(() => {
|
|
16
|
+
setFocused(true);
|
|
17
|
+
}, []);
|
|
18
|
+
const onBlur = useCallback(() => {
|
|
19
|
+
setFocused(false);
|
|
20
|
+
}, []);
|
|
21
|
+
return (
|
|
22
|
+
<RNTextInput
|
|
23
|
+
ref={ref}
|
|
24
|
+
placeholderTextColor={'#b0b6b7'}
|
|
25
|
+
onFocus={onFocus}
|
|
26
|
+
onBlur={onBlur}
|
|
27
|
+
{...otherProps}
|
|
28
|
+
style={[
|
|
29
|
+
styles.textInput,
|
|
30
|
+
{
|
|
31
|
+
color: semantics.foreground[1],
|
|
32
|
+
backgroundColor: semantics.background[4],
|
|
33
|
+
borderColor: colorScheme === 'light' ? semantics.border[2] : semantics.border[1],
|
|
34
|
+
},
|
|
35
|
+
focused && {
|
|
36
|
+
borderColor: colorScheme === 'light' ? semantics.border[1] : semantics.border[2],
|
|
37
|
+
},
|
|
38
|
+
typeof otherProps.editable === 'boolean' && !otherProps.editable && styles.disabled,
|
|
39
|
+
{
|
|
40
|
+
lineHeight,
|
|
41
|
+
},
|
|
42
|
+
style,
|
|
43
|
+
]}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const TextInput = memo(_TextInput);
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create({
|
|
51
|
+
textInput: {
|
|
52
|
+
// borderColor: colors.oc.gray[6].value,
|
|
53
|
+
borderWidth: 2,
|
|
54
|
+
borderRadius: 24,
|
|
55
|
+
paddingLeft: 16,
|
|
56
|
+
paddingRight: 16,
|
|
57
|
+
paddingTop: 16,
|
|
58
|
+
paddingBottom: 16,
|
|
59
|
+
backgroundColor: color.oc.white.value,
|
|
60
|
+
fontFamily: 'Pretendard',
|
|
61
|
+
includeFontPadding: false,
|
|
62
|
+
},
|
|
63
|
+
focused: {
|
|
64
|
+
borderColor: colors.oc.gray[4].value,
|
|
65
|
+
borderWidth: 2,
|
|
66
|
+
},
|
|
67
|
+
disabled: {
|
|
68
|
+
backgroundColor: '#f4eded',
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
_TextInput.displayName = 'TextInput';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import color from '@coldsurfers/ocean-road-design-tokens/js/color/variables';
|
|
2
|
+
import styled from '@emotion/native';
|
|
3
|
+
import { Text } from '../text';
|
|
4
|
+
import type { ToastType } from './toast.types';
|
|
5
|
+
|
|
6
|
+
export const StyledToastContainer = styled.View`
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
background-color: transparent;
|
|
10
|
+
position: absolute;
|
|
11
|
+
bottom: 24px;
|
|
12
|
+
left: 0px;
|
|
13
|
+
right: 0px;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
export const StyledToastPressable = styled.Pressable<{ type: ToastType }>`
|
|
17
|
+
padding-left: 16px;
|
|
18
|
+
padding-right: 16px;
|
|
19
|
+
padding-top: 16px;
|
|
20
|
+
padding-bottom: 16px;
|
|
21
|
+
border-radius: 24px;
|
|
22
|
+
background-color: ${({ type }) => {
|
|
23
|
+
switch (type) {
|
|
24
|
+
case 'info':
|
|
25
|
+
return color.oc.black.value;
|
|
26
|
+
case 'warning':
|
|
27
|
+
return color.oc.yellow[9].value;
|
|
28
|
+
case 'error':
|
|
29
|
+
return color.oc.pink[9].value;
|
|
30
|
+
default:
|
|
31
|
+
return color.oc.black.value;
|
|
32
|
+
}
|
|
33
|
+
}};
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
export const StyledToastText = styled(Text)`
|
|
37
|
+
font-weight: 700;
|
|
38
|
+
color: ${color.oc.white.value};
|
|
39
|
+
font-size: 14px;
|
|
40
|
+
`;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import type { GestureResponderEvent } from 'react-native';
|
|
3
|
+
import { StyledToastContainer, StyledToastPressable, StyledToastText } from './toast.styled';
|
|
4
|
+
import type { ToastProps } from './toast.types';
|
|
5
|
+
|
|
6
|
+
export const Toast = ({ type, message, onPress }: ToastProps) => {
|
|
7
|
+
const handlePress = useCallback(
|
|
8
|
+
(e: GestureResponderEvent) => {
|
|
9
|
+
if (onPress) {
|
|
10
|
+
onPress(e);
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
[onPress]
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<StyledToastContainer>
|
|
18
|
+
<StyledToastPressable type={type} onPress={handlePress}>
|
|
19
|
+
<StyledToastText>{message}</StyledToastText>
|
|
20
|
+
</StyledToastPressable>
|
|
21
|
+
</StyledToastContainer>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GestureResponderEvent } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface ToastProps {
|
|
4
|
+
type: ToastType;
|
|
5
|
+
message: string;
|
|
6
|
+
onPress?: (event: GestureResponderEvent) => void;
|
|
7
|
+
autoCloseOnPress?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ToastType = 'info' | 'warning' | 'error';
|