@firecms/core 3.0.0-canary.50 → 3.0.0-canary.52

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 (44) hide show
  1. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  2. package/dist/components/common/index.d.ts +1 -0
  3. package/dist/core/Drawer.d.ts +5 -12
  4. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  5. package/dist/core/Scaffold.d.ts +6 -9
  6. package/dist/core/index.d.ts +3 -4
  7. package/dist/hooks/index.d.ts +1 -0
  8. package/dist/index.es.js +3102 -3129
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/index.umd.js +5 -5
  11. package/dist/index.umd.js.map +1 -1
  12. package/dist/types/navigation.d.ts +2 -2
  13. package/dist/util/icon_synonyms.d.ts +0 -93
  14. package/dist/util/resolutions.d.ts +8 -4
  15. package/package.json +4 -4
  16. package/src/components/EntityCollectionView/EntityCollectionView.tsx +3 -7
  17. package/src/components/EntityView.tsx +1 -1
  18. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  19. package/src/components/ReferenceWidget.tsx +1 -1
  20. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +2 -2
  21. package/src/components/common/index.ts +1 -0
  22. package/src/components/common/types.tsx +1 -1
  23. package/src/components/common/useColumnsIds.tsx +10 -2
  24. package/src/core/Drawer.tsx +14 -66
  25. package/src/core/DrawerNavigationItem.tsx +62 -0
  26. package/src/core/EntitySidePanel.tsx +1 -1
  27. package/src/core/FireCMS.tsx +3 -4
  28. package/src/core/Scaffold.tsx +75 -61
  29. package/src/core/index.tsx +3 -4
  30. package/src/form/EntityForm.tsx +2 -2
  31. package/src/form/field_bindings/SelectFieldBinding.tsx +4 -1
  32. package/src/hooks/index.tsx +1 -0
  33. package/src/hooks/useBuildNavigationController.tsx +0 -1
  34. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  35. package/src/internal/useBuildSideEntityController.tsx +3 -2
  36. package/src/preview/components/EnumValuesChip.tsx +1 -1
  37. package/src/preview/property_previews/NumberPropertyPreview.tsx +1 -0
  38. package/src/types/navigation.ts +1 -2
  39. package/src/types/storage.ts +1 -1
  40. package/src/util/enums.ts +1 -1
  41. package/src/util/icon_synonyms.ts +2 -95
  42. package/src/util/resolutions.ts +26 -7
  43. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  44. package/src/internal/useBuildCustomizationController.tsx +0 -5
@@ -0,0 +1,62 @@
1
+ import React from "react";
2
+
3
+ import { NavLink } from "react-router-dom";
4
+ import { cn, Tooltip } from "@firecms/ui";
5
+
6
+ export function DrawerNavigationItem({
7
+ name,
8
+ icon,
9
+ drawerOpen,
10
+ tooltipsOpen,
11
+ url,
12
+ onClick
13
+ }: {
14
+ icon: React.ReactElement,
15
+ name: string,
16
+ tooltipsOpen: boolean,
17
+ drawerOpen: boolean,
18
+ url: string,
19
+ onClick?: () => void,
20
+ }) {
21
+
22
+ const iconWrap = <div
23
+ className={"text-gray-600 dark:text-gray-500"}>
24
+ {icon}
25
+ </div>;
26
+
27
+ const listItem = <NavLink
28
+ onClick={onClick}
29
+ style={{
30
+ width: !drawerOpen ? "72px" : "280px",
31
+ transition: drawerOpen ? "width 150ms ease-in" : undefined
32
+ }}
33
+ className={({ isActive }: any) => cn("rounded-r-lg truncate",
34
+ "hover:bg-slate-300 hover:bg-opacity-75 dark:hover:bg-gray-700 dark:hover:bg-opacity-75 text-gray-800 dark:text-gray-200 hover:text-gray-900 hover:dark:text-white",
35
+ "flex flex-row items-center mr-8",
36
+ // "transition-all ease-in-out delay-100 duration-300",
37
+ // drawerOpen ? "w-full" : "w-18",
38
+ drawerOpen ? "pl-8 h-12" : "pl-6 h-11",
39
+ "font-medium text-sm",
40
+ isActive ? "bg-slate-200 bg-opacity-60 dark:bg-gray-800 dark:bg-opacity-30" : ""
41
+ )}
42
+ to={url}
43
+ >
44
+
45
+ {iconWrap}
46
+
47
+ <div
48
+ className={cn(
49
+ drawerOpen ? "opacity-100" : "opacity-0 hidden",
50
+ "ml-4 font-inherit text-inherit"
51
+ )}>
52
+ {name.toUpperCase()}
53
+ </div>
54
+ </NavLink>;
55
+
56
+ return <Tooltip
57
+ open={drawerOpen ? false : tooltipsOpen}
58
+ side="right"
59
+ title={name}>
60
+ {listItem}
61
+ </Tooltip>;
62
+ }
@@ -33,7 +33,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
33
33
  if (!props) return undefined;
