@firecms/core 3.0.0-beta.7 → 3.0.0-beta.8

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 (94) hide show
  1. package/dist/app/AppBar.d.ts +12 -0
  2. package/dist/app/Drawer.d.ts +17 -0
  3. package/dist/app/Scaffold.d.ts +30 -0
  4. package/dist/app/index.d.ts +4 -0
  5. package/dist/app/useApp.d.ts +16 -0
  6. package/dist/components/VirtualTable/VirtualTableProps.d.ts +4 -0
  7. package/dist/components/index.d.ts +1 -1
  8. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +2 -7
  9. package/dist/core/DefaultDrawer.d.ts +19 -0
  10. package/dist/core/EntityEditView.d.ts +17 -3
  11. package/dist/core/NavigationRoutes.d.ts +1 -1
  12. package/dist/core/index.d.ts +2 -2
  13. package/dist/form/PropertiesForm.d.ts +8 -0
  14. package/dist/form/components/FieldHelperText.d.ts +3 -3
  15. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  16. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  17. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  18. package/dist/form/index.d.ts +0 -2
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.es.js +5595 -5574
  21. package/dist/index.es.js.map +1 -1
  22. package/dist/index.umd.js +5 -5
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  25. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  26. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  27. package/dist/types/auth.d.ts +1 -1
  28. package/dist/types/collections.d.ts +14 -0
  29. package/dist/types/datasource.d.ts +18 -8
  30. package/dist/types/fields.d.ts +31 -30
  31. package/dist/types/plugins.d.ts +11 -3
  32. package/dist/types/properties.d.ts +7 -2
  33. package/dist/util/icons.d.ts +2 -2
  34. package/dist/util/storage.d.ts +23 -2
  35. package/dist/util/useStorageUploadController.d.ts +1 -1
  36. package/package.json +13 -22
  37. package/src/app/AppBar.tsx +18 -0
  38. package/src/app/Drawer.tsx +25 -0
  39. package/src/{core → app}/Scaffold.tsx +61 -107
  40. package/src/app/index.ts +4 -0
  41. package/src/app/useApp.tsx +32 -0
  42. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +7 -9
  43. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -1
  44. package/src/components/EntityCollectionView/EntityCollectionView.tsx +7 -4
  45. package/src/components/VirtualTable/VirtualTable.tsx +3 -1
  46. package/src/components/VirtualTable/VirtualTableProps.tsx +5 -0
  47. package/src/components/common/useTableSearchHelper.ts +52 -12
  48. package/src/components/index.tsx +1 -1
  49. package/src/contexts/DialogsProvider.tsx +2 -2
  50. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +26 -28
  51. package/src/core/DefaultDrawer.tsx +177 -0
  52. package/src/core/EntityEditView.tsx +669 -129
  53. package/src/core/EntitySidePanel.tsx +0 -1
  54. package/src/core/NavigationRoutes.tsx +3 -3
  55. package/src/core/index.tsx +2 -2
  56. package/src/form/PropertiesForm.tsx +81 -0
  57. package/src/form/PropertyFieldBinding.tsx +29 -5
  58. package/src/form/components/FieldHelperText.tsx +3 -3
  59. package/src/form/components/StorageItemPreview.tsx +19 -10
  60. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
  61. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -4
  62. package/src/form/field_bindings/KeyValueFieldBinding.tsx +40 -35
  63. package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
  64. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +0 -7
  65. package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
  66. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +6 -35
  67. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  68. package/src/form/index.tsx +4 -4
  69. package/src/form/validation.ts +1 -17
  70. package/src/index.ts +1 -0
  71. package/src/internal/useBuildDataSource.ts +12 -0
  72. package/src/preview/PropertyPreview.tsx +5 -2
  73. package/src/preview/PropertyPreviewProps.tsx +6 -0
  74. package/src/preview/components/ImagePreview.tsx +21 -33
  75. package/src/preview/components/ReferencePreview.tsx +2 -1
  76. package/src/preview/components/StorageThumbnail.tsx +5 -1
  77. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  78. package/src/types/auth.tsx +1 -1
  79. package/src/types/collections.ts +14 -0
  80. package/src/types/customization_controller.tsx +0 -1
  81. package/src/types/datasource.ts +20 -16
  82. package/src/types/fields.tsx +33 -33
  83. package/src/types/plugins.tsx +12 -3
  84. package/src/types/properties.ts +7 -2
  85. package/src/util/entities.ts +4 -3
  86. package/src/util/objects.ts +17 -7
  87. package/src/util/permissions.ts +1 -0
  88. package/src/util/storage.ts +75 -21
  89. package/src/util/useStorageUploadController.tsx +21 -3
  90. package/dist/core/Drawer.d.ts +0 -16
  91. package/dist/core/Scaffold.d.ts +0 -51
  92. package/dist/form/EntityForm.d.ts +0 -77
  93. package/src/core/Drawer.tsx +0 -139
  94. package/src/form/EntityForm.tsx +0 -736
