@spaced-out/ui-design-system 0.1.30 → 0.1.32

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 (51) hide show
  1. package/.cspell/custom-words.txt +5 -0
  2. package/.github/workflows/pages.yml +3 -0
  3. package/.github/workflows/publish_to_npm.yml +1 -1
  4. package/.github/workflows/pull_request_checks.yml +44 -0
  5. package/.github/workflows/pull_request_semantics_checker.yml +1 -0
  6. package/.storybook/preview-head.html +2 -2
  7. package/CHANGELOG.md +25 -0
  8. package/design-tokens/color/app-color.json +3 -0
  9. package/design-tokens/color/base-color.json +3 -0
  10. package/design-tokens/size/base-size.json +15 -0
  11. package/lib/components/Dialog/Dialog.module.css +1 -1
  12. package/lib/components/FileUpload/FileUpload.js +195 -0
  13. package/lib/components/FileUpload/FileUpload.js.flow +301 -0
  14. package/lib/components/FileUpload/FileUpload.module.css +186 -0
  15. package/lib/components/FileUpload/index.js +16 -0
  16. package/lib/components/FileUpload/index.js.flow +3 -0
  17. package/lib/components/Input/Input.js +2 -2
  18. package/lib/components/Input/Input.js.flow +11 -7
  19. package/lib/components/Input/Input.module.css +16 -5
  20. package/lib/components/LinearLoader/LinearLoader.js +10 -3
  21. package/lib/components/LinearLoader/LinearLoader.js.flow +15 -2
  22. package/lib/components/LinearLoader/LinearLoader.module.css +34 -1
  23. package/lib/components/Modal/Modal.js +3 -2
  24. package/lib/components/Modal/Modal.js.flow +10 -4
  25. package/lib/components/Modal/Modal.module.css +13 -1
  26. package/lib/components/Modal/index.js.flow +1 -0
  27. package/lib/components/Textarea/Textarea.js +2 -2
  28. package/lib/components/Textarea/Textarea.js.flow +10 -6
  29. package/lib/components/Textarea/Textarea.module.css +16 -6
  30. package/lib/components/index.js +11 -0
  31. package/lib/components/index.js.flow +1 -0
  32. package/lib/hooks/index.js +11 -0
  33. package/lib/hooks/index.js.flow +1 -0
  34. package/lib/hooks/useFileUpload/index.js +16 -0
  35. package/lib/hooks/useFileUpload/index.js.flow +3 -0
  36. package/lib/hooks/useFileUpload/useFileUpload.js +279 -0
  37. package/lib/hooks/useFileUpload/useFileUpload.js.flow +304 -0
  38. package/lib/styles/index.css +12 -0
  39. package/lib/styles/index.js +15 -3
  40. package/lib/styles/index.js.flow +12 -0
  41. package/lib/styles/variables/_color.css +2 -0
  42. package/lib/styles/variables/_color.js +3 -1
  43. package/lib/styles/variables/_color.js.flow +2 -0
  44. package/lib/styles/variables/_size.css +10 -0
  45. package/lib/styles/variables/_size.js +11 -1
  46. package/lib/styles/variables/_size.js.flow +10 -0
  47. package/lib/utils/helpers/helpers.js +39 -2
  48. package/lib/utils/helpers/helpers.js.flow +37 -0
  49. package/lib/utils/tokens/tokens.js +1 -2
  50. package/lib/utils/tokens/tokens.js.flow +1 -3
  51. package/package.json +3 -2
