@firecms/core 3.0.0-canary.174 → 3.0.0-canary.176

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.
@@ -426,10 +426,12 @@ export type EntityCustomView<M extends Record<string, any> = any> = {
426
426
  */
427
427
  name: string;
428
428
  /**
429
- * If set to true, the actions of the entity will be included in the
430
- * bottom of the panel (save buttons, delete buttons, etc.)
429
+ * If set to true, the actions of the entity (save, discard,delete) will be
430
+ * included in the view. By default the actions are located in the right or bottom,
431
+ * based on the screen size. You can force the actions to be located at the bottom
432
+ * by setting this prop to "bottom".
431
433
  */
432
- includeActions?: boolean;
434
+ includeActions?: boolean | "bottom";
433
435
  /**
434
436
  * Builder for rendering the custom view
435
437
  */
@@ -67,7 +67,8 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
67
67
  */
68
68
  partOfArray?: boolean;
69
69
  /**
70
- * Should this field render with the minimal amount of UI elements
70
+ * Display the child properties directly, without being wrapped in an
71
+ * extendable panel. Note that this will also hide the title of this property.
71
72
  */
72
73
  minimalistView?: boolean;
73
74
  /**
@@ -170,7 +171,8 @@ export interface PropertyFieldBindingProps<T extends CMSType, M extends Record<s
170
171
  */
171
172
  partOfArray?: boolean;
172
173
  /**
173
- * Is this field part of a block (oneOf array)
174
+ * Display the child properties directly, without being wrapped in an
175
+ * extendable panel. Note that this will also hide the title of this property.
174
176
  */
175
177
  minimalistView?: boolean;
176
178
  /**
@@ -211,11 +211,11 @@ export type PropertyBuilder<T extends CMSType = any, M extends Record<string, an
211
211
  /**
212
212
  * @group Entity properties
213
213
  */
214
- export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>> = Property<T> | PropertyBuilder<T, M>;
214
+ export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = any> = Property<T> | PropertyBuilder<T, M>;
215
215
  /**
216
216
  * @group Entity properties
217
217
  */
218
- export type PropertiesOrBuilders<M extends Record<string, any> = Record<string, any>> = {
218
+ export type PropertiesOrBuilders<M extends Record<string, any> = any> = {
219
219
  [k in keyof M]: PropertyOrBuilder<M[k], M>;
220
220
  };
221
221
  /**
@@ -361,6 +361,11 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
361
361
  * Should the field be initially expanded. Defaults to `true`
362
362
  */
363
363
  expanded?: boolean;
364
+ /**
365
+ * Display the child properties directly, without being wrapped in an
366
+ * extendable panel.
367
+ */
368
+ minimalistView?: boolean;
364
369
  }
365
370
  /**
366
371
  * @group Entity properties
@@ -400,6 +405,11 @@ export interface MapProperty<T extends Record<string, CMSType> = Record<string,
400
405
  * view
401
406
  */
402
407
  spreadChildren?: boolean;
408
+ /**
409
+ * Display the child properties directly, without being wrapped in an
410
+ * extendable panel. Note that this will also hide the title of this property.
411
+ */
412
+ minimalistView?: boolean;
403
413
  /**
404
414
  * Should the field be initially expanded. Defaults to `true`
405
415
  */
@@ -12,7 +12,7 @@ export declare function buildCollection<M extends Record<string, any> = any, USE
12
12
  * @param property
13
13
  * @group Builder
14
14
  */
15
- export declare function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = Record<string, any>>(property: P): P extends StringProperty ? StringProperty : P extends NumberProperty ? NumberProperty : P extends BooleanProperty ? BooleanProperty : P extends DateProperty ? DateProperty : P extends GeopointProperty ? GeopointProperty : P extends ReferenceProperty ? ReferenceProperty : P extends ArrayProperty ? ArrayProperty : P extends MapProperty ? MapProperty : P extends PropertyBuilder<T, M> ? PropertyBuilder<T, M> : never;
15
+ export declare function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = any>(property: P): P extends StringProperty ? StringProperty : P extends NumberProperty ? NumberProperty : P extends BooleanProperty ? BooleanProperty : P extends DateProperty ? DateProperty : P extends GeopointProperty ? GeopointProperty : P extends ReferenceProperty ? ReferenceProperty : P extends ArrayProperty ? ArrayProperty : P extends MapProperty ? MapProperty : P extends PropertyBuilder<T, M> ? PropertyBuilder<T, M> : never;
16
16
  /**
17
17
  * Identity function we use to defeat the type system of Typescript and preserve
18
18
  * the properties keys.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.174",
4
+ "version": "3.0.0-canary.176",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,24 +50,24 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.174",
54
- "@firecms/formex": "^3.0.0-canary.174",
55
- "@firecms/ui": "^3.0.0-canary.174",
53
+ "@firecms/editor": "^3.0.0-canary.176",
54
+ "@firecms/formex": "^3.0.0-canary.176",
55
+ "@firecms/ui": "^3.0.0-canary.176",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
- "@radix-ui/react-portal": "^1.1.2",
57
+ "@radix-ui/react-portal": "^1.1.3",
58
58
  "clsx": "^2.1.1",
59
59
  "date-fns": "^3.6.0",
60
60
  "fuse.js": "^7.0.0",
61
61
  "history": "^5.3.0",
62
62
  "markdown-it": "^14.1.0",
63
- "notistack": "^3.0.1",
63
+ "notistack": "^3.0.2",
64
64
  "object-hash": "^3.0.0",
65
65
  "react-dropzone": "^14.3.5",
66
66
  "react-fast-compare": "^3.2.2",
67
67
  "react-image-file-resizer": "^0.4.8",
68
68
  "react-transition-group": "^4.4.5",
69
69
  "react-use-measure": "^2.1.1",
70
- "react-window": "^1.8.10",
70
+ "react-window": "^1.8.11",
71
71
  "yup": "^0.32.11"
72
72
  },
73
73
  "peerDependencies": {
@@ -78,13 +78,13 @@
78
78
  },
79
79
  "devDependencies": {
80
80
  "@jest/globals": "^29.7.0",
81
- "@testing-library/react": "^16.0.1",
82
- "@testing-library/user-event": "^14.5.2",
81
+ "@testing-library/react": "^16.2.0",
82
+ "@testing-library/user-event": "^14.6.1",
83
83
  "@types/jest": "^29.5.14",
84
- "@types/node": "^20.17.9",
84
+ "@types/node": "^20.17.14",
85
85
  "@types/object-hash": "^3.0.6",
86
- "@types/react": "^18.3.11",
87
- "@types/react-dom": "^18.3.1",
86
+ "@types/react": "^18.3.18",
87
+ "@types/react-dom": "^18.3.0",
88
88
  "@types/react-measure": "^2.0.12",
89
89
  "@vitejs/plugin-react": "^4.3.4",
90
90
  "babel-plugin-react-compiler": "beta",
@@ -92,19 +92,19 @@
92
92
  "eslint-plugin-react-compiler": "beta",
93
93
  "jest": "^29.7.0",
94
94
  "npm-run-all": "^4.1.5",
95
- "react-router": "^6.28.0",
96
- "react-router-dom": "^6.28.0",
95
+ "react-router": "^6.28.2",
96
+ "react-router-dom": "^6.28.2",
97
97
  "ts-jest": "^29.2.5",
98
98
  "ts-node": "^10.9.2",
99
99
  "tsd": "^0.31.2",
100
- "typescript": "^5.7.2",
101
- "vite": "^5.4.11"
100
+ "typescript": "^5.7.3",
101
+ "vite": "^5.4.14"
102
102
  },
103
103
  "files": [
104
104
  "dist",
105
105
  "src"
106
106
  ],
107
- "gitHead": "268a99741b93a8b745422740faf90aa808da97fb",
107
+ "gitHead": "41075e0bfa191634e1a52442c8889d3ca53eb922",
108
108
  "publishConfig": {
109
109
  "access": "public"
110
110
  },
@@ -76,12 +76,12 @@ import {
76
76
  } from "@firecms/ui";
77
77
  import { Formex, FormexController, getIn, setIn, useCreateFormex } from "@firecms/formex";
78
78
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
79
- import { CustomIdField } from "../form/components/CustomIdField";
80
79
  import { CustomFieldValidator, getYupEntitySchema } from "../form/validation";
81
- import { ErrorFocus } from "../form/components/ErrorFocus";
82
80
  import { LabelWithIconAndTooltip, PropertyFieldBinding } from "../form";
83
81
  import { ValidationError } from "yup";
84
82
  import { getEntityFromCache, removeEntityFromCache, saveEntityToCache } from "../util/entity_cache";
83
+ import { CustomIdField } from "../form/components/CustomIdField";
84
+ import { ErrorFocus } from "../form/components/ErrorFocus";
85
85
 
86
86
  const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
87
87
 
@@ -158,6 +158,46 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
158
158
  />;
159
159
  }
160
160
 
161
+ function FormLayout({
162
+ id,
163
+ formex,
164
+ children,
165
+ className
166
+ }: {
167
+ id?: string,
168
+ formex: FormexController<any>,
169
+ children: React.ReactNode,
170
+ className?: string
171
+ }) {
172
+
173
+ return <div
174
+ role="tabpanel"
175
+ id={id}
176
+ className={cls("relative flex flex-row max-w-4xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-7xl w-full h-fit", className)}>
177
+
178
+ <div className={cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10")}>
179
+
180
+ {formex.dirty
181
+ ? <Tooltip title={"Unsaved changes"}
182
+ className={"self-end sticky top-4 z-10"}>
183
+ <Chip size={"small"} colorScheme={"orangeDarker"}>
184
+ <EditIcon size={"smallest"}/>
185
+ </Chip>
186
+ </Tooltip>
187
+ : <Tooltip title={"In sync with the database"}
188
+ className={"self-end sticky top-4 z-10"}>
189
+ <Chip size={"small"}>
190
+ <CheckIcon size={"smallest"}/>
191
+ </Chip>
192
+ </Tooltip>}
193
+
194
+ {children}
195
+
196
+ </div>
197
+
198
+ </div>
199
+ }
200
+
161
201
  export function EntityEditViewInner<M extends Record<string, any>>({
162
202
  path,
163
203
  entityId: entityIdProp,
@@ -533,9 +573,39 @@ export function EntityEditViewInner<M extends Record<string, any>>({
533
573
  : [];
534
574
 
535
575
  const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
536
- const shouldShowEntityActions = !autoSave && (selectedTab === MAIN_TAB_VALUE || selectedEntityView?.includeActions);
576
+ const shouldShowEntityActions = selectedTab === MAIN_TAB_VALUE || selectedEntityView?.includeActions;
577
+
578
+ const secondaryForms: React.ReactNode[] | undefined = customViews && resolvedEntityViews
579
+ .filter(e => e.includeActions)
580
+ .map(
581
+ (customView, colIndex) => {
582
+ if (!customView)
583
+ return null;
584
+ const Builder = customView.Builder;
585
+ if (!Builder) {
586
+ console.error("customView.Builder is not defined");
587
+ return null;
588
+ }
589
+
590
+ return <FormLayout
591
+ key={`custom_view_${customView.key}`}
592
+ className={selectedTab !== customView.key ? "hidden" : ""}
593
+ formex={formex}>
594
+ <ErrorBoundary>
595
+ {formContext && <Builder
596
+ collection={collection}
597
+ entity={usedEntity}
598
+ modifiedValues={formex.values ?? usedEntity?.values}
599
+ formContext={formContext}
600
+ />}
601
+ </ErrorBoundary>
602
+ </FormLayout>
603
+
604
+ }
605
+ ).filter(Boolean);
537
606
 
538
607
  const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
608
+ .filter(e => !e.includeActions)
539
609
  .map(
540
610
  (customView, colIndex) => {
541
611
  if (!customView)
@@ -545,6 +615,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
545
615
  console.error("customView.Builder is not defined");
546
616
  return null;
547
617
  }
618
+
548
619
  return <div
549
620
  className={cls(defaultBorderMixin,
550
621
  "relative flex-grow w-full h-full overflow-auto",
@@ -572,12 +643,10 @@ export function EntityEditViewInner<M extends Record<string, any>>({
572
643
  (subcollection, colIndex) => {
573
644
  const subcollectionId = subcollection.id ?? subcollection.path;
574
645
  const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
646
+ if (selectedTab !== subcollectionId) return null;
575
647
  return (
576
648
  <div
577
- className={cls("relative flex-grow h-full overflow-auto w-full",
578
- {
579
- "hidden": selectedTab !== subcollectionId
580
- })}
649
+ className={"relative flex-grow h-full overflow-auto w-full"}
581
650
  key={`subcol_${subcollectionId}`}
582
651
  role="tabpanel">
583
652
 
@@ -882,22 +951,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
882
951
  : (!readOnly
883
952
  ? (
884
953
  <ErrorBoundary>
885
- <div className="flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
886
-
887
- {formex.dirty
888
- ? <Tooltip title={"Unsaved changes"}
889
- className={"self-end sticky top-4 z-10"}>
890
- <Chip size={"small"} colorScheme={"orangeDarker"}>
891
- <EditIcon size={"smallest"}/>
892
- </Chip>
893
- </Tooltip>
894
- : <Tooltip title={"In sync with the database"}
895
- className={"self-end sticky top-4 z-10"}>
896
- <Chip size={"small"}>
897
- <CheckIcon size={"smallest"}/>
898
- </Chip>
899
- </Tooltip>}
900
-
954
+ <>
901
955
  <div
902
956
  className={"w-full py-2 flex flex-col items-start mt-4 lg:mt-8 mb-8"}>
903
957
 
@@ -929,12 +983,11 @@ export function EntityEditViewInner<M extends Record<string, any>>({
929
983
  <ErrorFocus containerRef={formRef}/>
930
984
 
931
985
  </div>
932
-
933
- {actionsAtTheBottom && <div className="h-16"/>}
934
-
935
986
  </>}
936
987
 
937
- </div>
988
+ {actionsAtTheBottom && <div className="h-16"/>}
989
+
990
+ </>
938
991
  </ErrorBoundary>
939
992
  )
940
993
  : (
@@ -1028,28 +1081,27 @@ export function EntityEditViewInner<M extends Record<string, any>>({
1028
1081
  noValidate
1029
1082
  className={"flex-1 flex flex-row w-full overflow-y-auto justify-center"}>
1030
1083
 
1031
- <div
1032
- role="tabpanel"
1033
- hidden={!mainViewVisible}
1084
+ <FormLayout
1085
+ className={!mainViewVisible ? "hidden" : ""}
1034
1086
  id={`form_${path}`}
1035
- className={cls("relative flex flex-row max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-5xl w-full h-fit", {
1036
- "hidden": !mainViewVisible
1037
- })}>
1038
-
1087
+ formex={formex}>
1039
1088
  {globalLoading
1040
- ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10"><CircularProgressCenter/></div>
1089
+ ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
1090
+ <CircularProgressCenter/>
1091
+ </div>
1041
1092
  : entityView}
1093
+ </FormLayout>
1042
1094
 
1043
- </div>
1044
-
1045
- {customViewsView}
1046
-
1047
- {subCollectionsViews}
1095
+ {secondaryForms}
1048
1096
 
1049
1097
  {shouldShowEntityActions && dialogActions}
1050
1098
 
1051
1099
  </form>
1052
1100
 
1101
+ {customViewsView}
1102
+
1103
+ {subCollectionsViews}
1104
+
1053
1105
  </div>;
1054
1106
 
1055
1107
  if (plugins) {
@@ -1238,7 +1290,7 @@ function buildSideActions<M extends object>({
1238
1290
  }: ActionsViewProps<M>) {
1239
1291
 
1240
1292
  return <div
1241
- className={cls("overflow-auto h-full flex flex-col gap-2 w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin)}>
1293
+ className={cls("overflow-auto h-full flex flex-col gap-2 w-80 xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin)}>
1242
1294
 
1243
1295
  <LoadingButton
1244
1296
  fullWidth={true}
@@ -74,7 +74,7 @@ export const PropertyFieldBinding = React.memo(PropertyFieldBindingInternal, (a:
74
74
  return false;
75
75
  }) as typeof PropertyFieldBindingInternal;
76
76
 
77
- function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>>
77
+ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Record<string, any> = any>
78
78
  ({
79
79
  propertyKey,
80
80
  property,
@@ -175,7 +175,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
175
175
 
176
176
  }
177
177
 
178
- type ResolvedPropertyFieldBindingProps<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>> =
178
+ type ResolvedPropertyFieldBindingProps<T extends CMSType = CMSType, M extends Record<string, any> = any> =
179
179
  Omit<PropertyFieldBindingProps<T, M>, "property">
180
180
  & {
181
181
  property: ResolvedProperty<T>
@@ -20,7 +20,7 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
20
20
  showError,
21
21
  isSubmitting,
22
22
  setValue,
23
- minimalistView,
23
+ minimalistView: minimalistViewProp,
24
24
  property,
25
25
  includeDescription,
26
26
  underlyingValueHasChanged,
@@ -28,6 +28,8 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
28
28
  disabled
29
29
  }: FieldProps<T, any, any>) {
30
30
 
31
+ const minimalistView = minimalistViewProp || property.minimalistView;
32
+
31
33
  let resolvedProperties = "resolvedProperties" in property ? property.resolvedProperties : undefined;
32
34
  if (!resolvedProperties) {
33
35
  resolvedProperties = getArrayResolvedProperties({
@@ -25,13 +25,15 @@ export function ArrayOfReferencesFieldBinding({
25
25
  showError,
26
26
  disabled,
27
27
  isSubmitting,
28
- minimalistView,
28
+ minimalistView: minimalistViewProp,
29
29
  property,
30
30
  includeDescription,
31
31
  setValue,
32
32
  setFieldValue
33
33
  }: ArrayOfReferencesFieldProps) {
34
34
 
35
+ const minimalistView = minimalistViewProp || property.minimalistView;
36
+
35
37
  const ofProperty = property.of as ResolvedProperty;
36
38
  if (ofProperty.dataType !== "reference") {
37
39
  throw Error("ArrayOfReferencesField expected a property containing references");
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useState } from "react";
1
+ import React, { useEffect, useState } from "react";
2
2
 
3
3
  import { Field, useFormex } from "@firecms/formex";
4
4
 
@@ -28,7 +28,7 @@ export function BlockFieldBinding<T extends Array<any>>({
28
28
  isSubmitting,
29
29
  setValue,
30
30
  setFieldValue,
31
- minimalistView,
31
+ minimalistView: minimalistViewProp,
32
32
  property,
33
33
  includeDescription,
34
34
  underlyingValueHasChanged,
@@ -36,6 +36,8 @@ export function BlockFieldBinding<T extends Array<any>>({
36
36
  disabled
37
37
  }: FieldProps<T>) {
38
38
 
39
+ const minimalistView = minimalistViewProp || property.minimalistView;
40
+
39
41
  if (!property.oneOf)
40
42
  throw Error("ArrayOneOfField misconfiguration. Property `oneOf` not set");
41
43
 
@@ -21,7 +21,7 @@ export function MapFieldBinding({
21
21
  error,
22
22
  disabled,
23
23
  property,
24
- minimalistView,
24
+ minimalistView: minimalistViewProp,
25
25
  includeDescription,
26
26
  underlyingValueHasChanged,
27
27
  autoFocus,
@@ -31,6 +31,7 @@ export function MapFieldBinding({
31
31
 
32
32
  const pickOnlySomeKeys = property.pickOnlySomeKeys || false;
33
33
  const expanded = property.expanded === undefined ? true : property.expanded;
34
+ const minimalistView = minimalistViewProp || property.minimalistView;
34
35
 
35
36
  if (!property.properties) {
36
37
  throw Error(`You need to specify a 'properties' prop (or specify a custom field) in your map property ${propertyKey}`);
@@ -23,7 +23,7 @@ export function RepeatFieldBinding<T extends Array<any>>({
23
23
  isSubmitting,
24
24
  setValue,
25
25
  setFieldValue,
26
- minimalistView,
26
+ minimalistView: minimalistViewProp,
27
27
  property,
28
28
  includeDescription,
29
29
  underlyingValueHasChanged,
@@ -31,6 +31,8 @@ export function RepeatFieldBinding<T extends Array<any>>({
31
31
  disabled
32
32
  }: FieldProps<T>) {
33
33
 
34
+ const minimalistView = minimalistViewProp || property.minimalistView;
35
+
34
36
  if (!property.of)
35
37
  throw Error("RepeatFieldBinding misconfiguration. Property `of` not set");
36
38
 
@@ -11,7 +11,7 @@ import {
11
11
  } from "../util/navigation_from_path";
12
12
  import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
13
13
  import { toArray } from "../util/arrays";
14
- import { EntityCollectionView } from "../components";
14
+ import { EntityCollectionView, NotFoundPage } from "../components";
15
15
  import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
16
16
 
17
17
  export function FireCMSRoute() {
@@ -191,11 +191,11 @@ function EntityFullScreenRoute({
191
191
  const lastCollectionEntry = navigationEntries.findLast((entry) => entry.type === "collection");
192
192
 
193
193
  if (isNew && !lastCollectionEntry) {
194
- throw new Error("No collection found in the navigation");
194
+ throw new Error("INTERNAL: No collection found in the navigation");
195
195
  }
196
196
 
197
197
  if (!isNew && !lastEntityEntry) {
198
- throw new Error("No entity found in the navigation");
198
+ return <NotFoundPage/>;
199
199
  }
200
200
 
201
201
  const collection = isNew ? lastCollectionEntry!.collection : lastEntityEntry!.parentCollection;
@@ -498,21 +498,26 @@ export type EntityCustomView<M extends Record<string, any> = any> =
498
498
  /**
499
499
  * Key of this custom view.
500
500
  */
501
- key: string,
501
+ key: string;
502
+
502
503
  /**
503
504
  * Name of this custom view.
504
505
  */
505
- name: string,
506
+ name: string;
507
+
506
508
  /**
507
- * If set to true, the actions of the entity will be included in the
508
- * bottom of the panel (save buttons, delete buttons, etc.)
509
+ * If set to true, the actions of the entity (save, discard,delete) will be
510
+ * included in the view. By default the actions are located in the right or bottom,
511
+ * based on the screen size. You can force the actions to be located at the bottom
512
+ * by setting this prop to "bottom".
509
513
  */
510
- includeActions?: boolean;
514
+ includeActions?: boolean | "bottom";
515
+
511
516
  /**
512
517
  * Builder for rendering the custom view
513
518
  */
514
519
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
515
- }
520
+ };
516
521
 
