@firecms/core 3.0.0-canary.160 → 3.0.0-canary.162

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.
@@ -1222,7 +1222,6 @@ export declare const iconSynonyms: {
1222
1222
  picture_in_picture_alt: string;
1223
1223
  pie_chart: string;
1224
1224
  pie_chart_outline: string;
1225
- pie_chart_outlined: string;
1226
1225
  pin: string;
1227
1226
  pinch: string;
1228
1227
  pin_drop: string;
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.160",
4
+ "version": "3.0.0-canary.162",
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.160",
54
- "@firecms/formex": "^3.0.0-canary.160",
55
- "@firecms/ui": "^3.0.0-canary.159",
53
+ "@firecms/editor": "^3.0.0-canary.162",
54
+ "@firecms/formex": "^3.0.0-canary.162",
55
+ "@firecms/ui": "^3.0.0-canary.162",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.2",
58
58
  "clsx": "^2.1.1",
@@ -106,7 +106,7 @@
106
106
  "dist",
107
107
  "src"
108
108
  ],
109
- "gitHead": "840f2733672a90a6a56aed89259eaa5365589512",
109
+ "gitHead": "a1b322b8cdcd05a1598baefce37c89124d96cd79",
110
110
  "publishConfig": {
111
111
  "access": "public"
112
112
  },
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { useMemo, useState } from "react";
2
+ import { useMemo } from "react";
3
3
 
4
4
  import { Entity, ResolvedArrayProperty, ResolvedStringProperty, StorageConfig } from "../../../types";
5
5
  import { useDropzone } from "react-dropzone";
