@soul-refiner/design-system 0.1.8 → 0.1.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soul-refiner/design-system",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "main": "src/index.ts",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -6,3 +6,5 @@ export type {
6
6
  DropdownProps,
7
7
  DropdownSpacerProps,
8
8
  } from './dropdown';
9
+ export { Upload } from './upload';
10
+ export type { UploadProps } from './upload';
@@ -0,0 +1,2 @@
1
+ export { Upload } from './upload';
2
+ export type { UploadProps } from './upload';
@@ -0,0 +1,263 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { COLORS } from 'common';
4
+ import { Box, Button, P } from 'components';
5
+ import { UploadAudio, UploadFile, UploadImage, UploadVideo } from 'icons';
6
+
7
+ type UploadTypes = 'audio' | 'image' | 'file' | 'video';
8
+
9
+ export interface UploadProps extends React.PropsWithChildren {
10
+ background: (typeof COLORS)[number] | string;
11
+ borderColor: (typeof COLORS)[number];
12
+ iconColor: (typeof COLORS)[number];
13
+ multiple?: boolean;
14
+ onDrop?: (files: FileList) => void;
15
+ size?: 'small' | 'large' | 'fit-content';
16
+ subtext?: string;
17
+ text?: React.ReactNode;
18
+ type: UploadTypes;
19
+ }
20
+
21
+ export const Upload = ({
22
+ background = 'hue-blue-3',
23
+ borderColor = 'hue-blue-2',
24
+ children,
25
+ iconColor = 'primary-blue-2',
26
+ multiple,
27
+ onDrop,
28
+ size = 'large',
29
+ subtext,
30
+ text,
31
+ type,
32
+ }: UploadProps) => {
33
+ const filesRef = React.useRef<HTMLInputElement>(null);
34
+ const [draggingOver, setDraggingOver] = React.useState(false);
35
+
36
+ const fileTypeLookup = {
37
+ video: 'video/*',
38
+ audio: 'audio/*',
39
+ image: 'image/*',
40
+ file: '.xlsx, .xls, .doc, .docx, .ppt, .pptx, .txt, .pdf, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf,',
41
+ };
42
+
43
+ const heightLookup: Record<
44
+ UploadTypes,
45
+ Record<'height' | 'icon', Record<'small' | 'fit-content' | 'large', number>>
46
+ > = {
47
+ audio: {
48
+ icon: {
49
+ 'fit-content': 28,
50
+ large: 28,
51
+ small: 28,
52
+ },
53
+ height: {
54
+ 'fit-content': 281,
55
+ large: 281,
56
+ small: 75,
57
+ },
58
+ },
59
+ file: {
60
+ icon: {
61
+ 'fit-content': 68,
62
+ large: 68,
63
+ small: 57,
64
+ },
65
+ height: {
66
+ 'fit-content': 281,
67
+ large: 281,
68
+ small: 75,
69
+ },
70
+ },
71
+ image: {
72
+ icon: {
73
+ 'fit-content': 162,
74
+ large: 162,
75
+ small: 57,
76
+ },
77
+ height: {
78
+ 'fit-content': 281,
79
+ large: 281,
80
+ small: 75,
81
+ },
82
+ },
83
+ video: {
84
+ icon: {
85
+ 'fit-content': 140,
86
+ large: 140,
87
+ small: 57,
88
+ },
89
+ height: {
90
+ 'fit-content': 336,
91
+ large: 562,
92
+ small: 75,
93
+ },
94
+ },
95
+ };
96
+
97
+ const iconProps = {
98
+ color: iconColor,
99
+ size: heightLookup[type].icon[size],
100
+ };
101
+
102
+ const iconLookup: Record<UploadTypes, React.ReactElement> = {
103
+ audio: <UploadAudio {...iconProps} />,
104
+ file: <UploadFile {...iconProps} />,
105
+ image: <UploadImage {...iconProps} />,
106
+ video: <UploadVideo {...iconProps} />,
107
+ };
108
+
109
+ const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
110
+ event.preventDefault();
111
+ setDraggingOver(true);
112
+ };
113
+
114
+ const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
115
+ event.preventDefault();
116
+ setDraggingOver(false);
117
+ };
118
+
119
+ const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
120
+ event.preventDefault();
121
+ setDraggingOver(false);
122
+
123
+ const files = event.dataTransfer.files;
124
+ const dataTransfer: DataTransfer = new DataTransfer();
125
+
126
+ for (let i = 0; i < files.length; i++) {
127
+ const file: File | null = files.item(i);
128
+
129
+ if (file !== null) {
130
+ dataTransfer.items.add(file);
131
+ }
132
+ }
133
+
134
+ const fileInput: HTMLInputElement | null = filesRef.current;
135
+
136
+ if (fileInput !== null) {
137
+ fileInput.files = dataTransfer.files;
138
+
139
+ if (onDrop) {
140
+ onDrop(fileInput.files);
141
+ }
142
+ }
143
+ };
144
+
145
+ const handleFileChange = () => {
146
+ const fileInput: HTMLInputElement | null = filesRef.current;
147
+
148
+ if (fileInput !== null) {
149
+ if (onDrop && fileInput.files && fileInput.files.length) {
150
+ onDrop(fileInput.files);
151
+ }
152
+ }
153
+ };
154
+
155
+ const removeFileFromState = () => {
156
+ if (filesRef.current) filesRef.current.value = '';
157
+ };
158
+
159
+ return (
160
+ <>
161
+ <Wrapper
162
+ $background={background}
163
+ $borderColor={borderColor}
164
+ $draggingOver={draggingOver}
165
+ $height={heightLookup[type].height[size]}
166
+ $size={size}
167
+ onDragOver={handleDragOver}
168
+ onDragLeave={handleDragLeave}
169
+ onDrop={handleDrop}
170
+ >
171
+ <Box
172
+ $align="center"
173
+ $borderRadius="medium"
174
+ $dir="column"
175
+ $display="flex"
176
+ $gap={16}
177
+ $justify="center"
178
+ sx="height: 100%; width: 100%; svg { flex-shrink: 0; };"
179
+ >
180
+ {iconLookup[type]}
181
+ {size !== 'small' && (
182
+ <Box
183
+ $align="center"
184
+ $dir="column"
185
+ $display="flex"
186
+ $gap={8}
187
+ $justify="center"
188
+ sx="width: 100%;"
189
+ >
190
+ <P $textAlign="center" sx="width: 100%;">
191
+ {text}
192
+ <Button
193
+ onClick={() => filesRef.current?.click()}
194
+ size="small"
195
+ sx="display: inline;"
196
+ type="text"
197
+ >
198
+ Browse
199
+ </Button>
200
+ </P>
201
+ <P $textAlign="center" sx="width: 100%;">
202
+ {subtext}
203
+ </P>
204
+ </Box>
205
+ )}
206
+ <Input
207
+ data-testid="dropzone-upload-input"
208
+ ref={filesRef}
209
+ type="file"
210
+ multiple={multiple}
211
+ accept={fileTypeLookup[type]}
212
+ name="Files"
213
+ onChange={handleFileChange}
214
+ />
215
+ </Box>
216
+ </Wrapper>
217
+ {React.Children.map(children, (child) => {
218
+ if (React.isValidElement(child)) {
219
+ return React.cloneElement(child, {
220
+ handleUpload: () => filesRef.current?.click(),
221
+ removeFileFromState,
222
+ } as Partial<unknown> & React.Attributes);
223
+ }
224
+ return child;
225
+ })}
226
+ </>
227
+ );
228
+ };
229
+
230
+ const Wrapper = styled.div<{
231
+ $background: string;
232
+ $borderColor: string;
233
+ $draggingOver: boolean;
234
+ $height: number;
235
+ $size: 'large' | 'small' | 'fit-content';
236
+ }>`
237
+ box-sizing: border-box;
238
+ width: ${({ $size }) =>
239
+ $size === 'large'
240
+ ? '100%'
241
+ : $size === 'fit-content'
242
+ ? 'fit-content'
243
+ : '134px'};
244
+ height: ${({ $height }) => $height}px;
245
+ padding: ${({ $size }) =>
246
+ $size === 'large'
247
+ ? '64px 32px'
248
+ : $size === 'fit-content'
249
+ ? '64px 16px'
250
+ : 'initial'};
251
+ background-color: ${({ $background }) =>
252
+ COLORS.includes($background as (typeof COLORS)[number])
253
+ ? `var(--color-${$background})`
254
+ : $background};
255
+ border: 2px dashed var(--color-${({ $borderColor }) => $borderColor});
256
+ border-radius: ${({ $size }) => ($size === 'large' ? '16px' : '8px')};
257
+ `;
258
+
259
+ const TextWrapper = styled.div``;
260
+
261
+ const Input = styled.input`
262
+ display: none;
263
+ `;
@@ -33,6 +33,7 @@ const Table = ({
33
33
  $dir="column"
34
34
  $gap={32}
35
35
  $padding={32}
36
+ sx={compact ? 'width: fit-content;' : ''}
36
37
  >
37
38
  {!!header && header}
38
39
  <Box
@@ -59,7 +60,7 @@ const TableElement = styled.table<{
59
60
  $striped?: boolean;
60
61
  $sx?: string;
61
62
  }>`
62
- width: max-content;
63
+ width: 100%;
63
64
  border-collapse: collapse;
64
65
  border-spacing: 0;
65
66
  ${({ $compact }) => ($compact ? 'width: fit-content;' : '')}
@@ -14,6 +14,7 @@ export * from './people';
14
14
  export * from './phone';
15
15
  export * from './security';
16
16
  export * from './shopping';
17
+ export * from './special';
17
18
  export * from './symbols';
18
19
  export * from './technology';
19
20
  export * from './text';
@@ -0,0 +1,4 @@
1
+ export { UploadAudio } from './upload_audio';
2
+ export { UploadFile } from './upload_file';
3
+ export { UploadImage } from './upload_image';
4
+ export { UploadVideo } from './upload_video';
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { COLORS, colorReference } from 'common';
3
+
4
+ type NativeProps = Pick<
5
+ React.HTMLAttributes<SVGElement>,
6
+ | 'children'
7
+ | 'className'
8
+ | 'dangerouslySetInnerHTML'
9
+ | 'id'
10
+ | 'onBlur'
11
+ | 'onBlurCapture'
12
+ | 'onClick'
13
+ | 'onChange'
14
+ | 'onCopy'
15
+ | 'onCut'
16
+ | 'onKeyDown'
17
+ | 'onKeyDownCapture'
18
+ | 'onKeyUp'
19
+ | 'onKeyUpCapture'
20
+ | 'onMouseDown'
21
+ | 'onMouseDownCapture'
22
+ | 'onMouseEnter'
23
+ | 'onMouseLeave'
24
+ | 'onMouseOut'
25
+ | 'onMouseOver'
26
+ > & { value?: string };
27
+
28
+ interface IconProps extends NativeProps {
29
+ color?: (typeof COLORS)[number];
30
+ size?: number;
31
+ }
32
+
33
+ export const UploadAudio = ({
34
+ color = 'hue-blue-2',
35
+ size = 28,
36
+ ...rest
37
+ }: IconProps) => {
38
+ return (
39
+ <svg
40
+ width={size + 'px'}
41
+ height={size + 'px'}
42
+ viewBox="0 0 28 28"
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ fill={colorReference[color]}
45
+ {...rest}
46
+ >
47
+ <g clipPath="url(#clip0_844_42855)">
48
+ <path d="M8.16667 5.8334V12.8334H19.8333V5.8334H19.8096C19.5416 2.75532 17.0429 0.343201 14 0.343201C10.9571 0.343201 8.45837 2.75532 8.19045 5.8334H8.16667Z" />
49
+ <path d="M19.8096 15.5098H19.8333V15.1667H8.16667V15.5098H8.19045C8.42319 18.1838 10.3394 20.3551 12.8333 20.8792V22.6609C9.19906 22.0997 6.41667 18.9581 6.41667 15.1667C6.41667 14.8446 6.1555 14.5834 5.83333 14.5834C5.51117 14.5834 5.25 14.8446 5.25 15.1667C5.25 19.6037 8.55241 23.2693 12.8333 23.8396V25.6667H8.16667C6.878 25.6667 5.83333 26.7114 5.83333 28.0001H23.3333C23.3333 26.7114 22.2887 25.6667 21 25.6667H15.1667V23.8396C19.4476 23.2693 22.75 19.6037 22.75 15.1667C22.75 14.8446 22.4888 14.5834 22.1667 14.5834C21.8445 14.5834 21.5833 14.8446 21.5833 15.1667C21.5833 18.9581 18.8009 22.0997 15.1667 22.6609V20.8792C17.6606 20.3551 19.5768 18.1838 19.8096 15.5098Z" />
50
+ </g>
51
+ <defs>
52
+ <clipPath id="clip0_844_42855">
53
+ <rect width={size} height={size} fill="white" />
54
+ </clipPath>
55
+ </defs>
56
+ </svg>
57
+ );
58
+ };
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { COLORS, colorReference } from 'common';
3
+
4
+ type NativeProps = Pick<
5
+ React.HTMLAttributes<SVGElement>,
6
+ | 'children'
7
+ | 'className'
8
+ | 'dangerouslySetInnerHTML'
9
+ | 'id'
10
+ | 'onBlur'
11
+ | 'onBlurCapture'
12
+ | 'onClick'
13
+ | 'onChange'
14
+ | 'onCopy'
15
+ | 'onCut'
16
+ | 'onKeyDown'
17
+ | 'onKeyDownCapture'
18
+ | 'onKeyUp'
19
+ | 'onKeyUpCapture'
20
+ | 'onMouseDown'
21
+ | 'onMouseDownCapture'
22
+ | 'onMouseEnter'
23
+ | 'onMouseLeave'
24
+ | 'onMouseOut'
25
+ | 'onMouseOver'
26
+ > & { value?: string };
27
+
28
+ interface IconProps extends NativeProps {
29
+ color?: (typeof COLORS)[number];
30
+ size?: number;
31
+ }
32
+
33
+ export const UploadFile = ({
34
+ color = 'hue-blue-1',
35
+ size = 44,
36
+ ...rest
37
+ }: IconProps) => {
38
+ return (
39
+ <svg
40
+ width={size + 'px'}
41
+ height={size * (31 / 44) + 'px'}
42
+ viewBox="0 0 44 31"
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ fill={colorReference[color]}
45
+ {...rest}
46
+ >
47
+ <path d="M22.0001 4.83331C24.2535 4.83666 26.4361 5.62014 28.1772 7.05061C29.9182 8.48108 31.1102 10.4703 31.5506 12.6802L32.143 15.6855L35.1989 15.8971C36.5321 15.9853 37.7787 16.5892 38.6743 17.5808C39.5699 18.5724 40.0442 19.8737 39.9967 21.2091C39.9492 22.5444 39.3836 23.8088 38.4197 24.7342C37.4559 25.6596 36.1696 26.1734 34.8335 26.1666H11.0001C9.21068 26.1678 7.48882 25.4831 6.18875 24.2535C4.88867 23.0239 4.10923 21.3429 4.01076 19.5561C3.91228 17.7694 4.50226 16.0128 5.65933 14.6478C6.81641 13.2828 8.45259 12.4131 10.2313 12.2176L12.365 11.9907L13.3561 10.0877C14.1759 8.50291 15.4161 7.17432 16.9408 6.24751C18.4655 5.3207 20.2158 4.83143 22.0001 4.83331ZM22.0001 0.833313C19.4847 0.833835 17.0177 1.52475 14.868 2.83078C12.7182 4.13681 10.9681 6.00784 9.80847 8.23997C7.01123 8.54372 4.43686 9.90826 2.61528 12.0527C0.793702 14.1972 -0.136476 16.9583 0.0162156 19.7679C0.168907 22.5774 1.39285 25.2215 3.4361 27.1559C5.47936 29.0903 8.18644 30.1678 11.0001 30.1666H34.8335C37.2066 30.1735 39.4895 29.2571 41.1992 27.6112C42.9089 25.9653 43.9114 23.719 43.9947 21.3473C44.0781 18.9756 43.2357 16.6644 41.6458 14.9026C40.0558 13.1407 37.8429 12.0663 35.4751 11.9066C34.8594 8.78576 33.1791 5.97548 30.7215 3.95585C28.2638 1.93622 25.1812 0.832531 22.0001 0.833313ZM23.9996 15.3271H27.8278L21.9996 9.49997L16.1725 15.3271H19.9996V21.3271H20.0001V23.5H24.0001V19.5H23.9996V15.3271Z" />
48
+ </svg>
49
+ );
50
+ };
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import { COLORS, colorReference } from 'common';
3
+
4
+ type NativeProps = Pick<
5
+ React.HTMLAttributes<SVGElement>,
6
+ | 'children'
7
+ | 'className'
8
+ | 'dangerouslySetInnerHTML'
9
+ | 'id'
10
+ | 'onBlur'
11
+ | 'onBlurCapture'
12
+ | 'onClick'
13
+ | 'onChange'
14
+ | 'onCopy'
15
+ | 'onCut'
16
+ | 'onKeyDown'
17
+ | 'onKeyDownCapture'
18
+ | 'onKeyUp'
19
+ | 'onKeyUpCapture'
20
+ | 'onMouseDown'
21
+ | 'onMouseDownCapture'
22
+ | 'onMouseEnter'
23
+ | 'onMouseLeave'
24
+ | 'onMouseOut'
25
+ | 'onMouseOver'
26
+ > & { value?: string };
27
+
28
+ interface IconProps extends NativeProps {
29
+ color?: (typeof COLORS)[number];
30
+ size?: number;
31
+ }
32
+
33
+ export const UploadImage = ({
34
+ color = 'primary-blue-2',
35
+ size = 162,
36
+ ...rest
37
+ }: IconProps) => {
38
+ return (
39
+ <svg
40
+ width={size + 'px'}
41
+ height={size * (120 / 162) + 'px'}
42
+ viewBox="0 0 162 120"
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ fill={colorReference[color]}
45
+ {...rest}
46
+ >
47
+ <path d="M20 13H124C127.866 13 131 16.134 131 20V69.0515C131.496 69.0174 131.996 69 132.5 69C133.692 69 134.861 69.097 136 69.2835V20C136 13.3726 130.627 8 124 8H20C13.3726 8 8 13.3726 8 20V78C8 84.6274 13.3726 90 20 90H111.006C111.045 88.2755 111.287 86.6012 111.71 85H20C16.134 85 13 81.866 13 78V20C13 16.134 16.134 13 20 13Z" />
48
+ <path d="M131 88.4996L128.914 90.5855C128.133 91.3665 126.867 91.3665 126.086 90.5855L125.914 90.4139C125.133 89.6329 125.133 88.3665 125.914 87.5855L131.586 81.9139C132.367 81.1329 133.633 81.1329 134.414 81.9139L140.086 87.5855C140.867 88.3665 140.867 89.6329 140.086 90.4139L139.914 90.5855C139.133 91.3665 137.867 91.3665 137.086 90.5855L135 88.4998V97.9998C135 99.1043 134.105 99.9998 133 99.9998C131.895 99.9998 131 99.1043 131 97.9998V88.4996Z" />
49
+ <path d="M86.6515 39.8111L110.172 70.7593H35.8965L54.4654 46.6197L67.4636 63.3317L85.4136 39.8111H86.6515ZM51.3706 39.8111C56.3223 39.8111 60.655 35.4784 60.655 30.5266C60.655 25.5749 56.3223 21.2422 51.3706 21.2422C46.4189 21.2422 42.0861 25.5749 42.0861 30.5266C42.0861 35.4784 46.4189 39.8111 51.3706 39.8111Z" />
50
+ </svg>
51
+ );
52
+ };
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { COLORS, colorReference } from 'common';
3
+
4
+ type NativeProps = Pick<
5
+ React.HTMLAttributes<SVGElement>,
6
+ | 'children'
7
+ | 'className'
8
+ | 'dangerouslySetInnerHTML'
9
+ | 'id'
10
+ | 'onBlur'
11
+ | 'onBlurCapture'
12
+ | 'onClick'
13
+ | 'onChange'
14
+ | 'onCopy'
15
+ | 'onCut'
16
+ | 'onKeyDown'
17
+ | 'onKeyDownCapture'
18
+ | 'onKeyUp'
19
+ | 'onKeyUpCapture'
20
+ | 'onMouseDown'
21
+ | 'onMouseDownCapture'
22
+ | 'onMouseEnter'
23
+ | 'onMouseLeave'
24
+ | 'onMouseOut'
25
+ | 'onMouseOver'
26
+ > & { value?: string };
27
+
28
+ interface IconProps extends NativeProps {
29
+ color?: (typeof COLORS)[number];
30
+ size?: number;
31
+ }
32
+
33
+ export const UploadVideo = ({
34
+ color = 'hue-blue-2',
35
+ size = 140,
36
+ ...rest
37
+ }: IconProps) => {
38
+ return (
39
+ <svg
40
+ width={size + 'px'}
41
+ height={size * (89 / 140) + 'px'}
42
+ viewBox="0 0 140 89"
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ fill={colorReference[color]}
45
+ {...rest}
46
+ >
47
+ <path d="M7.74194 4.20434H116.129C118.267 4.20434 120 5.93743 120 8.07531V52.7334C120.738 52.6397 121.491 52.5914 122.255 52.5914C122.8 52.5914 123.339 52.616 123.871 52.6641V8.07531C123.871 3.79956 120.405 0.333374 116.129 0.333374H7.74194C3.46618 0.333374 0 3.79956 0 8.07531V62.2689C0 66.5446 3.46618 70.0108 7.74194 70.0108H104.519C104.542 68.6795 104.713 67.3841 105.014 66.1398H7.74194C5.60406 66.1398 3.87097 64.4067 3.87097 62.2689V8.07531C3.87097 5.93743 5.60406 4.20434 7.74194 4.20434Z" />
48
+ <path d="M123.399 79.066V68.4437L127.097 72.142L129.378 69.861L121.786 62.2689L114.194 69.861L116.475 72.142L120.173 68.4437V79.066H123.399Z" />
49
+ <path
50
+ fillRule="evenodd"
51
+ clipRule="evenodd"
52
+ d="M122.258 88.0753C112.459 88.0753 104.516 80.132 104.516 70.3334C104.516 60.5348 112.459 52.5914 122.258 52.5914C132.057 52.5914 140 60.5348 140 70.3334C140 80.132 132.057 88.0753 122.258 88.0753ZM122.258 84.8495C130.275 84.8495 136.774 78.3504 136.774 70.3334C136.774 62.3163 130.275 55.8172 122.258 55.8172C114.241 55.8172 107.742 62.3163 107.742 70.3334C107.742 78.3504 114.241 84.8495 122.258 84.8495Z"
53
+ />
54
+ <path
55
+ fillRule="evenodd"
56
+ clipRule="evenodd"
57
+ d="M52.9032 23.5592V46.785C52.9032 47.8058 54.0326 48.4224 54.8913 47.8704L72.9558 36.2575C73.7459 35.7496 73.7459 34.5946 72.9558 34.0867L54.8913 22.4738C54.0326 21.9218 52.9032 22.5383 52.9032 23.5592ZM69.8719 35.1721L55.4839 44.4215V25.9226L69.8719 35.1721Z"
58
+ />
59
+ </svg>
60
+ );
61
+ };