517
522
  /**
518
523
  * Parameters passed to the builder in charge of rendering a custom panel for
@@ -81,7 +81,8 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
81
81
  partOfArray?: boolean;
82
82
 
83
83
  /**
84
- * Should this field render with the minimal amount of UI elements
84
+ * Display the child properties directly, without being wrapped in an
85
+ * extendable panel. Note that this will also hide the title of this property.
85
86
  */
86
87
  minimalistView?: boolean;
87
88
 
@@ -207,7 +208,8 @@ export interface PropertyFieldBindingProps<T extends CMSType, M extends Record<s
207
208
  partOfArray?: boolean;
208
209
 
209
210
  /**
210
- * Is this field part of a block (oneOf array)
211
+ * Display the child properties directly, without being wrapped in an
212
+ * extendable panel. Note that this will also hide the title of this property.
211
213
  */
212
214
  minimalistView?: boolean;
213
215
 
@@ -285,14 +285,14 @@ export type PropertyBuilder<T extends CMSType = any, M extends Record<string, an
285
285
  /**
286
286
  * @group Entity properties
287
287
  */
288
- export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>> =
288
+ export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = any> =
289
289
  Property<T>
290
290
  | PropertyBuilder<T, M>;
291
291
 
292
292
  /**
293
293
  * @group Entity properties
294
294
  */
