@opengovsg/oui 0.0.0-snapshot-20251002073151 → 0.0.0-snapshot-20251201075851

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 (141) hide show
  1. package/dist/cjs/badge/badge.cjs +4 -4
  2. package/dist/cjs/badge/use-badge.cjs +6 -6
  3. package/dist/cjs/banner/banner.cjs +10 -5
  4. package/dist/cjs/button/button.cjs +3 -3
  5. package/dist/cjs/calendar/calendar-bottom-content.cjs +3 -3
  6. package/dist/cjs/calendar/calendar-header.cjs +2 -2
  7. package/dist/cjs/calendar/calendar-month-day-selector.cjs +4 -3
  8. package/dist/cjs/calendar/calendar.cjs +4 -4
  9. package/dist/cjs/calendar/hooks/use-calendar-selectors.cjs +4 -4
  10. package/dist/cjs/calendar/utils.cjs +3 -3
  11. package/dist/cjs/combo-box/combo-box-fuzzy.cjs +6 -6
  12. package/dist/cjs/combo-box/combo-box-item.cjs +2 -2
  13. package/dist/cjs/combo-box/combo-box.cjs +3 -3
  14. package/dist/cjs/date-field/date-field.cjs +15 -6
  15. package/dist/cjs/date-picker/date-picker.cjs +36 -11
  16. package/dist/cjs/date-range-picker/date-range-picker.cjs +3 -3
  17. package/dist/cjs/field/field.cjs +20 -6
  18. package/dist/cjs/field/index.cjs +1 -0
  19. package/dist/cjs/file-dropzone/contexts.cjs +18 -0
  20. package/dist/cjs/file-dropzone/file-dropzone.cjs +311 -0
  21. package/dist/cjs/file-dropzone/file-info.cjs +146 -0
  22. package/dist/cjs/file-dropzone/index.cjs +13 -0
  23. package/dist/cjs/file-dropzone/types.cjs +3 -0
  24. package/dist/cjs/file-dropzone/utils.cjs +31 -0
  25. package/dist/cjs/govt-banner/govt-banner.cjs +3 -3
  26. package/dist/cjs/hooks/use-callback-ref.cjs +4 -4
  27. package/dist/cjs/hooks/use-controllable-state.cjs +2 -2
  28. package/dist/cjs/index.cjs +10 -0
  29. package/dist/cjs/input/input.cjs +2 -2
  30. package/dist/cjs/menu/menu.cjs +6 -6
  31. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/Icon.cjs +4 -4
  32. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/createLucideIcon.cjs +3 -3
  33. 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
  34. 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
  35. 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
  36. package/dist/cjs/number-field/index.cjs +8 -0
  37. package/dist/cjs/number-field/number-field.cjs +136 -0
  38. package/dist/cjs/pagination/hooks/use-pagination.cjs +7 -7
  39. package/dist/cjs/pagination/pagination.cjs +6 -6
  40. package/dist/cjs/pagination/use-pagination-item.cjs +7 -8
  41. package/dist/cjs/pagination/use-pagination.cjs +8 -8
  42. package/dist/cjs/range-calendar/range-calendar.cjs +6 -6
  43. package/dist/cjs/ripple/use-ripple.cjs +4 -4
  44. package/dist/cjs/select/select.cjs +2 -2
  45. package/dist/cjs/spinner/use-spinner.cjs +3 -3
  46. package/dist/cjs/system/react-utils/context.cjs +3 -3
  47. package/dist/cjs/system/react-utils/refs.cjs +3 -3
  48. package/dist/cjs/system/utils.cjs +3 -3
  49. package/dist/cjs/tabs/tabs.cjs +2 -2
  50. package/dist/cjs/tag-field/tag-field-item.cjs +2 -2
  51. package/dist/cjs/tag-field/tag-field-list.cjs +4 -4
  52. package/dist/cjs/tag-field/tag-field-root.cjs +14 -14
  53. package/dist/cjs/tag-field/tag-field-state-context.cjs +2 -2
  54. package/dist/cjs/tag-field/tag-field-tag-list.cjs +3 -3
  55. package/dist/cjs/tag-field/tag-field-trigger.cjs +2 -2
  56. package/dist/cjs/tag-field/tag-field.cjs +2 -2
  57. package/dist/cjs/tag-field/use-tag-field-state.cjs +6 -6
  58. package/dist/cjs/tag-field/use-tag-field.cjs +4 -4
  59. package/dist/cjs/text-area/text-area.cjs +2 -2
  60. package/dist/cjs/toggle/toggle.cjs +3 -3
  61. package/dist/esm/banner/banner.js +7 -2
  62. package/dist/esm/calendar/calendar-month-day-selector.js +2 -1
  63. package/dist/esm/date-field/date-field.js +12 -3
  64. package/dist/esm/date-picker/date-picker.js +34 -9
  65. package/dist/esm/field/field.js +20 -7
  66. package/dist/esm/field/index.js +1 -1
  67. package/dist/esm/file-dropzone/contexts.js +13 -0
  68. package/dist/esm/file-dropzone/file-dropzone.js +309 -0
  69. package/dist/esm/file-dropzone/file-info.js +144 -0
  70. package/dist/esm/file-dropzone/index.js +4 -0
  71. package/dist/esm/file-dropzone/types.js +1 -0
  72. package/dist/esm/file-dropzone/utils.js +28 -0
  73. package/dist/esm/index.js +5 -1
  74. 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
  75. 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
  76. 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
  77. package/dist/esm/number-field/index.js +2 -0
  78. package/dist/esm/number-field/number-field.js +134 -0
  79. package/dist/esm/pagination/use-pagination-item.js +5 -6
  80. package/dist/types/banner/banner.d.ts +1 -1
  81. package/dist/types/banner/banner.d.ts.map +1 -1
  82. package/dist/types/calendar/calendar-month-day-selector.d.ts.map +1 -1
  83. package/dist/types/date-field/date-field.d.ts +1 -0
  84. package/dist/types/date-field/date-field.d.ts.map +1 -1
  85. package/dist/types/date-picker/date-picker.d.ts +5 -2
  86. package/dist/types/date-picker/date-picker.d.ts.map +1 -1
  87. package/dist/types/field/field.d.ts +4 -1
  88. package/dist/types/field/field.d.ts.map +1 -1
  89. package/dist/types/file-dropzone/contexts.d.ts +4 -0
  90. package/dist/types/file-dropzone/contexts.d.ts.map +1 -0
  91. package/dist/types/file-dropzone/file-dropzone.d.ts +82 -0
  92. package/dist/types/file-dropzone/file-dropzone.d.ts.map +1 -0
  93. package/dist/types/file-dropzone/file-info.d.ts +9 -0
  94. package/dist/types/file-dropzone/file-info.d.ts.map +1 -0
  95. package/dist/types/file-dropzone/index.d.ts +7 -0
  96. package/dist/types/file-dropzone/index.d.ts.map +1 -0
  97. package/dist/types/file-dropzone/types.d.ts +24 -0
  98. package/dist/types/file-dropzone/types.d.ts.map +1 -0
  99. package/dist/types/file-dropzone/utils.d.ts +8 -0
  100. package/dist/types/file-dropzone/utils.d.ts.map +1 -0
  101. package/dist/types/index.d.mts +2 -0
  102. package/dist/types/index.d.ts +2 -0
  103. package/dist/types/index.d.ts.map +1 -1
  104. package/dist/types/menu/menu.d.ts.map +1 -1
  105. package/dist/types/number-field/index.d.ts +3 -0
  106. package/dist/types/number-field/index.d.ts.map +1 -0
  107. package/dist/types/number-field/number-field.d.ts +24 -0
  108. package/dist/types/number-field/number-field.d.ts.map +1 -0
  109. package/package.json +12 -8
  110. package/dist/cjs/node_modules/.pnpm/@react-aria_focus@3.20.5_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/focus/dist/useFocusRing.cjs +0 -45
  111. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/context.cjs +0 -21
  112. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/textSelection.cjs +0 -72
  113. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocus.cjs +0 -60
  114. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocusVisible.cjs +0 -210
  115. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocusWithin.cjs +0 -100
  116. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useHover.cjs +0 -152
  117. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/usePress.cjs +0 -676
  118. package/dist/cjs/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/utils.cjs +0 -160
  119. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_check_private_redeclaration.cjs +0 -9
  120. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_apply_descriptor_get.cjs +0 -9
  121. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_apply_descriptor_set.cjs +0 -16
  122. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_extract_field_descriptor.cjs +0 -9
  123. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_get.cjs +0 -11
  124. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_init.cjs +0 -10
  125. package/dist/cjs/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_set.cjs +0 -12
  126. package/dist/esm/node_modules/.pnpm/@react-aria_focus@3.20.5_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/focus/dist/useFocusRing.js +0 -43
  127. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/context.js +0 -19
  128. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/textSelection.js +0 -69
  129. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocus.js +0 -58
  130. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocusVisible.js +0 -205
  131. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useFocusWithin.js +0 -98
  132. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/useHover.js +0 -150
  133. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/usePress.js +0 -674
  134. package/dist/esm/node_modules/.pnpm/@react-aria_interactions@3.25.3_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/@react-aria/interactions/dist/utils.js +0 -155
  135. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_check_private_redeclaration.js +0 -7
  136. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_apply_descriptor_get.js +0 -7
  137. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_apply_descriptor_set.js +0 -14
  138. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_extract_field_descriptor.js +0 -7
  139. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_get.js +0 -9
  140. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_init.js +0 -8
  141. package/dist/esm/node_modules/.pnpm/@swc_helpers@0.5.17/node_modules/@swc/helpers/esm/_class_private_field_set.js +0 -10
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+ "use client";
3
+ 'use strict';
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var 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 = react.useCallback(
69
+ (error) => utils$1.formatErrorMessage(error, {
70
+ maxFileSize,
71
+ minFileSize,
72
+ maxFiles
73
+ }),
74
+ [maxFileSize, maxFiles, minFileSize]
75
+ );
76
+ const onDrop = 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 = react.useCallback(
95
+ (fileName) => {
96
+ setValue((files) => files.filter((file) => file.name !== fileName));
97
+ },
98
+ [setValue]
99
+ );
100
+ const handleRemoveRejection = 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 = 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 = react.useCallback(() => {
146
+ if (isDisabled || isReadOnly) return;
147
+ dropzoneState.inputRef.current?.click();
148
+ }, [dropzoneState, isDisabled, isReadOnly]);
149
+ 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 = 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 = 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 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] = react.useState("");
29
+ 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;
@@ -3,7 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
- var $670gB$react = require('react');
6
+ var react = require('react');
7
7
  var reactAria = require('react-aria');
