@firecms/core 3.0.0-canary.282 → 3.0.0-canary.284

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.
@@ -1,51 +1,44 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useEffect, useRef } from "react";
2
2
  import { useFormex } from "@firecms/formex";
3
3
 
4
4
  export const ErrorFocus = ({ containerRef }:
5
5
  {
6
6
  containerRef?: React.RefObject<HTMLDivElement>
7
7
  }) => {
8
- const { isSubmitting, isValidating, errors } = useFormex();
8
+ const {
9
+ isValidating,
10
+ errors,
11
+ version
12
+ } = useFormex();
13
+
14
+ const prevVersion = useRef(version);
9
15
 
10
16
  useEffect(() => {
17
+
18
+ if (version === prevVersion.current) {
19
+ return;
20
+ }
21
+
11
22
  const keys = Object.keys(errors);
12
23
 
13
- // Whenever there are errors and the form is submitting but finished validating.
14
- if (keys.length > 0 && isSubmitting && !isValidating) {
24
+ // Whenever there are errors and the form has been submitted and is not validating
25
+ if (!isValidating && keys.length > 0) {
15
26
  const errorElement = containerRef?.current?.querySelector<HTMLDivElement>(
16
27
  `#form_field_${keys[0]}`
17
28
  );
18
29
 
19
- if (errorElement && containerRef?.current) {
20
- const scrollableParent = getScrollableParent(containerRef.current);
21
- if (scrollableParent) {
22
- const top = errorElement.getBoundingClientRect().top;
23
- scrollableParent.scrollTo({
24
- top: scrollableParent.scrollTop + top - 196,
25
- behavior: "smooth"
26
- });
27
- }
30
+ if (errorElement) {
31
+ errorElement.scrollIntoView({
32
+ behavior: "smooth",
33
+ block: "center"
34
+ });
28
35
  const input = errorElement.querySelector("input");
29
36
  if (input) input.focus();
30
37
  }
38
+ prevVersion.current = version;
31
39
  }
32
- }, [isSubmitting, isValidating, errors, containerRef]);
40
+ }, [isValidating, errors, containerRef, version]);
33
41
 
34
42
  // This component does not render anything by itself.
35
43
  return null;
36
44
  };
37
-
38
- const isScrollable = (ele: HTMLElement | null) => {
39
- const hasScrollableContent = ele && ele.scrollHeight > ele.clientHeight;
40
-
41
- const overflowYStyle = ele ? window.getComputedStyle(ele).overflowY : null;
42
- const isOverflowHidden = overflowYStyle && overflowYStyle.indexOf("hidden") !== -1;
43
-
44
- return hasScrollableContent && !isOverflowHidden;
45
- };
46
-
47
- const getScrollableParent = (ele: HTMLElement | null): HTMLElement | null => {
48
- return (!ele || ele === document.body)
49
- ? document.body
50
- : (isScrollable(ele) ? ele : getScrollableParent(ele.parentNode as HTMLElement));
51
- };
@@ -1,4 +1,8 @@
1
- export * from "./EntityForm";
1
+ export {
2
+ EntityForm,
3
+ yupToFormErrors,
4
+ } from "./EntityForm";
5
+ export type { EntityFormProps } from "./EntityForm";
2
6
 
3
7
  export { SelectFieldBinding } from "./field_bindings/SelectFieldBinding";
4
8
  export { MultiSelectFieldBinding } from "./field_bindings/MultiSelectFieldBinding";
@@ -457,8 +457,9 @@ export function useBuildNavigationController<EC extends EntityCollection, USER e
457
457
  [fullCollectionPath]);
458
458
 
459
459
  const urlPathToDataPath = useCallback((path: string): string => {
460
- if (path.startsWith(fullCollectionPath))
461
- return path.replace(fullCollectionPath, "");
460
+ const decodedPath = decodeURIComponent(path);
461
+ if (decodedPath.startsWith(fullCollectionPath))
462
+ return decodedPath.replace(fullCollectionPath, "");
462
463
  throw Error("Expected path starting with " + fullCollectionPath);
463
464
  }, [fullCollectionPath]);
464
465
 
@@ -2,6 +2,8 @@ import React from "react";
2
2
  import { PropertyPreviewProps } from "../PropertyPreviewProps";
3
3
  import { useInternalUserManagementController } from "../../hooks";
4
4
  import { UserDisplay } from "../../components/UserDisplay";
5
+ import { EmptyValue } from "./EmptyValue";
6
+ import { Typography } from "@firecms/ui";
5
7
 
6
8
  /**
7
9
  * Preview component for displaying user information.
@@ -13,10 +15,13 @@ export function UserPreview({ value }: PropertyPreviewProps<string>) {
13
15
  const { getUser } = useInternalUserManagementController();
14
16
 
15
17
  if (!value) {
16
- return null;
18
+ return <EmptyValue/>;
17
19
  }
18
20
 
19
21
  const user = getUser(value);
22
+ if (!user) {
23
+ return <Typography variant={"caption"} color={"secondary"}>User not found: {value}</Typography>;
24
+ }
20
25
 
21
- return <UserDisplay user={user} />;
26
+ return <UserDisplay user={user}/>;
22
27
  }
@@ -42,7 +42,7 @@ export function ArrayPropertyPreview({
42
42
  const childSize: PreviewSize = size === "medium" ? "medium" : "small";
43
43
 
44
44
  return (
45
- <div className="flex flex-col gap-2">
45
+ <div className="w-full flex flex-col gap-2">
46
46
  {values &&
47
47
  values.map((value, index) => {
48
48
  const of: ResolvedProperty = property.resolvedProperties[index] ??
@@ -352,6 +352,14 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
352
352
  * This prop has no effect if the history plugin is not enabled
353
353
  */
354
354
  history?: boolean;
355
+
356
+ /**
357
+ * If set to true, local changes to entities in this collection will be backed up
358
+ * in the browser's local storage. This allows users to recover unsaved changes
359
+ * in case of accidental navigation or browser crashes.
360
+ * Defaults to `true`.
361
+ */
362
+ enableLocalChangesBackup?: boolean;
355
363
  }
356
364
 
357
365
  /**
@@ -157,7 +157,6 @@ export function hasEntityInCache(path: string): boolean {
157
157
  */
158
158
  export function removeEntityFromCache(path: string): void {
159
159
 
160
-
161
160
  console.debug("Removing entity from cache", path);
162
161
 
163
162
  // Remove from the in-memory cache