@@ -79,7 +79,6 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
79
79
  <ErrorBoundary>
80
80
  <EntityEditView
81
81
  {...props}
82
- formWidth={props.width}
83
82
  collection={collection}
84
83
  parentCollectionIds={parentCollectionIds}
85
84
  onValuesAreModified={onValuesAreModified}
@@ -15,7 +15,7 @@ export type NavigationRoutesProps = {
15
15
  */
16
16
  homePage?: React.ReactNode;
17
17
 
18
- customRoutes?: React.ReactNode[]
18
+ children?: React.ReactNode | React.ReactNode[]
19
19
 
20
20
  };
21
21
 
@@ -31,7 +31,7 @@ export type NavigationRoutesProps = {
31
31
  export const NavigationRoutes = React.memo<NavigationRoutesProps>(
32
32
  function NavigationRoutes({
33
33
  homePage = <DefaultHomePage/>,
34
- customRoutes
34
+ children
35
35
  }: NavigationRoutesProps) {
36
36
 
37
37
  const location = useLocation();
@@ -111,7 +111,7 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
111
111
 
112
112
  {notFoundRoute}
113
113
 
114
- {customRoutes}
114
+ {children}
115
115
 
116
116
  </Routes>
117
117
  );
@@ -1,8 +1,8 @@
1
1
  export * from "./FireCMS";
2
2
 
3
- export * from "./Scaffold";
3
+ export * from "../app/Scaffold";
4
4
 
5
- export * from "./Drawer";
5
+ export * from "./DefaultDrawer";
6
6
  export * from "./DrawerNavigationItem";
7
7
 
8
8
  export * from "./field_configs";
@@ -0,0 +1,81 @@
1
+ import { FormContext, PropertiesOrBuilders, PropertyFieldBindingProps } from "../types";
2
+ import { Tooltip } from "@firecms/ui";
3
+ import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
4
+ import { PropertyFieldBinding } from "./PropertyFieldBinding";
5
+ import { ErrorBoundary } from "../components";
6
+ import { isHidden, isReadOnly, resolveProperties } from "../util";
7
+ import { FormexController } from "@firecms/formex";
8
+
9
+ export type PropertiesFormProps<M extends Record<string, any> = Record<string, any>> = {
10
+ properties: PropertiesOrBuilders<M>;
11
+ propertiesOrder?: string[];
12
+ formex: FormexController<M>;
13
+ }
14
+
15
+ export function PropertiesForm<M extends Record<string, any> = Record<string, any>>({
16
+ properties,
17
+ propertiesOrder,
18
+ formex
19
+ }: PropertiesFormProps<M>) {
20
+
21
+ const resolvedProperties = resolveProperties({ properties });
22
+
23
+ const formContext: FormContext<M> = {
24
+ // @ts-ignore
25
+ setFieldValue: useCallback(formex.setFieldValue, []),
26
+ values: formex.values ?? {},
27
+ // @ts-ignore
28
+ save: useCallback(() => {
29
+ throw new Error("Not implemented. You currently can't call save from a custom field, within a PropertiesForm (it works in standard Entity forms)");
30
+ }, []),
31
+ formex
32
+ };
33
+
34
+ const formFields = (
35
+ <div className={"flex flex-col gap-8"}>
36
+ {(propertiesOrder ?? Object.keys(resolvedProperties))
37
+ .map((key) => {
38
+
39
+ const property = resolvedProperties[key];
40
+ if (!property) {
41
+ console.warn(`Property ${key} not found in collection PropertiesForm`);
42
+ return null;
43
+ }
44
+
45
+ const disabled = formex.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
46
+ const hidden = isHidden(property);
47
+ if (hidden) return null;
48
+ const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
49
+ propertyKey: key,
50
+ disabled,
51
+ property,
52
+ includeDescription: property.description || property.longDescription,
53
+ context: formContext,
54
+ tableMode: false,
55
+ partOfArray: false,
56
+ partOfBlock: false,
57
+ autoFocus: false
58
+ };
59
+
60
+ return (
61
+ <div id={`form_field_${key}`}
62
+ key={`field_${key}`}>
63
+ <ErrorBoundary>
64
+ <Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
65
+ delayDuration={800}
66
+ side={"left"}
67
+ align={"start"}
68
+ sideOffset={16}>
69
+ <PropertyFieldBinding {...cmsFormFieldProps}/>
70
+ </Tooltip>
71
+ </ErrorBoundary>
72
+ </div>
73
+ );
74
+ })
75
+ .filter(Boolean)}
76
+
77
+ </div>
78
+ );
79
+
80
+ return <div></div>
81
+ }
@@ -85,6 +85,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
85
85
 
86
86
  return (
87
87
  <Field
88
+ key={propertyKey}
88
89
  name={propertyKey}
89
90
  >
90
91
  {(fieldProps) => {
@@ -110,7 +111,12 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
110
111
  } else {
111
112
  const propertyConfig = getFieldConfig(resolvedProperty, customizationController.propertyConfigs);
112
113
  if (!propertyConfig) {
113
- console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: customizationController.propertyConfigs, propertyConfig });
114
+ console.log("INTERNAL: Could not find field config for property", {
115
+ propertyKey,
116
+ resolvedProperty,
117
+ fields: customizationController.propertyConfigs,
118
+ propertyConfig
119
+ });
114
120
  throw new Error(`INTERNAL: Could not find field config for property ${propertyKey}`);
115
121
  }
116
122
  const configProperty = resolveProperty({
@@ -194,7 +200,14 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
194
200
  (fieldProps.form.submitCount > 0 || property.validation?.unique) &&
195
201
  (!Array.isArray(error) || !!error.filter((e: any) => !!e).length);
196
202
 
197
- const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent(context.path, context.collection, propertyKey, property, Component, plugins);
203
+ const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent({
204
+ path: context.path,
205
+ collection: context.collection,
206
+ propertyKey: propertyKey,
207
+ property: property,
208
+ Component: Component,
209
+ plugins: plugins
210
+ });
198
211
  const UsedComponent: ComponentType<FieldProps<T>> = WrappedComponent ?? Component;
199
212
 
200
213
  const isSubmitting = fieldProps.form.isSubmitting;
@@ -264,13 +277,24 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
264
277
  }
265
278
  }
266
279
 
267
- function useWrappedComponent<T extends CMSType = CMSType, M extends Record<string, any> = any>(
268
- path: string,
269
- collection: EntityCollection<M>,
280
+ interface UseWrappedComponentParams<T extends CMSType = CMSType, M extends Record<string, any> = any> {
281
+ path?: string,
282
+ collection?: EntityCollection<M>,
270
283
  propertyKey: string,
271
284
  property: ResolvedProperty<T>,
272
285
  Component: ComponentType<FieldProps<T, any, M>>,
273
286
  plugins?: FireCMSPlugin[]
287
+ }
288
+
289
+ function useWrappedComponent<T extends CMSType = CMSType, M extends Record<string, any> = any>(
290
+ {
291
+ path,
292
+ collection,
293
+ propertyKey,
294
+ property,
295
+ Component,
296
+ plugins
297
+ }: UseWrappedComponentParams<T, M>
274
298
  ): ComponentType<FieldProps<T, any, M>> | null {
275
299
 
276
300
  const wrapperRef = useRef<ComponentType<FieldProps<T, any, M>> | null>((() => {
@@ -1,4 +1,4 @@
1
- import { ResolvedProperty } from "../../types";
1
+ import { Property, ResolvedProperty } from "../../types";
2
2
  import { IconButton, InfoIcon, Tooltip, Typography } from "@firecms/ui";
3
3
 
4
4
  /**
@@ -13,8 +13,8 @@ export function FieldHelperText({
13
13
  disabled
14
14
  }: {
15
15
  error?: string,
16
- showError: boolean,
17
- property: ResolvedProperty,
16
+ showError?: boolean,
17
+ property: ResolvedProperty | Property,
18
18
  includeDescription?: boolean,
19
19
  disabled?: boolean,
20
20
  }
@@ -1,39 +1,40 @@
1
1
  import React from "react";
2
2
 
3
- import { Entity, EntityCollection, ResolvedStringProperty } from "../../types";
3
+ import { ResolvedStringProperty } from "../../types";
4
4
  import { PreviewSize, PropertyPreview } from "../../preview";
5
5
 
6
- import { cls, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
6
+ import { cls, DescriptionIcon, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
7
7
  import { ErrorBoundary } from "../../components";
8
8
 
9
9
  interface StorageItemPreviewProps {
10
10
  name: string;
11
11
  property: ResolvedStringProperty;
12
12
  value: string,
13
- entity: Entity<any>,
14
13
  onRemove: (value: string) => void;
15
14
  size: PreviewSize;
16
15
  disabled: boolean;
17
- collection: EntityCollection;
16
+ placeholder?: boolean;
17
+ className?: string;
18
18
  }
19
19
 
20
20
  export function StorageItemPreview({
21
21
  name,
22
22
  property,
23
23
  value,
24
- entity,
25
24
  onRemove,
26
25
  disabled,
27
26
  size,
28
- collection
27
+ placeholder,
28
+ className
29
29
  }: StorageItemPreviewProps) {
30
30
 
31
31
  return (
32
32
  <div className={cls(paperMixin,
33
33
  "relative m-4 border-box flex items-center justify-center",
34
- size === "medium" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]")}>
34
+ size === "medium" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]",
35
+ className)}>
35
36
 
36
- {!disabled &&
37
+ {!placeholder && !disabled &&
37
38
  <div
38
39
  className="absolute rounded-full -top-2 -right-2 z-10 bg-white dark:bg-gray-900">
39
40
 
@@ -51,16 +52,24 @@ export function StorageItemPreview({
51
52
  </div>
52
53
  }
53
54
 
54
- {value &&
55
+ {!placeholder && value &&
55
56
  <ErrorBoundary>
56
57
  <PropertyPreview propertyKey={name}
57
58
  value={value}
58
59
  property={property}
59
- // entity={entity}
60
+ interactive={false}
60
61
  size={size}/>
61
62
  </ErrorBoundary>
62
63
  }
63
64
 
65
+ {placeholder &&
66
+ <div
67
+ onClick={(e) => e.stopPropagation()}
68
+ className="flex flex-col items-center justify-center w-full h-full">
69
+ <DescriptionIcon className="text-gray-700 dark:text-gray-300"/>
70
+ </div>
71
+ }
72
+
64
73
 
65
74
  </div>
66
75
  );
@@ -2,7 +2,7 @@ import React from "react";
2
2
  import { FieldProps } from "../../types";
3
3
  import { FieldHelperText, LabelWithIcon } from "../components";
4
4
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
5
- import { ExpandablePanel } from "@firecms/ui";
5
+ import { ExpandablePanel, Typography } from "@firecms/ui";
6
6
  import { getIconForProperty } from "../../util";
7
7
  import { useClearRestoreValue } from "../useClearRestoreValue";
8
8
 
@@ -39,10 +39,13 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
39
39
  setValue
40
40
  });
41
41
 
42
- const title = <LabelWithIcon icon={getIconForProperty(property, "small")}
43
- required={property.validation?.required}
44
- className={"text-text-secondary dark:text-text-secondary-dark"}
45
- title={property.name}/>;
42
+ const title = (<>
43
+ <LabelWithIcon icon={getIconForProperty(property, "small")}
44
+ required={property.validation?.required}
45
+ title={property.name}
46
+ className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
47
+ {Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
48
+ </>);
46
49
 
47
50
  const body = property.resolvedProperties.map((childProperty, index) => {
48
51
  const fieldProps = {
@@ -6,7 +6,7 @@ import { ErrorView } from "../../components";
6
6
  import { getIconForProperty, getReferenceFrom } from "../../util";
7
7
 
8
8
  import { useNavigationController, useReferenceDialog } from "../../hooks";
9
- import { Button, cls, ExpandablePanel, fieldBackgroundMixin } from "@firecms/ui";
9
+ import { Button, cls, ExpandablePanel, fieldBackgroundMixin, Typography } from "@firecms/ui";
10
10
  import { useClearRestoreValue } from "../useClearRestoreValue";
11
11
 
12
12
  type ArrayOfReferencesFieldProps = FieldProps<EntityReference[]>;
@@ -94,12 +94,13 @@ export function ArrayOfReferencesFieldBinding({
94
94
  );
95
95
  }, [ofProperty.path, ofProperty.previewProperties, value]);
96
96
 
97
- const title = (
97
+ const title = (<>
98
98
  <LabelWithIcon icon={getIconForProperty(property, "small")}
99
99
  required={property.validation?.required}
100
100
  title={property.name}
101
- className={"text-text-secondary dark:text-text-secondary-dark"}/>
102
- );
101
+ className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
102
+ {Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
103
+ </>);
103
104
 
104
105
  const body = <>
105
106
  {!collection && <ErrorView
@@ -21,6 +21,7 @@ import {
21
21
  } from "@firecms/ui";
22
22
  import { getDefaultValueForDataType, getIconForProperty } from "../../util";
23
23
  import { useCustomizationController } from "../../hooks";
24
+ import { getIn } from "@firecms/formex";
24
25
 
25
26
  type MapEditViewRowState = [number, {
26
27
  key: string,
@@ -52,9 +53,13 @@ export function KeyValueFieldBinding({
52
53
  if (!property.keyValue) {
53
54
  throw Error(`Your property ${propertyKey} needs to have the 'keyValue' prop in order to use this field binding`);
54
55
  }
56
+
57
+ const initialValues = getIn(context.formex.initialValues, propertyKey);
58
+
55
59
  const mapFormView = <MapEditView value={value}
56
60
  setValue={setValue}
57
61
  disabled={disabled}
62
+ initialValue={initialValues}
58
63
  fieldName={property.name ?? propertyKey}/>;
59
64
 
60
65
  const title = <LabelWithIcon
@@ -84,6 +89,7 @@ export function KeyValueFieldBinding({
84
89
 
85
90
  interface MapEditViewParams<T extends Record<string, any>> {
86
91
  value?: T;
92
+ initialValue?: T;
87
93
  setValue: (value: (T | null)) => void;
88
94
  fieldName?: string,
89
95
  disabled?: boolean
@@ -91,14 +97,15 @@ interface MapEditViewParams<T extends Record<string, any>> {
91
97
 
92
98
  function MapEditView<T extends Record<string, any>>({
93
99
  value,
100
+ initialValue,
94
101
  setValue,
95
102
  fieldName,
96
103
  disabled
97
104
  }: MapEditViewParams<T>) {
98
105
  const [internalState, setInternalState] = React.useState<MapEditViewRowState[]>(
99
- Object.keys(value ?? {}).map((key) => [getRandomId(), {
106
+ Object.keys(initialValue ?? {}).map((key) => [getRandomId(), {
100
107
  key,
101
- dataType: getDataType(value?.[key]) ?? "string"
108
+ dataType: getDataType(initialValue?.[key]) ?? "string"
102
109
  }])
103
110
  );
104
111
 
@@ -121,8 +128,6 @@ function MapEditView<T extends Record<string, any>>({
121
128
  setInternalState(newRowIds);
122
129
  }, [value]);
123
130
 
124
- const originalValue = React.useRef<T>(value ?? {} as T);
125
-
126
131
  const updateDataType = (rowId: number, dataType: DataType) => {
127
132
  if (!rowId) {
128
133
  console.warn("No key selected for data type update");
@@ -168,7 +173,7 @@ function MapEditView<T extends Record<string, any>>({
168
173
  }
169
174
 
170
175
  const newValue = { ...(value ?? {}) } as T;
171
- if (typeof originalValue.current === "object" && fieldKey in originalValue.current) {
176
+ if (typeof initialValue === "object" && fieldKey in initialValue) {
172
177
  // @ts-ignore
173
178
  newValue[fieldKey] = undefined; // set to undefined to remove from the object, the datasource will remove it from the backend
174
179
  } else {
@@ -186,7 +191,7 @@ function MapEditView<T extends Record<string, any>>({
186
191
  value={value ?? {} as T}
187
192
  onDeleteClick={() => {
188
193
  const newValue = { ...(value ?? {}) as T };
189
- if (originalValue.current && fieldKey in originalValue.current) {
194
+ if (initialValue && fieldKey in initialValue) {
190
195
  // @ts-ignore
191
196
  newValue[fieldKey] = undefined;
192
197
  } else {
@@ -305,7 +310,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
305
310
  }}/>;
306
311
  } else if (dataType === "boolean") {
307
312
  return <BooleanSwitchWithLabel value={entryValue}
308
- size={"small"}
313
+ size={"medium"}
309
314
  position={"start"}
310
315
  disabled={disabled || !fieldKey}
311
316
  onValueChange={(newValue) => {
@@ -375,7 +380,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
375
380
  <Typography key={rowId.toString()}
376
381
  component={"div"}
377
382
  className="font-mono flex flex-row gap-1">
378
- <div className="w-[200px] max-w-[25%]">
383
+ <div className="w-[300px] max-w-[30%]">
379
384
  <TextField
380
385
  value={fieldKey}
381
386
  placeholder={"key"}
@@ -389,32 +394,32 @@ function MapKeyValueRow<T extends Record<string, any>>({
389
394
  <div className="flex-grow">
390
395
  {(dataType !== "map" && dataType !== "array") && buildInput(entryValue, fieldKey, dataType)}
391
396
  </div>
392
- <Menu
393
- trigger={<IconButton size={"small"}
394
- className="h-7 w-7">
395
- <ArrowDropDownIcon/>
396
- </IconButton>}
397
- >
398
- <MenuItem dense
399
- onClick={() => doUpdateDataType("string")}>string</MenuItem>
400
- <MenuItem dense
401
- onClick={() => doUpdateDataType("number")}>number</MenuItem>
402
- <MenuItem dense
403
- onClick={() => doUpdateDataType("boolean")}>boolean</MenuItem>
404
- <MenuItem dense
405
- onClick={() => doUpdateDataType("date")}>date</MenuItem>
406
- <MenuItem dense
407
- onClick={() => doUpdateDataType("map")}>map</MenuItem>
408
- <MenuItem dense
409
- onClick={() => doUpdateDataType("array")}>array</MenuItem>
410
- </Menu>
411
-
412
- <IconButton aria-label="delete"
413
- size={"small"}
414
- onClick={onDeleteClick}
415
- className="h-7 w-7">
416
- <RemoveIcon size={"small"}/>
417
- </IconButton>
397
+ <div className={"flex flex-col"}>
398
+ <Menu
399
+ trigger={<IconButton size={"smallest"}>
400
+ <ArrowDropDownIcon size={"small"}/>
401
+ </IconButton>}
402
+ >
403
+ <MenuItem dense
404
+ onClick={() => doUpdateDataType("string")}>string</MenuItem>
405
+ <MenuItem dense
406
+ onClick={() => doUpdateDataType("number")}>number</MenuItem>
407
+ <MenuItem dense
408
+ onClick={() => doUpdateDataType("boolean")}>boolean</MenuItem>
409
+ <MenuItem dense
410
+ onClick={() => doUpdateDataType("date")}>date</MenuItem>
411
+ <MenuItem dense
412
+ onClick={() => doUpdateDataType("map")}>map</MenuItem>
413
+ <MenuItem dense
414
+ onClick={() => doUpdateDataType("array")}>array</MenuItem>
415
+ </Menu>
416
+
417
+ <IconButton aria-label="delete"
418
+ size={"smallest"}
419
+ onClick={onDeleteClick}>
420
+ <RemoveIcon size={"smallest"}/>
421
+ </IconButton>
422
+ </div>
418
423
  </Typography>
419
424
 
420
425
  {(dataType === "map" || dataType === "array") && buildInput(entryValue, fieldKey, dataType)}
@@ -472,7 +477,7 @@ function ArrayKeyValueRow<T>({
472
477
  }}/>;
473
478
  } else if (dataType === "boolean") {
474
479
  return <BooleanSwitchWithLabel value={entryValue}
475
- size={"small"}
480
+ size={"medium"}
476
481
  position={"start"}
477
482
  onValueChange={(v) => {
478
483
  setValue(v as T);
@@ -1,5 +1,13 @@
1
1
  import React from "react";
2
- import { FieldProps, Properties, ResolvedProperties } from "../../types";
2
+ import {
3
+ CMSType,
4
+ FieldProps,
5
+ FormContext,
6
+ MapProperty,
7
+ Properties,
8
+ ResolvedProperties,
9
+ ResolvedProperty
10
+ } from "../../types";
3
11
 
4
12
  import { ErrorBoundary } from "../../components";
5
13
  import { getIconForProperty, isHidden, pick } from "../../util";
@@ -21,7 +29,6 @@ export function MapFieldBinding({
21
29
  error,
22
30
  disabled,
23
31
  property,
24
- setValue,
25
32
  partOfBlock,
26
33
  tableMode,
27
34
  includeDescription,
@@ -68,6 +75,7 @@ export function MapFieldBinding({
68
75
  partOfBlock: false,
69
76
  autoFocus: autoFocus && index === 0
70
77
  };
78
+
71
79
  return (
72
80
  <div key={`map-${propertyKey}-${index}`}>
73
81
  <ErrorBoundary>
@@ -101,7 +109,7 @@ export function MapFieldBinding({
101
109
  {(tableMode || partOfBlock) && mapFormView}
102
110
 
103
111
  <FieldHelperText includeDescription={includeDescription}
104
- showError={showError}
112
+ showError={showError ?? false}
105
113
  error={error ? (typeof error === "string" ? error : "A property of this map has an error") : undefined}
106
114
  disabled={disabled}
107
115
  property={property}/>
@@ -30,12 +30,6 @@ export function ReadOnlyFieldBinding({
30
30
  if (!context.entityId)
31
31
  throw new Error("ReadOnlyFieldBinding: Entity id is null");
32
32
 
33
- const entity: Entity<any> = {
34
- id: context.entityId!,
35
- values: context.values,
36
- path: context.path
37
- };
38
-
39
33
  return (
40
34
 
41
35
  <>
@@ -53,7 +47,6 @@ export function ReadOnlyFieldBinding({
53
47
  <PropertyPreview propertyKey={propertyKey}
54
48
  value={value}
55
49
  property={property}
56
- // entity={entity}
57
50
  size={"medium"}/>
58
51
  </ErrorBoundary>
59
52
 
@@ -2,9 +2,9 @@ import React, { useState } from "react";
2
2
  import { CMSType, FieldProps, ResolvedProperty } from "../../types";
3
3
  import { FieldHelperText, FormikArrayContainer, LabelWithIcon } from "../components";
4
4
  import { ErrorBoundary } from "../../components";
5
- import { getIconForProperty } from "../../util";
5
+ import { getDefaultValueFor, getIconForProperty } from "../../util";
6
6
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
7
- import { ExpandablePanel } from "@firecms/ui";
7
+ import { ExpandablePanel, Typography } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
 
10
10
  /**
@@ -75,12 +75,15 @@ export function RepeatFieldBinding<T extends Array<any>>({
75
75
  onInternalIdAdded={setLastAddedId}
76
76
  disabled={isSubmitting || Boolean(property.disabled)}
77
77
  includeAddButton={!property.disabled}
78
- newDefaultEntry={property.of.defaultValue}/>;
78
+ newDefaultEntry={getDefaultValueFor(property.of)}/>;
79
79
 
80
- const title = (<LabelWithIcon icon={getIconForProperty(property, "small")}
81
- required={property.validation?.required}
82
- title={property.name}
83
- className={"text-text-secondary dark:text-text-secondary-dark"}/>);
80
+ const title = (<>
81
+ <LabelWithIcon icon={getIconForProperty(property, "small")}
82
+ required={property.validation?.required}
83
+ title={property.name}
84
+ className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
85
+ {Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
86
+ </>);
84
87
 
85
88
  return (
86
89