@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,7 @@
|
|
|
1
|
+
// This file is needed for projects that have `moduleResolution` set to `node`
|
|
2
|
+
// in their tsconfig.json to be able to `import {} from '@coldsurfers/ocean-road/native'`.
|
|
3
|
+
// Other module resolutions strategies will look for the `exports` in `package.json`,
|
|
4
|
+
// but with `node`, TypeScript will look for a .d.ts file with that name at the
|
|
5
|
+
// root of the package.
|
|
6
|
+
|
|
7
|
+
export * from '../dist/native';
|
package/next/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// This file is needed for projects that have `moduleResolution` set to `node`
|
|
2
|
+
// in their tsconfig.json to be able to `import {} from '@coldsurfers/ocean-road/next'`.
|
|
3
|
+
// Other module resolutions strategies will look for the `exports` in `package.json`,
|
|
4
|
+
// but with `node`, TypeScript will look for a .d.ts file with that name at the
|
|
5
|
+
// root of the package.
|
|
6
|
+
|
|
7
|
+
export * from '../dist/next';
|
package/package.json
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coldsurf/ocean-road",
|
|
3
|
+
"author": {
|
|
4
|
+
"name": "Dong-Ho Choi",
|
|
5
|
+
"email": "imcoldsurf@gmail.com",
|
|
6
|
+
"url": "https://coldsurf.io"
|
|
7
|
+
},
|
|
8
|
+
"version": "1.13.2",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/coldsurfers/ocean-road/issues"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/coldsurfers/ocean-road",
|
|
15
|
+
"directory": "packages/ocean-road"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://storybook.ocean-road.coldsurf.io",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./next": {
|
|
24
|
+
"types": "./dist/next.d.ts",
|
|
25
|
+
"default": "./dist/next.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./native": {
|
|
28
|
+
"types": "./dist/native.d.ts",
|
|
29
|
+
"default": "./dist/native.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"type": "module",
|
|
34
|
+
"module": "dist/index.js",
|
|
35
|
+
"source": "src/",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"src",
|
|
39
|
+
"next",
|
|
40
|
+
"native",
|
|
41
|
+
"dist",
|
|
42
|
+
"package.json"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "pnpm build:core",
|
|
46
|
+
"build:core": "tsdown",
|
|
47
|
+
"lint": "biome lint .",
|
|
48
|
+
"lint:fix": "biome lint --write .",
|
|
49
|
+
"format": "biome format .",
|
|
50
|
+
"format:fix": "biome format --write .",
|
|
51
|
+
"check": "biome check .",
|
|
52
|
+
"check:fix": "biome check --write .",
|
|
53
|
+
"check:type": "tsc --noEmit"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@coldsurf/shared-utils": "1.1.15",
|
|
57
|
+
"ts-pattern": "5.8.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@babel/preset-react": "^7.18.6",
|
|
61
|
+
"@babel/preset-typescript": "^7.21.4",
|
|
62
|
+
"@biomejs/biome": "1.9.4",
|
|
63
|
+
"@coldsurfers/ocean-road-design-tokens": "1.10.8",
|
|
64
|
+
"@emotion/css": "11.10.6",
|
|
65
|
+
"@emotion/native": "11.11.0",
|
|
66
|
+
"@emotion/react": "11.10.6",
|
|
67
|
+
"@emotion/styled": "11.10.6",
|
|
68
|
+
"@types/react": "18.3.27",
|
|
69
|
+
"@types/react-dom": "19.0.3",
|
|
70
|
+
"framer-motion": "11.11.13",
|
|
71
|
+
"lucide-react": "0.469.0",
|
|
72
|
+
"lucide-react-native": "0.468.0",
|
|
73
|
+
"next": "15.5.9",
|
|
74
|
+
"overlay-kit": "^1.8.6",
|
|
75
|
+
"prettier": "*",
|
|
76
|
+
"react": "19.2.3",
|
|
77
|
+
"react-dom": "19.2.3",
|
|
78
|
+
"react-native": "0.81.4",
|
|
79
|
+
"react-native-reanimated": "4.1.2",
|
|
80
|
+
"react-native-svg": "15.13.0",
|
|
81
|
+
"react-native-worklets": "0.6.0",
|
|
82
|
+
"tsdown": "^0.11.9"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"@emotion/css": "^11.10.6",
|
|
86
|
+
"@emotion/native": "^11.11.0",
|
|
87
|
+
"@emotion/react": "^11.10.6",
|
|
88
|
+
"@emotion/styled": "^11.10.6",
|
|
89
|
+
"lucide-react-native": "^0.468.0",
|
|
90
|
+
"react": ">= 19.1.0",
|
|
91
|
+
"react-dom": ">= 19.1.4",
|
|
92
|
+
"react-native-reanimated": ">= 3.17.1",
|
|
93
|
+
"react-native-svg": "^15.11.1",
|
|
94
|
+
"react-native-worklets": "^0.6.0"
|
|
95
|
+
},
|
|
96
|
+
"peerDependenciesMeta": {
|
|
97
|
+
"next": {
|
|
98
|
+
"optional": true
|
|
99
|
+
},
|
|
100
|
+
"react-dom": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
103
|
+
"react-native": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"react-native-reanimated": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"react-native-worklets": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"react-native-svg": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"lucide-react-native": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"overlay-kit": {
|
|
119
|
+
"optional": true
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"publishConfig": {
|
|
123
|
+
"registry": "https://registry.npmjs.org/",
|
|
124
|
+
"access": "public"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Global, css } from '@emotion/react';
|
|
2
|
+
import { darkModeTheme, lightModeTheme, themeToStyles } from './contexts/ColorSchemeProvider';
|
|
3
|
+
import { colors, semantics } from './tokens';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
themeStorageItem?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const SAFE_STORAGE_KEY_PATTERN = /^[A-Za-z0-9._:@/-]+$/;
|
|
10
|
+
const DEFAULT_THEME_STORAGE_KEY = 'ocean-road-theme';
|
|
11
|
+
|
|
12
|
+
export default function GlobalStyle({ themeStorageItem }: Props) {
|
|
13
|
+
const safeThemeStorageItem =
|
|
14
|
+
themeStorageItem && SAFE_STORAGE_KEY_PATTERN.test(themeStorageItem)
|
|
15
|
+
? themeStorageItem
|
|
16
|
+
: DEFAULT_THEME_STORAGE_KEY;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<Global
|
|
21
|
+
styles={css`
|
|
22
|
+
html,
|
|
23
|
+
body {
|
|
24
|
+
padding: 0;
|
|
25
|
+
margin: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
html {
|
|
29
|
+
${themeToStyles(lightModeTheme)}
|
|
30
|
+
}
|
|
31
|
+
html.dark {
|
|
32
|
+
${themeToStyles(darkModeTheme)}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
background-color: ${semantics.color.background[2]};
|
|
37
|
+
color: ${semantics.color.foreground[1]};
|
|
38
|
+
white-space: pre-wrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
a {
|
|
42
|
+
color: ${colors.oc.blue[5].value};
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
* {
|
|
47
|
+
box-sizing: border-box;
|
|
48
|
+
}
|
|
49
|
+
`}
|
|
50
|
+
/>
|
|
51
|
+
{themeStorageItem && (
|
|
52
|
+
<script
|
|
53
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
|
|
54
|
+
dangerouslySetInnerHTML={{
|
|
55
|
+
__html: `
|
|
56
|
+
(function () {
|
|
57
|
+
var themeStorage = ${JSON.stringify(safeThemeStorageItem)};
|
|
58
|
+
|
|
59
|
+
function setTheme(newTheme) {
|
|
60
|
+
window.__theme = newTheme;
|
|
61
|
+
if (newTheme === 'dark') {
|
|
62
|
+
document.documentElement.classList.add('dark');
|
|
63
|
+
} else if (newTheme === 'light') {
|
|
64
|
+
document.documentElement.classList.remove('dark');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var preferredTheme;
|
|
69
|
+
try {
|
|
70
|
+
preferredTheme = localStorage.getItem(themeStorage);
|
|
71
|
+
} catch (err) { }
|
|
72
|
+
|
|
73
|
+
window.__setPreferredTheme = function(newTheme) {
|
|
74
|
+
preferredTheme = newTheme;
|
|
75
|
+
setTheme(newTheme);
|
|
76
|
+
try {
|
|
77
|
+
localStorage.setItem(themeStorage, newTheme);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(err);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
var initialTheme = preferredTheme;
|
|
84
|
+
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
85
|
+
|
|
86
|
+
if (!initialTheme) {
|
|
87
|
+
initialTheme = darkQuery.matches ? 'dark' : 'light';
|
|
88
|
+
}
|
|
89
|
+
setTheme(initialTheme);
|
|
90
|
+
|
|
91
|
+
darkQuery.addEventListener('change', function (e) {
|
|
92
|
+
if (!preferredTheme) {
|
|
93
|
+
setTheme(e.matches ? 'dark' : 'light');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Detect whether the browser is Mac to display platform specific content
|
|
98
|
+
// An example of such content can be the keyboard shortcut displayed in the search bar
|
|
99
|
+
// document.documentElement.classList.add(
|
|
100
|
+
// window.navigator.platform.includes('Mac')
|
|
101
|
+
// ? "platform-mac"
|
|
102
|
+
// : "platform-win"
|
|
103
|
+
// );
|
|
104
|
+
})();
|
|
105
|
+
`,
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
import type { icons as Icons } from 'lucide-react';
|
|
3
|
+
import { type ReactElement, forwardRef } from 'react';
|
|
4
|
+
import { semantics } from '../../tokens';
|
|
5
|
+
import { createStyledIcon } from '../button/button.styled';
|
|
6
|
+
import { Text } from '../text';
|
|
7
|
+
|
|
8
|
+
const StyledFeedNavigationItem = styled.div<{ $isHighlighted?: boolean }>`
|
|
9
|
+
display: flex;
|
|
10
|
+
border-radius: 999px;
|
|
11
|
+
background-color: ${({ $isHighlighted }) => ($isHighlighted ? semantics.color.background[4] : semantics.color.background[3])};
|
|
12
|
+
padding: 0.5rem 1rem;
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
user-select: none;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const StyledFeedNavigationItemText = styled(Text)`
|
|
18
|
+
font-size: 1rem;
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
color: ${semantics.color.foreground[1]};
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
type Props = {
|
|
24
|
+
leftIcon?: keyof typeof Icons;
|
|
25
|
+
onClick?: () => void;
|
|
26
|
+
isHighlighted?: boolean;
|
|
27
|
+
children?: string | ReactElement;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const Badge = forwardRef<HTMLDivElement, Props>(
|
|
31
|
+
({ children, leftIcon, isHighlighted, onClick, ...otherProps }, ref) => {
|
|
32
|
+
return (
|
|
33
|
+
<StyledFeedNavigationItem
|
|
34
|
+
ref={ref}
|
|
35
|
+
$isHighlighted={isHighlighted}
|
|
36
|
+
onClick={onClick}
|
|
37
|
+
{...otherProps}
|
|
38
|
+
>
|
|
39
|
+
{leftIcon && createStyledIcon(leftIcon, 'lg', 'left', 'transparent')}
|
|
40
|
+
{typeof children === 'string' ? (
|
|
41
|
+
<StyledFeedNavigationItemText>{children}</StyledFeedNavigationItemText>
|
|
42
|
+
) : (
|
|
43
|
+
children
|
|
44
|
+
)}
|
|
45
|
+
</StyledFeedNavigationItem>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
Badge.displayName = 'Badge';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './badge';
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
import { icons as Icons } from 'lucide-react';
|
|
3
|
+
import { Text } from '../text';
|
|
4
|
+
import type { ButtonTheme } from './button.types';
|
|
5
|
+
import { getButtonBackgroundColor, getButtonForegroundColor } from './button.utils';
|
|
6
|
+
|
|
7
|
+
export const StyledButton = styled.button<{
|
|
8
|
+
colorTheme: ButtonTheme;
|
|
9
|
+
size: 'lg' | 'md' | 'sm';
|
|
10
|
+
}>`
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
background-color: ${({ colorTheme }) => getButtonBackgroundColor(colorTheme)};
|
|
14
|
+
border: none;
|
|
15
|
+
font-family: inherit;
|
|
16
|
+
|
|
17
|
+
padding: ${(props) => {
|
|
18
|
+
switch (props.size) {
|
|
19
|
+
case 'lg':
|
|
20
|
+
return '18px';
|
|
21
|
+
case 'md':
|
|
22
|
+
return '14px';
|
|
23
|
+
default:
|
|
24
|
+
return '10px';
|
|
25
|
+
}
|
|
26
|
+
}};
|
|
27
|
+
|
|
28
|
+
border-radius: ${(props) => {
|
|
29
|
+
switch (props.size) {
|
|
30
|
+
case 'lg':
|
|
31
|
+
return '24px';
|
|
32
|
+
case 'md':
|
|
33
|
+
return '22px';
|
|
34
|
+
default:
|
|
35
|
+
return '20px';
|
|
36
|
+
}
|
|
37
|
+
}};
|
|
38
|
+
|
|
39
|
+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
|
|
40
|
+
|
|
41
|
+
opacity: ${(props) => (props.colorTheme === 'transparentDarkGray' ? 0.5 : 1.0)};
|
|
42
|
+
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
|
|
47
|
+
&:hover {
|
|
48
|
+
opacity: ${({ disabled }) => (disabled ? 1.0 : 0.75)};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&:active {
|
|
52
|
+
opacity: ${({ disabled }) => (disabled ? 1.0 : 0.5)};
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const StyledButtonText = styled(Text)<{
|
|
57
|
+
colorTheme: ButtonTheme;
|
|
58
|
+
size: 'lg' | 'md' | 'sm';
|
|
59
|
+
textWeight: 'light' | 'medium' | 'bold';
|
|
60
|
+
}>`
|
|
61
|
+
font-weight: ${({ textWeight }) => {
|
|
62
|
+
switch (textWeight) {
|
|
63
|
+
case 'light':
|
|
64
|
+
return '300';
|
|
65
|
+
case 'medium':
|
|
66
|
+
return '500';
|
|
67
|
+
default:
|
|
68
|
+
return '700';
|
|
69
|
+
}
|
|
70
|
+
}};
|
|
71
|
+
color: ${({ colorTheme }) => getButtonForegroundColor(colorTheme)};
|
|
72
|
+
font-family: inherit;
|
|
73
|
+
margin: unset;
|
|
74
|
+
|
|
75
|
+
font-size: ${(props) => {
|
|
76
|
+
switch (props.size) {
|
|
77
|
+
case 'lg':
|
|
78
|
+
return '16px';
|
|
79
|
+
case 'md':
|
|
80
|
+
return '14px';
|
|
81
|
+
default:
|
|
82
|
+
return '12px';
|
|
83
|
+
}
|
|
84
|
+
}};
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const iconSize = (size: 'lg' | 'md' | 'sm') => {
|
|
88
|
+
switch (size) {
|
|
89
|
+
case 'lg':
|
|
90
|
+
return '18px';
|
|
91
|
+
case 'md':
|
|
92
|
+
return '16px';
|
|
93
|
+
default:
|
|
94
|
+
return '14px';
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const createStyledIcon = (
|
|
99
|
+
icon: keyof typeof Icons,
|
|
100
|
+
size: 'lg' | 'md' | 'sm',
|
|
101
|
+
position: 'left' | 'right',
|
|
102
|
+
colorTheme: ButtonTheme
|
|
103
|
+
) => {
|
|
104
|
+
const TargetIcon = styled(Icons[icon])`
|
|
105
|
+
color: ${getButtonForegroundColor(colorTheme)};
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<TargetIcon
|
|
110
|
+
size={iconSize(size)}
|
|
111
|
+
// strokeWidth={2.5}
|
|
112
|
+
style={{
|
|
113
|
+
marginLeft: position === 'right' ? 4 : undefined,
|
|
114
|
+
marginRight: position === 'left' ? 4 : undefined,
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const StyledIconWrapper = styled.div<{ $position: 'left' | 'right' }>`
|
|
121
|
+
margin-right: ${({ $position }) => ($position === 'left' ? '4px' : '0px')};
|
|
122
|
+
margin-left: ${({ $position }) => ($position === 'right' ? '4px' : '0px')};
|
|
123
|
+
`;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { icons as Icons } from 'lucide-react';
|
|
2
|
+
import { type ButtonHTMLAttributes, forwardRef } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
StyledButton,
|
|
5
|
+
StyledButtonText,
|
|
6
|
+
StyledIconWrapper,
|
|
7
|
+
createStyledIcon,
|
|
8
|
+
} from './button.styled';
|
|
9
|
+
import type { ButtonProps } from './button.types';
|
|
10
|
+
|
|
11
|
+
export const Button = forwardRef<
|
|
12
|
+
HTMLButtonElement,
|
|
13
|
+
ButtonProps & ButtonHTMLAttributes<HTMLButtonElement>
|
|
14
|
+
>(
|
|
15
|
+
(
|
|
16
|
+
{
|
|
17
|
+
variant = 'indigo',
|
|
18
|
+
leftIcon,
|
|
19
|
+
rightIcon,
|
|
20
|
+
textWeight = 'medium',
|
|
21
|
+
size = 'md',
|
|
22
|
+
children,
|
|
23
|
+
className,
|
|
24
|
+
...otherProps
|
|
25
|
+
},
|
|
26
|
+
ref
|
|
27
|
+
) => {
|
|
28
|
+
return (
|
|
29
|
+
<StyledButton
|
|
30
|
+
ref={ref}
|
|
31
|
+
colorTheme={variant}
|
|
32
|
+
size={size}
|
|
33
|
+
className={className}
|
|
34
|
+
{...otherProps}
|
|
35
|
+
>
|
|
36
|
+
{typeof children === 'string' ? (
|
|
37
|
+
<>
|
|
38
|
+
{typeof leftIcon === 'string' ? (
|
|
39
|
+
createStyledIcon(leftIcon as keyof typeof Icons, size, 'left', variant)
|
|
40
|
+
) : (
|
|
41
|
+
<StyledIconWrapper $position="left">{leftIcon}</StyledIconWrapper>
|
|
42
|
+
)}
|
|
43
|
+
<StyledButtonText size={size} textWeight={textWeight} colorTheme={variant}>
|
|
44
|
+
{children}
|
|
45
|
+
</StyledButtonText>
|
|
46
|
+
{typeof rightIcon === 'string' ? (
|
|
47
|
+
createStyledIcon(rightIcon as keyof typeof Icons, size, 'right', variant)
|
|
48
|
+
) : (
|
|
49
|
+
<StyledIconWrapper $position="right">{rightIcon}</StyledIconWrapper>
|
|
50
|
+
)}
|
|
51
|
+
</>
|
|
52
|
+
) : (
|
|
53
|
+
children
|
|
54
|
+
)}
|
|
55
|
+
</StyledButton>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
Button.displayName = 'Button';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { icons } from 'lucide-react';
|
|
2
|
+
import type { PropsWithChildren, ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export type ButtonProps = PropsWithChildren<{
|
|
5
|
+
// @TODO: remove theme prop
|
|
6
|
+
theme?: ButtonTheme;
|
|
7
|
+
variant?: ButtonTheme;
|
|
8
|
+
size?: 'lg' | 'md' | 'sm';
|
|
9
|
+
leftIcon?: keyof typeof icons | ReactElement;
|
|
10
|
+
rightIcon?: keyof typeof icons | ReactElement;
|
|
11
|
+
textWeight?: 'light' | 'medium' | 'bold';
|
|
12
|
+
}>;
|
|
13
|
+
|
|
14
|
+
export type ButtonTheme =
|
|
15
|
+
| 'transparent'
|
|
16
|
+
| 'transparentDarkGray'
|
|
17
|
+
| 'white'
|
|
18
|
+
| 'pink'
|
|
19
|
+
| 'indigo'
|
|
20
|
+
| 'border';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { colors, semantics } from '../../tokens';
|
|
2
|
+
import type { ButtonTheme } from './button.types';
|
|
3
|
+
|
|
4
|
+
export const getButtonBackgroundColor = (colorTheme: ButtonTheme) => {
|
|
5
|
+
switch (colorTheme) {
|
|
6
|
+
case 'indigo':
|
|
7
|
+
return colors.oc.indigo[9].value;
|
|
8
|
+
case 'pink':
|
|
9
|
+
return colors.oc.pink[9].value;
|
|
10
|
+
case 'transparent':
|
|
11
|
+
return 'transparent';
|
|
12
|
+
case 'transparentDarkGray':
|
|
13
|
+
return colors.oc.black.value;
|
|
14
|
+
case 'white':
|
|
15
|
+
return colors.oc.white.value;
|
|
16
|
+
// @todo: for now, border type only supports react native, (do not support dark mode)
|
|
17
|
+
case 'border':
|
|
18
|
+
return colors.oc.white.value;
|
|
19
|
+
default:
|
|
20
|
+
return colors.oc.indigo[9].value;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const getButtonForegroundColor = (colorTheme: ButtonTheme) => {
|
|
25
|
+
switch (colorTheme) {
|
|
26
|
+
case 'transparent':
|
|
27
|
+
case 'transparentDarkGray':
|
|
28
|
+
case 'white':
|
|
29
|
+
return semantics.color.foreground[1];
|
|
30
|
+
// @todo: for now, border type only supports react native
|
|
31
|
+
case 'border':
|
|
32
|
+
return colors.oc.black.value;
|
|
33
|
+
default:
|
|
34
|
+
return colors.oc.white.value;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
import { Check } from 'lucide-react';
|
|
3
|
+
import { semantics } from '../../tokens';
|
|
4
|
+
|
|
5
|
+
const sizesStringify = (size: 'lg' | 'md' | 'sm') => {
|
|
6
|
+
switch (size) {
|
|
7
|
+
case 'lg':
|
|
8
|
+
return '32px';
|
|
9
|
+
case 'md':
|
|
10
|
+
return '24px';
|
|
11
|
+
case 'sm':
|
|
12
|
+
return '16px';
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const StyledCheckboxLabel = styled.label`
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
|
|
21
|
+
position: relative;
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
export const StyledCheckboxInput = styled.input<{ $size: 'lg' | 'md' | 'sm' }>`
|
|
25
|
+
appearance: none;
|
|
26
|
+
width: ${({ $size }) => sizesStringify($size)};
|
|
27
|
+
height: ${({ $size }) => sizesStringify($size)};
|
|
28
|
+
border: 2px solid #333;
|
|
29
|
+
border-radius: 4px;
|
|
30
|
+
background-color: #fff;
|
|
31
|
+
margin-right: 8px;
|
|
32
|
+
position: relative;
|
|
33
|
+
|
|
34
|
+
&:checked {
|
|
35
|
+
background-color: ${semantics.color.background[4]};
|
|
36
|
+
border-color: ${semantics.color.background[4]};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:checked + svg {
|
|
40
|
+
display: block;
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
export const StyledCheckboxIcon = styled(Check)<{ size: 'lg' | 'md' | 'sm' }>`
|
|
45
|
+
position: absolute;
|
|
46
|
+
top: 6px;
|
|
47
|
+
left: 6px;
|
|
48
|
+
|
|
49
|
+
width: ${({ size }) => `calc(${sizesStringify(size)} - 4px)`};
|
|
50
|
+
height: ${({ size }) => `calc(${sizesStringify(size)} - 4px)`};
|
|
51
|
+
display: none; /* Hidden by default */
|
|
52
|
+
`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, forwardRef, memo } from 'react';
|
|
2
|
+
import { Text } from '../text';
|
|
3
|
+
import { StyledCheckboxIcon, StyledCheckboxInput, StyledCheckboxLabel } from './checkbox.styled';
|
|
4
|
+
|
|
5
|
+
type CheckboxProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'formAction'> & {
|
|
6
|
+
size?: 'lg' | 'md' | 'sm';
|
|
7
|
+
labelText?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const Checkbox = memo(
|
|
11
|
+
forwardRef<HTMLInputElement, CheckboxProps>(
|
|
12
|
+
({ size = 'md', labelText, style, ...otherProps }, ref) => {
|
|
13
|
+
return (
|
|
14
|
+
<StyledCheckboxLabel style={style}>
|
|
15
|
+
<StyledCheckboxInput ref={ref} type="checkbox" $size={size} {...otherProps} />
|
|
16
|
+
<StyledCheckboxIcon size={size} width={undefined} height={undefined} />
|
|
17
|
+
<Text as="p" style={{ margin: 'unset' }}>
|
|
18
|
+
{labelText}
|
|
19
|
+
</Text>
|
|
20
|
+
</StyledCheckboxLabel>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
Checkbox.displayName = 'Checkbox';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './checkbox';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import { StyledIconButton } from './icon-button.styled';
|
|
3
|
+
import type { IconButtonProps } from './icon-button.types';
|
|
4
|
+
|
|
5
|
+
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
6
|
+
({ children, ...otherProps }, ref) => {
|
|
7
|
+
return (
|
|
8
|
+
<StyledIconButton ref={ref} {...otherProps}>
|
|
9
|
+
{children}
|
|
10
|
+
</StyledIconButton>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
IconButton.displayName = 'IconButton';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Button } from './button';
|
|
2
|
+
export * from './checkbox';
|
|
3
|
+
export * from './icon-button';
|
|
4
|
+
export * from './modal';
|
|
5
|
+
export * from './spinner';
|
|
6
|
+
export * from './text';
|
|
7
|
+
export * from './text-area';
|
|
8
|
+
export * from './text-input';
|
|
9
|
+
export * from './toast';
|
|
10
|
+
export * from './switch';
|
|
11
|
+
export * from './badge';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './label';
|