295
- export type PropertiesOrBuilders<M extends Record<string, any> = Record<string, any>> =
295
+ export type PropertiesOrBuilders<M extends Record<string, any> = any> =
296
296
  {
297
297
  [k in keyof M]: PropertyOrBuilder<M[k], M>;
298
298
  };
@@ -469,6 +469,12 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
469
469
  */
470
470
  expanded?: boolean;
471
471
 
472
+ /**
473
+ * Display the child properties directly, without being wrapped in an
474
+ * extendable panel.
475
+ */
476
+ minimalistView?: boolean;
477
+
472
478
  }
473
479
 
474
480
  /**
@@ -517,6 +523,12 @@ export interface MapProperty<T extends Record<string, CMSType> = Record<string,
517
523
  */
518
524
  spreadChildren?: boolean;
519
525
 
526
+ /**
527
+ * Display the child properties directly, without being wrapped in an
528
+ * extendable panel. Note that this will also hide the title of this property.
529
+ */
530
+ minimalistView?: boolean;
531
+
520
532
  /**
521
533
  * Should the field be initially expanded. Defaults to `true`
522
534
  */
@@ -26,8 +26,10 @@ import {
26
26
  * @param collection
27
27
  * @group Builder
28
28
  */
29
- export function buildCollection<M extends Record<string, any> = any,
30
- USER extends User = User>(
29
+ export function buildCollection<
30
+ M extends Record<string, any> = any,
31
+ USER extends User = User>
32
+ (
31
33
  collection: EntityCollection<M, USER>
32
34
  ): EntityCollection<M, USER> {
33
35
  return collection;
@@ -39,7 +41,7 @@ export function buildCollection<M extends Record<string, any> = any,
39
41
  * @param property
40
42
  * @group Builder
41
43
  */
42
- export function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = Record<string, any>>(
44
+ export function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = any>(
43
45
  property: P
44
46
  ):
45
47
  P extends StringProperty ? StringProperty :