@opengovsg/oui 0.0.21 → 0.0.23

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 (55) hide show
  1. package/dist/cjs/button/button.cjs +1 -1
  2. package/dist/cjs/calendar/calendar-month-day-selector.cjs +4 -3
  3. package/dist/cjs/date-picker/date-picker.cjs +34 -9
  4. package/dist/cjs/field/field.cjs +1 -1
  5. package/dist/cjs/file-dropzone/contexts.cjs +18 -0
  6. package/dist/cjs/file-dropzone/file-dropzone.cjs +311 -0
  7. package/dist/cjs/file-dropzone/file-info.cjs +146 -0
  8. package/dist/cjs/file-dropzone/index.cjs +13 -0
  9. package/dist/cjs/file-dropzone/types.cjs +3 -0
  10. package/dist/cjs/file-dropzone/utils.cjs +31 -0
  11. package/dist/cjs/index.cjs +43 -34
  12. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/plus.cjs +22 -0
  13. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/trash-2.cjs +25 -0
  14. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/upload.cjs +23 -0
  15. package/dist/cjs/number-field/index.cjs +8 -0
  16. package/dist/cjs/number-field/number-field.cjs +136 -0
  17. package/dist/esm/button/button.js +1 -1
  18. package/dist/esm/calendar/calendar-month-day-selector.js +4 -3
  19. package/dist/esm/date-picker/date-picker.js +34 -9
  20. package/dist/esm/field/field.js +1 -1
  21. package/dist/esm/file-dropzone/contexts.js +13 -0
  22. package/dist/esm/file-dropzone/file-dropzone.js +309 -0
  23. package/dist/esm/file-dropzone/file-info.js +144 -0
  24. package/dist/esm/file-dropzone/index.js +4 -0
  25. package/dist/esm/file-dropzone/types.js +1 -0
  26. package/dist/esm/file-dropzone/utils.js +28 -0
  27. package/dist/esm/index.js +13 -9
  28. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/plus.js +17 -0
  29. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/trash-2.js +20 -0
  30. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/upload.js +18 -0
  31. package/dist/esm/number-field/index.js +2 -0
  32. package/dist/esm/number-field/number-field.js +134 -0
  33. package/dist/types/calendar/calendar-month-day-selector.d.ts.map +1 -1
  34. package/dist/types/date-picker/date-picker.d.ts +5 -2
  35. package/dist/types/date-picker/date-picker.d.ts.map +1 -1
  36. package/dist/types/file-dropzone/contexts.d.ts +4 -0
  37. package/dist/types/file-dropzone/contexts.d.ts.map +1 -0
  38. package/dist/types/file-dropzone/file-dropzone.d.ts +82 -0
  39. package/dist/types/file-dropzone/file-dropzone.d.ts.map +1 -0
  40. package/dist/types/file-dropzone/file-info.d.ts +9 -0
  41. package/dist/types/file-dropzone/file-info.d.ts.map +1 -0
  42. package/dist/types/file-dropzone/index.d.ts +7 -0
  43. package/dist/types/file-dropzone/index.d.ts.map +1 -0
  44. package/dist/types/file-dropzone/types.d.ts +24 -0
  45. package/dist/types/file-dropzone/types.d.ts.map +1 -0
  46. package/dist/types/file-dropzone/utils.d.ts +8 -0
  47. package/dist/types/file-dropzone/utils.d.ts.map +1 -0
  48. package/dist/types/index.d.mts +2 -0
  49. package/dist/types/index.d.ts +2 -0
  50. package/dist/types/index.d.ts.map +1 -1
  51. package/dist/types/number-field/index.d.ts +3 -0
  52. package/dist/types/number-field/index.d.ts.map +1 -0
  53. package/dist/types/number-field/number-field.d.ts +24 -0
  54. package/dist/types/number-field/number-field.d.ts.map +1 -0
  55. package/package.json +4 -3
@@ -7,9 +7,9 @@ var $670gB$react = require('react');
7
7
  var utils = require('@react-aria/utils');
8
8
  var reactAriaComponents = require('react-aria-components');
9
9
  var ouiTheme = require('@opengovsg/oui-theme');
10
+ var ripple = require('../ripple/ripple.cjs');
10
11
  var useRipple = require('../ripple/use-ripple.cjs');
