Skip to content

Commit

Permalink
feat: add onSiderCollapsed to RefineThemedLayoutV2Props (#6527) (reso…
Browse files Browse the repository at this point in the history
…lves #6508)

Co-authored-by: Alican Erdurmaz <[email protected]>
Co-authored-by: Batuhan Wilhelm <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent d082ce0 commit 1d26133
Show file tree
Hide file tree
Showing 20 changed files with 197 additions and 15 deletions.
9 changes: 9 additions & 0 deletions .changeset/warm-plums-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@refinedev/chakra-ui": minor
"@refinedev/ui-types": minor
"@refinedev/mantine": minor
"@refinedev/antd": minor
"@refinedev/mui": minor
---

Enhanced the ThemedSideV2 component with new functionality to support dynamic onSiderCollapsed handling. This allows better customization of sider collapse/expand events and improved responsiveness for mobile and desktop views. Added additional type definitions and ensured compatibility across all layout contexts. resolves #6508
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const App: React.FC = () => {
| `meta` | `Record<string,any>` | Meta data to use when creating routes for the menu items |
| `fixed` | `boolean` | Whether the sider is fixed or not |
| `activeItemDisabled` | `boolean` | Whether clicking on an active sider item should reload the page |
| `onSiderCollapsed` | `(collapsed: boolean) => void` | Callback function invoked when the sider collapses or expands |

```tsx
type SiderRenderFunction = (props: {
Expand All @@ -236,6 +237,33 @@ This prop is used to set the initial collapsed state of the [`<ThemedSiderV2>`][
</ThemedLayoutV2>
```

### `onSiderCollapsed`

Will be triggered when the [`<ThemedSiderV2>`][themed-sider] component's `collapsed` state changes.

Can be used to persist collapsed state on the localstorage. Then you can use localStorage item to decide if sider should be collapsed initially or not.

Here's an example of how to use the `onSiderCollapsed` prop:

```tsx
const MyLayout = () => {
const onSiderCollapse = (collapsed: boolean) => {
localStorage.setItem("siderCollapsed", collapsed);
};

const initialSiderCollapsed = Boolean(localStorage.getItem("siderCollapsed"));

return (
<ThemedLayoutV2
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapse}
>
{/* ... */}
</ThemedLayoutV2>
);
};
```

### Header

In `<ThemedLayoutV2>`, the header section is rendered using the [`<ThemedHeaderV2>`][themed-header] component by default. It uses [`useGetIdentity`](/docs/authentication/hooks/use-get-identity) hook to display the user's name and avatar on the right side of the header. However, if desired, it's possible to replace the default [`<ThemedHeaderV2>`][themed-header] component by passing a custom component to the `Header` prop.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,33 @@ This prop is used to set the initial collapsed state of the [`<ThemedSiderV2>`][
</ThemedLayoutV2>
```

### `onSiderCollapsed`

Will be triggered when the [`<ThemedSiderV2>`][themed-sider] component's `collapsed` state changes.

Can be used to persist collapsed state on the localstorage. Then you can use localStorage item to decide if sider should be collapsed initially or not.

Here's an example of how to use the `onSiderCollapsed` prop:

```tsx
const MyLayout = () => {
const onSiderCollapse = (collapsed: boolean) => {
localStorage.setItem("siderCollapsed", collapsed);
};

const initialSiderCollapsed = Boolean(localStorage.getItem("siderCollapsed"));

return (
<ThemedLayoutV2
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapse}
>
{/* ... */}
</ThemedLayoutV2>
);
};
```

### Header

In `<ThemedLayoutV2>`, the header section is rendered using the [`<ThemedHeader>`][themed-header] component by default. It uses the [`useGetIdentity`](/docs/authentication/hooks/use-get-identity) hook to display the user's name and avatar on the right side of the header. However, if desired, it's possible to replace the default [`<ThemedHeader>`][themed-header] component by passing a custom component to the `Header` prop.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,33 @@ This prop is used to set the initial collapsed state of the [`<ThemedSiderV2>`][
</ThemedLayoutV2>
```

### `onSiderCollapsed`

Will be triggered when the [`<ThemedSiderV2>`][themed-sider] component's `collapsed` state changes.

Can be used to persist collapsed state on the localstorage. Then you can use localStorage item to decide if sider should be collapsed initially or not.

Here's an example of how to use the `onSiderCollapsed` prop:

```tsx
const MyLayout = () => {
const onSiderCollapse = (collapsed: boolean) => {
localStorage.setItem("siderCollapsed", collapsed);
};

const initialSiderCollapsed = Boolean(localStorage.getItem("siderCollapsed"));

return (
<ThemedLayoutV2
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapse}
>
{/* ... */}
</ThemedLayoutV2>
);
};
```

### Header

In `<ThemedLayoutV2>`, the header section is rendered using the [`<ThemedHeaderV2>`][themed-header] component by default. It uses the [`useGetIdentity`](/docs/authentication/hooks/use-get-identity) hook to display the user's name and avatar on the right side of the header. However, if desired, it's possible to replace the default [`<ThemedHeaderV2>`][themed-header] component by passing a custom component to the `Header` prop.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,33 @@ This prop is used to set the initial collapsed state of the [`<ThemedSiderV2>`][
</ThemedLayoutV2>
```

### `onSiderCollapsed`

Will be triggered when the [`<ThemedSiderV2>`][themed-sider] component's `collapsed` state changes.

Can be used to persist collapsed state on the localstorage. Then you can use localStorage item to decide if sider should be collapsed initially or not.

Here's an example of how to use the `onSiderCollapsed` prop:

```tsx
const MyLayout = () => {
const onSiderCollapse = (collapsed: boolean) => {
localStorage.setItem("siderCollapsed", collapsed);
};

const initialSiderCollapsed = Boolean(localStorage.getItem("siderCollapsed"));

return (
<ThemedLayoutV2
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapse}
>
{/* ... */}
</ThemedLayoutV2>
);
};
```

### Header

In `<ThemedLayoutV2>`, the header section is rendered using the [`<ThemedHeaderV2>`][themed-header] component by default. It uses [`useGetIdentity`](/docs/authentication/hooks/use-get-identity) hook to display the user's name and avatar on the right side of the header. However, if desired, it's possible to replace the default [`<ThemedHeaderV2>`][themed-header] component by passing a custom component to the `Header` prop.
Expand Down
6 changes: 5 additions & 1 deletion packages/antd/src/components/themedLayoutV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const ThemedLayoutV2: React.FC<RefineThemedLayoutV2Props> = ({
Footer,
OffLayoutArea,
initialSiderCollapsed,
onSiderCollapsed,
}) => {
const breakpoint = Grid.useBreakpoint();
const SiderToRender = Sider ?? DefaultSider;
Expand All @@ -22,7 +23,10 @@ export const ThemedLayoutV2: React.FC<RefineThemedLayoutV2Props> = ({
const hasSider = !!SiderToRender({ Title });

return (
<ThemedLayoutContextProvider initialSiderCollapsed={initialSiderCollapsed}>
<ThemedLayoutContextProvider
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapsed}
>
<AntdLayout style={{ minHeight: "100vh" }} hasSider={hasSider}>
<SiderToRender Title={Title} />
<AntdLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface IThemedLayoutContext {
setSiderCollapsed: (visible: boolean) => void;
mobileSiderOpen: boolean;
setMobileSiderOpen: (visible: boolean) => void;
onSiderCollapsed?: (collapsed: boolean) => void;
}
12 changes: 10 additions & 2 deletions packages/antd/src/contexts/themedLayoutContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ export const ThemedLayoutContext = React.createContext<IThemedLayoutContext>({
export const ThemedLayoutContextProvider: React.FC<{
children: ReactNode;
initialSiderCollapsed?: boolean;
}> = ({ children, initialSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsed] = useState(
onSiderCollapsed?: (collapsed: boolean) => void;
}> = ({ children, initialSiderCollapsed, onSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsedState] = useState(
initialSiderCollapsed ?? false,
);
const [mobileSiderOpen, setMobileSiderOpen] = useState(false);

const setSiderCollapsed = (collapsed: boolean) => {
setSiderCollapsedState(collapsed);
if (onSiderCollapsed) {
onSiderCollapsed(collapsed);
}
};

return (
<ThemedLayoutContext.Provider
value={{
Expand Down
6 changes: 5 additions & 1 deletion packages/chakra-ui/src/components/themedLayoutV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ export const ThemedLayoutV2: React.FC<RefineThemedLayoutV2Props> = ({
OffLayoutArea,
children,
initialSiderCollapsed,
onSiderCollapsed,
}) => {
const SiderToRender = Sider ?? DefaultSider;
const HeaderToRender = Header ?? DefaultHeader;

return (
<ThemedLayoutContextProvider initialSiderCollapsed={initialSiderCollapsed}>
<ThemedLayoutContextProvider
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapsed}
>
<Box display="flex">
<SiderToRender Title={Title} />
<Box
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface IThemedLayoutContext {
setSiderCollapsed: (visible: boolean) => void;
mobileSiderOpen: boolean;
setMobileSiderOpen: (visible: boolean) => void;
onSiderCollapsed?: (collapsed: boolean) => void;
}
12 changes: 10 additions & 2 deletions packages/chakra-ui/src/contexts/themedLayoutContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ export const ThemedLayoutContext = React.createContext<IThemedLayoutContext>({
export const ThemedLayoutContextProvider: React.FC<{
children: ReactNode;
initialSiderCollapsed?: boolean;
}> = ({ children, initialSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsed] = useState(
onSiderCollapsed?: (collapsed: boolean) => void;
}> = ({ children, initialSiderCollapsed, onSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsedState] = useState(
initialSiderCollapsed ?? false,
);
const [mobileSiderOpen, setMobileSiderOpen] = useState(false);

const setSiderCollapsed = (collapsed: boolean) => {
setSiderCollapsedState(collapsed);
if (onSiderCollapsed) {
onSiderCollapsed(collapsed);
}
};

return (
<ThemedLayoutContext.Provider
value={{
Expand Down
6 changes: 5 additions & 1 deletion packages/mantine/src/components/themedLayoutV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ export const ThemedLayoutV2: React.FC<RefineThemedLayoutV2Props> = ({
OffLayoutArea,
initialSiderCollapsed,
children,
onSiderCollapsed,
}) => {
const SiderToRender = Sider ?? DefaultSider;
const HeaderToRender = Header ?? DefaultHeader;

return (
<ThemedLayoutContextProvider initialSiderCollapsed={initialSiderCollapsed}>
<ThemedLayoutContextProvider
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapsed}
>
<Box sx={{ display: "flex" }}>
<SiderToRender Title={Title} />
<Box
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface IThemedLayoutContext {
setSiderCollapsed: (visible: boolean) => void;
mobileSiderOpen: boolean;
setMobileSiderOpen: (visible: boolean) => void;
onSiderCollapsed?: (collapsed: boolean) => void;
}
12 changes: 10 additions & 2 deletions packages/mantine/src/contexts/themedLayoutContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ export const ThemedLayoutContext = React.createContext<IThemedLayoutContext>({
export const ThemedLayoutContextProvider: React.FC<{
children: ReactNode;
initialSiderCollapsed?: boolean;
}> = ({ children, initialSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsed] = useState(
onSiderCollapsed?: (collapsed: boolean) => void;
}> = ({ children, initialSiderCollapsed, onSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsedState] = useState(
initialSiderCollapsed ?? false,
);
const [mobileSiderOpen, setMobileSiderOpen] = useState(false);

const setSiderCollapsed = (collapsed: boolean) => {
setSiderCollapsedState(collapsed);
if (onSiderCollapsed) {
onSiderCollapsed(collapsed);
}
};

return (
<ThemedLayoutContext.Provider
value={{
Expand Down
6 changes: 6 additions & 0 deletions packages/mui/src/components/themedLayoutV2/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { layoutLayoutTests } from "@refinedev/ui-tests";
import { ThemedLayoutV2 } from "./index";

describe("ThemedLayoutV2", () => {
layoutLayoutTests.bind(this)(ThemedLayoutV2);
});
6 changes: 5 additions & 1 deletion packages/mui/src/components/themedLayoutV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const ThemedLayoutV2: React.FC<ExtendedRefineThemedLayoutV2Props> = ({
OffLayoutArea,
children,
initialSiderCollapsed,
onSiderCollapsed,
childrenBoxProps = {},
containerBoxProps = {},
}) => {
Expand All @@ -40,7 +41,10 @@ export const ThemedLayoutV2: React.FC<ExtendedRefineThemedLayoutV2Props> = ({
const { sx: containerSx, ...restContainerProps } = containerBoxProps;

return (
<ThemedLayoutContextProvider initialSiderCollapsed={initialSiderCollapsed}>
<ThemedLayoutContextProvider
initialSiderCollapsed={initialSiderCollapsed}
onSiderCollapsed={onSiderCollapsed}
>
<Box
sx={{ display: "flex", flexDirection: "row", ...containerSx }}
{...restContainerProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface IThemedLayoutContext {
setSiderCollapsed: (visible: boolean) => void;
mobileSiderOpen: boolean;
setMobileSiderOpen: (visible: boolean) => void;
onSiderCollapsed?: (collapsed: boolean) => void;
}
13 changes: 11 additions & 2 deletions packages/mui/src/contexts/themedLayoutContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,28 @@ export const ThemedLayoutContext = React.createContext<IThemedLayoutContext>({
export const ThemedLayoutContextProvider: React.FC<{
children: ReactNode;
initialSiderCollapsed?: boolean;
}> = ({ children, initialSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsed] = useState(
onSiderCollapsed?: (collapsed: boolean) => void;
}> = ({ children, initialSiderCollapsed, onSiderCollapsed }) => {
const [siderCollapsed, setSiderCollapsedState] = useState(
initialSiderCollapsed ?? false,
);
const [mobileSiderOpen, setMobileSiderOpen] = useState(false);

const setSiderCollapsed = (collapsed: boolean) => {
setSiderCollapsedState(collapsed);
if (onSiderCollapsed) {
onSiderCollapsed(collapsed);
}
};

return (
<ThemedLayoutContext.Provider
value={{
siderCollapsed,
mobileSiderOpen,
setSiderCollapsed,
setMobileSiderOpen,
onSiderCollapsed,
}}
>
{children}
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-tests/src/tests/layout/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from "react";
import type { RefineLayoutLayoutProps } from "@refinedev/ui-types";
import type { RefineThemedLayoutV2Props } from "@refinedev/ui-types";

import { act, render, TestWrapper } from "@test";
import { render, TestWrapper } from "@test";

export const layoutLayoutTests = (
LayoutElement: React.ComponentType<RefineLayoutLayoutProps>,
LayoutElement: React.ComponentType<RefineThemedLayoutV2Props>,
): void => {
describe("[@refinedev/ui-tests] Common Tests / Layout Element", () => {
it("Layout renders sider, header, footer, title, offLayoutArea if given props", async () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/ui-types/src/types/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export type RefineThemedLayoutV2Props = {
* Whether the sider is collapsed or not by default.
*/
initialSiderCollapsed?: boolean;

/**
* Callback function triggered when the sider's collapsed state changes.
*/
onSiderCollapsed?: (collapsed: boolean) => void;
} & RefineLayoutLayoutProps;
export type RefineThemedLayoutV2SiderProps = RefineLayoutSiderProps & {
activeItemDisabled?: boolean;
Expand Down

0 comments on commit 1d26133

Please sign in to comment.