mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
fork refine
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
import { LayoutProps } from "../../../interfaces";
|
||||
|
||||
export const DefaultLayout: React.FC<LayoutProps> = ({ children }) => {
|
||||
return <div>{children}</div>;
|
||||
};
|
||||
186
packages/core/src/components/layoutWrapper/index.spec.tsx
Normal file
186
packages/core/src/components/layoutWrapper/index.spec.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import React from "react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
|
||||
import { LayoutWrapper } from "@components/layoutWrapper";
|
||||
import {
|
||||
render,
|
||||
TestWrapper,
|
||||
MockJSONServer,
|
||||
mockLegacyRouterProvider,
|
||||
} from "@test";
|
||||
import { defaultRefineOptions } from "@contexts/refine";
|
||||
import { IRefineContextProvider } from "../../contexts/refine/IRefineContext";
|
||||
import { LayoutProps } from "../../interfaces";
|
||||
|
||||
const renderWithRefineContext = (
|
||||
children: React.ReactNode,
|
||||
refineProvider: IRefineContextProvider,
|
||||
) => {
|
||||
return render(<>{children}</>, {
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
legacyRouterProvider: mockLegacyRouterProvider(),
|
||||
refineProvider,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
describe("LayoutWrapper", () => {
|
||||
it("LayoutWrapper successfully pass the custom components to Layout component as a props", () => {
|
||||
const customSiderContent = "customSiderContent";
|
||||
const CustomSider = () => <p>{customSiderContent}</p>;
|
||||
|
||||
const customHeaderContent = "customHeaderContent";
|
||||
const CustomHeader = () => <p>{customHeaderContent}</p>;
|
||||
|
||||
const customFooterContent = "customFooterContent";
|
||||
const CustomFooter = () => <p>{customFooterContent}</p>;
|
||||
|
||||
const customOffLayoutAreaContent = "customOffLayoutAreaContent";
|
||||
const CustomOffLayoutArea = () => <p>{customOffLayoutAreaContent}</p>;
|
||||
|
||||
const customTitleContent = "customTitleContent";
|
||||
const CustomTitle = () => <p>{customTitleContent}</p>;
|
||||
|
||||
const CustomLayout: React.FC<LayoutProps> = ({
|
||||
Header,
|
||||
Sider,
|
||||
Footer,
|
||||
OffLayoutArea,
|
||||
Title,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
{Header && <Header />}
|
||||
{Title && <Title collapsed={true} />}
|
||||
{Sider && <Sider />}
|
||||
{children}
|
||||
{Footer && <Footer />}
|
||||
{OffLayoutArea && <OffLayoutArea />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const { getByText } = renderWithRefineContext(
|
||||
<LayoutWrapper>
|
||||
<div>test </div>
|
||||
</LayoutWrapper>,
|
||||
{
|
||||
hasDashboard: false,
|
||||
Layout: CustomLayout,
|
||||
Sider: CustomSider,
|
||||
Header: CustomHeader,
|
||||
Footer: CustomFooter,
|
||||
OffLayoutArea: CustomOffLayoutArea,
|
||||
Title: CustomTitle,
|
||||
...defaultRefineOptions,
|
||||
options: defaultRefineOptions,
|
||||
},
|
||||
);
|
||||
|
||||
getByText(customSiderContent);
|
||||
getByText(customHeaderContent);
|
||||
getByText(customFooterContent);
|
||||
getByText(customOffLayoutAreaContent);
|
||||
getByText(customTitleContent);
|
||||
});
|
||||
|
||||
it("By default, LayoutWrapper not renders the custom components", () => {
|
||||
const customSiderContent = "customSiderContent";
|
||||
const CustomSider = () => <p>{customSiderContent}</p>;
|
||||
|
||||
const customHeaderContent = "customHeaderContent";
|
||||
const CustomHeader = () => <p>{customHeaderContent}</p>;
|
||||
|
||||
const customFooterContent = "customFooterContent";
|
||||
const CustomFooter = () => <p>{customFooterContent}</p>;
|
||||
|
||||
const customOffLayoutAreaContent = "customOffLayoutAreaContent";
|
||||
const CustomOffLayoutArea = () => <p>{customOffLayoutAreaContent}</p>;
|
||||
|
||||
const customTitleContent = "customTitleContent";
|
||||
const CustomTitle = () => <p>{customTitleContent}</p>;
|
||||
|
||||
const { queryByText } = renderWithRefineContext(
|
||||
<LayoutWrapper>
|
||||
<div>test </div>
|
||||
</LayoutWrapper>,
|
||||
{
|
||||
hasDashboard: false,
|
||||
Sider: CustomSider,
|
||||
Header: CustomHeader,
|
||||
Footer: CustomFooter,
|
||||
OffLayoutArea: CustomOffLayoutArea,
|
||||
Title: CustomTitle,
|
||||
...defaultRefineOptions,
|
||||
options: defaultRefineOptions,
|
||||
},
|
||||
);
|
||||
|
||||
expect(queryByText(customSiderContent)).toBeNull();
|
||||
expect(queryByText(customHeaderContent)).toBeNull();
|
||||
expect(queryByText(customFooterContent)).toBeNull();
|
||||
expect(queryByText(customOffLayoutAreaContent)).toBeNull();
|
||||
expect(queryByText(customTitleContent)).toBeNull();
|
||||
});
|
||||
|
||||
it("LayoutWrapper renders custom layout, sider, header, footer, title, offLayoutArea if given props", () => {
|
||||
const customTitleContent = "customTitleContent";
|
||||
const CustomTitle = () => <p>{customTitleContent}</p>;
|
||||
|
||||
const CustomLayout: React.FC<LayoutProps> = ({
|
||||
Header,
|
||||
Sider,
|
||||
Footer,
|
||||
OffLayoutArea,
|
||||
children,
|
||||
}) => (
|
||||
<div>
|
||||
{Header && <Header />}
|
||||
{Sider && <Sider />}
|
||||
{children}
|
||||
<div>custom layout</div>
|
||||
{Footer && <Footer />}
|
||||
{OffLayoutArea && <OffLayoutArea />}
|
||||
</div>
|
||||
);
|
||||
|
||||
const customSiderContent = "customSiderContent";
|
||||
const CustomSider = () => <p>{customSiderContent}</p>;
|
||||
|
||||
const customHeaderContent = "customHeaderContent";
|
||||
const CustomHeader = () => <p>{customHeaderContent}</p>;
|
||||
|
||||
const customFooterContent = "customFooterContent";
|
||||
const CustomFooter = () => <p>{customFooterContent}</p>;
|
||||
|
||||
const customOffLayoutAreaContent = "customOffLayoutAreaContent";
|
||||
const CustomOffLayoutArea = () => <p>{customOffLayoutAreaContent}</p>;
|
||||
|
||||
const { getByText } = renderWithRefineContext(
|
||||
<LayoutWrapper
|
||||
Layout={CustomLayout}
|
||||
Title={CustomTitle}
|
||||
Sider={CustomSider}
|
||||
Header={CustomHeader}
|
||||
Footer={CustomFooter}
|
||||
OffLayoutArea={CustomOffLayoutArea}
|
||||
>
|
||||
<div>test</div>
|
||||
</LayoutWrapper>,
|
||||
{
|
||||
...defaultRefineOptions,
|
||||
options: defaultRefineOptions,
|
||||
hasDashboard: false,
|
||||
},
|
||||
);
|
||||
|
||||
expect(getByText(customSiderContent));
|
||||
expect(getByText(customHeaderContent));
|
||||
expect(getByText(customFooterContent));
|
||||
expect(getByText(customOffLayoutAreaContent));
|
||||
expect(getByText("custom layout"));
|
||||
});
|
||||
});
|
||||
121
packages/core/src/components/layoutWrapper/index.tsx
Normal file
121
packages/core/src/components/layoutWrapper/index.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import {
|
||||
useRefineContext,
|
||||
useRouterContext,
|
||||
useTranslate,
|
||||
useWarnAboutChange,
|
||||
} from "@hooks";
|
||||
import { LayoutProps, TitleProps } from "../../interfaces";
|
||||
|
||||
export interface LayoutWrapperProps {
|
||||
/**
|
||||
* Outer component that renders other components
|
||||
* @default *
|
||||
*/
|
||||
Layout?: React.FC<LayoutProps>;
|
||||
/**
|
||||
* [Custom sider to use](/api-reference/core/components/refine-config.md#sider)
|
||||
* @default *
|
||||
*/
|
||||
Sider?: React.FC;
|
||||
/**
|
||||
* [Custom header to use](/api-reference/core/components/refine-config.md#header)
|
||||
* @default *
|
||||
*/
|
||||
Header?: React.FC;
|
||||
/**
|
||||
* [Custom title to use](/api-reference/core/components/refine-config.md#title)
|
||||
* @default *
|
||||
*/
|
||||
Title?: React.FC<TitleProps>;
|
||||
/**
|
||||
* [Custom footer to use](/api-reference/core/components/refine-config.md#footer)
|
||||
* @default *
|
||||
*/
|
||||
Footer?: React.FC;
|
||||
/**
|
||||
* [Custom off layout area to use](/api-reference/core/components/refine-config.md#offlayoutarea)
|
||||
* @default *
|
||||
*/
|
||||
OffLayoutArea?: React.FC;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* `<LayoutWrapper>` wraps its contents in **refine's** layout with all customizations made in {@link https://refine.dev/docs/core/components/refine-config `<Refine>`} component.
|
||||
* It is the default layout used in resource pages.
|
||||
* It can be used in custom pages to use global layout.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/core/components/layout-wrapper} for more details.
|
||||
*
|
||||
* @deprecated This component is obsolete and only works with the legacy router providers.
|
||||
*/
|
||||
export const LayoutWrapper: React.FC<LayoutWrapperProps> = ({
|
||||
children,
|
||||
Layout: LayoutFromProps,
|
||||
Sider: SiderFromProps,
|
||||
Header: HeaderFromProps,
|
||||
Title: TitleFromProps,
|
||||
Footer: FooterFromProps,
|
||||
OffLayoutArea: OffLayoutAreaFromProps,
|
||||
}) => {
|
||||
const { Layout, Footer, Header, Sider, Title, OffLayoutArea } =
|
||||
useRefineContext();
|
||||
|
||||
const LayoutToRender = LayoutFromProps ?? Layout;
|
||||
|
||||
return (
|
||||
<LayoutToRender
|
||||
Sider={SiderFromProps ?? Sider}
|
||||
Header={HeaderFromProps ?? Header}
|
||||
Footer={FooterFromProps ?? Footer}
|
||||
Title={TitleFromProps ?? Title}
|
||||
OffLayoutArea={OffLayoutAreaFromProps ?? OffLayoutArea}
|
||||
>
|
||||
{children}
|
||||
<UnsavedPrompt />
|
||||
</LayoutToRender>
|
||||
);
|
||||
};
|
||||
|
||||
const UnsavedPrompt: React.FC = () => {
|
||||
const { Prompt } = useRouterContext();
|
||||
|
||||
const translate = useTranslate();
|
||||
|
||||
const { warnWhen, setWarnWhen } = useWarnAboutChange();
|
||||
|
||||
const warnWhenListener = (e: {
|
||||
preventDefault: () => void;
|
||||
returnValue: string;
|
||||
}) => {
|
||||
e.preventDefault();
|
||||
|
||||
e.returnValue = translate(
|
||||
"warnWhenUnsavedChanges",
|
||||
"Are you sure you want to leave? You have unsaved changes.",
|
||||
);
|
||||
|
||||
return e.returnValue;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (warnWhen) {
|
||||
window.addEventListener("beforeunload", warnWhenListener);
|
||||
}
|
||||
|
||||
return window.removeEventListener("beforeunload", warnWhenListener);
|
||||
}, [warnWhen]);
|
||||
|
||||
return (
|
||||
<Prompt
|
||||
when={warnWhen}
|
||||
message={translate(
|
||||
"warnWhenUnsavedChanges",
|
||||
"Are you sure you want to leave? You have unsaved changes.",
|
||||
)}
|
||||
setWarnWhen={setWarnWhen}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user