@firecms/core 3.0.0-alpha.58 → 3.0.0-alpha.59

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
- "version": "3.0.0-alpha.58",
3
+ "version": "3.0.0-alpha.59",
4
4
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
5
5
  "funding": {
6
6
  "url": "https://github.com/sponsors/firecmsco"
@@ -45,7 +45,7 @@
45
45
  "generateIcons": "ts-node --esm src/icons/generateIcons.ts"
46
46
  },
47
47
  "dependencies": {
48
- "@firecms/ui": "^3.0.0-alpha.58",
48
+ "@firecms/ui": "^3.0.0-alpha.59",
49
49
  "@fontsource/ibm-plex-mono": "^5.0.8",
50
50
  "@fontsource/roboto": "^5.0.8",
51
51
  "@hello-pangea/dnd": "^16.5.0",
@@ -116,7 +116,7 @@
116
116
  "dist",
117
117
  "src"
118
118
  ],
119
- "gitHead": "64c77fec3109f226216fe452ab828c9fcca6f7c8",
119
+ "gitHead": "9d82460b4b28c7b31d097ff3e0e28f77c05b1023",
120
120
  "publishConfig": {
121
121
  "access": "public"
122
122
  }
@@ -1,52 +1,38 @@
1
1
  import React, { useCallback, useMemo } from "react";
2
2
 
3
- import { Entity, EntityCollection, EntityReference, FilterValues, ResolvedProperty } from "../types";
4
- import { getReferenceFrom, getReferencePreviewKeys } from "../util";
5
- import { PropertyPreview, SkeletonPropertyComponent } from "../preview";
6
- import {
7
- useEntityFetch,
8
- useFireCMSContext,
9
- useNavigationController,
10
- useReferenceDialog,
11
- useSideEntityController
12
- } from "../hooks";
13
- import { LabelWithIcon } from "../components";
14
- import {
15
- Button,
16
- ClearIcon,
17
- cn,
18
- ErrorIcon,
19
- IconButton,
20
- KeyboardTabIcon,
21
- LinkIcon,
22
- Tooltip,
23
- Typography
24
- } from "@firecms/ui";
25
- import { ErrorBoundary, ErrorView } from "../components";
3
+ import { Entity, EntityCollection, EntityReference, FilterValues } from "../types";
4
+ import { getReferenceFrom } from "../util";
5
+ import { PreviewSize, ReferencePreview } from "../preview";
6
+ import { useNavigationController, useReferenceDialog } from "../hooks";
7
+ import { Button, cn } from "@firecms/ui";
26
8
 
27
9
  /**
28
10
  * This field allows selecting reference/s.
29
- * @param name
30
- * @param path
31
- * @param disabled
32
- * @param value
33
- * @param setValue
34
- * @param previewProperties
35
- * @param forceFilter
36
- * @constructor
37
11
  */
