@firecms/core 3.0.0-canary.250 → 3.0.0-canary.251

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.
@@ -61,7 +61,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
61
61
  * e.g. 'account_tree' or 'person'.
62
62
  * Find all the icons in https://firecms.co/docs/icons
63
63
  */
64
- icon?: string;
64
+ icon?: string | React.ReactNode;
65
65
  /**
66
66
  * Optional field used to group top level navigation entries under a~
67
67
  * navigation view. If you set this value in a subcollection it has no
@@ -172,7 +172,7 @@ export interface CMSView {
172
172
  * e.g. 'account_tree' or 'person'
173
173
  * Find all the icons in https://firecms.co/docs/icons
174
174
  */
175
- icon?: string;
175
+ icon?: string | React.ReactNode;
176
176
  /**
177
177
  * Should this view be hidden from the main navigation panel.
178
178
  * It will still be accessible if you reach the specified path
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
2
  import { IconColor } from "@firecms/ui";
3
- export declare function getIcon(iconKey?: string, className?: string, color?: IconColor, size?: "smallest" | "small" | "medium" | "large" | number): React.ReactElement | undefined;
3
+ export declare function getIcon(iconKey?: string | React.ReactNode, className?: string, color?: IconColor, size?: "smallest" | "small" | "medium" | "large" | number): React.ReactElement | undefined;
4
4
  export type IconViewProps = {
5
5
  path: string;
6
6
  name: string;
7
7
  singularName?: string;
8
8
  group?: string;
9
- icon?: string;
9
+ icon?: string | React.ReactNode;
10
10
  };
11
11
  export declare const IconForView: React.NamedExoticComponent<{
12
12
  collectionOrView?: IconViewProps;
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.250",
4
+ "version": "3.0.0-canary.251",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -53,9 +53,9 @@
53
53
  "@dnd-kit/core": "^6.3.1",
54
54
  "@dnd-kit/modifiers": "^9.0.0",
55
55
  "@dnd-kit/sortable": "^10.0.0",
56
- "@firecms/editor": "^3.0.0-canary.250",
57
- "@firecms/formex": "^3.0.0-canary.250",
58
- "@firecms/ui": "^3.0.0-canary.250",
56
+ "@firecms/editor": "^3.0.0-canary.251",
57
+ "@firecms/formex": "^3.0.0-canary.251",
58
+ "@firecms/ui": "^3.0.0-canary.251",
59
59
  "@radix-ui/react-portal": "^1.1.3",
60
60
  "clsx": "^2.1.1",
61
61
  "date-fns": "^3.6.0",
@@ -107,7 +107,7 @@
107
107
  "dist",
108
108
  "src"
109
109
  ],
110
- "gitHead": "946e1f4f5695190e903af3a71dd7111accfc1efa",
110
+ "gitHead": "b7b0d3730e3c3bea284f1d6f482ca038282fb554",
111
111
  "publishConfig": {
112
112
  "access": "public"
113
113
  },
@@ -1,7 +1,7 @@
1
1
  import { useNavigate } from "react-router-dom";
2
2
 
3
3
  import { useCustomizationController, useFireCMSContext } from "../../hooks";
4
- import { PluginHomePageActionsProps, NavigationEntry } from "../../types";
4
+ import { NavigationEntry, PluginHomePageActionsProps } from "../../types";
5
5
  import { IconForView } from "../../util";
6
6
  import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
7
7
  import { IconButton, StarIcon } from "@firecms/ui";
@@ -31,7 +31,7 @@ export function NavigationCardBinding({
31
31
  description,
32
32
  onClick,
33
33
  type,
34
- shrink // <-- add shrink prop
34
+ shrink
35
35
  }: NavigationEntry & {
36
36
  onClick?: () => void,
37
37
  shrink?: boolean // <-- add shrink prop type
@@ -30,7 +30,7 @@ export function StorageItemPreview({
30
30
 
31
31
  return (
32
32
  <div className={cls(paperMixin,
33
- "relative m-4 border-box flex items-center justify-center",
33
+ "relative border-box flex items-center justify-center",
34
34
  size === "large" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]",
35
35
  className)}>
36
36
 
@@ -79,7 +79,7 @@ export function StorageUploadProgress({
79
79
  }, [entry.file, entry.fileName, upload]);
80
80
 
81
81
  if (simple) {
82
- return <div className={`m-4 w-${imageSize} h-${imageSize}`}>
82
+ return <div className={`w-${imageSize} h-${imageSize}`}>
83
83
 
84
84
  {loading && <Skeleton className={`w-${imageSize} h-${imageSize}`}/>}
85
85
 
@@ -88,11 +88,11 @@ export function StorageUploadProgress({
88
88
  return (
89
89
 
90
90
  <div className={cls(paperMixin,
91
- "relative m-4 border-box flex items-center justify-center",
91
+ "p-4 relative border-box flex items-center justify-center",
92
92
  `min-w-[${imageSize}px] min-h-[${imageSize}px]`)}>
93
93
 
94
94
  {loading &&
95
- <Skeleton className="m-4 w-full h-full"/>}
95
+ <Skeleton className="w-full h-full"/>}
96
96
 
97
97
  {error && <ErrorView title={"Error uploading file"}
98
98
  error={error}/>}
@@ -157,13 +157,11 @@ function SortableStorageItem({
157
157
  id,
158
158
  entry,
159
159
  property,
160
- name,
161
160
  metadata,
162
161
  storagePathBuilder,
163
162
  onFileUploadComplete,
164
163
  onClear,
165
164
  disabled,
166
- isSortable // This prop might be redundant if SortableContext is always used for multiple items
167
165
  }: SortableStorageItemProps) {
168
166
 
169
167
  const {
@@ -178,8 +176,7 @@ function SortableStorageItem({
178
176
  const style: React.CSSProperties = {
179
177
  transform: CSS.Transform.toString(transform),
180
178
  transition,
181
- zIndex: isDragging ? 100 : undefined, // Higher z-index when dragging
182
- opacity: isDragging ? 0.8 : 1 // Slight opacity for dragged item
179
+ zIndex: isDragging ? 100 : undefined
183
180
  };
184
181
 
185
182
  const getImageSizeNumber = (previewSize: PreviewSize): number => {
@@ -187,9 +184,9 @@ function SortableStorageItem({
187
184
  case "small":
188
185
  return 40;
189
186
  case "medium":
190
- return 118; // As per original logic for multiple items
187
+ return 118;
191
188
  case "large":
192
- return 220; // As per original logic for single item
189
+ return 220;
193
190
  default:
194
191
  return 118;
195
192
  }
@@ -225,7 +222,7 @@ function SortableStorageItem({
225
222
  style={style}
226
223
  {...attributes}
227
224
  {...listeners}
228
- className={cls("rounded-md m-1")} // Added margin for spacing between items
225
+ className={cls("rounded-md m-1")}
229
226
  tabIndex={-1}
230
227
  >
231
228
  {child}
@@ -247,11 +244,11 @@ function FileDropComponent({
247
244
  onFileUploadComplete,
248
245
  name,
249
246
  helpText,
250
- isDndItemDragging // New prop to disable dropzone when internal D&D is active
247
+ isDndItemDragging
251
248
  }: {
252
249
  storage: StorageConfig,
253
250
  disabled: boolean,
254
- onFilesAdded: (acceptedFiles: File[]) => Promise<void>, // useStorageUploadController returns Promise<void>
251
+ onFilesAdded: (acceptedFiles: File[]) => Promise<void>,
255
252
  multipleFilesSupported: boolean,
256
253
  autoFocus: boolean,
257
254
  internalValue: StorageFieldItem[],
@@ -278,7 +275,7 @@ function FileDropComponent({
278
275
  ...acc,
279
276
  [ext]: []
280
277
  }), {}) : undefined,
281
- disabled: disabled || isDndItemDragging, // Disable if form field is disabled OR an internal item is being dragged
278
+ disabled: disabled || isDndItemDragging,
282
279
  noDragEventsBubbling: true,
283
280
  maxSize: storage.maxSize,
284
281
  onDrop: onFilesAdded,
@@ -311,7 +308,7 @@ function FileDropComponent({
311
308
  disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
312
309
  disabled ? "text-surface-accent-600 dark:text-surface-accent-500" : "",
313
310
  dropZoneClasses,
314
- multipleFilesSupported && internalValue.length === 0 && "flex", // Keep flex for empty state centering
311
+ multipleFilesSupported && internalValue.length ? "" : "flex",
315
312
  {
316
313
  [nonActiveDropClasses]: !isDragActive,
317
314
  [activeDropClasses]: isDragActive, // OS file drag active
@@ -321,11 +318,9 @@ function FileDropComponent({
321
318
  })}
322
319
  >
323
320
  <div
324
- className={cls("flex items-center p-1 no-scrollbar",
325
- multipleFilesSupported && internalValue.length ? "flex-row overflow-x-auto" : "flex-col", // flex-col for single or empty
326
- internalValue.length === 0 && "min-h-[250px] justify-center", // Centering for empty dropzone
327
- multipleFilesSupported && internalValue.length > 0 && "min-h-[180px]", // Min height for multiple items
328
- !multipleFilesSupported && internalValue.length > 0 && "min-h-[250px]" // Min height for single item
321
+ className={cls("flex items-center p-1 px-4 no-scrollbar",
322
+ multipleFilesSupported && internalValue.length ? "overflow-auto" : "",
323
+ multipleFilesSupported && internalValue.length ? "min-h-[180px]" : "min-h-[250px]"
329
324
  )}
330
325
  >
331
326
  <input
@@ -70,7 +70,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
70
70
  * e.g. 'account_tree' or 'person'.
71
71
  * Find all the icons in https://firecms.co/docs/icons
72
72
  */