@@ -0,0 +1,301 @@
1
+ // @flow strict
2
+ import * as React from 'react';
3
+
4
+ // $FlowFixMe[untyped-import] -- this should be fixed soon
5
+ import {
6
+ type UseFileUploadReturnProps,
7
+ useFileUpload,
8
+ } from '../../hooks/useFileUpload';
9
+ import classify from '../../utils/classify';
10
+ import {UnstyledButton} from '../Button';
11
+ import {ClickableIcon, CloseIcon, Icon} from '../Icon';
12
+ import {LinearLoader} from '../LinearLoader';
13
+ import {Truncate} from '../Truncate';
14
+
15
+ import css from './FileUpload.module.css';
16
+
17
+
18
+ type ClassNames = $ReadOnly<{
19
+ wrapper?: string,
20
+ instruction?: string,
21
+ secondaryInstruction?: string,
22
+ }>;
23
+
24
+ export type FileProgress = number | 'indeterminate';
25
+
26
+ export type FileObject = {
27
+ file: File,
28
+ id: string,
29
+ reject?: boolean,
30
+ rejectReason?: string,
31
+ progress?: FileProgress,
32
+ success?: boolean,
33
+ successMessage?: string,
34
+ // This is a flag that is used to show/hide re-upload button
35
+ showReUpload?: boolean,
36
+ };
37
+
38
+ // This is a file error object that is passed to onRejectedFilesDrop callback in useFileUpload hook
39
+ export type FileError = {
40
+ code: string,
41
+ };
42
+
43
+ // This is a file rejection object that is passed to handleDropRejected function in useFileUpload hook
44
+ export type FileRejection = {
45
+ errors: Array<FileError>,
46
+ file: File,
47
+ ...
48
+ };
49
+
50
+ // This is a ref object that is passed to FileUpload component for managing state of a single file
51
+ export type FileUploadRef = {
52
+ moveFileToProgress: (id: string, progress: FileProgress) => mixed,
53
+ moveFileToSuccess: (id: string, successMessage?: string) => mixed,
54
+ moveFileToReject: (id: string, rejectReason?: string) => mixed,
55
+ setShowReUpload: (id: string, showReUpload?: boolean) => mixed,
56
+ validFiles: Array<FileObject>,
57
+ rejectedFiles: Array<FileObject>,
58
+ files: Array<FileObject>,
59
+ };
60
+
61
+ // These props are shared between FileUpload component and useFileUpload hook
62
+ export type FileUploadBaseProps = {
63
+ maxFiles?: number,
64
+ maxSize?: number,
65
+ accept?: {[string]: string[]},
66
+ disabled?: boolean,
67
+
68
+ // File drop callbacks
69
+ onValidFilesDrop?: (acceptedFiles: Array<FileObject>) => void,
70
+ onRejectedFilesDrop?: (fileRejections: Array<FileObject>) => void,
71
+
72
+ // File clear callbacks
73
+ onFileClear?: (id: string) => void,
74
+ onClear?: () => void,
75
+ };
76
+
77
+ export type FileUploadProps = {
78
+ ...FileUploadBaseProps,
79
+
80
+ classNames?: ClassNames,
81
+ label?: React.Node,
82
+ instruction?: React.Node,
83
+ draggingInstruction?: React.Node,
84
+ secondaryInstruction?: React.Node,
85
+ required?: boolean,
86
+
87
+ // File refresh callback
88
+ onFileRefreshClick?: (file: FileObject) => void,
89
+ };
90
+
91
+ export type FileBlockProps = {
92
+ file: FileObject,
93
+ onFileRefreshClick?: (file: FileObject) => void,
94
+ handleFileClear?: (id: string) => mixed,
95
+ };
96
+
97
+ const FileUploadBase = (props: FileUploadProps, ref) => {
98
+ const {
99
+ classNames,
100
+ label = 'Upload File',
101
+ disabled = false,
102
+ instruction = 'Drag and drop or click to upload',
103
+ draggingInstruction = 'Drop here to start uploading..',
104
+ error = false,
105
+ required = false,
106
+ secondaryInstruction = '',
107
+ maxSize,
108
+ accept,
109
+ onValidFilesDrop,
110
+ onRejectedFilesDrop,
111
+ onFileClear,
112
+ onFileRefreshClick,
113
+ maxFiles = 1,
114
+ } = props;
115
+
116
+ // Get file upload state from useFileUpload hook
117
+ const {
118
+ validFiles,
119
+ rejectedFiles,
120
+ isDragActive,
121
+ getRootProps,
122
+ shouldAcceptFiles,
123
+ getInputProps,
124
+ handleFileClear,
125
+ moveFileToProgress,
126
+ moveFileToSuccess,
127
+ moveFileToReject,
128
+ setShowReUpload,
129
+ }: UseFileUploadReturnProps = useFileUpload({
130
+ maxFiles,
131
+ maxSize,
132
+ accept,
133
+ disabled,
134
+ onValidFilesDrop,
135
+ onRejectedFilesDrop,
136
+ onFileClear,
137
+ });
138
+
139
+ // Expose file upload actions to parent component
140
+ React.useImperativeHandle(ref, () => ({
141
+ moveFileToProgress,
142
+ moveFileToSuccess,
143
+ moveFileToReject,
144
+ setShowReUpload,
145
+ validFiles,
146
+ rejectedFiles,
147
+ files: [...validFiles, ...rejectedFiles],
148
+ }));
149
+
150
+ // Merge valid and rejected files
151
+ const files = [...validFiles, ...rejectedFiles];
152
+
153
+ return (
154
+ <div className={classify(css.wrapper, classNames?.wrapper)}>
155
+ {Boolean(label) && (
156
+ <div className={css.label}>
157
+ <Truncate>{label}</Truncate>
158
+ {required && <span className={css.required}>{'*'}</span>}
159
+ </div>
160
+ )}
161
+
162
+ <UnstyledButton
163
+ disabled={disabled || !shouldAcceptFiles}
164
+ {...getRootProps()}
165
+ className={classify(css.dropzone, {
166
+ [css.disabled]: disabled || !shouldAcceptFiles,
167
+ [css.dragActive]: isDragActive,
168
+ [css.error]: error,
169
+ })}
170
+ >
171
+ <input {...getInputProps()} />
172
+ <div className={classify(css.instruction, classNames?.instruction)}>
173
+ {isDragActive ? draggingInstruction : instruction}
174
+ </div>
175
+ <div
176
+ className={classify(
177
+ css.secondaryInstruction,
178
+ classNames?.secondaryInstruction,
179
+ )}
180
+ >
181
+ {secondaryInstruction}
182
+ </div>
183
+ </UnstyledButton>
184
+
185
+ {files.length > 0 && (
186
+ <div className={css.files}>
187
+ {files.map((file: FileObject) => (
188
+ <React.Fragment key={file.id}>
189
+ <FileBlock
190
+ file={file}
191
+ onFileRefreshClick={onFileRefreshClick}
192
+ handleFileClear={handleFileClear}
193
+ />
194
+ </React.Fragment>
195
+ ))}
196
+ </div>
197
+ )}
198
+ </div>
199
+ );
200
+ };
201
+
202
+ const FileBlock = ({
203
+ file,
204
+ onFileRefreshClick,
205
+ handleFileClear,
206
+ }: FileBlockProps): React.Node => (
207
+ <>
208
+ <div className={css.file}>
209
+ <div className={css.fileInfo}>
210
+ <div className={css.fileNameBlock}>
211
+ <div className={css.icon}>
212
+ <FileStatusIcon file={file} />
213
+ </div>
214
+ <div className={css.fileName}>
215
+ <Truncate>{file.file.name}</Truncate>
216
+ </div>
217
+ </div>
218
+
219
+ {file.success && !!file.successMessage && (
220
+ <div className={css.fileSuccess}>
221
+ <Truncate>{file.successMessage}</Truncate>
222
+ </div>
223
+ )}
224
+
225
+ {file.reject && !!file.rejectReason && (
226
+ <div className={css.fileError}>
227
+ <Truncate>{file.rejectReason}</Truncate>
228
+ </div>
229
+ )}
230
+
231
+ {!!file.progress && (
232
+ <div className={css.progress}>
233
+ <LinearLoader
234
+ size="small"
235
+ value={file.progress === 'indeterminate' ? 0 : file.progress}
236
+ indeterminate={file.progress === 'indeterminate'}
237
+ ></LinearLoader>
238
+ </div>
239
+ )}
240
+ </div>
241
+ <div className={css.rightSection}>
242
+ {file.showReUpload && (
243
+ <div className={css.rightBlock}>
244
+ <ClickableIcon
245
+ name="refresh"
246
+ size="small"
247
+ onClick={() => onFileRefreshClick?.(file)}
248
+ />
249
+ </div>
250
+ )}
251
+
252
+ <div className={css.rightBlock}>
253
+ <CloseIcon size="small" onClick={() => handleFileClear?.(file.id)} />
254
+ </div>
255
+ </div>
256
+ </div>
257
+ </>
258
+ );
259
+
260
+ // This function returns the status of a file
261
+ const getFileStatus = (file: FileObject) => {
262
+ if (file.progress) {
263
+ return 'progress';
264
+ }
265
+ if (file.success) {
266
+ return 'success';
267
+ }
268
+ if (file.reject) {
269
+ return 'error';
270
+ }
271
+
272
+ return 'default';
273
+ };
274
+
275
+ // This component renders the status icon for a file
276
+ const FileStatusIcon = ({file}: {file: FileObject}) => {
277
+ const status = getFileStatus(file);
278
+ switch (status) {
279
+ case 'progress':
280
+ return <Icon size="small" name="loader" color="tertiary" />;
281
+ case 'success':
282
+ return <Icon size="small" name="check" color="success" />;
283
+ case 'error':
284
+ return (
285
+ <Icon
286
+ size="small"
287
+ name="circle-exclamation"
288
+ color="danger"
289
+ type="solid"
290
+ />
291
+ );
292
+
293
+ default:
294
+ return <Icon size="small" name="check" color="success" />;
295
+ }
296
+ };
297
+
298
+ export const FileUpload: React.AbstractComponent<
299
+ FileUploadProps,
300
+ FileUploadRef,
301
+ > = React.forwardRef<FileUploadProps, FileUploadRef>(FileUploadBase);
@@ -0,0 +1,186 @@
1
+ @value (
2
+ colorTextSecondary,
3
+ colorBackgroundPrimary,
4
+ colorBackgroundTertiary,
5
+ colorBorderTertiary,
6
+ colorTextPrimary,
7
+ colorTextTertiary,
8
+ colorTextSuccess,
9
+ colorTextDisabled,
10
+ colorBorderPrimary,
11
+ colorBorderSecondary,
12
+ colorTextClickable,
13
+ colorTextDanger,
14
+ colorDangerLightest,
15
+ colorInformationLightest,
16
+ colorFocusPrimary
17
+ ) from '../../styles/variables/_color.css';
18
+
19
+ @value (
20
+ borderWidthNone,
21
+ borderWidthPrimary,
22
+ borderWidthTertiary,
23
+ borderRadiusMedium
24
+ ) from '../../styles/variables/_border.css';
25
+
26
+ @value (
27
+ spaceXXSmall,
28
+ spaceXSmall,
29
+ spaceMedium,
30
+ spaceLarge
31
+ ) from '../../styles/variables/_space.css';
32
+
33
+ @value (
34
+ size2,
35
+ size18,
36
+ size34
37
+ size48,
38
+ size50,
39
+ size70,
40
+ size125,
41
+ size240,
42
+ sizeFluid
43
+ ) from '../../styles/variables/_size.css';
44
+
45
+ .wrapper {
46
+ display: flex;
47
+ flex-direction: column;
48
+ width: sizeFluid;
49
+ gap: spaceXSmall;
50
+ }
51
+
52
+ .dropzone {
53
+ cursor: pointer;
54
+ display: flex;
55
+ flex-flow: column;
56
+ gap: spaceXSmall;
57
+ width: sizeFluid;
58
+ padding: spaceLarge;
59
+ justify-content: center;
60
+ align-items: center;
61
+ min-height: size125;
62
+ border: borderWidthPrimary solid colorBorderPrimary;
63
+ border-radius: borderRadiusMedium;
64
+ outline: none;
65
+ color: colorTextSecondary;
66
+ background-color: colorBackgroundTertiary;
67
+ }
68
+
69
+ .dropzone:hover,
70
+ .dragActive {
71
+ border-color: colorBorderTertiary;
72
+ background-color: colorBackgroundPrimary;
73
+ }
74
+
75
+ .dropzone:focus {
76
+ background-color: colorBackgroundPrimary;
77
+ border-color: colorTextClickable;
78
+ box-shadow: borderWidthNone borderWidthNone borderWidthNone
79
+ borderWidthTertiary colorFocusPrimary;
80
+ }
81
+
82
+ .dropzone.disabled {
83
+ pointer-events: none;
84
+ cursor: not-allowed;
85
+ color: colorTextDisabled;
86
+ border: borderWidthPrimary solid colorBorderPrimary;
87
+ background-color: colorBackgroundPrimary;
88
+ }
89
+
90
+ .instruction {
91
+ composes: buttonTextSmall from '../../styles/typography.module.css';
92
+ color: inherit;
93
+ text-decoration: underline;
94
+ max-width: size125;
95
+ text-align: center;
96
+ }
97
+
98
+ .secondaryInstruction {
99
+ composes: bodySmall from '../../styles/typography.module.css';
100
+ color: inherit;
101
+ max-width: size240;
102
+ text-align: center;
103
+ }
104
+
105
+ .files {
106
+ display: flex;
107
+ flex-flow: column;
108
+ gap: spaceXSmall;
109
+ }
110
+
111
+ .file {
112
+ display: flex;
113
+ height: size50;
114
+ padding: spaceXSmall;
115
+ align-items: center;
116
+ justify-content: space-between;
117
+ gap: spaceXSmall;
118
+ background-color: colorBackgroundPrimary;
119
+ border-bottom: borderWidthPrimary solid colorBorderSecondary;
120
+ }
121
+
122
+ .fileInfo {
123
+ display: flex;
124
+ flex-flow: column;
125
+ gap: spaceXSmall;
126
+ width: sizeFluid;
127
+ }
128
+
129
+ .fileNameBlock {
130
+ display: flex;
131
+ composes: formLabelMedium from '../../styles/typography.module.css';
132
+ color: colorTextPrimary;
133
+ gap: spaceXXSmall;
134
+ align-items: flex-start;
135
+ }
136
+
137
+ .fileName {
138
+ display: flex;
139
+ color: inherit;
140
+ }
141
+
142
+ .fileError,
143
+ .fileSuccess {
144
+ composes: bodySmall from '../../styles/typography.module.css';
145
+ margin-left: calc(size18 + spaceXXSmall);
146
+ margin-top: calc(spaceXSmall * -1);
147
+ }
148
+
149
+ .fileError {
150
+ color: colorTextDanger;
151
+ }
152
+
153
+ .fileSuccess {
154
+ color: colorTextSuccess;
155
+ }
156
+
157
+ .icon {
158
+ display: flex;
159
+ justify-content: center;
160
+ align-items: center;
161
+ min-width: size18;
162
+ min-height: size18;
163
+ }
164
+
165
+ .rightSection {
166
+ display: flex;
167
+ }
168
+
169
+ .rightBlock {
170
+ min-width: size34;
171
+ min-height: size34;
172
+ display: flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+ }
176
+
177
+ .label {
178
+ display: flex;
179
+ gap: spaceXXSmall;
180
+ composes: formLabelSmall from '../../styles/typography.module.css';
181
+ color: colorTextSecondary;
182
+ }
183
+
184
+ .required {
185
+ color: colorTextDanger;
186
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _FileUpload = require("./FileUpload");
7
+ Object.keys(_FileUpload).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _FileUpload[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _FileUpload[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,3 @@
1
+ // @flow strict
2
+
3
+ export * from './FileUpload';
@@ -82,13 +82,13 @@ const Input_ = (props, ref) => {
82
82
  }, label ?? ''), "\xA0", required && /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
83
83
  color: "danger"
84
84
  }, '*'))), /*#__PURE__*/React.createElement("div", {
85
- className: (0, _classify.classify)(_InputModule.default.box, classNames?.box, {
85
+ className: (0, _classify.classify)(_InputModule.default.box, {
86
86
  [_InputModule.default.inputDisabled]: disabled ?? false,
87
87
  [_InputModule.default.medium]: size === 'medium',
88
88
  [_InputModule.default.small]: size === 'small',
89
89
  [_InputModule.default.locked]: locked,
90
90
  [_InputModule.default.color]: type === 'color'
91
- }),
91
+ }, classNames?.box),
92
92
  onClick: !(disabled || locked) ? onContainerClick : null,
93
93
  ref: boxRef
94
94
  }, iconLeftName && /*#__PURE__*/React.createElement(_Icon.Icon, {
@@ -137,13 +137,17 @@ const Input_ = (props: InputProps, ref): React.Node => {
137
137
  </div>
138
138
  )}
139
139
  <div
140
- className={classify(css.box, classNames?.box, {
141
- [css.inputDisabled]: disabled ?? false,
142
- [css.medium]: size === 'medium',
143
- [css.small]: size === 'small',
144
- [css.locked]: locked,
145
- [css.color]: type === 'color',
146
- })}
140
+ className={classify(
141
+ css.box,
142
+ {
143
+ [css.inputDisabled]: disabled ?? false,
144
+ [css.medium]: size === 'medium',
145
+ [css.small]: size === 'small',
146
+ [css.locked]: locked,
147
+ [css.color]: type === 'color',
148
+ },
149
+ classNames?.box,
150
+ )}
147
151
  onClick={!(disabled || locked) ? onContainerClick : null}
148
152
  ref={boxRef}
149
153
  >
@@ -17,7 +17,7 @@
17
17
  @value (
18
18
  borderRadiusMedium,
19
19
  borderRadiusSmall,
20
- borderWidthSecondary,
20
+ borderWidthPrimary,
21
21
  borderWidthTertiary,
22
22
  borderWidthNone,
23
23
  borderRadiusXSmall
@@ -26,6 +26,7 @@
26
26
  @value (
27
27
  colorTextPrimary,
28
28
  colorTextSecondary,
29
+ colorTextTertiary,
29
30
  colorBorderPrimary,
30
31
  colorFillPrimary,
31
32
  colorFocusPrimary,
@@ -33,7 +34,8 @@
33
34
  colorTextDisabled,
34
35
  colorFillDisabled,
35
36
  colorTextDanger,
36
- colorBackgroundTertiary
37
+ colorBackgroundTertiary,
38
+ colorBorderTertiary
37
39
  ) from '../../styles/variables/_color.css';
38
40
 
39
41
  .container {
@@ -48,10 +50,19 @@
48
50
  gap: spaceXSmall;
49
51
  height: size42;
50
52
  padding: spaceNone spaceSmall;
51
- border: borderWidthSecondary solid colorBorderPrimary;
53
+ border: borderWidthPrimary solid colorBorderPrimary;
52
54
  background-color: colorBackgroundTertiary;
53
55
  }
54
56
 
57
+ .wrapper:not(.withError) .box:not(.inputDisabled):not(.locked):hover {
58
+ border-color: colorBorderTertiary;
59
+ }
60
+
61
+ .wrapper:not(.withError):focus-within
62
+ .box:not(.inputDisabled):not(.locked):hover {
63
+ border-color: colorFillPrimary;
64
+ }
65
+
55
66
  .locked {
56
67
  border-style: dashed;
57
68
  }
@@ -92,7 +103,7 @@
92
103
  cursor: inherit;
93
104
  }
94
105
 
95
- .wrapper:not(.inputDisabled):not(.withError):focus-within .box {
106
+ .wrapper:not(.withError):focus-within .box:not(.inputDisabled) {
96
107
  border-color: colorFillPrimary;
97
108
  box-shadow: borderWidthNone borderWidthNone borderWidthNone
98
109
  borderWidthTertiary colorFocusPrimary;
@@ -105,7 +116,7 @@
105
116
  }
106
117
 
107
118
  input::placeholder {
108
- color: colorTextSecondary;
119
+ color: colorTextTertiary;
109
120
  }
110
121
 
111
122
  .inputDisabled input::placeholder {
@@ -15,7 +15,8 @@ const LinearLoader = /*#__PURE__*/React.forwardRef((_ref, ref) => {
15
15
  let {
16
16
  value,
17
17
  size = 'medium',
18
- className
18
+ className,
19
+ indeterminate
19
20
  } = _ref;
20
21
  return /*#__PURE__*/React.createElement("div", {
21
22
  className: (0, _classify.classify)(_LinearLoaderModule.default.lineContainer, {
@@ -25,10 +26,16 @@ const LinearLoader = /*#__PURE__*/React.forwardRef((_ref, ref) => {
25
26
  }, className),
26
27
  ref: ref
27
28
  }, /*#__PURE__*/React.createElement("div", {
28
- className: _LinearLoaderModule.default.progressBar,
29
+ className: (0, _classify.classify)(_LinearLoaderModule.default.progressBar, {
30
+ [_LinearLoaderModule.default.indeterminate]: indeterminate
31
+ }),
29
32
  style: {
30
33
  width: `${value + '%'}`
31
- }
34
+ },
35
+ role: "progressbar",
36
+ "aria-valuenow": indeterminate ? undefined : value,
37
+ "aria-valuemin": "0",
38
+ "aria-valuemax": "100"
32
39
  }));
33
40
  });
34
41
  exports.LinearLoader = LinearLoader;
@@ -11,13 +11,17 @@ export type LinearLoaderProps = {
11
11
  value: number,
12
12
  size?: 'large' | 'medium' | 'small',
13
13
  className?: string,
14
+ indeterminate?: boolean,
14
15
  };
15
16
 
16
17
  export const LinearLoader: React$AbstractComponent<
17
18
  LinearLoaderProps,
18
19
  HTMLDivElement,
19
20
  > = React.forwardRef<LinearLoaderProps, HTMLDivElement>(
20
- ({value, size = 'medium', className}: LinearLoaderProps, ref): React.Node => (
21
+ (
22
+ {value, size = 'medium', className, indeterminate}: LinearLoaderProps,
23
+ ref,
24
+ ): React.Node => (
21
25
  <div
22
26
  className={classify(
23
27
  css.lineContainer,
@@ -30,7 +34,16 @@ export const LinearLoader: React$AbstractComponent<
30
34
  )}
31
35
  ref={ref}
32
36
  >
33
- <div className={css.progressBar} style={{width: `${value + '%'}`}}></div>
37
+ <div
38
+ className={classify(css.progressBar, {
39
+ [css.indeterminate]: indeterminate,
40
+ })}
41
+ style={{width: `${value + '%'}`}}
42
+ role="progressbar"
43
+ aria-valuenow={indeterminate ? undefined : value}
44
+ aria-valuemin="0"
45
+ aria-valuemax="100"
46
+ ></div>
34
47
  </div>
35
48
  ),
36
49
  );