34
34
  let usedCollection = props.collection;
35
35
 
36
- const registryCollection = navigationController.getCollection(props.path, props.entityId);
36
+ const registryCollection = navigationController.getCollection(props.path);
37
37
  if (registryCollection) {
38
38
  usedCollection = registryCollection;
39
39
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useMemo } from "react";
2
2
 
3
- import { EntityCollection, FireCMSContext, FireCMSPlugin, FireCMSProps, User } from "../types";
3
+ import { CustomizationController, EntityCollection, FireCMSContext, FireCMSPlugin, FireCMSProps, User } from "../types";
4
4
  import { AuthControllerContext, ModeControllerContext } from "../contexts";
5
5
  import { useBuildSideEntityController } from "../internal/useBuildSideEntityController";
6
6
  import { useCustomizationController, useFireCMSContext, useModeController } from "../hooks";
@@ -15,7 +15,6 @@ import { SideDialogsControllerContext } from "../contexts/SideDialogsControllerC
15
15
  import { CenteredView, Typography, useLocaleConfig } from "@firecms/ui";
16
16
  import { DialogsProvider } from "../contexts/DialogsProvider";
17
17
  import { useBuildDataSource } from "../internal/useBuildDataSource";
18
- import { useBuildCustomizationController } from "../internal/useBuildCustomizationController";
19
18
  import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
20
19
  import { AnalyticsContext } from "../contexts/AnalyticsContext";
21
20
  import { useProjectLog } from "../hooks/useProjectLog";
@@ -70,7 +69,7 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
70
69
 
71
70
  const loading = authController.initialLoading || navigationController.loading || pluginsLoading;
72
71
 
73
- const customizationController = useBuildCustomizationController({
72
+ const customizationController: CustomizationController = {
74
73
  dateTimeFormat,
75
74
  locale,
76
75
  entityLinkBuilder,
@@ -78,7 +77,7 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
78
77
  entityViews: entityViews ?? [],
79
78
  propertyConfigs: propertyConfigs ?? {},
80
79
  components
81
- });
80
+ };
82
81
 