38
12
  export function ReferenceWidget<M extends Record<string, any>>({
39
13
  name,
14
+ multiselect = false,
40
15
  path,
41
16
  disabled,
42
17
  value,
43
- setValue,
18
+ onReferenceSelected,
19
+ onMultipleReferenceSelected,
44
20
  previewProperties,
45
- forceFilter
21
+ forceFilter,
22
+ size,
23
+ className
46
24
  }: {
47
25
  name?: string,
48
- value?: EntityReference,
49
- setValue: (value: EntityReference | null) => void,
26
+ multiselect?: boolean,
27
+ value: EntityReference | EntityReference[] | null,
28
+ onReferenceSelected?: (params: {
29
+ reference: EntityReference | null,
30
+ entity: Entity<M> | null
31
+ }) => void,
32
+ onMultipleReferenceSelected?: (params: {
33
+ references: EntityReference[] | null,
34
+ entities: Entity<M>[] | null
35
+ }) => void,
50
36
  path: string,
51
37
  disabled?: boolean,
52
38
  previewProperties?: string[];
@@ -54,11 +40,11 @@ export function ReferenceWidget<M extends Record<string, any>>({
54
40
  * Allow selection of entities that pass the given filter only.
55
41
  */
56
42
  forceFilter?: FilterValues<string>;
43
+ size: PreviewSize;
44
+ className?: string;
57
45
  }) {
58
46
 
59
- const fireCMSContext = useFireCMSContext();
60
47
  const navigationController = useNavigationController();
61
- const sideEntityController = useSideEntityController();
62
48
 
63
49
  const collection: EntityCollection | undefined = useMemo(() => {
64
50
  return navigationController.getCollection(path);
@@ -68,188 +54,90 @@ export function ReferenceWidget<M extends Record<string, any>>({
68
54
  throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
69
55
  }
70
56
 
71
- const validValue = value && value instanceof EntityReference;
72
-
73
- const {
74
- entity,
75
- dataLoading,
76
- dataLoadingError
77
- } = useEntityFetch({
78
- path,
79
- entityId: validValue ? value.id : undefined,
80
- collection,
81
- useCache: true
82
- });
57
+ const onSingleEntitySelected = useCallback((entity: Entity<M> | null) => {
58
+ if (disabled)
59
+ return;
60
+ if (onReferenceSelected) {
61
+ const reference = entity ? getReferenceFrom(entity) : null;
62
+ onReferenceSelected?.({ reference, entity });
63
+ }
64
+ }, [disabled, onReferenceSelected]);
83
65
 
84
- const onSingleEntitySelected = useCallback((entity: Entity<M>) => {
66
+ const onMultipleEntitiesSelected = useCallback((entities: Entity<M>[]) => {
85
67
  if (disabled)
86
68
  return;
87
- setValue(entity ? getReferenceFrom(entity) : null);
88
- }, [disabled, setValue]);
69
+ if (onMultipleReferenceSelected) {
70
+ const references = entities ? entities.map(e => getReferenceFrom(e)) : null;
71
+ onMultipleReferenceSelected({ references, entities });
72
+ }
73
+ }, [disabled, onReferenceSelected]);
89
74
 
90
75
  const referenceDialogController = useReferenceDialog({
91
- multiselect: false,
76
+ multiselect,
92
77
  path,
93
78
  collection,
94
79
  onSingleEntitySelected,
80
+ onMultipleEntitiesSelected,
95
81
  forceFilter
96
82
  }
97
83
  );
98
84
 
99
- const handleClickOpen = useCallback(() => {
100
- referenceDialogController.open();
101
- }, [referenceDialogController]);
102
-
103
85
  const clearValue = useCallback((e: React.MouseEvent) => {
104
86
  e.stopPropagation();
105
- setValue(null);
106
- }, [setValue]);
107
-
108
- const seeEntityDetails = useCallback((e: React.MouseEvent) => {
109
- e.stopPropagation();
110
- if (entity) {
111
- fireCMSContext.onAnalyticsEvent?.("entity_click_from_reference", {
112
- path: entity.path,
113
- entityId: entity.id
114
- });
115
- sideEntityController.open({
116
- entityId: entity.id,
117
- path,
118
- updateUrl: true
119
- });
120
- }
121
- }, [entity, path, sideEntityController]);
122
-
123
- const buildEntityView = (collection?: EntityCollection<any>) => {
124
-
125
- const missingEntity = entity && !entity.values;
126
-
127
- let body: React.ReactNode;
128
- if (!collection) {
129
- body = (
130
- <ErrorView
131
- error={"The specified collection does not exist. Check console"}/>
132
- );
133
- } else if (missingEntity) {
134
- body = (
135
- <Tooltip title={value && value.path}>
136
- <div className="flex items-center p-4 flex-grow">
137
- <ErrorIcon size={"small"} color={"error"}/>
138
- <div className="ml-4">Missing
139
- reference {entity && entity.id}</div>
140
- </div>
141
- </Tooltip>
142
- );
87
+ if (multiselect) {
88
+ onMultipleEntitiesSelected([]);
143
89
  } else {
144
- if (validValue) {
145
-
146
- const listProperties = getReferencePreviewKeys(collection, fireCMSContext.propertyConfigs, previewProperties, 3);
147
-
148
- body = (
149
- <div className="flex flex-col flex-grow ml-4 mr-4">
150
-
151
- {listProperties && listProperties.map((key) => {
152
- const property = collection.properties[key as string];
153
- if (!property) return null;
154
- return (
155
- <div
156
- key={`reference_previews_${key as string}`}
157
- className="mt-1 mb-1">
158
- <ErrorBoundary>{
159
- entity
160
- ? <PropertyPreview
161
- propertyKey={key as string}
162
- value={(entity.values)[key]}
163
- property={property as ResolvedProperty}
164
- entity={entity}
165
- size={"tiny"}/>
166
- : <SkeletonPropertyComponent
167
- property={property as ResolvedProperty}
168
- size={"tiny"}/>}
169
- </ErrorBoundary>
170
- </div>
171
- );
172
- })}
173
- </div>
174
- );
175
- } else {
176
- body = <div className="p-4 flex justify-center"
177
- onClick={disabled ? undefined : handleClickOpen}>
178
- <Typography variant={"label"}
179
- className="flex-grow text-center">No value
180
- set</Typography>
181
- {!disabled && <Button variant="outlined"
182
- color="primary">
183
- Set
184
- </Button>}
185
- </div>;
186
- }
90
+ onSingleEntitySelected(null);
187
91
  }
92
+ }, [onReferenceSelected]);
188
93
 
189
- return (
190
- <div
191
- onClick={disabled ? undefined : handleClickOpen}
192
- className="flex">
193
-
194
- <div className="flex flex-col flex-grow">
195
-
196
- <div className="flex flex-col flex-grow">
197
- <LabelWithIcon icon={<LinkIcon color={"inherit"}
198
- />}
199
- className="text-text-secondary dark:text-text-secondary-dark ml-3.5"
200
- title={name}
201
- />
202
-
203
- {entity &&
204
- <div className="self-center m-4">
205
- <Tooltip title={value && value.path}>
206
- <Typography variant={"caption"}
207
- className={"font-mono"}>
208
- {entity.id}
209
- </Typography>
210
- </Tooltip>
211
- </div>}
212
-
213
- {!missingEntity && entity && value &&
214
- <Tooltip title={`See details for ${entity.id}`}>
215
- <span>
216
- <IconButton
217
- onClick={seeEntityDetails}
218
- size="large">
219
- <KeyboardTabIcon/>
220
- </IconButton>
221
- </span>
222
- </Tooltip>}
223
-
224
- {value && <div>
225
- <Tooltip title=" Clear">
226
- <span>
227
- <IconButton
228
- disabled={disabled}
229
- onClick={disabled ? undefined : clearValue}
230
- size="large">
231
- <ClearIcon/>
232
- </IconButton>
233
- </span>
234
- </Tooltip>
235
- </div>}
236
-
237
- </div>
94
+ let child: React.ReactNode;
238
95
 
239
- {body}
240
-
241
- </div>
242
- </div>
243
- );
96
+ const onEntryClick = () => {
97
+ if (disabled)
98
+ return;
99
+ referenceDialogController.open();
244
100
  };
245
101
 
246
- return <Typography variant={"label"}
247
- className={cn("relative w-full transition-colors duration-200 ease-in border rounded font-medium",
248
- disabled ? "bg-opacity-50" : "hover:bg-opacity-75",
249
- "text-opacity-50 dark:text-white dark:text-opacity-50")}
250
- >
102
+ if (Array.isArray(value)) {
103
+ child = <div className={"flex flex-col gap-4"}>
104
+ {value.map((ref, index) => {
105
+ return <ReferencePreview
106
+ key={`reference_preview_${index}`}
107
+ onClick={onEntryClick}
108
+ reference={ref}
109
+ disabled={disabled}
110
+ previewProperties={previewProperties}
111
+ size={size}/>
112
+ })}
113
+ </div>
114
+ } else if (value instanceof EntityReference) {
115
+ child = <ReferencePreview
116
+ reference={value}
117
+ onClick={onEntryClick}
118
+ disabled={disabled}
119
+ previewProperties={previewProperties}
120
+ size={size}/>
251
121
 
252
- {collection && buildEntityView(collection)}
122
+ }
123
+ return <div className={cn("text-sm font-medium text-gray-500",
124
+ "min-w-80 flex flex-col gap-4",
125
+ "relative transition-colors duration-200 ease-in rounded font-medium",
126
+ disabled ? "bg-opacity-50" : "hover:bg-opacity-75",
127
+ "text-opacity-50 dark:text-white dark:text-opacity-50",
128
+ className
129
+ )}
130
+ >
253
131
 
254
- </Typography>;
132
+ {child}
133
+ {!value && <div className="justify-center text-left">
134
+ <Button variant="outlined"
135
+ color="primary"
136
+ disabled={disabled}
137
+ onClick={onEntryClick}>
138
+ Edit {name}
139
+ </Button>
140
+ </div>}
141
+
142
+ </div>;
255
143
  }