8
8
  var reactStately = require('react-stately');
9
9
  var ouiTheme = require('@opengovsg/oui-theme');
@@ -18,8 +18,8 @@ function GovtBanner({
18
18
  ...props
19
19
  }) {
20
20
  const state = reactStately.useDisclosureState(props);
21
- const panelRef = $670gB$react.useRef(null);
22
- const triggerRef = $670gB$react.useRef(null);
21
+ const panelRef = react.useRef(null);
22
+ const triggerRef = react.useRef(null);
23
23
  const { buttonProps: triggerProps, panelProps } = reactAria.useDisclosure(
24
24
  props,
25
25
  state,
@@ -2,16 +2,16 @@
2
2
  "use client";
3
3
  'use strict';
4
4
 
5
- var $670gB$react = require('react');
5
+ var react = require('react');
6
6
 
7
7
  function useCallbackRef(callback, deps = []) {
8
- const callbackRef = $670gB$react.useRef(() => {
8
+ const callbackRef = react.useRef(() => {
9
9
  throw new Error("Cannot call an event handler while rendering.");
10
10
  });
11
- $670gB$react.useInsertionEffect(() => {
11
+ react.useInsertionEffect(() => {
12
12
  callbackRef.current = callback;
13
13
  });
14
- return $670gB$react.useCallback((...args) => callbackRef.current?.(...args), deps);
14
+ return react.useCallback((...args) => callbackRef.current?.(...args), deps);
15
15
  }
16
16
 
17
17
  exports.useCallbackRef = useCallbackRef;
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  'use strict';
4
4
 
5
- var $670gB$react = require('react');
5
+ var react = require('react');
6
6
  var useCallbackRef = require('./use-callback-ref.cjs');
7
7
 
8
8
  function useControllableState(props) {
@@ -14,7 +14,7 @@ function useControllableState(props) {
14
14
  } = props;
15
15
  const onChangeProp = useCallbackRef.useCallbackRef(onChange);
16
16
  const shouldUpdateProp = useCallbackRef.useCallbackRef(shouldUpdate);
17
- const [uncontrolledState, setUncontrolledState] = $670gB$react.useState(defaultValue);
17
+ const [uncontrolledState, setUncontrolledState] = react.useState(defaultValue);
18
18
  const controlled = valueProp !== void 0;
19
19
  const value = controlled ? valueProp : uncontrolledState;
20
20
  const setValue = useCallbackRef.useCallbackRef(
@@ -44,6 +44,10 @@ var pagination = require('./pagination/pagination.cjs');
44
44
  var paginationCursor = require('./pagination/pagination-cursor.cjs');
45
45
  var paginationItem = require('./pagination/pagination-item.cjs');
46
46
  var usePagination$1 = require('./pagination/use-pagination.cjs');
47
+ var fileDropzone = require('./file-dropzone/file-dropzone.cjs');
48
+ var fileInfo = require('./file-dropzone/file-info.cjs');
49
+ var utils$1 = require('./file-dropzone/utils.cjs');
50
+ var numberField = require('./number-field/number-field.cjs');
47
51
 
48
52
 
49
53
 
@@ -60,6 +64,7 @@ exports.Input = input.Input;
60
64
  exports.TextField = textField.TextField;
61
65
  exports.Description = field.Description;
62
66
  exports.FieldError = field.FieldError;
67
+ exports.FieldErrorIcon = field.FieldErrorIcon;
63
68
  exports.FieldGroup = field.FieldGroup;
64
69
  exports.Label = field.Label;
65
70
  exports.TextArea = textArea.TextArea;
@@ -122,3 +127,8 @@ exports.PaginationCursor = paginationCursor.PaginationCursor;
122
127
  exports.PaginationItem = paginationItem.PaginationItem;
123
128
  exports.CURSOR_TRANSITION_TIMEOUT = usePagination$1.CURSOR_TRANSITION_TIMEOUT;
124
129
  exports.usePagination = usePagination$1.usePagination;
130
+ exports.FileDropzone = fileDropzone.FileDropzone;
131
+ exports.FileInfo = fileInfo.FileInfo;
132
+ exports.formatBytes = utils$1.formatBytes;
133
+ exports.formatErrorMessage = utils$1.formatErrorMessage;
134
+ exports.NumberField = numberField.NumberField;
@@ -3,11 +3,11 @@
3
3
  'use strict';
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
- var $670gB$react = require('react');
6
+ var react = require('react');
7
7
  var reactAriaComponents = require('react-aria-components');
8
8
  var ouiTheme = require('@opengovsg/oui-theme');
9
9
 
10
- const Input = $670gB$react.forwardRef(
10
+ const Input = react.forwardRef(
11
11
  ({ size, variant, isDisabled, ...props }, ref) => {
12
12
  return /* @__PURE__ */ jsxRuntime.jsx(
13
13
  reactAriaComponents.Input,
@@ -3,7 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
- var $670gB$react = require('react');
6
+ var react = require('react');
7
7
  var reactAriaComponents = require('react-aria-components');
8
8
  var ouiTheme = require('@opengovsg/oui-theme');
9
9
  var utils = require('../system/utils.cjs');
@@ -51,7 +51,7 @@ function MenuInner(originalProps, ref) {
51
51
  ) });
52
52
  }
53
53
  const Menu = utils.forwardRefGeneric(MenuInner);
54
- const MenuItem = $670gB$react.forwardRef(function MenuItem2(originalProps, ref) {
54
+ const MenuItem = react.forwardRef(function MenuItem2(originalProps, ref) {
55
55
  [originalProps, ref] = reactAriaComponents.useContextProps(
56
56
  originalProps,
57
57
  ref,
@@ -70,7 +70,7 @@ const MenuItem = $670gB$react.forwardRef(function MenuItem2(originalProps, ref)
70
70
  variantProps
71
71
  ] = utils.mapPropsVariants(originalProps, ouiTheme.listBoxItemStyles.variantKeys);
72
72
  const styles = ouiTheme.menuItemStyles(variantProps);
73
- const multipleSelectionIcon = $670gB$react.useMemo(() => {
73
+ const multipleSelectionIcon = react.useMemo(() => {
74
74
  if (multipleSelectionIconProp !== void 0) {
75
75
  return multipleSelectionIconProp;
76
76
  }
@@ -82,7 +82,7 @@ const MenuItem = $670gB$react.forwardRef(function MenuItem2(originalProps, ref)
82
82
  }
83
83
  );
84
84
  }, [classNames?.icon, multipleSelectionIconProp, styles]);
85
- const singleSelectionIcon = $670gB$react.useMemo(() => {
85
+ const singleSelectionIcon = react.useMemo(() => {
86
86
  if (singleSelectionIconProp !== void 0) {
87
87
  return singleSelectionIconProp;
88
88
  }
@@ -94,7 +94,7 @@ const MenuItem = $670gB$react.forwardRef(function MenuItem2(originalProps, ref)
94
94
  }
95
95
  );
96
96
  }, [classNames?.icon, singleSelectionIconProp, styles]);
97
- const showIconContainer = $670gB$react.useCallback(
97
+ const showIconContainer = react.useCallback(
98
98
  (selectionMode) => {
99
99
  switch (selectionMode) {
100
100
  case "none":
@@ -107,7 +107,7 @@ const MenuItem = $670gB$react.forwardRef(function MenuItem2(originalProps, ref)
107
107
  },
108
108
  [multipleSelectionIcon, singleSelectionIcon]
109
109
  );
110
- const defaultTextValue = $670gB$react.useMemo(() => {
110
+ const defaultTextValue = react.useMemo(() => {
111
111
  if (props.textValue) {
112
112
  return props.textValue;
113
113
  }