@firecms/core 3.5.2-canary.09e1281 → 3.5.2-canary.c5764a3

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.
Files changed (27) hide show
  1. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +0 -5
  2. package/dist/components/EntityCollectionView/utils.d.ts +3 -3
  3. package/dist/index.es.js +676 -817
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +670 -811
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/internal/useUnsavedChangesDialog.d.ts +12 -0
  8. package/dist/types/side_dialogs_controller.d.ts +2 -4
  9. package/package.json +3 -3
  10. package/src/components/EntityCollectionView/EntityCollectionView.tsx +111 -12
  11. package/src/components/EntityCollectionView/utils.ts +7 -7
  12. package/src/components/common/default_entity_actions.tsx +1 -2
  13. package/src/core/DefaultAppBar.tsx +9 -12
  14. package/src/core/EntityEditView.tsx +1 -26
  15. package/src/core/SideDialogs.tsx +13 -6
  16. package/src/hooks/useReferenceDialog.tsx +2 -2
  17. package/src/internal/useBuildSideDialogsController.tsx +2 -44
  18. package/src/internal/useUnsavedChangesDialog.tsx +142 -0
  19. package/src/types/side_dialogs_controller.tsx +2 -4
  20. package/dist/components/EntityCollectionView/CollectionCountBadge.d.ts +0 -8
  21. package/dist/components/EntityCollectionView/CollectionPathTitle.d.ts +0 -24
  22. package/dist/components/EntityCollectionView/EntityIdHeaderWidget.d.ts +0 -12
  23. package/dist/internal/useLeavePageConfirmation.d.ts +0 -11
  24. package/src/components/EntityCollectionView/CollectionCountBadge.tsx +0 -17
  25. package/src/components/EntityCollectionView/CollectionPathTitle.tsx +0 -68
  26. package/src/components/EntityCollectionView/EntityIdHeaderWidget.tsx +0 -124
  27. package/src/internal/useLeavePageConfirmation.ts +0 -25