11
12
  var spinner = require('../spinner/spinner.cjs');
12
- var ripple = require('../ripple/ripple.cjs');
13
13
 
14
14
  const Button = $670gB$react.forwardRef(
15
15
  ({
@@ -6,11 +6,11 @@ var jsxRuntime = require('react/jsx-runtime');
6
6
  var $670gB$react = require('react');
7
7
  var date = require('@internationalized/date');
8
8
  var reactAriaComponents = require('react-aria-components');
9
+ var select = require('../select/select.cjs');
10
+ var selectItem = require('../select/select-item.cjs');
9
11
  var agnosticCalendarStateContext = require('./agnostic-calendar-state-context.cjs');
10
12
  var calendarStyleContext = require('./calendar-style-context.cjs');
11
13
  var useCalendarSelectors = require('./hooks/use-calendar-selectors.cjs');
12
- var select = require('../select/select.cjs');
13
- var selectItem = require('../select/select-item.cjs');
14
14
  var useCalendarI18n = require('./hooks/use-calendar-i18n.cjs');
15
15
 
16
16
  const CalendarMonthDaySelector = () => {
@@ -63,7 +63,8 @@ const CalendarMonthDaySelector = () => {
63
63
  list: slots.yearList({ className: classNames?.yearList }),
64
64
  selectedText: slots.selectorText({
65
65
  className: classNames?.selectorText
66
- })
66
+ }),
67
+ popover: "min-w-[8ch]"
67
68
  },
68
69
  selectedKey: state.visibleRange.start.year,
69
70
  "aria-label": formatMessage("selectYear"),
@@ -25,6 +25,7 @@ function DatePicker(originalProps) {
25
25
  calendarProps,
26
26
  popoverProps,
27
27
  calendarButtonProps,
28
+ selectorIcon,
28
29
  ...props
29
30
  },
30
31
  variantProps
@@ -63,20 +64,44 @@ function DatePicker(originalProps) {
63
64
  className: classNames?.calendarButton
64
65
  }),
65
66
  ...calendarButtonProps,
66
- children: /* @__PURE__ */ jsxRuntime.jsx(calendar.default, { "aria-hidden": true })
67
+ children: selectorIcon ?? /* @__PURE__ */ jsxRuntime.jsx(
68
+ calendar.default,
69
+ {
70
+ className: styles.selectorIcon({
71
+ className: classNames?.selectorIcon
72
+ }),
73
+ "aria-hidden": true
74
+ }
75
+ )
67
76
  }
68
77
  )
69
78
  ] }),
70
- /* @__PURE__ */ jsxRuntime.jsx(popover.Popover, { placement: "bottom end", ...popoverProps, children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Dialog, { className: styles.dialog({ className: classNames?.dialog }), children: /* @__PURE__ */ jsxRuntime.jsx(
71
- calendar$1.Calendar,
79
+ /* @__PURE__ */ jsxRuntime.jsx(
80
+ popover.Popover,
72
81
  {
73
- size: variantProps.size === "xs" ? "sm" : variantProps.size,
74
- classNames: classNames?.calendar,
75
- ...calendarProps
82
+ placement: "bottom end",
83
+ classNames: classNames?.popover,
84
+ ...popoverProps,
85
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Dialog, { className: styles.dialog({ className: classNames?.dialog }), children: /* @__PURE__ */ jsxRuntime.jsx(
86
+ calendar$1.Calendar,
87
+ {
88
+ size: variantProps.size === "xs" ? "sm" : variantProps.size,
89
+ classNames: classNames?.calendar,
90
+ pageBehavior: props.pageBehavior,
91
+ ...calendarProps
92
+ }
93
+ ) })
76
94
  }
77
- ) }) }),
78
- description && /* @__PURE__ */ jsxRuntime.jsx(field.Description, { size: variantProps.size, children: description }),
79
- /* @__PURE__ */ jsxRuntime.jsx(field.FieldError, { size: variantProps.size, children: errorMessage })
95
+ ),
96
+ description && /* @__PURE__ */ jsxRuntime.jsx(
97
+ field.Description,
98
+ {
99
+ className: classNames?.description,
100
+ size: variantProps.size,
101
+ children: description
102
+ }
103
+ ),
104
+ /* @__PURE__ */ jsxRuntime.jsx(field.FieldError, { classNames: classNames?.error, size: variantProps.size, children: errorMessage })
80
105
  ]
