@transferwise/components 0.0.0-experimental-438bbba → 0.0.0-experimental-cf33ac7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/build/card/Card.js.map +1 -1
  2. package/build/card/Card.mjs.map +1 -1
  3. package/build/circularButton/CircularButton.js.map +1 -1
  4. package/build/circularButton/CircularButton.mjs.map +1 -1
  5. package/build/common/locale/index.js.map +1 -1
  6. package/build/common/locale/index.mjs.map +1 -1
  7. package/build/dateLookup/tableLink/TableLink.js.map +1 -1
  8. package/build/dateLookup/tableLink/TableLink.mjs.map +1 -1
  9. package/build/instructionsList/InstructionsList.js.map +1 -1
  10. package/build/instructionsList/InstructionsList.mjs.map +1 -1
  11. package/build/main.css +210 -210
  12. package/build/styles/main.css +210 -210
  13. package/build/styles/uploadInput/UploadInput.css +13 -81
  14. package/build/styles/uploadInput/uploadButton/UploadButton.css +78 -31
  15. package/build/styles/uploadInput/uploadItem/UploadItem.css +130 -109
  16. package/build/types/card/Card.d.ts.map +1 -1
  17. package/build/types/circularButton/CircularButton.d.ts.map +1 -1
  18. package/build/types/instructionsList/InstructionsList.d.ts.map +1 -1
  19. package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
  20. package/build/types/uploadInput/uploadButton/UploadButton.d.ts +6 -1
  21. package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
  22. package/build/types/uploadInput/uploadItem/UploadItem.d.ts +1 -5
  23. package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
  24. package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts +5 -5
  25. package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts.map +1 -1
  26. package/build/uploadInput/UploadInput.js +28 -38
  27. package/build/uploadInput/UploadInput.js.map +1 -1
  28. package/build/uploadInput/UploadInput.mjs +29 -39
  29. package/build/uploadInput/UploadInput.mjs.map +1 -1
  30. package/build/uploadInput/uploadButton/UploadButton.js +31 -38
  31. package/build/uploadInput/uploadButton/UploadButton.js.map +1 -1
  32. package/build/uploadInput/uploadButton/UploadButton.mjs +32 -39
  33. package/build/uploadInput/uploadButton/UploadButton.mjs.map +1 -1
  34. package/build/uploadInput/uploadItem/UploadItem.js +33 -56
  35. package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
  36. package/build/uploadInput/uploadItem/UploadItem.mjs +34 -57
  37. package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
  38. package/build/uploadInput/uploadItem/UploadItemLink.js +5 -7
  39. package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
  40. package/build/uploadInput/uploadItem/UploadItemLink.mjs +5 -7
  41. package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
  42. package/package.json +3 -3
  43. package/src/card/Card.spec.tsx +5 -4
  44. package/src/card/Card.story.tsx +6 -4
  45. package/src/card/Card.tsx +2 -3
  46. package/src/circularButton/CircularButton.tsx +1 -1
  47. package/src/common/locale/index.ts +1 -1
  48. package/src/dateLookup/tableLink/TableLink.tsx +15 -15
  49. package/src/instructionsList/InstructionsList.tsx +4 -1
  50. package/src/main.css +210 -210
  51. package/src/uploadInput/UploadInput.css +13 -81
  52. package/src/uploadInput/UploadInput.less +17 -79
  53. package/src/uploadInput/UploadInput.tests.story.tsx +8 -3
  54. package/src/uploadInput/UploadInput.tsx +41 -68
  55. package/src/uploadInput/uploadButton/UploadButton.css +78 -31
  56. package/src/uploadInput/uploadButton/UploadButton.less +78 -35
  57. package/src/uploadInput/uploadButton/UploadButton.tsx +153 -147
  58. package/src/uploadInput/uploadItem/UploadItem.css +130 -109
  59. package/src/uploadInput/uploadItem/UploadItem.less +129 -118
  60. package/src/uploadInput/uploadItem/UploadItem.tsx +123 -146
  61. package/src/uploadInput/uploadItem/UploadItemLink.tsx +25 -23
@@ -1,160 +1,171 @@
1
1
  @import (reference) "../../../node_modules/@transferwise/neptune-css/src/less/ring.less";
2
2
 