@@ -8,11 +8,9 @@ import { EntityFormProps } from "../form";
8
8
  export interface SideDialogsController {
9
9
 
10
10
  /**
11
- * Close the last panel.
12
- * When the `key` of a panel without a URL is given, that panel is closed
13
- * instead, even if other panels are open on top of it.
11
+ * Close the last panel
14
12
  */
15
- close: (key?: string) => void;
13
+ close: () => void;
16
14
 
17
15
  /**
18
16
  * List of side panels currently open
@@ -1,8 +0,0 @@
1
- import React from "react";
2
- /**
3
- * Number of entities in a collection, as shown next to its name.
4
- * `undefined` renders nothing, `null` a loading placeholder.
5
- */
6
- export declare function CollectionCountBadge({ count }: {
7
- count: number | null | undefined;
8
- }): React.JSX.Element | null;
@@ -1,24 +0,0 @@
1
- import React from "react";
2
- /**
3
- * A name and its entity count, under what is above it: breadcrumbs folded on two lines
4
- * for where a row of them would not fit.
5
- */
6
- export declare function PathTitle({ parents, name, count, className }: {
7
- parents: string[];
8
- name: string;
9
- /** `undefined` shows no count, `null` a loading one. */
10
- count: number | null | undefined;
11
- className?: string;
12
- }): React.JSX.Element;
13
- /**
14
- * A collection's name and entity count, under the collections and entities above it,
15
- * the same things the app bar's breadcrumbs show. A side panel covers those, so it
16
- * shows a subcollection's in its own top bar.
17
- */
18
- export declare function CollectionPathTitle({ path, name, count }: {
19
- /** The escaped chain, as in `fullIdPath`. */
20
- path: string;
21
- name: string;
22
- /** `undefined` shows no count, `null` a loading one. */
23
- count: number | null | undefined;
24
- }): React.JSX.Element;
@@ -1,12 +0,0 @@
1
- import React from "react";
2
- import { EntityCollection } from "../../types";
3
- /**
4
- * "Find by id" in the header of a collection's id column, listing the ids opened in it lately.
5
- */
6
- export declare function EntityIdHeaderWidget({ collection, path, pathSegments, fullIdPath }: {
7
- collection: EntityCollection;
8
- path: string;
9
- /** `path` split at its real segment boundaries, when the caller knows them. */
10
- pathSegments?: string[];
11
- fullIdPath: string;
12
- }): React.JSX.Element;
@@ -1,11 +0,0 @@
1
- /**
2
- * Asks the browser to confirm leaving the page (reload, tab close, a link that
3
- * loads another document) while `when` is true.
4
- *
5
- * Navigation inside the app is not intercepted: unsaved entity values are kept
6
- * in the dirty entity cache, so they survive it. Cancelling link clicks here
7
- * used to leave plain and new-tab links doing nothing, with no dialog shown.
8
- *
9
- * @param when - Whether leaving the page should be confirmed.
10
- */
11
- export declare function useLeavePageConfirmation(when: boolean): void;
@@ -1,17 +0,0 @@
1
- import React from "react";
2
- import { Skeleton } from "@firecms/ui";
3
-
4
- /**
5
- * Number of entities in a collection, as shown next to its name.
6
- * `undefined` renders nothing, `null` a loading placeholder.
7
- */
8
- export function CollectionCountBadge({ count }: { count: number | null | undefined }) {
9
- if (count === undefined)
10
- return null;
11
- if (count === null)
12
- return <Skeleton className="w-8 h-4 rounded-md"/>;
13
- return <span
14
- className="text-xs text-surface-accent-500 dark:text-surface-accent-400 bg-surface-100 dark:bg-surface-700 px-1 py-0 rounded">
15
- {count}
16
- </span>;
17
- }
@@ -1,68 +0,0 @@
1
- import React, { useMemo } from "react";
2
- import { cls, Typography } from "@firecms/ui";
3
- import { useNavigationController } from "../../hooks/useNavigationController";
4
- import { getNavigationEntriesFromPath } from "../../util/navigation_from_path";
5
- import { CollectionCountBadge } from "./CollectionCountBadge";
6
-
7
- /**
8
- * A name and its entity count, under what is above it: breadcrumbs folded on two lines
9
- * for where a row of them would not fit.
10
- */
11
- export function PathTitle({
12
- parents,
13
- name,
14
- count,
15
- className
16
- }: {
17
- parents: string[],
18
- name: string,
19
- /** `undefined` shows no count, `null` a loading one. */
20
- count: number | null | undefined,
21
- className?: string
22
- }) {
23
- return <div className={cls("flex flex-col", className)}>
24
- {parents.length > 0 && <Typography variant={"caption"} color={"secondary"} noWrap>
25
- {parents.join(" / ")}
26
- </Typography>}
27
- <div className="flex flex-row items-center gap-2 min-w-0">
28
- <Typography variant={"body2"} noWrap className={"font-medium"}>
29
- {name}
30
- </Typography>
31
- <CollectionCountBadge count={count}/>
32
- </div>
33
- </div>;
34
- }
35
-
36
- /**
37
- * A collection's name and entity count, under the collections and entities above it,
38
- * the same things the app bar's breadcrumbs show. A side panel covers those, so it
39
- * shows a subcollection's in its own top bar.
40
- */
41
- export function CollectionPathTitle({
42
- path,
43
- name,
44
- count
45
- }: {
46
- /** The escaped chain, as in `fullIdPath`. */
47
- path: string,
48
- name: string,
49
- /** `undefined` shows no count, `null` a loading one. */
50
- count: number | null | undefined
51
- }) {
52
- const navigation = useNavigationController();
53
- const parents = useMemo(() => getNavigationEntriesFromPath({
54
- path,
55
- collections: navigation.collections ?? []
56
- })
57
- .slice(0, -1)
58
- .map(entry => entry.type === "entity"
59
- ? entry.entityId
60
- : entry.type === "collection" ? entry.collection.name : entry.view.name),
61
- [path, navigation.collections]);
62
-
63
- // it keeps its width, up to the cap, and the tabs next to it scroll instead
64
- return <PathTitle parents={parents}
65
- name={name}
66
- count={count}
67
- className={"shrink-0 mx-2 max-w-[140px] sm:max-w-[240px] lg:max-w-[320px]"}/>;
68
- }
@@ -1,124 +0,0 @@
1
- import React from "react";
2
- import { Button, cls, focusedDisabled, IconButton, KeyboardTabIcon, Popover, SearchIcon, Tooltip } from "@firecms/ui";
3
- import { EntityCollection, EntityReference } from "../../types";
4
- import { navigateToEntity } from "../../util/navigation_utils";
5
- import { ReferencePreview } from "../../preview";
6
- import { useNavigationController } from "../../hooks/useNavigationController";
7
- import { useSideEntityController } from "../../hooks/useSideEntityController";
8
- import { useTranslation } from "../../hooks/useTranslation";
9
- import { addRecentId, getRecentIds } from "./utils";
10
-
11
- const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
12
-
13
- /**
14
- * "Find by id" in the header of a collection's id column, listing the ids opened in it lately.
15
- */
16
- export function EntityIdHeaderWidget({
17
- collection,
18
- path,
19
- pathSegments,
20
- fullIdPath
21
- }: {
22
- collection: EntityCollection,
23
- path: string,
24
- /** `path` split at its real segment boundaries, when the caller knows them. */
25
- pathSegments?: string[],
26
- fullIdPath: string
27
- }) {
28
-
29
- const navigation = useNavigationController();
30
- const [openPopup, setOpenPopup] = React.useState(false);
31
- const [searchString, setSearchString] = React.useState("");
32
- // Kept per full path rather than per collection: a subcollection has the same id under
33
- // every parent, and an id found under one parent does not exist under the others.
34
- const [recentIds, setRecentIds] = React.useState<string[]>(() => getRecentIds(fullIdPath));
35
- const sideEntityController = useSideEntityController();
36
- const { t } = useTranslation();
37
-
38
- const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
39
-
40
- return (
41
- <Tooltip title={!openPopup ? t("find_by_id") : undefined} asChild={false}>
42
- <Popover
43
- open={openPopup}
44
- onOpenChange={(open) => {
45
- // rows opened since this header mounted are recent too
46
- if (open) setRecentIds(getRecentIds(fullIdPath));
47
- setOpenPopup(open);
48
- }}
49
- sideOffset={0}
50
- align={"start"}
51
- alignOffset={-117}
52
- trigger={
53
- <IconButton size={"small"}>
54
- <SearchIcon size={"small"} />
55
- </IconButton>
56
- }>
57
- <div
58
- className={cls("my-2 rounded-lg bg-surface-50 dark:bg-surface-950 text-surface-900 dark:text-white")}>
59
- <form noValidate={true}
60
- onSubmit={(e) => {
61
- e.preventDefault();
62
- const entityId = searchString.trim();
63
- // Enter submits even while the button is disabled, and an empty
64
- // id would open a new entity instead
65
- if (!entityId) return;
66
- setOpenPopup(false);
67
- setRecentIds(addRecentId(fullIdPath, entityId));
68
- navigateToEntity({
69
- openEntityMode,
70
- collection,
71
- entityId,
72
- path,
73
- pathSegments,
74
- fullIdPath,
75
- sideEntityController,
76
- navigation
77
- })
78
- }}
79
- className={"w-96 max-w-full"}>
80
-
81
- <div className="flex p-2 w-full gap-2">
82
- <input
83
- autoFocus={openPopup}
84
- placeholder={t("find_entity_by_id")}
85
- // size={"small"}
86
- onChange={(e) => {
87
- setSearchString(e.target.value);
88
- }}
89
- value={searchString}
90
- className={"rounded-lg bg-white dark:bg-surface-800 flex-grow bg-transparent outline-none p-2 " + focusedDisabled} />
91
- <Button variant={"text"}
92
- disabled={!(searchString.trim())}
93
- type={"submit"}
94
- ><KeyboardTabIcon /></Button>
95
- </div>
96
- </form>
97
- {recentIds && recentIds.length > 0 && <div className="flex flex-col gap-2 p-2">
98
- {recentIds.map(id => (
99
- <ReferencePreview reference={new EntityReference(id, path, undefined, pathSegments)}
100
- key={id}
101
- hover={true}
102
- onClick={() => {
103
- setOpenPopup(false);
104
- navigateToEntity({
105
- openEntityMode,
106
- collection,
107
- entityId: id,
108
- path,
109
- pathSegments,
110
- fullIdPath,
111
- sideEntityController,
112
- navigation
113
- })
114
- }}
115
- includeEntityLink={false}
116
- size={"small"} />
117
- ))}
118
- </div>}
119
- </div>
120
- </Popover>
121
-
122
- </Tooltip>
123
- );
124
- }
@@ -1,25 +0,0 @@
1
- import { useEffect } from "react";
2
-
3
- /**
4
- * Asks the browser to confirm leaving the page (reload, tab close, a link that
5
- * loads another document) while `when` is true.
6
- *
7
- * Navigation inside the app is not intercepted: unsaved entity values are kept
8
- * in the dirty entity cache, so they survive it. Cancelling link clicks here
9
- * used to leave plain and new-tab links doing nothing, with no dialog shown.
10
- *
11
- * @param when - Whether leaving the page should be confirmed.
12
- */
13
- export function useLeavePageConfirmation(when: boolean): void {
14
- useEffect(() => {
15
- if (!when) return;
16
-
17
- const handleBeforeUnload = (e: BeforeUnloadEvent) => {
18
- e.preventDefault();
19
- e.returnValue = "";
20
- };
21
-
22
- window.addEventListener("beforeunload", handleBeforeUnload);
23
- return () => window.removeEventListener("beforeunload", handleBeforeUnload);
24
- }, [when]);
25
- }