81
106
  }
82
107
  );
@@ -15,8 +15,8 @@ function Description({ size, className, ...props }) {
15
15
  return /* @__PURE__ */ jsxRuntime.jsx(
16
16
  reactAriaComponents.Text,
17
17
  {
18
- ...props,
19
18
  slot: "description",
19
+ ...props,
20
20
  className: ouiTheme.descriptionStyles({ className, size })
21
21
  }
22
22
  );
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var context = require('../system/react-utils/context.cjs');
5
+
6
+ const [FileDropzoneStateContext, useFileDropzoneStateContext] = context.createContext({
7
+ strict: true,
8
+ name: "FileDropzoneStateContext"
9
+ });
10
+ const [FileDropzoneStyleContext, useFileDropzoneStyleContext] = context.createContext({
11
+ strict: true,
12
+ name: "FileDropzoneStyleContext"
13
+ });
14
+
15
+ exports.FileDropzoneStateContext = FileDropzoneStateContext;
16
+ exports.FileDropzoneStyleContext = FileDropzoneStyleContext;
17
+ exports.useFileDropzoneStateContext = useFileDropzoneStateContext;
18
+ exports.useFileDropzoneStyleContext = useFileDropzoneStyleContext;
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+ "use client";
3
+ 'use strict';
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var $670gB$react = require('react');
7
+ var form = require('@react-stately/form');
8
+ var reactAria = require('react-aria');
9
+ var reactAriaComponents = require('react-aria-components');
10
+ var reactDropzone = require('react-dropzone');
11
+ var ouiTheme = require('@opengovsg/oui-theme');
12
+ var utils = require('../system/utils.cjs');
13
+ var contexts = require('./contexts.cjs');
14
+ var fileInfo = require('./file-info.cjs');
15
+ var utils$1 = require('./utils.cjs');
16
+ var useControllableState = require('../hooks/use-controllable-state.cjs');
17
+ var upload = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/upload.cjs');
18
+ var field = require('../field/field.cjs');
19
+
20
+ const FileDropzone = (originalProps) => {
21
+ const [props, variantProps] = utils.mapPropsVariants(
22
+ originalProps,
23
+ ouiTheme.fileDropzoneStyles.variantKeys
24
+ );
25
+ const {
26
+ name,
27
+ allowedMimeTypes = [],
28
+ maxFileSize = Number.POSITIVE_INFINITY,
29
+ minFileSize = 0,
30
+ showFileSizeText = true,
31
+ maxFiles = 1,
32
+ isDisabled,
33
+ isReadOnly,
34
+ classNames,
35
+ itemClassNames,
36
+ validator,
37
+ showRejectedFiles,
38
+ onError,
39
+ errorMessage,
40
+ label,
41
+ description,
42
+ children,
43
+ hideDropzoneOnValue = maxFiles === 1,
44
+ imagePreview = "small"
45
+ } = props;
46
+ const [value, setValue] = useControllableState.useControllableState({
47
+ value: props.value,
48
+ defaultValue: props.defaultValue || [],
49
+ onChange: props.onChange
50
+ });
51
+ const [rejections, setRejections] = useControllableState.useControllableState({
52
+ value: props.rejections,
53
+ defaultValue: [],
54
+ onChange: props.onRejection
55
+ });
56
+ const validationState = form.useFormValidationState({
57
+ ...props,
58
+ value
59
+ });
60
+ const { isInvalid, validationErrors, validationDetails } = validationState.displayValidation;
61
+ const { labelProps, fieldProps, descriptionProps, errorMessageProps } = reactAria.useField({
62
+ ...props,
63
+ isInvalid,
64
+ errorMessage: props.errorMessage || validationErrors
65
+ });
66
+ const slots = ouiTheme.fileDropzoneStyles(variantProps);
67
+ const fileSizeTextId = reactAria.useId();
68
+ const formatError = $670gB$react.useCallback(
69
+ (error) => utils$1.formatErrorMessage(error, {
70
+ maxFileSize,
71
+ minFileSize,
72
+ maxFiles
73
+ }),
74
+ [maxFileSize, maxFiles, minFileSize]
75
+ );
76
+ const onDrop = $670gB$react.useCallback(
77
+ (acceptedFiles, fileRejections) => {
78
+ const files = acceptedFiles;
79
+ if (showRejectedFiles) {
80
+ const invalidFiles = fileRejections.map(({ file, errors }) => {
81
+ file.errors = errors;
82
+ return file;
83
+ });
84
+ setRejections(invalidFiles);
85
+ }
86
+ setValue(files);
87
+ if (onError && fileRejections.length > 0) {
88
+ const firstError = fileRejections[0].errors[0];
89
+ onError(formatError(firstError));
90
+ }
91
+ },
92
+ [formatError, onError, setRejections, setValue, showRejectedFiles]
93
+ );
94
+ const handleRemoveFile = $670gB$react.useCallback(
95
+ (fileName) => {
96
+ setValue((files) => files.filter((file) => file.name !== fileName));
97
+ },
98
+ [setValue]
99
+ );
100
+ const handleRemoveRejection = $670gB$react.useCallback(
101
+ (fileName) => {
102
+ setRejections(
103
+ (rejections2) => rejections2.filter((file) => file.name !== fileName)
104
+ );
105
+ },
106
+ [setRejections]
107
+ );
108
+ const { getInputProps, ...dropzoneState } = reactDropzone.useDropzone({
109
+ validator,
110
+ accept: allowedMimeTypes.reduce(
111
+ (acc, type) => ({ ...acc, [type]: [] }),
112
+ {}
113
+ ),
114
+ onError: (e) => onError?.(e.message),
115
+ onDrop,
116
+ disabled: isDisabled,
117
+ noDrag: isReadOnly,
118
+ // Prevent ref hijack when there is a label
119
+ noClick: true,
120
+ noKeyboard: true,
121
+ maxSize: maxFileSize,
122
+ minSize: minFileSize,
123
+ maxFiles,
124
+ multiple: maxFiles !== 1
125
+ });
126
+ const fileSizeText = $670gB$react.useMemo(() => {
127
+ const notDefaultMaxFileSize = maxFileSize !== Number.POSITIVE_INFINITY;
128
+ const notDefaultMinFileSize = minFileSize !== 0;
129
+ const shouldShow = showFileSizeText && (notDefaultMaxFileSize || notDefaultMinFileSize);
130
+ if (!shouldShow) return null;
131
+ if (notDefaultMaxFileSize && notDefaultMinFileSize) {
132
+ return `File size must be between ${utils$1.formatBytes(minFileSize, 2)} and ${utils$1.formatBytes(
133
+ maxFileSize,
134
+ 2
135
+ )}`;
136
+ }
137
+ if (notDefaultMaxFileSize) {
138
+ return `Maximum file size: ${utils$1.formatBytes(maxFileSize, 2)}`;
139
+ }
140
+ if (notDefaultMinFileSize) {
141
+ return `Minimum file size: ${utils$1.formatBytes(minFileSize, 2)}`;
142
+ }
143
+ return null;
144
+ }, [maxFileSize, minFileSize, showFileSizeText]);
145
+ const triggerFileSelector = $670gB$react.useCallback(() => {
146
+ if (isDisabled || isReadOnly) return;
147
+ dropzoneState.inputRef.current?.click();
148
+ }, [dropzoneState, isDisabled, isReadOnly]);
149
+ $670gB$react.useEffect(() => {
150
+ if (value.length <= maxFiles) {
151
+ let changed = false;
152
+ const newFiles = value.map((file) => {
153
+ if (file.errors?.some((e) => e.code === "too-many-files")) {
154
+ file.errors = file.errors.filter((e) => e.code !== "too-many-files");
155
+ changed = true;
156
+ }
157
+ return file;
158
+ });
159
+ if (changed) {
160
+ setValue(newFiles);
161
+ }
162
+ }
163
+ }, [maxFiles, setValue, value]);
164
+ const inputProps = $670gB$react.useMemo(() => {
165
+ const inputProps2 = { ...fieldProps, name };
166
+ if (fileSizeText) {
167
+ inputProps2["aria-describedby"] = inputProps2["aria-describedby"] ? `${inputProps2["aria-describedby"]} ${fileSizeTextId}` : fileSizeTextId;
168
+ }
169
+ return getInputProps(inputProps2);
170
+ }, [fieldProps, getInputProps, fileSizeTextId, name, fileSizeText]);
171
+ const showDropzone = $670gB$react.useMemo(() => {
172
+ if (hideDropzoneOnValue) {
173
+ return value.length < maxFiles;
174
+ }
175
+ return true;
176
+ }, [hideDropzoneOnValue, maxFiles, value.length]);
177
+ return /* @__PURE__ */ jsxRuntime.jsx(
178
+ reactAriaComponents.Provider,
179
+ {
180
+ values: [
181
+ [
182
+ contexts.FileDropzoneStyleContext,
183
+ { slots, classNames, itemClassNames, ...variantProps }
184
+ ],
185
+ [
186
+ contexts.FileDropzoneStateContext,
187
+ {
188
+ isDisabled,
189
+ isReadOnly,
190
+ maxFiles,
191
+ maxFileSize,
192
+ showDropzone,
193
+ files: value,
194
+ handleRemoveFile,
195
+ handleRemoveRejection,
196
+ formatError,
197
+ inputProps,
198
+ triggerFileSelector,
199
+ ...dropzoneState
200
+ }
201
+ ],
202
+ [reactAriaComponents.LabelContext, labelProps],
203
+ [
204
+ reactAriaComponents.GroupContext,
205
+ {
206
+ role: "presentation",
207
+ isInvalid,
208
+ isDisabled: props.isDisabled || false
209
+ }
210
+ ],
211
+ [
212
+ reactAriaComponents.TextContext,
213
+ {
214
+ slots: {
215
+ fileSize: {},
216
+ description: descriptionProps,
217
+ errorMessage: errorMessageProps
218
+ }
219
+ }
220
+ ],
221
+ [reactAriaComponents.FieldErrorContext, { isInvalid, validationErrors, validationDetails }]
222
+ ],
223
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.Group, { className: slots.base({ className: classNames?.base }), children: [
224
+ label && /* @__PURE__ */ jsxRuntime.jsx(field.Label, { size: variantProps.size, children: label }),
225
+ showDropzone && /* @__PURE__ */ jsxRuntime.jsx(FileDropzoneDropzone, {}),
226
+ value.map((file) => {
227
+ if (typeof children === "function") {
228
+ return children({
229
+ file,
230
+ removeFile: () => handleRemoveFile(file.name)
231
+ });
232
+ }
233
+ return /* @__PURE__ */ jsxRuntime.jsx(fileInfo.FileInfo, { imagePreview, file }, file.name);
234
+ }),
235
+ rejections.length >= 1 && rejections.map((rj) => /* @__PURE__ */ jsxRuntime.jsx(fileInfo.FileInfo, { imagePreview, file: rj }, rj.name)),
236
+ fileSizeText && /* @__PURE__ */ jsxRuntime.jsx(
237
+ field.Description,
238
+ {
239
+ size: variantProps.size,
240
+ id: fileSizeTextId,
241
+ slot: "fileSize",
242
+ children: fileSizeText
243
+ }
244
+ ),
245
+ description && /* @__PURE__ */ jsxRuntime.jsx(field.Description, { size: variantProps.size, children: description }),
246
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx(field.FieldError, { size: variantProps.size, children: errorMessage })
247
+ ] })
248
+ }
249
+ );
250
+ };
251
+ const FileDropzoneDropzone = () => {
252
+ const {
253
+ maxFiles,
254
+ getRootProps,
255
+ inputProps,
256
+ triggerFileSelector,
257
+ isDisabled,
258
+ isDragActive
259
+ } = contexts.useFileDropzoneStateContext();
260
+ const { slots, classNames } = contexts.useFileDropzoneStyleContext();
261
+ return /* @__PURE__ */ jsxRuntime.jsxs(
262
+ "div",
263
+ {
264
+ ...getRootProps({
265
+ "aria-disabled": isDisabled,
266
+ className: slots.group({
267
+ className: classNames?.group
268
+ })
269
+ }),
270
+ tabIndex: isDisabled ? void 0 : 0,
271
+ onClick: triggerFileSelector,
272
+ onKeyDown: (e) => {
273
+ if (e.key === "Enter" || e.key === " ") {
274
+ e.preventDefault();
275
+ triggerFileSelector();
276
+ }
277
+ },
278
+ children: [
279
+ /* @__PURE__ */ jsxRuntime.jsx("input", { ...inputProps }),
280
+ /* @__PURE__ */ jsxRuntime.jsxs(
281
+ "div",
282
+ {
283
+ "data-dragging": ouiTheme.dataAttr(isDragActive),
284
+ className: slots.dropzone({ className: classNames?.dropzone }),
285
+ children: [
286
+ /* @__PURE__ */ jsxRuntime.jsx(upload.default, { className: slots.icon({ className: classNames?.icon }) }),
287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slots.text({ className: classNames?.text }), children: [
288
+ /* @__PURE__ */ jsxRuntime.jsxs(
289
+ "span",
290
+ {
291
+ className: slots.dropzoneHighlight({
292
+ className: classNames?.dropzoneHighlight
293
+ }),
294
+ children: [
295
+ "Choose ",
296
+ maxFiles === 1 ? `file` : `files`
297
+ ]
298
+ }
299
+ ),
300
+ " ",
301
+ "or drag and drop here"
302
+ ] })
303
+ ]
304
+ }
305
+ )
306
+ ]
307
+ }
308
+ );
309
+ };
310
+
311
+ exports.FileDropzone = FileDropzone;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ "use client";
3
+ 'use strict';
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var $670gB$react = require('react');
7
+ var ouiTheme = require('@opengovsg/oui-theme');
8
+ var contexts = require('./contexts.cjs');
9
+ var utils = require('./utils.cjs');
10
+ var trash2 = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/trash-2.cjs');
11
+ var button = require('../button/button.cjs');
12
+
13
+ const FileInfo = ({ file, imagePreview, classNames }) => {
14
+ const {
15
+ handleRemoveFile,
16
+ handleRemoveRejection,
17
+ formatError,
18
+ isDisabled,
19
+ isReadOnly
20
+ } = contexts.useFileDropzoneStateContext();
21
+ const { size, variant, itemClassNames } = contexts.useFileDropzoneStyleContext();
22
+ const readableFileSize = utils.formatBytes(file.size, 2);
23
+ const styles = ouiTheme.fileInfoDropzoneStyles({
24
+ size,
25
+ variant,
26
+ imagePreview: imagePreview ?? void 0
27
+ });
28
+ const [previewSrc, setPreviewSrc] = $670gB$react.useState("");
29
+ $670gB$react.useEffect(() => {
30
+ let objectUrl = "";
31
+ if (file.type.startsWith("image/")) {
32
+ objectUrl = URL.createObjectURL(file);
33
+ setPreviewSrc(objectUrl);
34
+ }
35
+ return () => URL.revokeObjectURL(objectUrl);
36
+ }, [file]);
37
+ return /* @__PURE__ */ jsxRuntime.jsxs(
38
+ "div",
39
+ {
40
+ className: styles.base({
41
+ className: ouiTheme.cn(itemClassNames?.base, classNames?.base)
42
+ }),
43
+ children: [
44
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sr-only", children: [
45
+ "File attached: ",
46
+ file.name,
47
+ " with file size of ",
48
+ readableFileSize
49
+ ] }),
50
+ imagePreview && previewSrc && /* @__PURE__ */ jsxRuntime.jsx(
51
+ "div",
52
+ {
53
+ className: styles.imageContainer({
54
+ className: ouiTheme.cn(
55
+ itemClassNames?.imageContainer,
56
+ classNames?.imageContainer
57
+ )
58
+ }),
59
+ children: /* @__PURE__ */ jsxRuntime.jsx(
60
+ "img",
61
+ {
62
+ src: previewSrc,
63
+ alt: `Image preview of uploaded file: ${file.name}`,
64
+ className: styles.image({
65
+ className: ouiTheme.cn(itemClassNames?.image, classNames?.image)
66
+ })
67
+ }
68
+ )
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsxRuntime.jsxs(
72
+ "div",
73
+ {
74
+ className: styles.container({
75
+ className: ouiTheme.cn(itemClassNames?.container, classNames?.container)
76
+ }),
77
+ children: [
78
+ /* @__PURE__ */ jsxRuntime.jsxs(
79
+ "div",
80
+ {
81
+ className: styles.textContainer({
82
+ className: ouiTheme.cn(
83
+ itemClassNames?.textContainer,
84
+ classNames?.textContainer
85
+ )
86
+ }),
87
+ children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx(
89
+ "p",
90
+ {
91
+ title: file.name,
92
+ className: styles.name({
93
+ className: ouiTheme.cn(itemClassNames?.name, classNames?.name)
94
+ }),
95
+ children: file.name
96
+ }
97
+ ),
98
+ /* @__PURE__ */ jsxRuntime.jsx(
99
+ "p",
100
+ {
101
+ className: styles.size({
102
+ className: ouiTheme.cn(itemClassNames?.size, classNames?.size)
103
+ }),
104
+ children: readableFileSize
105
+ }
106
+ ),
107
+ file.errors?.length && /* @__PURE__ */ jsxRuntime.jsx(
108
+ "p",
109
+ {
110
+ className: styles.error({
111
+ className: ouiTheme.cn(itemClassNames?.error, classNames?.error)
112
+ }),
113
+ children: file.errors.map(formatError).join(", ")
114
+ }
115
+ )
116
+ ]
117
+ }
118
+ ),
119
+ /* @__PURE__ */ jsxRuntime.jsx(
120
+ button.Button,
121
+ {
122
+ isDisabled: isDisabled || isReadOnly,
123
+ isIconOnly: !file.errors?.length,
124
+ size: size === "md" ? "md" : "xs",
125
+ variant: "clear",
126
+ color: file.errors?.length ? "main" : "critical",
127
+ "aria-label": "Remove file",
128
+ className: styles.actionButton({
129
+ className: ouiTheme.cn(
130
+ itemClassNames?.actionButton,
131
+ classNames?.actionButton
132
+ )
133
+ }),
134
+ onPress: () => file.errors?.length ? handleRemoveRejection(file.name) : handleRemoveFile(file.name),
135
+ children: file.errors?.length ? "Dismiss" : /* @__PURE__ */ jsxRuntime.jsx(trash2.default, {})
136
+ }
137
+ )
138
+ ]
139
+ }
140
+ )
141
+ ]
142
+ }
143
+ );
144
+ };
145
+
146
+ exports.FileInfo = FileInfo;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var fileDropzone = require('./file-dropzone.cjs');
5
+ var fileInfo = require('./file-info.cjs');
6
+ var utils = require('./utils.cjs');
7
+
8
+
9
+
10
+ exports.FileDropzone = fileDropzone.FileDropzone;
11
+ exports.FileInfo = fileInfo.FileInfo;
12
+ exports.formatBytes = utils.formatBytes;
13
+ exports.formatErrorMessage = utils.formatErrorMessage;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ 'use strict';
3
+
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var reactDropzone = require('react-dropzone');
5
+
6
+ const formatBytes = (bytes, decimals = 2, size) => {
7
+ const k = 1e3;
8
+ const dm = decimals < 0 ? 0 : decimals;
9
+ const sizes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
10
+ if (bytes === 0 || bytes === void 0)
11
+ return size !== void 0 ? `0 ${size}` : "0 bytes";
12
+ const i = size !== void 0 ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k));
13
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
14
+ };
15
+ const formatErrorMessage = (error, config) => {
16
+ const { maxFileSize, minFileSize, maxFiles } = config;
17
+ switch (error.code) {
18
+ case reactDropzone.ErrorCode.FileTooLarge:
19
+ return `You have exceeded the size limit, please upload a file below ${formatBytes(maxFileSize, 2)}`;
20
+ case reactDropzone.ErrorCode.FileTooSmall:
21
+ return `Please upload a file above ${formatBytes(minFileSize, 2)}`;
22
+ case reactDropzone.ErrorCode.TooManyFiles:
23
+ return `Maximum number of files allowed is ${maxFiles}.`;
24
+ default: {
25
+ return error.message;
26
+ }
27
+ }
28
+ };
29
+
30
+ exports.formatBytes = formatBytes;
31
+ exports.formatErrorMessage = formatErrorMessage;