@firecms/core 3.0.0-canary.169 → 3.0.0-canary.170

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.
@@ -12,7 +12,7 @@ export interface DialogsController {
12
12
  * Open a dialog
13
13
  * @param props
14
14
  */
15
- open: (props: DialogControllerEntryProps) => {
15
+ open: <T extends object = object>(props: DialogControllerEntryProps<T>) => {
16
16
  closeDialog: () => void;
17
17
  };
18
18
  }
@@ -20,7 +20,7 @@ export interface DialogsController {
20
20
  * Props used to open a side dialog
21
21
  * @group Hooks and utilities
22
22
  */
23
- export interface DialogControllerEntryProps {
23
+ export interface DialogControllerEntryProps<T extends object = object> {
24
24
  key: string;
25
25
  /**
26
26
  * The component type that will be rendered
@@ -28,5 +28,9 @@ export interface DialogControllerEntryProps {
28
28
  Component: React.ComponentType<{
29
29
  open: boolean;
30
30
  closeDialog: () => void;
31
- }>;
31
+ } & T>;
32
+ /**
33
+ * Props to pass to the dialog component
34
+ */
35
+ props?: T;
32
36
  }
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.169",
4
+ "version": "3.0.0-canary.170",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,9 +50,9 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.169",
54
- "@firecms/formex": "^3.0.0-canary.169",
55
- "@firecms/ui": "^3.0.0-canary.169",
53
+ "@firecms/editor": "^3.0.0-canary.170",
54
+ "@firecms/formex": "^3.0.0-canary.170",
55
+ "@firecms/ui": "^3.0.0-canary.170",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.2",
58
58
  "clsx": "^2.1.1",
@@ -71,7 +71,6 @@
71
71
  "yup": "^0.32.11"
72
72
  },
73
73
  "peerDependencies": {
74
- "firebase": "^10.5.2",
75
74
  "react": "^18.3.1",
76
75
  "react-dom": "^18.3.1",
77
76
  "react-router": "^6.28.0",
@@ -91,7 +90,6 @@
91
90
  "babel-plugin-react-compiler": "beta",
92
91
  "cross-env": "^7.0.3",
93
92
  "eslint-plugin-react-compiler": "beta",
94
- "firebase": "^10.14.1",
95
93
  "jest": "^29.7.0",
96
94
  "npm-run-all": "^4.1.5",
97
95
  "react-router": "^6.28.0",
@@ -106,7 +104,7 @@
106
104
  "dist",
107
105
  "src"
108
106
  ],
109
- "gitHead": "8c086883fc1cb08a74d4bd66ef2f952affa9fdb9",
107
+ "gitHead": "21c8b5f6236a1824f5896b69bb4810c05326c5c7",
110
108
  "publishConfig": {
111
109
  "access": "public"
112
110
  },
@@ -41,6 +41,8 @@ export interface ArrayContainerProps<T> {
41
41
  newDefaultEntry: T;
42
42
  onValueChange: (value: T[]) => void,
43
43
  className?: string;
44
+ min?: number;
45
+ max?: number;
44
46
  }
45
47
 
46
48
  const buildIdsMap = (value: any[]) =>
@@ -67,7 +69,9 @@ export function ArrayContainer<T>({
67
69
  includeAddButton,
68
70
  newDefaultEntry,
69
71
  onValueChange,
70
- className
72
+ className,
73
+ min = 0,
74
+ max = Infinity
71
75
  }: ArrayContainerProps<T>) {
72
76
 
73
77
  const hasValue = value && Array.isArray(value) && value.length > 0;
@@ -78,7 +82,8 @@ export function ArrayContainer<T>({
78
82
  const [internalIds, setInternalIds] = useState<number[]>(
79
83
  hasValue
80
84
  ? Object.values(internalIdsRef.current)
81
- : []);
85
+ : []
86
+ );
82
87
 
83
88
  const itemCustomPropsRef = useRef<Record<number, object>>({});
84
89
 
@@ -104,7 +109,7 @@ export function ArrayContainer<T>({
104
109
 
105
110
  const insertInEnd = (e: React.SyntheticEvent) => {
106
111
  e.preventDefault();
107
- if (disabled) return;
112
+ if (disabled || value.length >= max) return;
108
113
  const id = getRandomId();
109
114
  const newIds: number[] = [...internalIds, id];
110
115
  if (onInternalIdAdded)
@@ -114,6 +119,7 @@ export function ArrayContainer<T>({
114
119
  };
115
120
 
116
121
  const remove = (index: number) => {
122
+ if (value.length <= min) return;
117
123
  const newIds = [...internalIds];
118
124
  newIds.splice(index, 1);
119
125
  setInternalIds(newIds);
@@ -121,12 +127,14 @@ export function ArrayContainer<T>({
121
127
  };
122
128
 
123
129
  const copy = (index: number) => {
130
+ if (value.length >= max) return;
124
131
  const id = getRandomId();
125
132
  const copyingItem = value[index];
126
133
  const newIds: number[] = [
127
- ...internalIds.splice(0, index + 1),
134
+ ...internalIds.slice(0, index + 1),
128
135
  id,
129
- ...internalIds.splice(index + 1, internalIds.length - index - 1)];
136
+ ...internalIds.slice(index + 1)
137
+ ];
130
138
  if (onInternalIdAdded)
131
139
  onInternalIdAdded(id);
132
140
  setInternalIds(newIds);
@@ -135,11 +143,13 @@ export function ArrayContainer<T>({
135
143
  };
136
144
 
137
145
  const addInIndex = (index: number) => {
146
+ if (value.length >= max) return;
138
147
  const id = getRandomId();
139
148
  const newIds: number[] = [
140
- ...internalIds.splice(0, index),
149
+ ...internalIds.slice(0, index),
141
150
  id,
142
- ...internalIds.slice(index)];
151
+ ...internalIds.slice(index)
152
+ ];
143
153
  if (onInternalIdAdded)
144
154
  onInternalIdAdded(id);
145
155
  setInternalIds(newIds);
@@ -183,6 +193,7 @@ export function ArrayContainer<T>({
183
193
  storedProps={itemCustomPropsRef.current[internalId]}
184
194
  updateItemCustomProps={updateItemCustomProps}
185
195
  addInIndex={addInIndex}
196
+ includeAddButton={includeAddButton}
186
197
  />
187
198
  );
188
199
  }}
@@ -213,6 +224,7 @@ export function ArrayContainer<T>({
213
224
  storedProps={itemCustomPropsRef.current[internalId]}
214
225
  updateItemCustomProps={updateItemCustomProps}
215
226
  addInIndex={addInIndex}
227
+ includeAddButton={includeAddButton}
216
228
  />
217
229
  )}
218
230
  </Draggable>
@@ -221,17 +233,19 @@ export function ArrayContainer<T>({
221
233
 
222
234
  {droppableProvided.placeholder}
223
235
 
224
- {includeAddButton && <div className="py-4 justify-center text-left">
225
- <Button
226
- variant={"text"}
227
- size={size === "small" ? "small" : "medium"}
228
- color="primary"
229
- disabled={disabled}
230
- startIcon={<AddIcon/>}
231
- onClick={insertInEnd}>
232
- {addLabel ?? "Add"}
233
- </Button>
234
- </div>}
236
+ {includeAddButton && (
237
+ <div className="my-4 justify-center text-left">
238
+ <Button
239
+ variant={"text"}
240
+ size={size === "small" ? "small" : "medium"}
241
+ color="primary"
242
+ disabled={disabled || value.length >= max}
243
+ startIcon={<AddIcon/>}
244
+ onClick={insertInEnd}>
245
+ {addLabel ?? "Add"}
246
+ </Button>
247
+ </div>
248
+ )}
235
249
  </div>
236
250
  )}
237
251
  </Droppable>
@@ -249,6 +263,7 @@ type ArrayContainerItemProps = {
249
263
  remove: (index: number) => void,
250
264
  copy: (index: number) => void,
251
265
  addInIndex?: (index: number) => void,
266
+ includeAddButton?: boolean,
252
267
  isDragging: boolean,
253
268
  storedProps?: object,
254
269
  updateItemCustomProps: (internalId: number, props: object) => void
@@ -263,6 +278,7 @@ export function ArrayContainerItem({
263
278
  buildEntry,
264
279
  remove,
265
280
  addInIndex,
281
+ includeAddButton,
266
282
  copy,
267
283
  isDragging,
268
284
  storedProps,
@@ -295,6 +311,7 @@ export function ArrayContainerItem({
295
311
  index={index}
296
312
  provided={provided}
297
313
  addInIndex={addInIndex}
314
+ includeAddButton={includeAddButton}
298
315
  copy={copy}/>
299
316
  </div>
300
317
  </div>;
@@ -307,6 +324,7 @@ export function ArrayItemOptions({
307
324
  index,
308
325
  provided,
309
326
  copy,
327
+ includeAddButton,
310
328
  addInIndex
311
329
  }: {
312
330
  direction?: "row" | "column",
@@ -315,6 +333,7 @@ export function ArrayItemOptions({
315
333
  index: number,
316
334
  provided: any,
317
335
  copy: (index: number) => void,
336
+ includeAddButton?: boolean,
318
337
  addInIndex?: (index: number) => void
319
338
  }) {
320
339
 
@@ -365,20 +384,20 @@ export function ArrayItemOptions({
365
384
  Copy
366
385
  </MenuItem>
367
386
 
368
- {addInIndex && <MenuItem dense
369
- onClick={() => {
370
- setMenuOpen(false);
371
- addInIndex(index);
372
- }}>
387
+ {includeAddButton && addInIndex && <MenuItem dense
388
+ onClick={() => {
389
+ setMenuOpen(false);
390
+ addInIndex(index);
391
+ }}>
373
392
  <KeyboardArrowUpIcon size={"small"}/>
374
393
  Add on top
375
394
  </MenuItem>}
376
395
 
377
- {addInIndex && <MenuItem dense
378
- onClick={() => {
379
- setMenuOpen(false);
380
- addInIndex(index + 1);
381
- }}>
396
+ {includeAddButton && addInIndex && <MenuItem dense
397
+ onClick={() => {
398
+ setMenuOpen(false);
399
+ addInIndex(index + 1);
400
+ }}>
382
401
  <KeyboardArrowDownIcon size={"small"}/>
383
402
  Add below
384
403
  </MenuItem>}
@@ -8,7 +8,7 @@ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) =
8
8
  const [dialogEntries, setDialogEntries] = useState<DialogControllerEntryProps[]>([]);
9
9
  const dialogEntriesRef = useRef<DialogControllerEntryProps[]>(dialogEntries);
10
10
 
11
- const updateDialogEntries = (newPanels: DialogControllerEntryProps[]) => {
11
+ const updateDialogEntries = (newPanels: DialogControllerEntryProps<any>[]) => {
12
12
  dialogEntriesRef.current = newPanels;
13
13
  setDialogEntries(newPanels);
14
14
  };
@@ -23,7 +23,7 @@ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) =
23
23
 
24
24
  }, [dialogEntries]);
25
25
 
26
- const open = useCallback((dialogEntry: DialogControllerEntryProps) => {
26
+ const open = useCallback(<T extends object = object>(dialogEntry: DialogControllerEntryProps<T>) => {
27
27
 
28
28
  const updatedPanels = [...dialogEntriesRef.current, dialogEntry];
29
29
  updateDialogEntries(updatedPanels);
@@ -46,6 +46,7 @@ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) =
46
46
  key={`dialog_${i}`}
47
47
  open={true}
48
48
  closeDialog={close}
49
+ {...entry.props}
49
50
  />)}
50
51
  </DialogsControllerContext.Provider>
51
52
  );
@@ -175,7 +175,7 @@ export function DrawerLogo({ logo }: {
175
175
  {logo
176
176
  ? <img src={logo}
177
177
  alt="Logo"
178
- className={cls("max-w-full max-h-full transition-all",
178
+ className={cls("max-w-full max-h-full transition-all object-contain",
179
179
  drawerOpen ? "w-[96px] h-[96px]" : "w-[32px] h-[32px]")}/>
180
180
  : <FireCMSLogo/>}
181
181
 
@@ -414,6 +414,7 @@ function encodePath(input: string) {
414
414
 
415
415
  function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[], authController: AuthController<User>): EntityCollection[] {
416
416
  return resolvedCollections
417
+ .filter((c) => Boolean(c.path))
417
418
  .filter((c) => {
418
419
  if (!c.permissions) return true;
419
420
  const resolvedPermissions = resolvePermissions(c, authController, c.path, null);
@@ -90,7 +90,6 @@ export function useBuildSideDialogsController(): SideDialogsController {
90
90
 
91
91
  const replace = useCallback((panelProps: SideDialogPanelProps | SideDialogPanelProps[]) => {
92
92
 
93
- console.log("replace", panelProps);
94
93
  const newPanels: SideDialogPanelProps[] = Array.isArray(panelProps) ? panelProps : [panelProps];
95
94
  newPanels.forEach((panel) => {
96
95
  routesStore.current[panel.key] = panel;
@@ -15,19 +15,23 @@ export interface DialogsController {
15
15
  * Open a dialog
16
16
  * @param props
17
17
  */
18
- open: (props: DialogControllerEntryProps) => { closeDialog: () => void };
18
+ open: <T extends object = object>(props: DialogControllerEntryProps<T>) => { closeDialog: () => void };
19
19
  }
20
20
 
21
21
  /**
22
22
  * Props used to open a side dialog
23
23
  * @group Hooks and utilities
24
24
  */
25
- export interface DialogControllerEntryProps {
25
+ export interface DialogControllerEntryProps<T extends object = object> {
26
26
 
27
27
  key: string;
28
28
  /**
29
29
  * The component type that will be rendered
30
30
  */
31
- Component: React.ComponentType<{ open: boolean, closeDialog: () => void }>;
31
+ Component: React.ComponentType<{ open: boolean, closeDialog: () => void } & T>;
32
+ /**
33
+ * Props to pass to the dialog component
34
+ */
35
+ props?: T;
32
36
 
33
37
  }