@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.24c8270

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 (50) hide show
  1. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  2. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +5 -10
  3. package/dist/components/ErrorBoundary.d.ts +1 -1
  4. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
  5. package/dist/form/components/ErrorFocus.d.ts +1 -1
  6. package/dist/index.es.js +302 -227
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.umd.js +300 -225
  9. package/dist/index.umd.js.map +1 -1
  10. package/dist/internal/useRestoreScroll.d.ts +1 -1
  11. package/dist/types/analytics.d.ts +1 -1
  12. package/dist/types/collections.d.ts +8 -0
  13. package/dist/types/plugins.d.ts +16 -0
  14. package/dist/util/entities.d.ts +1 -1
  15. package/dist/util/resolutions.d.ts +2 -2
  16. package/package.json +9 -9
  17. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  18. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  19. package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
  20. package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
  21. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +23 -3
  22. package/src/components/EntityCollectionView/EntityCollectionView.tsx +50 -16
  23. package/src/components/EntityCollectionView/ViewModeToggle.tsx +27 -30
  24. package/src/components/VirtualTable/VirtualTable.tsx +116 -113
  25. package/src/components/VirtualTable/VirtualTableHeader.tsx +42 -42
  26. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
  27. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
  28. package/src/components/common/useDataSourceTableController.tsx +21 -4
  29. package/src/core/DefaultAppBar.tsx +1 -1
  30. package/src/core/EntityEditView.tsx +1 -1
  31. package/src/core/EntitySidePanel.tsx +28 -26
  32. package/src/core/field_configs.tsx +14 -9
  33. package/src/form/EntityForm.tsx +69 -60
  34. package/src/form/PropertyFieldBinding.tsx +3 -3
  35. package/src/form/components/ErrorFocus.tsx +3 -3
  36. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  37. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  38. package/src/hooks/useBuildNavigationController.tsx +29 -9
  39. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  40. package/src/internal/useBuildDataSource.ts +1 -2
  41. package/src/internal/useBuildSideEntityController.tsx +22 -20
  42. package/src/preview/PropertyPreview.tsx +1 -0
  43. package/src/types/analytics.ts +10 -0
  44. package/src/types/collections.ts +9 -0
  45. package/src/types/plugins.tsx +18 -0
  46. package/src/util/entities.ts +1 -1
  47. package/src/util/join_collections.ts +10 -8
  48. package/src/util/previews.ts +2 -2
  49. package/src/util/property_utils.tsx +1 -1
  50. package/src/util/resolutions.ts +5 -3
@@ -105,7 +105,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
105
105
  }, [collection?.name, setBlocked, setBlockedNavigationMessage]);
106
106
 
107
107
  if (!props || !collection) {
108
- return <div className={"w-full"}/>;
108
+ return <div className={"w-full"} />;
109
109
  }
110
110
 
