oneslash-design-system 1.0.3
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/.eslintrc.json +3 -0
- package/README.md +36 -0
- package/components/alert/alert.tsx +42 -0
- package/components/button/button.tsx +107 -0
- package/components/checkBox/checkBox.tsx +57 -0
- package/components/iconButton/iconButton.tsx +96 -0
- package/components/menuItem/menuItem.tsx +57 -0
- package/components/modal/modal.tsx +41 -0
- package/components/popover/popover.tsx +74 -0
- package/components/tab/tab.tsx +62 -0
- package/components/tag/tag.tsx +95 -0
- package/components/textField/textField.tsx +107 -0
- package/components/tooltip/tooltip.tsx +61 -0
- package/components/userImage/userImage.tsx +28 -0
- package/designTokens.js +234 -0
- package/dist/output.css +1049 -0
- package/global.d.ts +155 -0
- package/index.css +4 -0
- package/index.ts +16 -0
- package/next.config.mjs +4 -0
- package/package.json +31 -0
- package/postcss.config.mjs +8 -0
- package/tailwind.config.ts +232 -0
- package/tsconfig.json +40 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
export default function TextField({
|
|
5
|
+
id,
|
|
6
|
+
label,
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
iconLeft,
|
|
10
|
+
iconRight,
|
|
11
|
+
multiline = false,
|
|
12
|
+
maxRows = 6,
|
|
13
|
+
disabled = false,
|
|
14
|
+
error = false,
|
|
15
|
+
}: TextFieldProps) {
|
|
16
|
+
|
|
17
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
18
|
+
|
|
19
|
+
// Base styles
|
|
20
|
+
const baseClasses = 'w-full border rounded-[8px] p-2';
|
|
21
|
+
|
|
22
|
+
// Background color
|
|
23
|
+
const bgColor = 'bg-light-background-default dark:bg-dark-background-default transition-colors duration-300 ease-in-out';
|
|
24
|
+
|
|
25
|
+
// Border color
|
|
26
|
+
const borderColor = 'border-light-outlinedBorder-active dark:border-dark-outlinedBorder-active';
|
|
27
|
+
|
|
28
|
+
// State styles
|
|
29
|
+
const disabledClasses = 'bg-gray-200 cursor-not-allowed';
|
|
30
|
+
const errorClasses = 'border-red-500 focus:ring-red-500';
|
|
31
|
+
const focusClasses = 'focus:border-light-accent-main focus:dark:border-dark-accent-main outline-none';
|
|
32
|
+
const hoverClasses = 'hover:border-light-outlinedBorder-hover';
|
|
33
|
+
const defaultClasses = 'border-gray-300';
|
|
34
|
+
|
|
35
|
+
// Container styles
|
|
36
|
+
const containerClasses = `
|
|
37
|
+
${bgColor}
|
|
38
|
+
${borderColor}
|
|
39
|
+
${baseClasses}
|
|
40
|
+
${disabled ? disabledClasses : ''}
|
|
41
|
+
${error ? errorClasses : ''}
|
|
42
|
+
${isFocused ? focusClasses : ''}
|
|
43
|
+
${!disabled && !error ? hoverClasses : ''}
|
|
44
|
+
${defaultClasses}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
// Render iconRight in TextField
|
|
48
|
+
const renderIconRight = () => {
|
|
49
|
+
if (React.isValidElement(iconRight)) {
|
|
50
|
+
return iconRight;
|
|
51
|
+
}
|
|
52
|
+
if (typeof iconRight === 'function') {
|
|
53
|
+
return React.createElement(iconRight);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className="flex flex-col w-full">
|
|
60
|
+
{label && (
|
|
61
|
+
<label htmlFor={id} className="mb-1 text-body2 text-light-text-secondary dark:text-dark-text-secondary">
|
|
62
|
+
{label}
|
|
63
|
+
</label>
|
|
64
|
+
)}
|
|
65
|
+
<div className="relative">
|
|
66
|
+
{iconLeft && (
|
|
67
|
+
<span className="absolute inset-y-0 left-0 pl-3 flex items-center">
|
|
68
|
+
{iconLeft}
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
{iconRight && (
|
|
72
|
+
<span className="absolute inset-y-0 right-0 pr-3 flex items-center">
|
|
73
|
+
{renderIconRight()}
|
|
74
|
+
</span>
|
|
75
|
+
)}
|
|
76
|
+
{multiline ? (
|
|
77
|
+
<textarea
|
|
78
|
+
id={id}
|
|
79
|
+
rows={maxRows}
|
|
80
|
+
className={containerClasses}
|
|
81
|
+
value={value}
|
|
82
|
+
onChange={onChange}
|
|
83
|
+
onFocus={() => setIsFocused(true)}
|
|
84
|
+
onBlur={() => setIsFocused(false)}
|
|
85
|
+
disabled={disabled}
|
|
86
|
+
/>
|
|
87
|
+
) : (
|
|
88
|
+
<input
|
|
89
|
+
id={id}
|
|
90
|
+
type="text"
|
|
91
|
+
className={containerClasses}
|
|
92
|
+
value={value}
|
|
93
|
+
onChange={onChange}
|
|
94
|
+
onFocus={() => setIsFocused(true)}
|
|
95
|
+
onBlur={() => setIsFocused(false)}
|
|
96
|
+
disabled={disabled}
|
|
97
|
+
/>
|
|
98
|
+
)}
|
|
99
|
+
</div>
|
|
100
|
+
{error && (
|
|
101
|
+
<p className="mt-1 text-light-error-main text-body2">
|
|
102
|
+
This field is required
|
|
103
|
+
</p>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
export default function Tooltip({ title, children }: TooltipProps) {
|
|
5
|
+
const [visible, setVisible] = useState(false);
|
|
6
|
+
const [position, setPosition] = useState<'top' | 'bottom'>('bottom');
|
|
7
|
+
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
8
|
+
const buttonRef = useRef<HTMLDivElement>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const handlePosition = () => {
|
|
12
|
+
if (tooltipRef.current && buttonRef.current) {
|
|
13
|
+
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
14
|
+
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
15
|
+
// Check if there's enough space below; if not, place tooltip above
|
|
16
|
+
if (window.innerHeight - buttonRect.bottom < tooltipRect.height + 8) {
|
|
17
|
+
setPosition('top');
|
|
18
|
+
} else {
|
|
19
|
+
setPosition('bottom');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
if (visible) {
|
|
24
|
+
handlePosition();
|
|
25
|
+
}
|
|
26
|
+
}, [visible]);
|
|
27
|
+
|
|
28
|
+
const handleClick = () => {
|
|
29
|
+
setVisible(false); // Hide tooltip on click
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
ref={buttonRef}
|
|
35
|
+
onMouseEnter={() => setVisible(true)}
|
|
36
|
+
onMouseLeave={() => setVisible(false)}
|
|
37
|
+
onClick={handleClick}
|
|
38
|
+
className="relative inline-block"
|
|
39
|
+
>
|
|
40
|
+
{children}
|
|
41
|
+
{visible && (
|
|
42
|
+
<div
|
|
43
|
+
ref={tooltipRef}
|
|
44
|
+
className={`absolute whitespace-nowrap text-caption rounded-[8px] py-1 px-2 z-50
|
|
45
|
+
dark:bg-light-background-accent300 bg-dark-background-accent300
|
|
46
|
+
dark:text-light-text-primary text-dark-text-primary
|
|
47
|
+
${position === 'bottom' ? 'mt-1' : 'mb-1'}`}
|
|
48
|
+
style={{
|
|
49
|
+
bottom: position === 'top' ? '100%' : undefined,
|
|
50
|
+
top: position === 'bottom' ? '100%' : undefined,
|
|
51
|
+
left: '50%',
|
|
52
|
+
transform: 'translateX(-50%)',
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{title}
|
|
56
|
+
</div>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export default function UserImage({
|
|
4
|
+
userHandle,
|
|
5
|
+
userImgUrl,
|
|
6
|
+
}: UserImageProps) {
|
|
7
|
+
|
|
8
|
+
const defaultInitial = userHandle.charAt(0).toUpperCase();
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
className="flex items-center justify-center w-6 h-6 rounded-full overflow-hidden
|
|
13
|
+
bg-light-background-accent200 dark:bg-dark-background-accent200
|
|
14
|
+
text-light-text-secondary dark:text-dark-text-secondary ">
|
|
15
|
+
{userImgUrl ? (
|
|
16
|
+
<img
|
|
17
|
+
src={userImgUrl}
|
|
18
|
+
alt={userHandle}
|
|
19
|
+
className="w-full h-full object-cover rounded-full"
|
|
20
|
+
/>
|
|
21
|
+
) : (
|
|
22
|
+
<span className="text-body1">
|
|
23
|
+
{defaultInitial}
|
|
24
|
+
</span>
|
|
25
|
+
)}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
package/designTokens.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// design tokens definitions
|
|
2
|
+
module.exports = {
|
|
3
|
+
colors: {
|
|
4
|
+
// light
|
|
5
|
+
light:{
|
|
6
|
+
text:{
|
|
7
|
+
primary: '#000000',
|
|
8
|
+
secondary: '#6D6D6D',
|
|
9
|
+
disabled: '#9E9E9E',
|
|
10
|
+
contrast: '#ffffff',
|
|
11
|
+
},
|
|
12
|
+
accent:{
|
|
13
|
+
main: '#EEAE03',
|
|
14
|
+
dark: '#CE8602',
|
|
15
|
+
light: '#FFDD43',
|
|
16
|
+
contrast: '#000000',
|
|
17
|
+
},
|
|
18
|
+
primary:{
|
|
19
|
+
main: '#454545',
|
|
20
|
+
dark: '#262626',
|
|
21
|
+
light: '#888888',
|
|
22
|
+
},
|
|
23
|
+
secondary:{
|
|
24
|
+
main: '#B0B0B0',
|
|
25
|
+
dark: '#888888',
|
|
26
|
+
light: '#D1D1D1',
|
|
27
|
+
},
|
|
28
|
+
error:{
|
|
29
|
+
main: '#D32F2F',
|
|
30
|
+
dark: '#B22323',
|
|
31
|
+
light: '#F27777',
|
|
32
|
+
},
|
|
33
|
+
warning:{
|
|
34
|
+
main: '#EF6C00',
|
|
35
|
+
dark: '#CC5302',
|
|
36
|
+
light: '#FFA732',
|
|
37
|
+
},
|
|
38
|
+
info:{
|
|
39
|
+
main: '#0087D4',
|
|
40
|
+
dark: '#006BAB',
|
|
41
|
+
light: '#2CC1FF',
|
|
42
|
+
},
|
|
43
|
+
success:{
|
|
44
|
+
main: '#328736',
|
|
45
|
+
dark: '#2A6B2D',
|
|
46
|
+
light: '#67C16B',
|
|
47
|
+
},
|
|
48
|
+
background:{
|
|
49
|
+
default: '#FFFFFF',
|
|
50
|
+
accent100:'#F6F6F6',
|
|
51
|
+
accent200:'#E7E7E7',
|
|
52
|
+
accent300:'#D1D1D1',
|
|
53
|
+
},
|
|
54
|
+
action:{
|
|
55
|
+
active: '#888888',
|
|
56
|
+
hover: '#F3F3F3',
|
|
57
|
+
selected: '#E3E3E3',
|
|
58
|
+
disabledBackground: '#D1D1D1',
|
|
59
|
+
disabled: '#B0B0B0',
|
|
60
|
+
},
|
|
61
|
+
actionBackground:{
|
|
62
|
+
enabled: '#FFFFFF',
|
|
63
|
+
hovered: '#FFFFFF',
|
|
64
|
+
selected: '#FFFFFF',
|
|
65
|
+
disabled: '#EEEEEE',
|
|
66
|
+
},
|
|
67
|
+
actionOutlinedBorder:{
|
|
68
|
+
enabled: '#888888',
|
|
69
|
+
hovered: '#CDCDCD',
|
|
70
|
+
selected: '#E8E8E8',
|
|
71
|
+
disabled: '#B0B0B0',
|
|
72
|
+
},
|
|
73
|
+
misc:{
|
|
74
|
+
divider: '#D1D1D1',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// dark
|
|
79
|
+
dark:{
|
|
80
|
+
text:{
|
|
81
|
+
primary: '#FFFFFF',
|
|
82
|
+
secondary: '#B0B0B0',
|
|
83
|
+
disabled: '#6D6D6D',
|
|
84
|
+
contrast: '#000000',
|
|
85
|
+
},
|
|
86
|
+
accent:{
|
|
87
|
+
main: '#FFCD29',
|
|
88
|
+
dark: '#CE8602',
|
|
89
|
+
light: '#FFDD43',
|
|
90
|
+
contrast: '#000000',
|
|
91
|
+
},
|
|
92
|
+
primary:{
|
|
93
|
+
main: '#D5D5D5',
|
|
94
|
+
dark: '#E9E9E9',
|
|
95
|
+
light: '#9A9A9A',
|
|
96
|
+
},
|
|
97
|
+
secondary:{
|
|
98
|
+
main: '#4F4F4F',
|
|
99
|
+
dark: '#454545',
|
|
100
|
+
light: '#6D6D6D',
|
|
101
|
+
},
|
|
102
|
+
error:{
|
|
103
|
+
main: '#E74C4C',
|
|
104
|
+
dark: '#B22323',
|
|
105
|
+
light: '#F27777',
|
|
106
|
+
},
|
|
107
|
+
warning:{
|
|
108
|
+
main: '#FF8C0A',
|
|
109
|
+
dark: '#CC5302',
|
|
110
|
+
light: '#FFA732',
|
|
111
|
+
},
|
|
112
|
+
info:{
|
|
113
|
+
main: '#00AFFF',
|
|
114
|
+
dark: '#006BAB',
|
|
115
|
+
light: '#2CC1FF',
|
|
116
|
+
},
|
|
117
|
+
success:{
|
|
118
|
+
main: '#42A547',
|
|
119
|
+
dark: '#2A6B2D',
|
|
120
|
+
light: '#67C16B',
|
|
121
|
+
},
|
|
122
|
+
background:{
|
|
123
|
+
default: '#262626',
|
|
124
|
+
accent100:'#333333',
|
|
125
|
+
accent200:'#454545',
|
|
126
|
+
accent300:'#4F4F4F',
|
|
127
|
+
},
|
|
128
|
+
action:{
|
|
129
|
+
active: '#171717',
|
|
130
|
+
hover: '#3D3D3D',
|
|
131
|
+
selected: '#4E4E4E',
|
|
132
|
+
disabledBackground: '#3C3C3C',
|
|
133
|
+
disabled: '#383838',
|
|
134
|
+
},
|
|
135
|
+
actionBackground:{
|
|
136
|
+
enabled: '#FFFFFF',
|
|
137
|
+
hovered: '#FFFFFF',
|
|
138
|
+
selected: '#FFFFFF',
|
|
139
|
+
disabled: '#383838',
|
|
140
|
+
},
|
|
141
|
+
actionOutlinedBorder:{
|
|
142
|
+
enabled: '#7B7B7B',
|
|
143
|
+
hovered: '#2F2F2F',
|
|
144
|
+
selected: '#404040',
|
|
145
|
+
disabled: '#383838',
|
|
146
|
+
},
|
|
147
|
+
misc:{
|
|
148
|
+
divider: '#404040',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
spacing: {
|
|
154
|
+
small: '4px',
|
|
155
|
+
medium: '8px',
|
|
156
|
+
large: '16px',
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
typography: {
|
|
160
|
+
family: 'Inter, sans-serif',
|
|
161
|
+
h1: {
|
|
162
|
+
weight: '300',
|
|
163
|
+
size: '96px',
|
|
164
|
+
lineHeight: '120%',
|
|
165
|
+
letterSpacing: '-1.5px',
|
|
166
|
+
},
|
|
167
|
+
h2: {
|
|
168
|
+
weight: '300',
|
|
169
|
+
size: '60px',
|
|
170
|
+
lineHeight: '120%',
|
|
171
|
+
letterSpacing: '-0.5px',
|
|
172
|
+
},
|
|
173
|
+
h3: {
|
|
174
|
+
weight: '400',
|
|
175
|
+
size: '48px',
|
|
176
|
+
lineHeight: '120%',
|
|
177
|
+
letterSpacing: '0px',
|
|
178
|
+
},
|
|
179
|
+
h4: {
|
|
180
|
+
weight: '400',
|
|
181
|
+
size: '34px',
|
|
182
|
+
lineHeight: '120%',
|
|
183
|
+
letterSpacing: '0.3px',
|
|
184
|
+
},
|
|
185
|
+
h5: {
|
|
186
|
+
weight: '400',
|
|
187
|
+
size: '24px',
|
|
188
|
+
lineHeight: '120%',
|
|
189
|
+
letterSpacing: '0px',
|
|
190
|
+
},
|
|
191
|
+
h6: {
|
|
192
|
+
weight: '500',
|
|
193
|
+
size: '20px',
|
|
194
|
+
lineHeight: '150%',
|
|
195
|
+
letterSpacing: '0.2px',
|
|
196
|
+
},
|
|
197
|
+
subtitle1: {
|
|
198
|
+
weight: '500',
|
|
199
|
+
size: '16px',
|
|
200
|
+
lineHeight: '150%',
|
|
201
|
+
letterSpacing: '0.2px',
|
|
202
|
+
},
|
|
203
|
+
subtitle2: {
|
|
204
|
+
weight: '500',
|
|
205
|
+
size: '14px',
|
|
206
|
+
lineHeight: '150%',
|
|
207
|
+
letterSpacing: '0.1px',
|
|
208
|
+
},
|
|
209
|
+
body1: {
|
|
210
|
+
weight: '400',
|
|
211
|
+
size: '16px',
|
|
212
|
+
lineHeight: '150%',
|
|
213
|
+
letterSpacing: '0.2px',
|
|
214
|
+
},
|
|
215
|
+
body2: {
|
|
216
|
+
weight: '400',
|
|
217
|
+
size: '14px',
|
|
218
|
+
lineHeight: '150%',
|
|
219
|
+
letterSpacing: '0.2px',
|
|
220
|
+
},
|
|
221
|
+
caption: {
|
|
222
|
+
weight: '400',
|
|
223
|
+
size: '12px',
|
|
224
|
+
lineHeight: '150%',
|
|
225
|
+
letterSpacing: '1.2px',
|
|
226
|
+
},
|
|
227
|
+
alignments: {
|
|
228
|
+
left: 'left',
|
|
229
|
+
center: 'center',
|
|
230
|
+
right: 'right',
|
|
231
|
+
justify: 'justify',
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
};
|