3
- // Be aware of touching styles related to :before/:after pseudo-elements in this file, delimiters between items build by using them
4
- .np-upload-item {
5
- border: 1px solid var(--color-interactive-secondary);
3
+ .np-upload-input__item {
6
4
  position: relative;
5
+ padding: var(--size-16);
6
+ display: flex;
7
+ align-items: flex-start;
8
+ border-left: var(--outerBorder);
9
+ border-right: var(--outerBorder);
7
10
 
8
- &:first-child ~ div:not(.np-upload-item--link):before,
9
- &:not(:first-child).np-upload-item--link .np-upload-item__link:before,
10
- &.np-upload-item--link:hover .np-upload-item__link:after {
11
- display: block;
12
- position: absolute;
13
- height: 1px;
14
- background-color: var(--color-border-neutral);
15
- content: " ";
16
- left: var(--size-16);
17
- width: calc(100% - 2 * var(--size-16));
11
+ &:first-child {
12
+ border-top: var(--outerBorder);
13
+ border-top-left-radius: var(--radius-small);
14
+ border-top-right-radius: var(--radius-small);
18
15
  }
19
16
 
20
- &:first-child ~ div:not(.np-upload-item--link):before,
21
- &:not(:first-child).np-upload-item--link .np-upload-item__link:before {
22
- top: 0;
17
+ & + .np-upload-input__item {
18
+ &:before {
19
+ content: " ";
20
+ display: block;
21
+ position: absolute;
22
+ height: 1px;
23
+ left: var(--size-16);
24
+ width: calc(100% - 2 * var(--size-16));
25
+ top: 0;
26
+ background: var(--color-border-neutral);
27
+ }
23
28
  }
24
29
 
25
- &.np-upload-item--link:hover .np-upload-item__link:after {
26
- bottom: -1px;
27
- }
30
+ .np-upload-input__item-content {
31
+ padding-right: var(--size-32);
32
+ flex: 1;
28
33
 
29
- &:first-child {
30
- & ~ div {
31
- border-top: 1px;
34
+ @media (max-width: 320px) {
35
+ padding-right: var(--size-64);
32
36
  }
33
37
  }
34
38
 
35
- &:not(:first-child) {
36
- .np-upload-item__link:hover {
37
- border-top-color: var(--color-border-neutral);
38
- }
39
+ .np-upload-input__title,
40
+ .np-upload-input__text {
41
+ margin: 0;
42
+ text-align-last: left;
43
+ color: var(--color-content-secondary);
39
44
  }
40
45
 
41
- &:not(:last-child) {
42
- border-bottom: 0;
46
+ .np-upload-input__title + .np-upload-input__text {
47
+ margin-top: var(--size-4);
43
48
  }
44
49
 
45
-
46
- &.np-upload-item--link:hover + .np-upload-item,
47
- &.np-upload-item--link:hover + .np-upload-button-container {
48
- &:before,
49
- .np-upload-item__link:before {
50
- display: none;
51
- }
50
+ .np-upload-input__icon {
51
+ padding-right: var(--size-16);
52
52
  }
53
- }
54
53
 
55
- .np-upload-button-container {
56
- &:hover:before,
57
- &.droppable-dropping:before {
58
- left: 0 !important;
59
- width: 100% !important;
54
+ .np-upload-input__item-link,
55
+ .np-upload-input__item-container {
56
+ align-items: flex-start;
57
+ display: flex;
58
+ width: 100%;
60
59
  }
61
60
 
62
- &:has(:focus-visible) {
63
- .ring();
64
- border-color: transparent;
65
- outline-offset: -3px;
66
- }
67
- }
61
+ .np-upload-input__item-action {
62
+ --iconSize: var(--size-24);
63
+ --clickArea: 44px;
64
+ --buttonTopRightOffset: var(--size-16);
65
+ // Offset towards the parent's top-right edge
66
+ // ensuring no overflow on smaller screens
67
+ --clickAreaTopRightOffset: calc((var(--clickArea) - var(--iconSize)) * -.5);
68
68
 
69
- .np-upload-item--single-file:focus-visible,
70
- .np-upload-item__link:focus-visible,
71
- .np-upload-button-container:has(:focus-visible) {
72
- outline-width: 3px;
73
- }
74
-
75
- .np-upload-item--link {
76
- a {
77
- flex: 1;
78
- text-decoration: none;
79
- border-top: 1px solid transparent;
80
- border-radius: inherit;
69
+ position: absolute;
70
+ right: var(--buttonTopRightOffset);
71
+ top: var(--buttonTopRightOffset);
81
72
 
82
- &:focus-visible {
83
- outline-offset: -2px;
73
+ @media (--screen-400-zoom) {
74
+ --iconSize: var(--size-48);
75
+ --clickAreaTopRightOffset: calc(-1 * var(--buttonTopRightOffset));
84
76
  }
85
77
 
86
- &:hover {
78
+ .np-upload-input__item-button {
79
+ appearance: none;
80
+ height: var(--iconSize);
81
+ width: var(--iconSize);
82
+ padding: 0 var(--size-4);
83
+ border-radius: 50%;
84
+ border: 0;
85
+ background-color: var(--color-background-neutral);
86
+ color: var(--color-interactive-primary);
87
+ transition: color, background-color 0.15s ease-in-out;
88
+ outline-offset: 0;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+
87
93
  &:before {
88
- display: none !important;
94
+ content: '';
95
+ display: block;
96
+ width: var(--clickArea);
97
+ height: var(--clickArea);
98
+ border-radius: 50%;
99
+ position: absolute;
100
+ top: var(--clickAreaTopRightOffset);
101
+ right: var(--clickAreaTopRightOffset);
102
+ }
103
+
104
+ &:hover {
105
+ background-color: var(--color-sentiment-negative);
106
+ color: var(--color-contrast-overlay) !important;
107
+ }
108
+
109
+ &:active {
110
+ background-color: var(--color-background-neutral-active);
89
111
  }
112
+ }
113
+ }
90
114
 
91
- &:after {
92
- left: 0 !important;
93
- width: 100% !important;
115
+ &.is-interactive {
116
+ padding: 0;
117
+
118
+ &:hover:not(:has(.np-upload-input__item-button:hover)) {
119
+ &:before,
120
+ & + .np-upload-input__item:before {
121
+ width: 100%;
122
+ left: 0;
94
123
  }
95
124
  }
96
125
 
97
- &:hover,
98
- &:active {
126
+ .np-upload-input__item-link {
127
+ padding: var(--size-16);
99
128
  text-decoration: none;
100
- .np-upload-button {
129
+ border-radius: inherit;
130
+ border-top: 1px solid transparent;
131
+ background-clip: padding-box;
132
+
133
+ &:focus-visible {
134
+ outline-offset: -2px;
135
+ outline-width: 3px;
136
+ }
137
+
138
+ &:hover,
139
+ &:active {
101
140
  background-color: var(--color-background-neutral);
102
- border-radius: inherit;
103
141
  }
104
142
  }
105
- }
106
143
 
107
- &:first-of-type a {
108
- border-top: 0;
144
+ &:first-child {
145
+ .np-upload-input__item-link {
146
+ border-top-width: 0;
147
+ }
148
+ }
109
149
  }
110
- }
111
150
 
112
- .np-upload-item__body {
113
- display: flex;
114
- align-items: center;
115
- justify-content: space-between;
116
- // We should have the `relative` position for the body, because we have `absolute` position for `np-upload-item__remove-button` to achieve appropriate `hover` effects
117
- position: relative;
118
- border-radius: inherit;
119
- }
151
+ .np-upload-input-errors {
152
+ padding-left: 0;
153
+ list-style-type: "";
120
154
 
121
- .np-upload-item__remove-button {
122
- display: flex;
123
- align-items: center;
124
- justify-content: center;
125
- align-self: flex-start;
126
- position: absolute;
127
- height: var(--size-24);
128
- min-height: 0;
129
- width: var(--size-24);
130
- padding: 0;
131
- border-radius: 50% !important;
132
- outline-offset: 0 !important;
133
- background-color: var(--color-background-neutral);
134
- border: none;
135
- color: var(--color-interactive-primary);
136
- right: var(--size-16);
137
- top: var(--size-16);
138
- transition: color, background-color 0.15s ease-in-out;
139
-
140
- @media (--screen-400-zoom) {
141
- top: var(--size-16);
142
- right: var(--size-16);
143
- height: var(--size-48);
144
- width: var(--size-48);
145
- }
155
+ & > li {
156
+ position: relative;
157
+ padding-left: var(--size-16);
146
158
 
147
- &:hover {
148
- background-color: var(--color-sentiment-negative);
149
- color: var(--color-contrast-overlay) !important;
150
- }
159
+ &::before {
160
+ content: '•';
161
+ position: absolute;
162
+ display: block;
163
+ left: 0;
164
+ }
151
165
 
152
- &:before {
153
- display: block;
154
- width: 44px;
155
- height: 44px;
156
- content: '';
157
- border-radius: 50%;
158
- position: absolute;
166
+ @media (max-width: 320px) {
167
+ padding-left: var(--size-32);
168
+ }
169
+ }
159
170
  }
160
171
  }
@@ -1,6 +1,5 @@
1
1
  import { Bin, CheckCircleFill, CrossCircleFill } from '@transferwise/icons';
2
2
  import { clsx } from 'clsx';
3
- import { forwardRef, useImperativeHandle, useRef } from 'react';
4
3
  import { useIntl } from 'react-intl';
5
4
 
6
5
  import Body from '../../body';
@@ -28,167 +27,145 @@ export type UploadItemProps = React.JSX.IntrinsicAttributes & {
28
27
  * @param file
29
28
  */
30
29
  onDownload?: (file: UploadedFile) => void;
31
- ref?: React.Ref<UploadItemRef>;
32
30
  };
33
31
 
34
- interface UploadItemRef {
35
- focus: () => void;
36
- }
37
-
38
32
  export enum TEST_IDS {
39
33
  uploadItem = 'uploadItem',
40
34
  mediaBody = 'mediaBody',
41
35
  }
42
36
 
43
- const UploadItem = forwardRef<UploadItemRef, UploadItemProps>(
44
- ({ file, canDelete, onDelete, onDownload, singleFileUpload }, ref) => {
45
- const { formatMessage } = useIntl();
46
- const { status, filename, error, errors, url } = file;
47
- const linkRef = useRef<HTMLAnchorElement>(null);
48
- const buttonRef = useRef<HTMLButtonElement>(null);
49
-
50
- useImperativeHandle<UploadItemRef, UploadItemRef>(ref, () => ({
51
- focus: () => {
52
- if (linkRef.current) {
53
- linkRef.current.focus();
54
- } else if (buttonRef.current) {
55
- buttonRef.current.focus();
56
- }
57
- },
58
- }));
59
-
60
- const isSucceeded = [Status.SUCCEEDED, undefined].includes(status) && !!url;
61
-
62
- /**
63
- * We're temporarily reverting to the regular icon components,
64
- * until the StatusIcon receives 24px sizing. Some misalignment
65
- * to be expected.
66
- */
67
- const getIcon = () => {
68
- if (error || errors?.length || status === Status.FAILED) {
69
- return <CrossCircleFill size={24} className="emphasis--negative" />;
70
- }
71
-
72
- let processIndicator: React.ReactNode;
73
-
74
- switch (status) {
75
- case Status.PROCESSING:
76
- case Status.PENDING:
77
- processIndicator = (
78
- <ProcessIndicator size={Size.EXTRA_SMALL} status={Status.PROCESSING} />
79
- );
80
- break;
81
- case Status.SUCCEEDED:
82
- case Status.DONE:
83
- default:
84
- processIndicator = <CheckCircleFill size={24} className="emphasis--positive" />;
85
- }
86
-
87
- return processIndicator;
88
- };
89
-
90
- const getErrorMessage = (error?: UploadError) =>
91
- typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);
92
-
93
- const getMultipleErrors = (errors?: UploadError[]) => {
94
- if (!errors?.length) {
95
- return null;
96
- }
97
-
98
- if (errors?.length === 1) {
99
- return getErrorMessage(errors[0]);
100
- }
37
+ const UploadItem = ({
38
+ file,
39
+ canDelete,
40
+ onDelete,
41
+ onDownload,
42
+ singleFileUpload,
43
+ }: UploadItemProps) => {
44
+ const { formatMessage } = useIntl();
45
+ const { status, filename, error, errors, url } = file;
46
+
47
+ const isSucceeded = [Status.SUCCEEDED, undefined].includes(status) && !!url;
48
+
49
+ /**
50
+ * We're temporarily reverting to the regular icon components,
51
+ * until the StatusIcon receives 24px sizing. Some misalignment
52
+ * to be expected.
53
+ */
54
+ const getIcon = () => {
55
+ if (error || errors?.length || status === Status.FAILED) {
56
+ return <CrossCircleFill size={24} className="emphasis--negative" />;
57
+ }
58
+
59
+ let processIndicator: React.ReactNode;
60
+
61
+ switch (status) {
62
+ case Status.PROCESSING:
63
+ case Status.PENDING:
64
+ processIndicator = <ProcessIndicator size={Size.EXTRA_SMALL} status={Status.PROCESSING} />;
65
+ break;
66
+ case Status.SUCCEEDED:
67
+ case Status.DONE:
68
+ default:
69
+ processIndicator = <CheckCircleFill size={24} className="emphasis--positive" />;
70
+ }
71
+
72
+ return processIndicator;
73
+ };
74
+
75
+ const getErrorMessage = (error?: UploadError) =>
76
+ typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);
77
+
78
+ const getMultipleErrors = (errors?: UploadError[]) => {
79
+ if (!errors?.length) {
80
+ return null;
81
+ }
82
+
83
+ if (errors?.length === 1) {
84
+ return getErrorMessage(errors[0]);
85
+ }
86
+
87
+ return (
88
+ <ul className="np-upload-input-errors m-b-0">
89
+ {errors.map((error, index) => {
90
+ // eslint-disable-next-line react/no-array-index-key
91
+ return <li key={index}>{getErrorMessage(error)}</li>;
92
+ })}
93
+ </ul>
94
+ );
95
+ };
101
96
 
97
+ const getDescription = () => {
98
+ if (error || errors?.length || status === Status.FAILED) {
102
99
  return (
103
- <ul className="np-upload-input-errors m-b-0">
104
- {errors.map((error, index) => {
105
- // eslint-disable-next-line react/no-array-index-key
106
- return <li key={index}>{getErrorMessage(error)}</li>;
107
- })}
108
- </ul>
100
+ <Body type={Typography.BODY_DEFAULT_BOLD} className="np-upload-input__text text-negative">
101
+ {errors?.length ? getMultipleErrors(errors) : getErrorMessage(error)}
102
+ </Body>
109
103
  );
110
- };
104
+ }
111
105
 
112
- const getDescription = () => {
113
- if (error || errors?.length || status === Status.FAILED) {
106
+ switch (status) {
107
+ case Status.PENDING:
114
108
  return (
115
- <Body type={Typography.BODY_DEFAULT_BOLD} className="text-negative">
116
- {errors?.length ? getMultipleErrors(errors) : getErrorMessage(error)}
109
+ <Body type={Typography.BODY_DEFAULT} className="np-upload-input__text">
110
+ {formatMessage(MESSAGES.uploading)}
117
111
  </Body>
118
112
  );
119
- }
120
-
121
- switch (status) {
122
- case Status.PENDING:
123
- return (
124
- <Body type={Typography.BODY_DEFAULT_BOLD}>{formatMessage(MESSAGES.uploading)}</Body>
125
- );
126
- case Status.PROCESSING:
127
- return <Body>{formatMessage(MESSAGES.deleting)}</Body>;
128
- case Status.SUCCEEDED:
129
- case Status.DONE:
130
- default:
131
- return (
132
- <Body type={Typography.BODY_DEFAULT_BOLD} className="text-positive">
133
- {formatMessage(MESSAGES.uploaded)}
134
- </Body>
135
- );
136
- }
137
- };
138
-
139
- const getTitle = () => {
140
- return filename || formatMessage(MESSAGES.uploadedFile);
141
- };
142
-
143
- const onDownloadFile = (event: React.MouseEvent): void => {
144
- if (onDownload) {
145
- event.preventDefault();
146
- onDownload(file);
147
- }
148
- };
149
-
150
- return (
151
- <div
152
- className={clsx('np-upload-item', { 'np-upload-item--link': isSucceeded })}
153
- data-testid={TEST_IDS.uploadItem}
113
+ case Status.PROCESSING:
114
+ return <Body className="np-upload-input__text">{formatMessage(MESSAGES.deleting)}</Body>;
115
+ case Status.SUCCEEDED:
116
+ case Status.DONE:
117
+ default:
118
+ return (
119
+ <Body type={Typography.BODY_DEFAULT_BOLD} className="np-upload-input__text">
120
+ {formatMessage(MESSAGES.uploaded)}
121
+ </Body>
122
+ );
123
+ }
124
+ };
125
+
126
+ const getTitle = () => {
127
+ return filename || formatMessage(MESSAGES.uploadedFile);
128
+ };
129
+
130
+ const onDownloadFile = (event: React.MouseEvent): void => {
131
+ if (onDownload) {
132
+ event.preventDefault();
133
+ onDownload(file);
134
+ }
135
+ };
136
+
137
+ return (
138
+ <div
139
+ className={clsx('np-upload-input__item', { 'is-interactive': isSucceeded && url })}
140
+ data-testid={TEST_IDS.uploadItem}
141
+ >
142
+ <UploadItemLink
143
+ url={isSucceeded ? url : undefined}
144
+ singleFileUpload={singleFileUpload}
145
+ onDownload={onDownloadFile}
154
146
  >
155
- <div className="np-upload-item__body">
156
- <UploadItemLink
157
- ref={linkRef}
158
- url={isSucceeded ? url : undefined}
159
- singleFileUpload={singleFileUpload}
160
- onDownload={onDownloadFile}
147
+ <span className="np-upload-input__icon">{getIcon()}</span>
148
+ <div className="np-upload-input__item-content">
149
+ <Body type={Typography.BODY_LARGE} className="np-upload-input__title text-word-break">
150
+ {getTitle()}
151
+ </Body>
152
+ {getDescription()}
153
+ </div>
154
+ </UploadItemLink>
155
+ {canDelete && (
156
+ <div className="np-upload-input__item-action">
157
+ <button
158
+ aria-label={formatMessage(MESSAGES.removeFile, { filename })}
159
+ className="np-upload-input__item-button"
160
+ type="button"
161
+ onClick={() => onDelete()}
161
162
  >
162
- <div className="np-upload-button" aria-live="polite">
163
- <div className="media">
164
- <div className="np-upload-icon media-left">{getIcon()}</div>
165
- <div className="media-body text-xs-left" data-testid={TEST_IDS.mediaBody}>
166
- <Body className="text-word-break d-block text-primary">{getTitle()}</Body>
167
- {getDescription()}
168
- </div>
169
- </div>
170
- </div>
171
- </UploadItemLink>
172
- {canDelete && (
173
- <button
174
- ref={buttonRef}
175
- aria-label={formatMessage(MESSAGES.removeFile, { filename })}
176
- className={clsx('btn', 'np-upload-item__remove-button', 'media-left', {
177
- 'np-upload-item--single-file': singleFileUpload,
178
- })}
179
- type="button"
180
- tabIndex={0}
181
- onClick={() => onDelete()}
182
- >
183
- <Bin size={16} />
184
- </button>
185
- )}
163
+ <Bin size={16} />
164
+ </button>
186
165
  </div>
187
- </div>
188
- );
189
- },
190
- );
191
-
192
- UploadItem.displayName = 'UploadItem';
166
+ )}
167
+ </div>
168
+ );
169
+ };
193
170
 
194
171
  export default UploadItem;
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren, MouseEvent, forwardRef } from 'react';
1
+ import { PropsWithChildren, MouseEvent } from 'react';
2
2
  import { clsx } from 'clsx';
3
3
 
4
4
  type UploadItemLinkProps = PropsWithChildren<{
@@ -7,26 +7,28 @@ type UploadItemLinkProps = PropsWithChildren<{
7
7
  singleFileUpload: boolean;
8
8
  }>;
9
9
 
10
- export const UploadItemLink = forwardRef<HTMLAnchorElement | HTMLDivElement, UploadItemLinkProps>(
11
- ({ children, url, onDownload, singleFileUpload }, ref) => {
12
- if (!url) {
13
- return <div ref={ref as React.RefObject<HTMLDivElement>}>{children}</div>;
14
- }
10
+ export const UploadItemLink = ({
11
+ children,
12
+ url,
13
+ onDownload,
14
+ singleFileUpload,
15
+ }: UploadItemLinkProps) => {
16
+ if (!url) {
17
+ return <div className={clsx('np-upload-input__item-container')}>{children}</div>;
18
+ }
15
19
 
16
- return (
17
- <a
18
- ref={ref as React.RefObject<HTMLAnchorElement>}
19
- href={url}
20
- target="_blank"
21
- rel="noopener noreferrer"
22
- className={clsx(
23
- 'np-upload-item__link',
24
- singleFileUpload ? 'np-upload-item--single-file' : '',
25
- )}
26
- onClick={onDownload}
27
- >
28
- {children}
29
- </a>
30
- );
31
- },
32
- );
20
+ return (
21
+ <a
22
+ href={url}
23
+ target="_blank"
24
+ rel="noopener noreferrer"
25
+ className={clsx(
26
+ 'np-upload-input__item-link',
27
+ singleFileUpload ? 'np-upload-input__item-link--single-file' : '',
28
+ )}
29
+ onClick={onDownload}
30
+ >
31
+ {children}
32
+ </a>
33
+ );
34
+ };