@@ -140,9 +140,7 @@ function StorageUpload({
140
140
  storagePathBuilder,
141
141
  }: StorageUploadProps) {
142
142
 
143
- const [onHover, setOnHover] = useState(false);
144
-
145
- const previewSize = multipleFilesSupported && previewSizeInput === "medium" ? "small" : previewSizeInput;
143
+ const previewSize = previewSizeInput;
146
144
  if (multipleFilesSupported) {
147
145
  const arrayProperty = property as ResolvedArrayProperty<string[]>;
148
146
  if (Array.isArray(arrayProperty.of)) {
@@ -212,9 +210,6 @@ function StorageUpload({
212
210
 
213
211
  return (
214
212
  <div {...rootProps}
215
- onMouseEnter={() => setOnHover(true)}
216
- onMouseMove={() => setOnHover(true)}
217
- onMouseLeave={() => setOnHover(false)}
218
213
  className={cls(dropZoneClasses,
219
214
  "relative w-full h-full flex",
220
215
  `justify-${hasValue ? "start" : "center"}`,
@@ -252,8 +247,7 @@ function StorageUpload({
252
247
  }
253
248
 
254
249
  return child;
255
- })
256
- }
250
+ })}
257
251
 
258
252
  {!internalValue && <div
259
253
  className="flex-grow m-2 max-w-[200px]"
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
 
3
3
  import useMeasure from "react-use-measure";
4
4
 
5
- import { cls, RemoveCircleIcon, Tooltip } from "@firecms/ui";
5
+ import { cls, DoNotDisturbOnIcon, Tooltip } from "@firecms/ui";
6
6
  import { ErrorBoundary } from "../../../components";
7
7
  import { getRowHeight, TableSize } from "../../common/table_height";
8
8
 
@@ -236,7 +236,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
236
236
  {disabled && onHover && disabledTooltip &&
237
237
  <div className="absolute top-1 right-1 text-xs">
238
238
  <Tooltip title={disabledTooltip}>
239
- <RemoveCircleIcon size={"smallest"} color={"disabled"} className={"text-surface-500"}/>
239
+ <DoNotDisturbOnIcon size={"smallest"} color={"disabled"} className={"text-surface-500"}/>
240
240
  </Tooltip>
241
241
  </div>}
242
242
 
@@ -1,4 +1,4 @@
1
- import { ErrorOutlineIcon, IconButton } from "@firecms/ui";
1
+ import { ErrorIcon, IconButton } from "@firecms/ui";
2
2
  import { ErrorTooltip } from "../../ErrorTooltip";
3
3
  import { useCallback, useEffect, useRef } from "react";
4
4
 
@@ -68,7 +68,7 @@ export function EntityTableCellActions({
68
68
  width: 32,
69
69
  height: 32
70
70
  }}>
71
- <ErrorOutlineIcon
71
+ <ErrorIcon
72
72
  size={"small"}
73
73
  color={"error"}
74
74
  />
@@ -19,7 +19,7 @@ import { CustomFieldValidator, getYupEntitySchema } from "../../../../form/valid
19
19
  import { useWindowSize } from "./useWindowSize";
20
20
  import { ElementResizeListener } from "./ElementResizeListener";
21
21
  import { getPropertyInPath, isReadOnly, resolveCollection } from "../../../../util";
22
- import { Button, ClearIcon, DialogActions, IconButton, Typography } from "@firecms/ui";
22
+ import { Button, CloseIcon, DialogActions, IconButton, Typography } from "@firecms/ui";
23
23
  import { PropertyFieldBinding } from "../../../../form";
24
24
  import { useCustomizationController, useDataSource, useFireCMSContext } from "../../../../hooks";
25
25
  import { OnCellValueChangeParams } from "../../../common";
@@ -394,7 +394,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
394
394
  event.stopPropagation();
395
395
  onClose();
396
396
  }}>
397
- <ClearIcon className="text-white"
397
+ <CloseIcon className="text-white"
398
398
  size={"small"}/>
399
399
  </IconButton>
400
400
  </div>
@@ -71,21 +71,28 @@ export function EntityPreview({
71
71
  const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
72
72
  const imagePropertyKey = getEntityImagePreviewPropertyKey(resolvedCollection);
73
73
  const imageProperty = imagePropertyKey ? resolvedCollection.properties[imagePropertyKey] : undefined;
74
-
74
+ const usedImageProperty = imageProperty && "of" in imageProperty ? imageProperty.of : imageProperty;
75
75
  const restProperties = listProperties.filter(p => p !== titleProperty && p !== imagePropertyKey);
76
76
 
77
+ const imageValue = imagePropertyKey ? getValueInPath(entity.values, imagePropertyKey) : undefined;
78
+ const usedImageValue = imageProperty !== undefined ? ("of" in imageProperty
79
+ ? ((imageValue ?? []).length > 0
80
+ ? imageValue[0] : undefined)
81
+ : imageValue)
82
+ : undefined;
83
+
77
84
  return <EntityPreviewContainer onClick={disabled ? undefined : onClick}
78
85
  hover={disabled ? undefined : hover}
79
86
  size={size}>
80
87
  <div className={cls("flex w-10 h-10 ml-1 mr-2 shrink-0", size === "small" ? "my-0.5" : "m-2 self-start")}>
81
- {imageProperty && <PropertyPreview property={imageProperty}
82
- propertyKey={imagePropertyKey as string}
83
- size={"small"}
84
- value={getValueInPath(entity.values, imagePropertyKey as string)}/>}
85
- {!imageProperty && <IconForView collectionOrView={collection}
86
- color={"primary"}
87
- size={size}
88
- className={"m-auto p-1"}/>}
88
+ {usedImageProperty && usedImageValue && <PropertyPreview property={usedImageProperty}
89
+ propertyKey={imagePropertyKey as string}
90
+ size={"small"}
91
+ value={usedImageValue}/>}
92
+ {(!usedImageProperty || !usedImageValue) && <IconForView collectionOrView={collection}
93
+ color={"primary"}
94
+ size={size}
95
+ className={"m-auto p-1"}/>}
89
96
  </div>
90
97
 
91
98
 
@@ -105,7 +112,7 @@ export function EntityPreview({
105
112
  : <Skeleton/>)}
106
113
 
107
114
  {titleProperty && (
108
- <div className={"my-0.5 text-sm font-medium"}>
115
+ <div className={"truncate my-0.5 text-sm font-medium"}>
109
116
  {
110
117
  entity
111
118
  ? <PropertyPreview
@@ -126,7 +133,7 @@ export function EntityPreview({
126
133
 
127
134
  return (
128
135
  <div key={"ref_prev_" + key}
129
- className={restProperties.length > 1 ? "my-0.5" : "my-0"}>
136
+ className={cls("truncate", restProperties.length > 1 ? "my-0.5" : "my-0")}>
130
137
  {
131
138
  entity
132
139
  ? <PropertyPreview
@@ -220,3 +227,5 @@ export const EntityPreviewContainer = React.forwardRef<HTMLDivElement, EntityPre
220
227
  {children}
221
228
  </div>;
222
229
  });
230
+
231
+ EntityPreviewContainer.displayName = "EntityPreviewContainer";
@@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
2
2
  import { useNavigationController } from "../../hooks";
3
3
  import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
4
4
  import { TopNavigationEntry } from "../../types";
5
- import { Chip, Collapse, StarBorderIcon, StarIcon } from "@firecms/ui";
5
+ import { Chip, Collapse, StarIcon } from "@firecms/ui";
6
6
 
7
7
  function NavigationChip({ entry }: { entry: TopNavigationEntry }) {
8
8
 
@@ -29,16 +29,11 @@ function NavigationChip({ entry }: { entry: TopNavigationEntry }) {
29
29
  return <Chip
30
30
  key={entry.path}
31
31
  onClick={() => navigate(entry.url)}
32
- icon={
33
- favourite
34
- ? <StarIcon
35
- onClick={onIconClick}
36
- size={18}
37
- className={"text-secondary"}/>
38
- : <StarBorderIcon
39
- onClick={onIconClick}
40
- size={18}
41
- className={"text-surface-400 dark:text-surface-500"}/>}>
32
+ icon={<StarIcon
33
+ onClick={onIconClick}
34
+ size={18}
35
+ className={favourite ? "text-secondary" : "text-surface-400 dark:text-surface-500"}/>
36
+ }>
42
37
  {entry.name}
43
38
  </Chip>;
44
39
  }
@@ -4,7 +4,7 @@ import { useCustomizationController, useFireCMSContext } from "../../hooks";
4
4
  import { PluginHomePageActionsProps, TopNavigationEntry } from "../../types";
5
5
  import { IconForView } from "../../util";
6
6
  import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
7
- import { IconButton, StarBorderIcon, StarIcon } from "@firecms/ui";
7
+ import { IconButton, StarIcon } from "@firecms/ui";
8
8
  import { NavigationCard } from "./NavigationCard";
9
9
  import { SmallNavigationCard } from "./SmallNavigationCard";
10
10
 
@@ -60,14 +60,9 @@ export function NavigationCardBinding({
60
60
  );
61
61
  }
62
62
  }}>
63
- {
64
- favourite
65
- ? <StarIcon
66
- size={18}
67
- className={"text-secondary"}/>
68
- : <StarBorderIcon
69
- size={18}
70
- className={"text-surface-400 dark:text-surface-500"}/>}
63
+ <StarIcon
64
+ size={18}
65
+ className={favourite ? "text-secondary" : "text-surface-400 dark:text-surface-500"}/>
71
66
  </IconButton>
72
67
  ]
73
68
  : [];
@@ -3,7 +3,7 @@ import { EnumValuesChip } from "../../../preview";
3
3
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
4
4
  import {
5
5
  Checkbox,
6
- ClearIcon,
6
+ CloseIcon,
7
7
  IconButton,
8
8
  Label,
9
9
  MultiSelect,
@@ -125,7 +125,7 @@ export function StringNumberFilterField({
125
125
  }}
126
126
  endAdornment={internalValue && <IconButton
127
127
  onClick={(e) => updateFilter(operation, undefined)}>
128
- <ClearIcon/>
128
+ <CloseIcon/>
129
129
  </IconButton>}
130
130
  />}
131
131
 
@@ -141,7 +141,7 @@ export function StringNumberFilterField({
141
141
  endAdornment={internalValue && <IconButton
142
142
  className="absolute right-2 top-3"
143
143
  onClick={(e) => updateFilter(operation, undefined)}>
144
- <ClearIcon/>
144
+ <CloseIcon/>
145
145
  </IconButton>}
146
146
  renderValue={(enumKey) => {
147
147
  if (enumKey === null)
@@ -178,7 +178,7 @@ export function StringNumberFilterField({
178
178
  endAdornment={internalValue && <IconButton
179
179
  className="absolute right-2 top-3"
180
180
  onClick={(e) => updateFilter(operation, undefined)}>
181
- <ClearIcon/>
181
+ <CloseIcon/>
182
182
  </IconButton>}
183
183
  // renderValues={(enumKeys) => {
184
184
  // console.log("renderValues", enumKeys);
@@ -79,9 +79,9 @@ export function DefaultDrawer({
79
79
  <DrawerLogo logo={logo}/>
80
80
 
81
81
  <div className={"mt-4 flex-grow overflow-scroll no-scrollbar"}
82
- style={{
83
- maskImage: "linear-gradient(to bottom, transparent 0, black 20px, black calc(100% - 20px), transparent 100%)",
84
- }}>
82
+ style={{
83
+ maskImage: "linear-gradient(to bottom, transparent 0, black 20px, black calc(100% - 20px), transparent 100%)",
84
+ }}>
85
85
 
86
86
  {groupsWithoutAdmin.map((group) => (
87
87
  <div
@@ -93,7 +93,8 @@ export function DefaultDrawer({
93
93
  .map((view, index) =>
94
94
  <DrawerNavigationItem
95
95
  key={`navigation_${index}`}
96
- icon={<IconForView collectionOrView={view.collection ?? view.view} size={"small"}/>}
96
+ icon={<IconForView collectionOrView={view.collection ?? view.view}
97
+ size={"small"}/>}
97
98
  tooltipsOpen={tooltipsOpen}
98
99
  adminMenuOpen={adminMenuOpen}
99
100
  drawerOpen={drawerOpen}
@@ -173,8 +174,8 @@ export function DrawerLogo({ logo }: {
173
174
  {logo
174
175
  ? <img src={logo}
175
176
  alt="Logo"
176
- className={cls("max-w-full max-h-full",
177
- drawerOpen ?? "w-[112px] h-[112px]")}/>
177
+ className={cls("max-w-full max-h-full transition-all",
178
+ drawerOpen ? "w-[96px] h-[96px]" : "w-[32px] h-[32px]")}/>
178
179
  : <FireCMSLogo/>}
179
180
 
180
181
  </Link>
@@ -785,7 +785,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
785
785
  })?.toString()}
786
786
  </>;
787
787
  return (
788
- <div>
788
+ <div key={`additional_${key}`}>
789
789
  <LabelWithIconAndTooltip
790
790
  propertyKey={key}
791
791
  icon={<NotesIcon size={"small"}/>}
@@ -808,8 +808,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
808
808
  })
809
809
  .filter(Boolean)}
810
810
 
811
- </>
812
- );
811
+ </>);
813
812
 
814
813
  const disabled = formex.isSubmitting || (!modified && status === "existing");
815
814
  const formRef = React.useRef<HTMLDivElement>(null);
@@ -23,7 +23,6 @@ import {
23
23
  AddLinkIcon,
24
24
  BallotIcon,
25
25
  DriveFolderUploadIcon,
26
- EmailIcon,
27
26
  FlagIcon,
28
27
  FormatListNumberedIcon,
29
28
  FormatQuoteIcon,
@@ -31,6 +30,7 @@ import {
31
30
  LinkIcon,
32
31
  ListAltIcon,
33
32
  ListIcon,
33
+ MailIcon,
34
34
  NumbersIcon,
35
35
  RepeatIcon,
36
36
  ScheduleIcon,
@@ -96,7 +96,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
96
96
  key: "email",
97
97
  name: "Email",
98
98
  description: "Text with email validation",
99
- Icon: EmailIcon,
99
+ Icon: MailIcon,
100
100
  color: "#154fb3",
101
101
  property: {
102
102
  dataType: "string",
@@ -4,7 +4,7 @@ import { EnumType, FieldProps } from "../../types";
4
4
  import { FieldHelperText, LabelWithIcon } from "../components";
5
5
  import { EnumValuesChip } from "../../preview";
6
6
  import { getIconForProperty, resolveEnumValues } from "../../util";
7
- import { ClearIcon, cls, IconButton, Select, SelectItem } from "@firecms/ui";
7
+ import { CloseIcon, cls, IconButton, Select, SelectItem } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
  import { PropertyIdCopyTooltip } from "../../components";
10
10
 
@@ -68,7 +68,7 @@ export function SelectFieldBinding<T extends EnumType>({
68
68
  endAdornment={
69
69
  property.clearable && <IconButton
70
70
  onClick={handleClearClick}>
71
- <ClearIcon/>
71
+ <CloseIcon/>
72
72
  </IconButton>
73
73
  }
74
74
  onValueChange={(updatedValue: string) => {
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback } from "react";
2
2
 
3
- import { ClearIcon, Collapse, IconButton, TextField } from "@firecms/ui";
3
+ import { CloseIcon, Collapse, IconButton, TextField } from "@firecms/ui";
4
4
  import { FieldProps, PreviewType } from "../../types";
5
5
  import { FieldHelperText, LabelWithIcon } from "../components";
6
6
  import { getIconForProperty } from "../../util";
@@ -85,7 +85,7 @@ export function TextFieldBinding<T extends string | number>({
85
85
  endAdornment={
86
86
  property.clearable && <IconButton
87
87
  onClick={handleClearClick}>
88
- <ClearIcon/>
88
+ <CloseIcon/>
89
89
  </IconButton>
90
90
  }
91
91
  error={showError ? error : undefined}
@@ -202,6 +202,7 @@ export function useBuildNavigationController<EC extends EntityCollection, USER e
202
202
  let shouldUpdateTopLevelNav = false;
203
203
  if (!areCollectionListsEqual(collectionsRef.current ?? [], resolvedCollections)) {
204
204
  collectionsRef.current = resolvedCollections;
205
+ console.log("Collections have changed", resolvedCollections);
205
206
  shouldUpdateTopLevelNav = true;
206
207
  }
207
208
  if (collectionsRef.current === undefined) {
@@ -56,7 +56,6 @@ export function ImagePreview({
56
56
  className={"rounded-md"}
57
57
  style={imageStyle}/>
58
58
 
59
-
60
59
  <div className={"flex flex-row gap-2 absolute bottom-[-4px] right-[-4px] invisible group-hover:visible"}>
61
60
  {navigator && <Tooltip
62
61
  asChild={true}
@@ -127,7 +127,7 @@ export function KeyValuePreview({ value }: { value: any }) {
127
127
  </div>
128
128
  <div
129
129
  className="flex-grow max-w-[75%]">
130
- {childValue && ("toString" in childValue) && <Typography>
130
+ {childValue && <Typography>
131
131
  <ErrorBoundary>
132
132
  {childValue.toString()}
133
133
  </ErrorBoundary>
@@ -15,6 +15,7 @@ const map = iconKeys
15
15
  export const iconsSearch = new Fuse(map, {
16
16
  isCaseSensitive: false,
17
17
  shouldSort: true,
18
+ ignoreLocation: true,
18
19
  distance: 0,
19
20
  keys: ["key", "synonyms"]
20
21
  })
@@ -1222,7 +1222,6 @@ export const iconSynonyms = {
1222
1222
  picture_in_picture_alt: "cropped overlap photo position shape",
1223
1223
  pie_chart: "analytics bars data diagram infographic measure metrics statistics tracking",
1224
1224
  pie_chart_outline: "analytics bars data diagram infographic measure metrics statistics tracking",
1225
- pie_chart_outlined: "graph",
1226
1225
  pin: "1 2 3 digit key login logout number password pattern security star symbol unlock",
1227
1226
  pinch: "arrows compress direction finger grasp hand navigation nip squeeze tweak",
1228
1227
  pin_drop: "destination direction gps location maps navigation place stop",
@@ -42,13 +42,19 @@ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collect
42
42
 
43
43
  export function getEntityImagePreviewPropertyKey<M extends object>(collection: ResolvedEntityCollection<M>): string | undefined {
44
44
 
45
- // find first text field property
45
+ // find first storage property of type image
46
46
  for (const key in collection.properties) {
47
47
  const property = collection.properties[key];
48
48
  if (property.dataType === "string" && property.storage?.acceptedFiles?.includes("image/*")) {
49
49
  return key;
50
50
  }
51
-
51
+ }
52
+ // alternatively, look for the first array of images
53
+ for (const key in collection.properties) {
54
+ const property = collection.properties[key];
55
+ if (property.dataType === "array" && property.of?.dataType === "string" && property.of.storage?.acceptedFiles?.includes("image/*")) {
56
+ return key;
57
+ }
52
58
  }
53
59
  return undefined;
54
60
  }