73
- icon?: string;
73
+ icon?: string | React.ReactNode;
74
74
 
75
75
  /**
76
76
  * Optional field used to group top level navigation entries under a~
@@ -206,7 +206,7 @@ export interface CMSView {
206
206
  * e.g. 'account_tree' or 'person'
207
207
  * Find all the icons in https://firecms.co/docs/icons
208
208
  */
209
- icon?: string;
209
+ icon?: string | React.ReactNode;
210
210
 
211
211
  /**
212
212
  * Should this view be hidden from the main navigation panel.
@@ -4,17 +4,28 @@ import { coolIconKeys, Icon, IconColor, iconKeys } from "@firecms/ui";
4
4
  import { slugify } from "./strings";
5
5
  import equal from "react-fast-compare"
6
6
 
7
- export function getIcon(iconKey?: string,
7
+ export function getIcon(iconKey?: string | React.ReactNode,
8
8
  className?: string,
9
9
  color?: IconColor,
10
10
  size?: "smallest" | "small" | "medium" | "large" | number,): React.ReactElement | undefined {
11
+
12
+ if (React.isValidElement(iconKey)) {
13
+ return iconKey;
14
+ }
15
+
11
16
  if (!iconKey) return undefined;
12
- iconKey = slugify(iconKey);
13
- if (!(iconKey in iconKeysMap)) {
14
- return undefined;
17
+ if (typeof iconKey === "string") {
18
+
19
+ const usedIconKey = slugify(iconKey);
20
+ if (!(usedIconKey in iconKeysMap)) {
21
+ return undefined;
22
+ }
23
+ return usedIconKey in iconKeysMap ?
24
+ <Icon iconKey={usedIconKey} size={size} className={className} color={color}/> : undefined;
15
25
  }
16
- return iconKey in iconKeysMap ?
17
- <Icon iconKey={iconKey} size={size} className={className} color={color}/> : undefined;
26
+
27
+ console.warn("Invalid icon key provided:", iconKey);
28
+ return undefined;
18
29
  }
19
30
 
20
31
  export type IconViewProps = {
@@ -22,7 +33,7 @@ export type IconViewProps = {
22
33
  name: string;
23
34
  singularName?: string;
24
35
  group?: string;
25
- icon?: string;
36
+ icon?: string | React.ReactNode;
26
37
  }
27
38
 
28
39
  export const IconForView = React.memo(