111
111
  return (
@@ -120,32 +120,34 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
120
120
  onValuesModified={onValuesModified}
121
121
  onSaved={onUpdate}
122
122
  barActions={({
123
- status,
124
- values
125
- }) => <>
126
- <IconButton
127
- className="self-center"
128
- onClick={onClose}>
129
- <CloseIcon size={"small"}/>
130
- </IconButton>
131
- {allowFullScreen && <IconButton
132
- className="self-center"
133
- onClick={() => {
134
- const key = (status === "new" || status === "copy") ? path + "#new" : path + "/" + entityId;
135
- saveEntityToMemoryCache(key, values);
136
- if (entityId)
137
- navigate(location.pathname);
138
- else
139
- navigate(location.pathname + "#new");
140
- }}>
141
- <OpenInFullIcon size={"small"}/>
142
- </IconButton>}
143
- </>}
123
+ status,
124
+ values
125
+ }) => <>
126
+ <IconButton
127
+ className="self-center"
128
+ size={"smallest"}
129
+ onClick={onClose}>
130
+ <CloseIcon size={"smallest"} />
131
+ </IconButton>
132
+ {allowFullScreen && <IconButton
133
+ className="self-center"
134
+ size={"smallest"}
135
+ onClick={() => {
136
+ const key = (status === "new" || status === "copy") ? path + "#new" : path + "/" + entityId;
137
+ saveEntityToMemoryCache(key, values);
138
+ if (entityId)
139
+ navigate(location.pathname + location.search);
140
+ else
141
+ navigate(location.pathname + location.search + "#new");
142
+ }}>
143
+ <OpenInFullIcon size={"smallest"} />
144
+ </IconButton>}
145
+ </>}
144
146
  onTabChange={({
145
- entityId,
146
- selectedTab,
147
- collection,
148
- }) => {
147
+ entityId,
148
+ selectedTab,
149
+ collection,
150
+ }) => {
149
151
  sideEntityController.replace({
150
152
  path,
151
153
  entityId,
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { ArrayProperty, FieldProps, Property, PropertyConfig, ResolvedProperty } from "../types";
3
+ import { ArrayProperty, FieldProps, NumberProperty, Property, PropertyConfig, ResolvedProperty, StringProperty } from "../types";
4
4
  import {
5
5
  ArrayCustomShapedFieldBinding,
6
6
  ArrayOfReferencesFieldBinding,
@@ -397,14 +397,19 @@ export function getDefaultFieldId(property: Property | ResolvedProperty) {
397
397
  return "custom_array";
398
398
  } else if (isPropertyBuilder(of)) {
399
399
  return "repeat";
400
- } else if (of?.dataType === "string" && of.enumValues) {
401
- return "multi_select";
402
- } else if (of?.dataType === "number" && of.enumValues) {
403
- return "multi_number_select";
404
- } else if (of?.dataType === "string" && of.storage) {
405
- return "multi_file_upload";
406
- } else if (of?.dataType === "reference") {
407
- return "multi_references";
400
+ } else if (of) {
401
+ const ofProperty = of as Property;
402
+ if (ofProperty.dataType === "string" && (ofProperty as StringProperty).enumValues) {
403
+ return "multi_select";
404
+ } else if (ofProperty.dataType === "number" && (ofProperty as NumberProperty).enumValues) {
405
+ return "multi_number_select";
406
+ } else if (ofProperty.dataType === "string" && (ofProperty as StringProperty).storage) {
407
+ return "multi_file_upload";
408
+ } else if (ofProperty.dataType === "reference") {
409
+ return "multi_references";
410
+ } else {
411
+ return "repeat";
412
+ }
408
413
  } else {
409
414
  return "repeat";
410
415
  }
@@ -181,30 +181,30 @@ export function getChanges<T extends object>(source: Partial<T>, comparison: Par
181
181
  }
182
182
 
183
183
  export function EntityForm<M extends Record<string, any>>({
184
- path,
185
- fullIdPath,
186
- entityId: entityIdProp,
187
- collection,
188
- onValuesModified,
189
- onIdChange,
190
- onSaved,
191
- entity,
192
- initialDirtyValues,
193
- onFormContextReady,
194
- forceActionsAtTheBottom,
195
- initialStatus,
196
- className,
197
- onStatusChange,
198
- onEntityChange,
199
- openEntityMode = "full_screen",
200
- formex: formexProp,
201
- disabled: disabledProp,
202
- Builder,
203
- EntityFormActionsComponent = EntityFormActions,
204
- showDefaultActions = true,
205
- showEntityPath = true,
206
- children
207
- }: EntityFormProps<M>) {
184
+ path,
185
+ fullIdPath,
186
+ entityId: entityIdProp,
187
+ collection,
188
+ onValuesModified,
189
+ onIdChange,
190
+ onSaved,
191
+ entity,
192
+ initialDirtyValues,
193
+ onFormContextReady,
194
+ forceActionsAtTheBottom,
195
+ initialStatus,
196
+ className,
197
+ onStatusChange,
198
+ onEntityChange,
199
+ openEntityMode = "full_screen",
200
+ formex: formexProp,
201
+ disabled: disabledProp,
202
+ Builder,
203
+ EntityFormActionsComponent = EntityFormActions,
204
+ showDefaultActions = true,
205
+ showEntityPath = true,
206
+ children
207
+ }: EntityFormProps<M>) {
208
208
 
209
209
  if (collection.customId && collection.formAutoSave) {
210
210
  console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
@@ -455,12 +455,12 @@ export function EntityForm<M extends Record<string, any>>({
455
455
  }, [entityId, path, snackbarController]);
456
456
 
457
457
  const saveEntity = ({
458
- values,
459
- previousValues,
460
- entityId,
461
- collection,
462
- path
463
- }: {
458
+ values,
459
+ previousValues,
460
+ entityId,
461
+ collection,
462
+ path
463
+ }: {
464
464
  collection: EntityCollection<M>,
465
465
  path: string,
466
466
  entityId: string | undefined,
@@ -493,13 +493,13 @@ export function EntityForm<M extends Record<string, any>>({
493
493
  };
494
494
 
495
495
  const onSaveEntityRequest = async ({
496
- collection,
497
- path,
498
- entityId,
499
- values,
500
- previousValues,
501
- autoSave
502
- }: EntityFormSaveParams<M>): Promise<void> => {
496
+ collection,
497
+ path,
498
+ entityId,
499
+ values,
500
+ previousValues,
501
+ autoSave
502
+ }: EntityFormSaveParams<M>): Promise<void> => {
503
503
  if (!status)
504
504
  return;
505
505
  if (autoSave) {
@@ -567,6 +567,7 @@ export function EntityForm<M extends Record<string, any>>({
567
567
  }, [snackbarController]);
568
568
 
569
569
  const pluginActions: React.ReactNode[] = [];
570
+ const pluginBeforeTitle: React.ReactNode[] = [];
570
571
  const plugins = customizationController.plugins;
571
572
 
572
573
  const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
@@ -590,6 +591,12 @@ export function EntityForm<M extends Record<string, any>>({
590
591
  key={`actions_${plugin.key}`} {...actionProps} />
591
592
  : null
592
593
  )).filter(Boolean));
594
+ pluginBeforeTitle.push(...plugins.map((plugin) => (
595
+ plugin.form?.BeforeTitle
596
+ ? <plugin.form.BeforeTitle
597
+ key={`before_title_${plugin.key}`} {...actionProps} />
598
+ : null
599
+ )).filter(Boolean));
593
600
  }
594
601
 
595
602
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
@@ -631,17 +638,17 @@ export function EntityForm<M extends Record<string, any>>({
631
638
  const modified = formex.dirty;
632
639
 
633
640
  const uniqueFieldValidator: CustomFieldValidator = useCallback(({
634
- name,
635
- value
636
- }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
641
+ name,
642
+ value
643
+ }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
637
644
  [dataSource, path, entityId]);
638
645
 
639
646
  const validationSchema = useMemo(() => entityId
640
- ? getYupEntitySchema(
641
- entityId,
642
- resolvedCollection.properties,
643
- uniqueFieldValidator)
644
- : undefined,
647
+ ? getYupEntitySchema(
648
+ entityId,
649
+ resolvedCollection.properties,
650
+ uniqueFieldValidator)
651
+ : undefined,
645
652
  [entityId, resolvedCollection.properties, uniqueFieldValidator]);
646
653
 
647
654
  useOnAutoSave(autoSave, formex, lastSavedValues, save);
@@ -699,8 +706,8 @@ export function EntityForm<M extends Record<string, any>>({
699
706
 
700
707
  return (
701
708
  <FormEntry propertyKey={key}
702
- widthPercentage={widthPercentage}
703
- key={`field_${key}`}>
709
+ widthPercentage={widthPercentage}
710
+ key={`field_${key}`}>
704
711
  <PropertyFieldBinding {...cmsFormFieldProps} />
705
712
  </FormEntry>
706
713
  );
@@ -713,7 +720,7 @@ export function EntityForm<M extends Record<string, any>>({
713
720
  throw new Error("When using additional fields you need to provide a Builder or a value");
714
721
  }
715
722
  const child = Builder
716
- ? <Builder entity={entity} context={context}/>
723
+ ? <Builder entity={entity} context={context} />
717
724
  : <div className={"w-full"}>
718
725
  {additionalField.value?.({
719
726
  entity,
@@ -725,9 +732,9 @@ export function EntityForm<M extends Record<string, any>>({
725
732
  <div key={`additional_${key}`} className={"w-full"}>
726
733
  <LabelWithIconAndTooltip
727
734
  propertyKey={key}
728
- icon={<NotesIcon size={"small"}/>}
735
+ icon={<NotesIcon size={"small"} />}
729
736
  title={additionalField.name}
730
- className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
737
+ className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
731
738
  <div
732
739
  className={cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
733
740
  <ErrorBoundary>
@@ -749,6 +756,8 @@ export function EntityForm<M extends Record<string, any>>({
749
756
 
750
757
  const formView = <ErrorBoundary>
751
758
  <>
759
+ {pluginBeforeTitle}
760
+
752
761
  {!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
753
762
  <Typography
754
763
  className={"my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : "")}
@@ -777,22 +786,22 @@ export function EntityForm<M extends Record<string, any>>({
777
786
 
778
787
  {!Builder && !collection.hideIdFromForm &&
779
788
  <CustomIdField customId={collection.customId}
780
- entityId={entityId}
781
- status={status}
782
- onChange={setEntityId}
783
- error={entityIdError}
784
- loading={customIdLoading}
785
- entity={entity}/>
789
+ entityId={entityId}
790
+ status={status}
791
+ onChange={setEntityId}
792
+ error={entityIdError}
793
+ loading={customIdLoading}
794
+ entity={entity} />
786
795
  }
787
796
 
788
797
  {entityId && formContext && <>
789
798
  <div className="mt-12 flex flex-col gap-8" ref={formRef}>
790
799
  {formFields()}
791
- <ErrorFocus containerRef={formRef}/>
800
+ <ErrorFocus containerRef={formRef} />
792
801
  </div>
793
802
  </>}
794
803
 
795
- {forceActionsAtTheBottom && <div className="h-16"/>}
804
+ {forceActionsAtTheBottom && <div className="h-16" />}
796
805
  </>
797
806
  </ErrorBoundary>;
798
807
 
@@ -852,12 +861,12 @@ export function EntityForm<M extends Record<string, any>>({
852
861
  {formex.dirty
853
862
  ? <Tooltip title={"This form has been modified"}>
854
863
  <Chip size={"small"} className={"py-1"} colorScheme={"orangeDarker"}>
855
- <EditIcon size={"smallest"}/>
864
+ <EditIcon size={"smallest"} />
856
865
  </Chip>
857
866
  </Tooltip>
858
867
  : <Tooltip title={"The current form is in sync with the database"}>
859
868
  <Chip size={"small"} className={"py-1"}>
860
- <CheckIcon size={"smallest"}/>
869
+ <CheckIcon size={"smallest"} />
861
870
  </Chip>
862
871
  </Tooltip>}
863
872
  </div>
@@ -137,7 +137,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
137
137
  }
138
138
  const configProperty = resolveProperty({
139
139
  propertyKey,
140
- propertyOrBuilder: propertyConfig.property,
140
+ propertyOrBuilder: propertyConfig.property as any,
141
141
  values: fieldProps.form.values,
142
142
  path: context.path,
143
143
  entityId: context.entityId,
@@ -145,7 +145,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
145
145
  index,
146
146
  authController
147
147
  });
148
- Component = configProperty.Field as ComponentType<FieldProps<T>>;
148
+ Component = configProperty?.Field as ComponentType<FieldProps<T>> | undefined;
149
149
  }
150
150
  if (!Component) {
151
151
  console.warn(`No field component found for property ${propertyKey}`);
@@ -302,7 +302,7 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
302
302
  if (plugins?.some((plugin) => plugin.form?.fieldBuilder)) {
303
303
  return true;
304
304
  }
305
- if (isPropertyBuilder(property)) {
305
+ if (isPropertyBuilder(property as any)) {
306
306
  return true;
307
307
  }
308
308
  const defAProperty = property as Property | ResolvedProperty;
@@ -2,9 +2,9 @@ import React, { useEffect, useRef } from "react";
2
2
  import { useFormex } from "@firecms/formex";
3
3
 
4
4
  export const ErrorFocus = ({ containerRef }:
5
- {
6
- containerRef?: React.RefObject<HTMLDivElement>
7
- }) => {
5
+ {
6
+ containerRef?: React.RefObject<HTMLDivElement | null>
7
+ }) => {
8
8
  const {
9
9
  isValidating,
10
10
  errors,
@@ -65,7 +65,7 @@ export function MarkdownEditorFieldBinding({
65
65
  }, [value]);
66
66
 
67
67
  const resolvedProperty = resolveProperty({
68
- propertyOrBuilder: property as PropertyOrBuilder,
68
+ propertyOrBuilder: property as PropertyOrBuilder<string>,
69
69
  values: entityValues,
70
70
  authController
71
71
  }) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
@@ -52,18 +52,18 @@ const rejectDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0
52
52
  type StorageUploadFieldProps = FieldProps<string | string[]>;
53
53
 
54
54
  export function StorageUploadFieldBinding({
55
- propertyKey,
56
- value,
57
- setValue,
58
- error,
59
- showError,
60
- autoFocus,
61
- minimalistView,
62
- property,
63
- includeDescription,
64
- context,
65
- isSubmitting,
66
- }: StorageUploadFieldProps) {
55
+ propertyKey,
56
+ value,
57
+ setValue,
58
+ error,
59
+ showError,
60
+ autoFocus,
61
+ minimalistView,
62
+ property,
63
+ includeDescription,
64
+ context,
65
+ isSubmitting,
66
+ }: StorageUploadFieldProps) {
67
67
 
68
68
  const authController = useAuthController();
69
69
 
@@ -100,7 +100,7 @@ export function StorageUploadFieldBinding({
100
100
  });
101
101
 
102
102
  const resolvedProperty = resolveProperty({
103
- propertyOrBuilder: property as PropertyOrBuilder,
103
+ propertyOrBuilder: property as PropertyOrBuilder<string>,
104
104
  authController
105
105
  }) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
106
106
 
@@ -114,7 +114,7 @@ export function StorageUploadFieldBinding({
114
114
  icon={getIconForProperty(property, "small")}
115
115
  required={property.validation?.required}
116
116
  title={property.name}
117
- className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>}
117
+ className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />}
118
118
 
119
119
  <StorageUpload
120
120
  value={internalValue}
@@ -128,13 +128,13 @@ export function StorageUploadFieldBinding({
128
128
  onFileUploadComplete={onFileUploadComplete}
129
129
  storagePathBuilder={storagePathBuilder}
130
130
  storage={storage}
131
- multipleFilesSupported={multipleFilesSupported}/>
131
+ multipleFilesSupported={multipleFilesSupported} />
132
132
 
133
133
  <FieldHelperText includeDescription={includeDescription}
134
- showError={showError}
135
- error={error}
136
- disabled={disabled}
137
- property={property}/>
134
+ showError={showError}
135
+ error={error}
136
+ disabled={disabled}
137
+ property={property} />
138
138
 
139
139
  </>
140
140
  );
@@ -154,15 +154,15 @@ interface SortableStorageItemProps {
154
154
  }
155
155
 
156
156
  function SortableStorageItem({
157
- id,
158
- entry,
159
- property,
160
- metadata,
161
- storagePathBuilder,
162
- onFileUploadComplete,
163
- onClear,
164
- disabled,
165
- }: SortableStorageItemProps) {
157
+ id,
158
+ entry,
159
+ property,
160
+ metadata,
161
+ storagePathBuilder,
162
+ onFileUploadComplete,
163
+ onClear,
164
+ disabled,
165
+ }: SortableStorageItemProps) {
166
166
 
167
167
  const {
168
168
  attributes,
@@ -201,7 +201,7 @@ function SortableStorageItem({
201
201
  disabled={disabled}
202
202
  value={entry.storagePathOrDownloadUrl}
203
203
  onRemove={() => onClear(entry.storagePathOrDownloadUrl!)}
204
- size={entry.size}/>
204
+ size={entry.size} />
205
205
  );
206
206
  } else if (entry.file) {
207
207
  child = (
@@ -231,21 +231,21 @@ function SortableStorageItem({
231
231
  }
232
232
 
233
233
  function FileDropComponent({
234
- storage,
235
- disabled,
236
- onFilesAdded,
237
- multipleFilesSupported,
238
- autoFocus,
239
- internalValue,
240
- property,
241
- onClear,
242
- metadata,
243
- storagePathBuilder,
244
- onFileUploadComplete,
245
- name,
246
- helpText,
247
- isDndItemDragging
248
- }: {
234
+ storage,
235
+ disabled,
236
+ onFilesAdded,
237
+ multipleFilesSupported,
238
+ autoFocus,
239
+ internalValue,
240
+ property,
241
+ onClear,
242
+ metadata,
243
+ storagePathBuilder,
244
+ onFileUploadComplete,
245
+ name,
246
+ helpText,
247
+ isDndItemDragging
248
+ }: {
249
249
  storage: StorageConfig,
250
250
  disabled: boolean,
251
251
  onFilesAdded: (acceptedFiles: File[]) => Promise<void>,
@@ -271,33 +271,33 @@ function FileDropComponent({
271
271
  isDragAccept,
272
272
  isDragReject
273
273
  } = useDropzone({
274
- accept: storage.acceptedFiles ? storage.acceptedFiles.reduce((acc, ext) => ({
275
- ...acc,
276
- [ext]: []
277
- }), {}) : undefined,
278
- disabled: disabled || isDndItemDragging,
279
- noDragEventsBubbling: true,
280
- maxSize: storage.maxSize,
281
- onDrop: onFilesAdded,
282
- onDropRejected: (fileRejections) => {
283
- for (const fileRejection of fileRejections) {
284
- for (const error of fileRejection.errors) {
285
- console.error("Error uploading file: ", error);
286
- if (error.code === "file-too-large") {
287
- snackbarContext.open({
288
- type: "error",
289
- message: `Error uploading file: File is larger than ${storage.maxSize} bytes`
290
- });
291
- } else if (error.code === "file-invalid-type") {
292
- snackbarContext.open({
293
- type: "error",
294
- message: "Error uploading file: File type is not supported"
295
- });
296
- }
274
+ accept: storage.acceptedFiles ? storage.acceptedFiles.reduce((acc, ext) => ({
275
+ ...acc,
276
+ [ext]: []
277
+ }), {}) : undefined,
278
+ disabled: disabled || isDndItemDragging,
279
+ noDragEventsBubbling: true,
280
+ maxSize: storage.maxSize,
281
+ onDrop: onFilesAdded,
282
+ onDropRejected: (fileRejections) => {
283
+ for (const fileRejection of fileRejections) {
284
+ for (const error of fileRejection.errors) {
285
+ console.error("Error uploading file: ", error);
286
+ if (error.code === "file-too-large") {
287
+ snackbarContext.open({
288
+ type: "error",
289
+ message: `Error uploading file: File is larger than ${storage.maxSize} bytes`
290
+ });
291
+ } else if (error.code === "file-invalid-type") {
292
+ snackbarContext.open({
293
+ type: "error",
294
+ message: "Error uploading file: File type is not supported"
295
+ });
297
296
  }
298
297
  }
299
298
  }
300
299
  }
300
+ }
301
301
  );
302
302
 
303
303
  return (
@@ -349,8 +349,8 @@ function FileDropComponent({
349
349
  <div
350
350
  className="flex-grow min-h-[38px] box-border m-2 text-center">
351
351
  <Typography align={"center"}
352
- variant={"label"}
353
- className={disabled ? "text-surface-accent-600 dark:text-surface-accent-500" : ""}>
352
+ variant={"label"}
353
+ className={disabled ? "text-surface-accent-600 dark:text-surface-accent-500" : ""}>
354
354
  {helpText}
355
355
  </Typography>
356
356
  </div>
@@ -374,19 +374,19 @@ export interface StorageUploadProps {
374
374
  }
375
375
 
376
376
  export function StorageUpload({
377
- property,
378
- name,
379
- value, // This is internalValue from useStorageUploadController
380
- setInternalValue,
381
- onChange,
382
- multipleFilesSupported,
383
- onFileUploadComplete,
384
- disabled,
385
- onFilesAdded,
386
- autoFocus,
387
- storage,
388
- storagePathBuilder,
389
- }: StorageUploadProps) {
377
+ property,
378
+ name,
379
+ value, // This is internalValue from useStorageUploadController
380
+ setInternalValue,
381
+ onChange,
382
+ multipleFilesSupported,
383
+ onFileUploadComplete,
384
+ disabled,
385
+ onFilesAdded,
386
+ autoFocus,
387
+ storage,
388
+ storagePathBuilder,
389
+ }: StorageUploadProps) {
390
390
 
391
391
  if (multipleFilesSupported) {
392
392
  const arrayProperty = property as ResolvedArrayProperty<string[]>;
@@ -500,6 +500,6 @@ export function StorageUpload({
500
500
  );
501
501
  } else {
502
502
  // For single file, no D&D context is needed
503
- return <FileDropComponent {...fileDropProps} isDndItemDragging={false}/>;
503
+ return <FileDropComponent {...fileDropProps} isDndItemDragging={false} />;
504
504
  }
505
505
  }