83
82
  const analyticsController = useMemo(() => ({
84
83
  onAnalyticsEvent
@@ -9,10 +9,26 @@ import { ChevronLeftIcon, cn, defaultBorderMixin, IconButton, MenuIcon, Sheet, T
9
9
 
10
10
  export const DRAWER_WIDTH = 280;
11
11
 
12
+ const DrawerContext = React.createContext<DrawerProps>({
13
+ hovered: false,
14
+ drawerOpen: false,
15
+ openDrawer: () => {
16
+ throw new Error("openDrawer not implemented");
17
+ },
18
+ closeDrawer: () => {
19
+ throw new Error("closeDrawer not implemented");
20
+ },
21
+ autoOpenDrawer: false
22
+ });
23
+
24
+ export function useDrawer() {
25
+ return React.useContext(DrawerContext);
26
+ }
27
+
12
28
  /**
13
29
  * @group Core
14
30
  */
15
- export interface ScaffoldProps<ExtraDrawerProps = object, ExtraAppbarProps = object> {
31
+ export interface ScaffoldProps<ExtraAppbarProps = object> {
16
32
 
17
33
  /**
18
34
  * Name of the app, displayed as the main title and in the tab title
@@ -30,15 +46,10 @@ export interface ScaffoldProps<ExtraDrawerProps = object, ExtraAppbarProps = obj
30
46
  includeDrawer?: boolean;
31
47
 
32
48
  /**
33
- * In case you need to override the view that gets rendered as a drawer
34
- * @see DefaultDrawer
35
- */
36
- Drawer?: React.ComponentType<DrawerProps<ExtraDrawerProps>>;
37
-
38
- /**
39
- * Additional props passed to the custom Drawer
49
+ * You can define a custom drawer to be displayed in the scaffold.
50
+ * Use the hook `useDrawer` to access the context values.
40
51
  */
41
- drawerProps?: Partial<DrawerProps> & ExtraDrawerProps;
52
+ drawer?: React.ReactNode;
42
53
 
43
54
  /**
44
55
  * Open the drawer on hover
@@ -78,8 +89,7 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
78
89
  logo,
79
90
  includeDrawer = true,
80
91
  autoOpenDrawer,
81
- Drawer = DefaultDrawer,
82
- drawerProps,
92
+ drawer = <DefaultDrawer/>,
83
93
  FireCMSAppBar = DefaultFireCMSAppBar,
84
94
  fireCMSAppBarProps,
85
95
  } = props;
@@ -92,61 +102,65 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
92
102
  const setOnHoverTrue = useCallback(() => setOnHover(true), []);
93
103
  const setOnHoverFalse = useCallback(() => setOnHover(false), []);
94
104
 
105
+ const handleDrawerOpen = useCallback(() => {
106
+ setDrawerOpen(true);
107
+ }, []);
108
+
95
109
  const handleDrawerClose = useCallback(() => {
96
110
  setDrawerOpen(false);
97
111
  }, []);
98
112
 
99
113
  const computedDrawerOpen: boolean = drawerOpen || Boolean(largeLayout && autoOpenDrawer && onHover);
114
+
100
115
  return (
101
- <div
102
- className="flex h-screen w-screen bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-white overflow-hidden"
103
- style={{
104
- paddingTop: "env(safe-area-inset-top)",
105
- paddingLeft: "env(safe-area-inset-left)",
106
- paddingRight: "env(safe-area-inset-right)",
107
- paddingBottom: "env(safe-area-inset-bottom)",
108
- height: "100dvh"
109
- // "@supports (height: 100dvh)": {
110
- // height: "100dvh"
111
- // }
112
- }}>
113
-
114
- <FireCMSAppBar title={name}
115
- includeDrawer={includeDrawer}
116
- logo={logo}
117
- drawerOpen={computedDrawerOpen}
118
- {...fireCMSAppBarProps}/>
119
-
120
- <StyledDrawer
121
- displayed={includeDrawer}
122
- onMouseEnter={setOnHoverTrue}
123
- onMouseMove={setOnHoverTrue}
124
- onMouseLeave={setOnHoverFalse}
125
- open={computedDrawerOpen}
126
- logo={logo}
127
- hovered={onHover}
128
- setDrawerOpen={setDrawerOpen}>
129
- {includeDrawer && (
130
- <Drawer
131
- hovered={onHover}
132
- drawerOpen={computedDrawerOpen}
133
- closeDrawer={handleDrawerClose}
134
- {...drawerProps}/>)}
135
- </StyledDrawer>
136
-
137
- <main
138
- className="flex flex-col flex-grow overflow-auto">
139
- <DrawerHeader/>
140
- <div
141
- className={cn(defaultBorderMixin, "flex-grow overflow-auto lg:m-0 lg:mx-4 lg:mb-4 lg:rounded-lg lg:border lg:border-solid m-0 mt-1")}>
142
-
143
- <ErrorBoundary>
144
- {children}
145
- </ErrorBoundary>
146
-
147
- </div>
148
- </main>
149
- </div>
116
+ <DrawerContext.Provider value={{
117
+ hovered: onHover,
118
+ drawerOpen: computedDrawerOpen,
119
+ closeDrawer: handleDrawerClose,
120
+ openDrawer: handleDrawerOpen,
121
+ autoOpenDrawer
122
+ }}>
123
+ <div
124
+ className="flex h-screen w-screen bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-white overflow-hidden"
125
+ style={{
126
+ paddingTop: "env(safe-area-inset-top)",
127
+ paddingLeft: "env(safe-area-inset-left)",
128
+ paddingRight: "env(safe-area-inset-right)",
129
+ paddingBottom: "env(safe-area-inset-bottom)",
130
+ height: "100dvh"
131
+ }}>
132
+
133
+ <FireCMSAppBar title={name}
134
+ includeDrawer={includeDrawer}
135
+ logo={logo}
136
+ drawerOpen={computedDrawerOpen}
137
+ {...fireCMSAppBarProps}/>
138
+ <DrawerWrapper
139
+ displayed={includeDrawer}
140
+ onMouseEnter={setOnHoverTrue}
141
+ onMouseMove={setOnHoverTrue}
142
+ onMouseLeave={setOnHoverFalse}
143
+ open={computedDrawerOpen}
144
+ logo={logo}
145
+ hovered={onHover}
146
+ setDrawerOpen={setDrawerOpen}>
147
+ {includeDrawer && drawer}
148
+ </DrawerWrapper>
149
+
150
+ <main
151
+ className="flex flex-col flex-grow overflow-auto">
152
+ <DrawerHeader/>
153
+ <div
154
+ className={cn(defaultBorderMixin, "flex-grow overflow-auto lg:m-0 lg:mx-4 lg:mb-4 lg:rounded-lg lg:border lg:border-solid m-0 mt-1")}>
155
+
156
+ <ErrorBoundary>
157
+ {children}
158
+ </ErrorBoundary>
159
+
160
+ </div>
161
+ </main>
162
+ </div>
163
+ </DrawerContext.Provider>
150
164
  );
151
165
  },
152
166
  equal
@@ -158,7 +172,7 @@ const DrawerHeader = () => {
158
172
  );
159
173
  };
160
174
 
161
- function StyledDrawer(props: {
175
+ function DrawerWrapper(props: {
162
176
  children: React.ReactNode,
163
177
  displayed: boolean,
164
178
  open: boolean,
@@ -1,10 +1,9 @@
1
1
  export * from "./FireCMS";
2
2
 
3
- export type { ScaffoldProps } from "./Scaffold";
4
- export { Scaffold } from "./Scaffold";
3
+ export * from "./Scaffold";
5
4
 
6
- export type { DrawerProps } from "./Drawer";
7
- export { Drawer, DrawerNavigationItem } from "./Drawer";
5
+ export * from "./Drawer";
6
+ export * from "./DrawerNavigationItem";
8
7
 
9
8
  export * from "./field_configs";
10
9
 
@@ -40,7 +40,7 @@ import { ErrorBoundary } from "../components";
40
40
  import {
41
41
  copyEntityAction,
42
42
  deleteEntityAction
43
- } from "../components/EntityCollectionTable/internal/default_entity_actions";
43
+ } from "../components/common/default_entity_actions";
44
44
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
45
45
  import { ValidationError } from "yup";
46
46
  import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
@@ -189,7 +189,7 @@ function EntityFormInternal<M extends Record<string, any>>({
189
189
  path,
190
190
  values: entity?.values,
191
191
  fields: customizationController.propertyConfigs
192
- }), [entity?.values, path]);
192
+ }), [entity?.values, path, customizationController.propertyConfigs]);
193
193
 
194
194
  const mustSetCustomId: boolean = (status === "new" || status === "copy") &&
195
195
  (Boolean(initialResolvedCollection.customId) && initialResolvedCollection.customId !== "optional");
@@ -30,6 +30,8 @@ export function SelectFieldBinding<T extends EnumType>({
30
30
  includeDescription
31
31
  }: SelectProps<T>) {
32
32
 
33
+ console.log("SelectFieldBinding", propertyKey, value,)
34
+
33
35
  const enumValues = property.enumValues;
34
36
 
35
37
  useClearRestoreValue({
@@ -48,7 +50,7 @@ export function SelectFieldBinding<T extends EnumType>({
48
50
  <>
49
51
 
50
52
  <Select
51
- value={value ? value.toString() : ""}
53
+ value={value !== undefined && value != null ? value.toString() : ""}
52
54
  disabled={disabled}
53
55
  position="item-aligned"
54
56
  inputClassName={cn("w-full")}
@@ -70,6 +72,7 @@ export function SelectFieldBinding<T extends EnumType>({
70
72
  return setValue(newValue as T);
71
73
  }}
72
74
  renderValue={(enumKey: any) => {
75
+ console.log("renderValue", enumKey)
73
76
  return <EnumValuesChip
74
77
  enumKey={enumKey}
75
78
  enumValues={enumValues}
@@ -10,6 +10,7 @@ export * from "./useResolvedNavigationFrom";
10
10
 
11
11
  export * from "./useStorageSource";
12
12
  export * from "./useAuthController";
13
+ export * from "./useDialogsController";
13
14
  export * from "./useSideDialogsController";
14
15
  export * from "./useSideEntityController";
15
16
  export * from "./useFireCMSContext";
@@ -241,7 +241,6 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
241
241
 
242
242
  const getCollection = useCallback((
243
243
  idOrPath: string,
244
- entityId?: string,
245
244
  includeUserOverride = false
246
245
  ): EC | undefined => {
247
246
  const collections = collectionsRef.current;
@@ -80,7 +80,7 @@ export function resolveNavigationFrom<M extends Record<string, any>, UserType ex
80
80
  if (entry.type === "collection") {
81
81
  return Promise.resolve(entry);
82
82
  } else if (entry.type === "entity") {
83
- const collection = navigation.getCollection(entry.path, entry.entityId);
83
+ const collection = navigation.getCollection(entry.path);
84
84
  if (!collection) {
85
85
  throw Error(`No collection defined in the navigation for the entity with path ${entry.path}`);
86
86
  }
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef } from "react";
2
2
  import {
3
3
  EntityCollection,
4
4
  EntitySidePanelProps,
5
- NavigationController,
5
+ NavigationController, PropertyConfig,
6
6
  ResolvedProperty,
7
7
  SideDialogPanelProps,
8
8
  SideDialogsController,
@@ -48,7 +48,8 @@ function calculateCollectionDesiredWidth(collection: EntityCollection<any>): str
48
48
  }
49
49
  const resolvedCollection = resolveCollection({
50
50
  collection,
51
- path: "__ignored"
51
+ path: "__ignored",
52
+ ignoreMissingFields: true
52
53
  });
53
54
 
54
55
  let result = FORM_CONTAINER_WIDTH
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
+ import { Chip } from "@firecms/ui";
2
3
  import { EnumValues } from "../../types";
3
4
  import { buildEnumLabel, enumToObjectEntries, getColorScheme, getLabelOrConfigFrom } from "../../util/enums";
4
- import { Chip } from "@firecms/ui";
5
5
 
6
6
  export interface EnumValuesChipProps {
7
7
  enumValues?: EnumValues;
@@ -15,6 +15,7 @@ export function NumberPropertyPreview({
15
15
  if (property.enumValues) {
16
16
  const enumKey = value;
17
17
  const enumValues = enumToObjectEntries(property.enumValues);
18
+ console.log("NumberPropertyPreview", enumValues)
18
19
  if (!enumValues)
19
20
  return <>{value}</>;
20
21
  return <EnumValuesChip
@@ -57,10 +57,9 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
57
57
  * The collection is resolved from the given path or alias.
58
58
  */
59
59
  getCollection: (pathOrId: string,
60
- entityId?: string,
61
60
  includeUserOverride?: boolean) => EC | undefined;
62
61
  /**
63
- * Get the collection configuration from its parent path segments.
62
+ * Get the collection configuration from its parent ids.
64
63
  */
65
64
  getCollectionFromIds: (ids: string[]) => EC | undefined;
66
65
 
@@ -101,5 +101,5 @@ export interface StorageSource {
101
101
  * @param props
102
102
  * @param bucket
103
103
  */
104
- getFile: (path:string, bucket?: string) => Promise<File | null>;
104
+ getFile: (path: string, bucket?: string) => Promise<File | null>;
105
105
  }
package/src/util/enums.ts CHANGED
@@ -22,7 +22,7 @@ export function enumToObjectEntries(enumValues: EnumValues): EnumValueConfig[] {
22
22
  }
23
23
 
24
24
  export function getLabelOrConfigFrom(enumValues: EnumValueConfig[], key?: string | number): EnumValueConfig | undefined {
25
- if (!key) return undefined;
25
+ if (key === null || key === undefined) return undefined;
26
26
  return enumValues.find((entry) => String(entry.id) === String(key));
27
27
  }
28
28