@etsoo/toolpad 1.0.0
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.
- package/.github/workflows/main.yml +49 -0
- package/.vscode/settings.json +3 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/build/src/Account/Account.d.ts +71 -0
- package/build/src/Account/Account.js +117 -0
- package/build/src/Account/Account.test.d.ts +1 -0
- package/build/src/Account/Account.test.js +35 -0
- package/build/src/Account/AccountPopoverFooter.d.ts +6 -0
- package/build/src/Account/AccountPopoverFooter.js +21 -0
- package/build/src/Account/AccountPopoverHeader.d.ts +6 -0
- package/build/src/Account/AccountPopoverHeader.js +15 -0
- package/build/src/Account/AccountPreview.d.ts +67 -0
- package/build/src/Account/AccountPreview.js +76 -0
- package/build/src/Account/AccountPreview.test.d.ts +1 -0
- package/build/src/Account/AccountPreview.test.js +47 -0
- package/build/src/Account/SignInButton.d.ts +2 -0
- package/build/src/Account/SignInButton.js +26 -0
- package/build/src/Account/SignOutButton.d.ts +3 -0
- package/build/src/Account/SignOutButton.js +28 -0
- package/build/src/Account/index.d.ts +6 -0
- package/build/src/Account/index.js +6 -0
- package/build/src/AppProvider/AppProvider.d.ts +98 -0
- package/build/src/AppProvider/AppProvider.js +4 -0
- package/build/src/AppProvider/AppProvider.test.d.ts +4 -0
- package/build/src/AppProvider/AppProvider.test.js +16 -0
- package/build/src/AppProvider/AppProviderComponent.d.ts +17 -0
- package/build/src/AppProvider/AppProviderComponent.js +120 -0
- package/build/src/AppProvider/AppThemeProvider.d.ts +12 -0
- package/build/src/AppProvider/AppThemeProvider.js +73 -0
- package/build/src/AppProvider/index.d.ts +1 -0
- package/build/src/AppProvider/index.js +1 -0
- package/build/src/DashboardLayout/DashboardLayout.d.ts +83 -0
- package/build/src/DashboardLayout/DashboardLayout.js +286 -0
- package/build/src/DashboardLayout/DashboardLayout.test.d.ts +1 -0
- package/build/src/DashboardLayout/DashboardLayout.test.js +291 -0
- package/build/src/DashboardLayout/DashboardSidebarSubNavigation.d.ts +16 -0
- package/build/src/DashboardLayout/DashboardSidebarSubNavigation.js +149 -0
- package/build/src/DashboardLayout/ThemeSwitcher.d.ts +5 -0
- package/build/src/DashboardLayout/ThemeSwitcher.js +40 -0
- package/build/src/DashboardLayout/ToolbarActions.d.ts +5 -0
- package/build/src/DashboardLayout/ToolbarActions.js +9 -0
- package/build/src/DashboardLayout/index.d.ts +2 -0
- package/build/src/DashboardLayout/index.js +3 -0
- package/build/src/DashboardLayout/utils.d.ts +8 -0
- package/build/src/DashboardLayout/utils.js +16 -0
- package/build/src/PageContainer/PageContainer.d.ts +66 -0
- package/build/src/PageContainer/PageContainer.js +97 -0
- package/build/src/PageContainer/PageContainer.test.d.ts +1 -0
- package/build/src/PageContainer/PageContainer.test.js +127 -0
- package/build/src/PageContainer/PageContainerToolbar.d.ts +16 -0
- package/build/src/PageContainer/PageContainerToolbar.js +24 -0
- package/build/src/PageContainer/PageContainerToolbar.test.d.ts +1 -0
- package/build/src/PageContainer/PageContainerToolbar.test.js +10 -0
- package/build/src/PageContainer/index.d.ts +2 -0
- package/build/src/PageContainer/index.js +2 -0
- package/build/src/index.d.ts +8 -0
- package/build/src/index.js +8 -0
- package/build/src/nextjs/AppProvider.d.ts +6 -0
- package/build/src/nextjs/AppProvider.js +16 -0
- package/build/src/nextjs/AppProvider.test.d.ts +1 -0
- package/build/src/nextjs/AppProvider.test.js +36 -0
- package/build/src/nextjs/AppProviderNextApp.d.ts +5 -0
- package/build/src/nextjs/AppProviderNextApp.js +27 -0
- package/build/src/nextjs/AppProviderNextPages.d.ts +5 -0
- package/build/src/nextjs/AppProviderNextPages.js +37 -0
- package/build/src/nextjs/index.d.ts +1 -0
- package/build/src/nextjs/index.js +1 -0
- package/build/src/persistence/codec.d.ts +47 -0
- package/build/src/persistence/codec.js +57 -0
- package/build/src/persistence/index.d.ts +1 -0
- package/build/src/persistence/index.js +1 -0
- package/build/src/persistence/useStorageState.d.ts +50 -0
- package/build/src/persistence/useStorageState.js +116 -0
- package/build/src/persistence/useStorageState.test.d.ts +1 -0
- package/build/src/persistence/useStorageState.test.js +61 -0
- package/build/src/react-router-dom/AppProvider.d.ts +6 -0
- package/build/src/react-router-dom/AppProvider.js +29 -0
- package/build/src/react-router-dom/AppProvider.test.d.ts +1 -0
- package/build/src/react-router-dom/AppProvider.test.js +12 -0
- package/build/src/react-router-dom/index.d.ts +1 -0
- package/build/src/react-router-dom/index.js +1 -0
- package/build/src/shared/Link.d.ts +8 -0
- package/build/src/shared/Link.js +19 -0
- package/build/src/shared/branding.d.ts +1 -0
- package/build/src/shared/branding.js +6 -0
- package/build/src/shared/components.d.ts +5 -0
- package/build/src/shared/components.js +23 -0
- package/build/src/shared/context.d.ts +12 -0
- package/build/src/shared/context.js +10 -0
- package/build/src/shared/locales/LocaleContext.d.ts +19 -0
- package/build/src/shared/locales/LocaleContext.js +18 -0
- package/build/src/shared/locales/en.d.ts +6 -0
- package/build/src/shared/locales/en.js +8 -0
- package/build/src/shared/navigation.d.ts +16 -0
- package/build/src/shared/navigation.js +129 -0
- package/build/src/useActivePage/index.d.ts +1 -0
- package/build/src/useActivePage/index.js +1 -0
- package/build/src/useActivePage/useActivePage.d.ts +11 -0
- package/build/src/useActivePage/useActivePage.js +48 -0
- package/build/src/useLocalStorageState/index.d.ts +1 -0
- package/build/src/useLocalStorageState/index.js +1 -0
- package/build/src/useLocalStorageState/useLocalStorageState.d.ts +2 -0
- package/build/src/useLocalStorageState/useLocalStorageState.js +14 -0
- package/build/src/useSessionStorageState/index.d.ts +1 -0
- package/build/src/useSessionStorageState/index.js +1 -0
- package/build/src/useSessionStorageState/useSessionStorageState.d.ts +2 -0
- package/build/src/useSessionStorageState/useSessionStorageState.js +14 -0
- package/build/src/utils/collections.d.ts +44 -0
- package/build/src/utils/collections.js +43 -0
- package/build/src/utils/describeConformance.d.ts +7 -0
- package/build/src/utils/describeConformance.js +3 -0
- package/build/src/utils/events.d.ts +27 -0
- package/build/src/utils/events.js +54 -0
- package/build/src/utils/hooks/index.d.ts +2 -0
- package/build/src/utils/hooks/index.js +2 -0
- package/build/src/utils/hooks/useBoolean.d.ts +11 -0
- package/build/src/utils/hooks/useBoolean.js +11 -0
- package/build/src/utils/hooks/useDebounced.d.ts +8 -0
- package/build/src/utils/hooks/useDebounced.js +28 -0
- package/build/src/utils/hooks/useDebouncedHandler.d.ts +12 -0
- package/build/src/utils/hooks/useDebouncedHandler.js +41 -0
- package/build/src/utils/hooks/useLatest.d.ts +6 -0
- package/build/src/utils/hooks/useLatest.js +9 -0
- package/build/src/utils/hooks/usePageTitle.d.ts +4 -0
- package/build/src/utils/hooks/usePageTitle.js +13 -0
- package/build/src/utils/hooks/useSsr.d.ts +4 -0
- package/build/src/utils/hooks/useSsr.js +16 -0
- package/build/src/utils/hooks/useStorageState.d.ts +10 -0
- package/build/src/utils/hooks/useStorageState.js +51 -0
- package/build/src/utils/warnOnce.d.ts +5 -0
- package/build/src/utils/warnOnce.js +11 -0
- package/build/vitest.setup.d.ts +1 -0
- package/build/vitest.setup.js +19 -0
- package/package.json +60 -0
- package/src/Account/Account.test.tsx +56 -0
- package/src/Account/Account.tsx +226 -0
- package/src/Account/AccountPopoverFooter.tsx +33 -0
- package/src/Account/AccountPopoverHeader.tsx +20 -0
- package/src/Account/AccountPreview.test.tsx +79 -0
- package/src/Account/AccountPreview.tsx +189 -0
- package/src/Account/SignInButton.tsx +38 -0
- package/src/Account/SignOutButton.tsx +44 -0
- package/src/Account/index.ts +6 -0
- package/src/AppProvider/AppProvider.test.tsx +25 -0
- package/src/AppProvider/AppProvider.tsx +116 -0
- package/src/AppProvider/AppProviderComponent.tsx +162 -0
- package/src/AppProvider/AppThemeProvider.tsx +177 -0
- package/src/AppProvider/index.ts +1 -0
- package/src/DashboardLayout/DashboardLayout.test.tsx +429 -0
- package/src/DashboardLayout/DashboardLayout.tsx +558 -0
- package/src/DashboardLayout/DashboardSidebarSubNavigation.tsx +301 -0
- package/src/DashboardLayout/ThemeSwitcher.tsx +81 -0
- package/src/DashboardLayout/ToolbarActions.tsx +11 -0
- package/src/DashboardLayout/index.ts +4 -0
- package/src/DashboardLayout/utils.ts +23 -0
- package/src/PageContainer/PageContainer.test.tsx +194 -0
- package/src/PageContainer/PageContainer.tsx +201 -0
- package/src/PageContainer/PageContainerToolbar.test.tsx +11 -0
- package/src/PageContainer/PageContainerToolbar.tsx +31 -0
- package/src/PageContainer/index.ts +2 -0
- package/src/index.ts +15 -0
- package/src/nextjs/AppProvider.test.tsx +48 -0
- package/src/nextjs/AppProvider.tsx +18 -0
- package/src/nextjs/AppProviderNextApp.tsx +37 -0
- package/src/nextjs/AppProviderNextPages.tsx +52 -0
- package/src/nextjs/index.tsx +1 -0
- package/src/persistence/codec.tsx +81 -0
- package/src/persistence/index.ts +1 -0
- package/src/persistence/useStorageState.test.tsx +101 -0
- package/src/persistence/useStorageState.tsx +244 -0
- package/src/react-router-dom/AppProvider.test.tsx +17 -0
- package/src/react-router-dom/AppProvider.tsx +40 -0
- package/src/react-router-dom/index.tsx +1 -0
- package/src/shared/Link.tsx +37 -0
- package/src/shared/branding.ts +7 -0
- package/src/shared/components.tsx +46 -0
- package/src/shared/context.ts +21 -0
- package/src/shared/locales/LocaleContext.tsx +44 -0
- package/src/shared/locales/en.tsx +9 -0
- package/src/shared/navigation.tsx +197 -0
- package/src/useActivePage/index.ts +1 -0
- package/src/useActivePage/useActivePage.ts +66 -0
- package/src/useLocalStorageState/index.ts +1 -0
- package/src/useLocalStorageState/useLocalStorageState.tsx +23 -0
- package/src/useSessionStorageState/index.tsx +1 -0
- package/src/useSessionStorageState/useSessionStorageState.tsx +23 -0
- package/src/utils/collections.ts +125 -0
- package/src/utils/describeConformance.ts +14 -0
- package/src/utils/events.ts +81 -0
- package/src/utils/hooks/index.ts +2 -0
- package/src/utils/hooks/useBoolean.ts +12 -0
- package/src/utils/hooks/useDebounced.ts +39 -0
- package/src/utils/hooks/useDebouncedHandler.ts +71 -0
- package/src/utils/hooks/useLatest.ts +16 -0
- package/src/utils/hooks/usePageTitle.ts +14 -0
- package/src/utils/hooks/useSsr.ts +24 -0
- package/src/utils/hooks/useStorageState.ts +130 -0
- package/src/utils/warnOnce.ts +12 -0
- package/tsconfig.json +19 -0
- package/vite.config.ts +27 -0
- package/vitest.setup.ts +22 -0
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { styled, useTheme, type Theme, SxProps } from "@mui/material";
|
|
5
|
+
import MuiAppBar from "@mui/material/AppBar";
|
|
6
|
+
import Box from "@mui/material/Box";
|
|
7
|
+
import Drawer from "@mui/material/Drawer";
|
|
8
|
+
import IconButton from "@mui/material/IconButton";
|
|
9
|
+
import Stack from "@mui/material/Stack";
|
|
10
|
+
import Toolbar from "@mui/material/Toolbar";
|
|
11
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
12
|
+
import Typography from "@mui/material/Typography";
|
|
13
|
+
import useMediaQuery from "@mui/material/useMediaQuery";
|
|
14
|
+
import type {} from "@mui/material/themeCssVarsAugmentation";
|
|
15
|
+
import MenuIcon from "@mui/icons-material/Menu";
|
|
16
|
+
import MenuOpenIcon from "@mui/icons-material/MenuOpen";
|
|
17
|
+
import { Link } from "../shared/Link";
|
|
18
|
+
import {
|
|
19
|
+
BrandingContext,
|
|
20
|
+
NavigationContext,
|
|
21
|
+
WindowContext
|
|
22
|
+
} from "../shared/context";
|
|
23
|
+
import { Account, type AccountProps } from "../Account";
|
|
24
|
+
import { useApplicationTitle } from "../shared/branding";
|
|
25
|
+
import { DashboardSidebarSubNavigation } from "./DashboardSidebarSubNavigation";
|
|
26
|
+
import { ToolbarActions } from "./ToolbarActions";
|
|
27
|
+
import { ThemeSwitcher } from "./ThemeSwitcher";
|
|
28
|
+
import {
|
|
29
|
+
getDrawerSxTransitionMixin,
|
|
30
|
+
getDrawerWidthTransitionMixin
|
|
31
|
+
} from "./utils";
|
|
32
|
+
|
|
33
|
+
const AppBar = styled(MuiAppBar)(({ theme }) => ({
|
|
34
|
+
borderWidth: 0,
|
|
35
|
+
borderBottomWidth: 1,
|
|
36
|
+
borderStyle: "solid",
|
|
37
|
+
borderColor: (theme.vars ?? theme).palette.divider,
|
|
38
|
+
boxShadow: "none",
|
|
39
|
+
zIndex: theme.zIndex.drawer + 1
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
const LogoContainer = styled("div")({
|
|
43
|
+
position: "relative",
|
|
44
|
+
height: 40,
|
|
45
|
+
"& img": {
|
|
46
|
+
maxHeight: 40
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export interface SidebarFooterProps {
|
|
51
|
+
mini: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface DashboardLayoutSlotProps {
|
|
55
|
+
toolbarActions?: {};
|
|
56
|
+
toolbarAccount?: AccountProps;
|
|
57
|
+
sidebarFooter?: SidebarFooterProps;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DashboardLayoutSlots {
|
|
61
|
+
/**
|
|
62
|
+
* The toolbar actions component used in the layout header.
|
|
63
|
+
* @default ToolbarActions
|
|
64
|
+
*/
|
|
65
|
+
toolbarActions?: React.JSXElementConstructor<{}>;
|
|
66
|
+
/**
|
|
67
|
+
* The toolbar account component used in the layout header.
|
|
68
|
+
* @default Account
|
|
69
|
+
*/
|
|
70
|
+
toolbarAccount?: React.JSXElementConstructor<AccountProps>;
|
|
71
|
+
/**
|
|
72
|
+
* Optional footer component used in the layout sidebar.
|
|
73
|
+
* @default null
|
|
74
|
+
*/
|
|
75
|
+
sidebarFooter?: React.JSXElementConstructor<SidebarFooterProps>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface DashboardLayoutProps {
|
|
79
|
+
/**
|
|
80
|
+
* The content of the dashboard.
|
|
81
|
+
*/
|
|
82
|
+
children: React.ReactNode;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the sidebar should not be collapsible to a mini variant in desktop and tablet viewports.
|
|
85
|
+
* @default false
|
|
86
|
+
*/
|
|
87
|
+
disableCollapsibleSidebar?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Whether the sidebar should start collapsed in desktop size screens.
|
|
90
|
+
* @default false
|
|
91
|
+
*/
|
|
92
|
+
defaultSidebarCollapsed?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Whether the navigation bar and menu icon should be hidden
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
hideNavigation?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Width of the sidebar when expanded.
|
|
100
|
+
* @default 320
|
|
101
|
+
*/
|
|
102
|
+
sidebarExpandedWidth?: number | string;
|
|
103
|
+
/**
|
|
104
|
+
* The components used for each slot inside.
|
|
105
|
+
* @default {}
|
|
106
|
+
*/
|
|
107
|
+
slots?: DashboardLayoutSlots;
|
|
108
|
+
/**
|
|
109
|
+
* The props used for each slot inside.
|
|
110
|
+
* @default {}
|
|
111
|
+
*/
|
|
112
|
+
slotProps?: DashboardLayoutSlotProps;
|
|
113
|
+
/**
|
|
114
|
+
* The system prop that allows defining system overrides as well as additional CSS styles.
|
|
115
|
+
*/
|
|
116
|
+
sx?: SxProps<Theme>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
* Demos:
|
|
122
|
+
*
|
|
123
|
+
* - [Dashboard Layout](https://mui.com/toolpad/core/react-dashboard-layout/)
|
|
124
|
+
*
|
|
125
|
+
* API:
|
|
126
|
+
*
|
|
127
|
+
* - [DashboardLayout API](https://mui.com/toolpad/core/api/dashboard-layout)
|
|
128
|
+
*/
|
|
129
|
+
function DashboardLayout(props: DashboardLayoutProps) {
|
|
130
|
+
const {
|
|
131
|
+
children,
|
|
132
|
+
disableCollapsibleSidebar = false,
|
|
133
|
+
defaultSidebarCollapsed = false,
|
|
134
|
+
hideNavigation = false,
|
|
135
|
+
sidebarExpandedWidth = 320,
|
|
136
|
+
slots,
|
|
137
|
+
slotProps,
|
|
138
|
+
sx
|
|
139
|
+
} = props;
|
|
140
|
+
|
|
141
|
+
const theme = useTheme();
|
|
142
|
+
|
|
143
|
+
const branding = React.useContext(BrandingContext);
|
|
144
|
+
const navigation = React.useContext(NavigationContext);
|
|
145
|
+
const appWindow = React.useContext(WindowContext);
|
|
146
|
+
const applicationTitle = useApplicationTitle();
|
|
147
|
+
|
|
148
|
+
const [isDesktopNavigationExpanded, setIsDesktopNavigationExpanded] =
|
|
149
|
+
React.useState(!defaultSidebarCollapsed);
|
|
150
|
+
const [isMobileNavigationExpanded, setIsMobileNavigationExpanded] =
|
|
151
|
+
React.useState(false);
|
|
152
|
+
|
|
153
|
+
const isUnderMdViewport = useMediaQuery(
|
|
154
|
+
theme.breakpoints.down("md"),
|
|
155
|
+
appWindow && {
|
|
156
|
+
matchMedia: appWindow.matchMedia
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
const isOverSmViewport = useMediaQuery(
|
|
160
|
+
theme.breakpoints.up("sm"),
|
|
161
|
+
appWindow && {
|
|
162
|
+
matchMedia: appWindow.matchMedia
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const isNavigationExpanded = isUnderMdViewport
|
|
167
|
+
? isMobileNavigationExpanded
|
|
168
|
+
: isDesktopNavigationExpanded;
|
|
169
|
+
|
|
170
|
+
const setIsNavigationExpanded = React.useCallback(
|
|
171
|
+
(newExpanded: boolean) => {
|
|
172
|
+
if (isUnderMdViewport) {
|
|
173
|
+
setIsMobileNavigationExpanded(newExpanded);
|
|
174
|
+
} else {
|
|
175
|
+
setIsDesktopNavigationExpanded(newExpanded);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
[isUnderMdViewport]
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const [isNavigationFullyExpanded, setIsNavigationFullyExpanded] =
|
|
182
|
+
React.useState(isNavigationExpanded);
|
|
183
|
+
|
|
184
|
+
React.useEffect(() => {
|
|
185
|
+
if (isNavigationExpanded) {
|
|
186
|
+
const drawerWidthTransitionTimeout = setTimeout(() => {
|
|
187
|
+
setIsNavigationFullyExpanded(true);
|
|
188
|
+
}, theme.transitions.duration.enteringScreen);
|
|
189
|
+
|
|
190
|
+
return () => clearTimeout(drawerWidthTransitionTimeout);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
setIsNavigationFullyExpanded(false);
|
|
194
|
+
|
|
195
|
+
return () => {};
|
|
196
|
+
}, [isNavigationExpanded, theme]);
|
|
197
|
+
|
|
198
|
+
const selectedItemIdRef = React.useRef("");
|
|
199
|
+
|
|
200
|
+
const handleSetNavigationExpanded = React.useCallback(
|
|
201
|
+
(newExpanded: boolean) => () => {
|
|
202
|
+
setIsNavigationExpanded(newExpanded);
|
|
203
|
+
},
|
|
204
|
+
[setIsNavigationExpanded]
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const toggleNavigationExpanded = React.useCallback(() => {
|
|
208
|
+
setIsNavigationExpanded(!isNavigationExpanded);
|
|
209
|
+
}, [isNavigationExpanded, setIsNavigationExpanded]);
|
|
210
|
+
|
|
211
|
+
const handleNavigationLinkClick = React.useCallback(() => {
|
|
212
|
+
selectedItemIdRef.current = "";
|
|
213
|
+
setIsMobileNavigationExpanded(false);
|
|
214
|
+
}, [setIsMobileNavigationExpanded]);
|
|
215
|
+
|
|
216
|
+
// If useEffect was used, the reset would also happen on the client render after SSR which we don't need
|
|
217
|
+
React.useMemo(() => {
|
|
218
|
+
if (navigation) {
|
|
219
|
+
selectedItemIdRef.current = "";
|
|
220
|
+
}
|
|
221
|
+
}, [navigation]);
|
|
222
|
+
|
|
223
|
+
const isDesktopMini =
|
|
224
|
+
!disableCollapsibleSidebar && !isDesktopNavigationExpanded;
|
|
225
|
+
const isMobileMini =
|
|
226
|
+
!disableCollapsibleSidebar && !isMobileNavigationExpanded;
|
|
227
|
+
|
|
228
|
+
const getMenuIcon = React.useCallback(
|
|
229
|
+
(isExpanded: boolean) => {
|
|
230
|
+
const expandMenuActionText = "Expand";
|
|
231
|
+
const collapseMenuActionText = "Collapse";
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<Tooltip
|
|
235
|
+
title={`${
|
|
236
|
+
isExpanded ? collapseMenuActionText : expandMenuActionText
|
|
237
|
+
} menu`}
|
|
238
|
+
enterDelay={1000}
|
|
239
|
+
>
|
|
240
|
+
<div>
|
|
241
|
+
<IconButton
|
|
242
|
+
aria-label={`${
|
|
243
|
+
isExpanded ? collapseMenuActionText : expandMenuActionText
|
|
244
|
+
} navigation menu`}
|
|
245
|
+
onClick={toggleNavigationExpanded}
|
|
246
|
+
>
|
|
247
|
+
{isExpanded ? <MenuOpenIcon /> : <MenuIcon />}
|
|
248
|
+
</IconButton>
|
|
249
|
+
</div>
|
|
250
|
+
</Tooltip>
|
|
251
|
+
);
|
|
252
|
+
},
|
|
253
|
+
[toggleNavigationExpanded]
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const hasDrawerTransitions =
|
|
257
|
+
isOverSmViewport && (disableCollapsibleSidebar || !isUnderMdViewport);
|
|
258
|
+
|
|
259
|
+
const ToolbarActionsSlot = slots?.toolbarActions ?? ToolbarActions;
|
|
260
|
+
const ToolbarAccountSlot = slots?.toolbarAccount ?? Account;
|
|
261
|
+
const SidebarFooterSlot = slots?.sidebarFooter ?? null;
|
|
262
|
+
|
|
263
|
+
const getDrawerContent = React.useCallback(
|
|
264
|
+
(isMini: boolean, viewport: "phone" | "tablet" | "desktop") => (
|
|
265
|
+
<React.Fragment>
|
|
266
|
+
<Toolbar />
|
|
267
|
+
<Box
|
|
268
|
+
component="nav"
|
|
269
|
+
aria-label={`${viewport.charAt(0).toUpperCase()}${viewport.slice(1)}`}
|
|
270
|
+
sx={{
|
|
271
|
+
height: "100%",
|
|
272
|
+
display: "flex",
|
|
273
|
+
flexDirection: "column",
|
|
274
|
+
justifyContent: "space-between",
|
|
275
|
+
overflow: "auto",
|
|
276
|
+
pt: navigation[0]?.kind === "header" && !isMini ? 0 : 2,
|
|
277
|
+
...(hasDrawerTransitions
|
|
278
|
+
? getDrawerSxTransitionMixin(isNavigationFullyExpanded, "padding")
|
|
279
|
+
: {})
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
<DashboardSidebarSubNavigation
|
|
283
|
+
subNavigation={navigation}
|
|
284
|
+
onLinkClick={handleNavigationLinkClick}
|
|
285
|
+
isMini={isMini}
|
|
286
|
+
isFullyExpanded={isNavigationFullyExpanded}
|
|
287
|
+
hasDrawerTransitions={hasDrawerTransitions}
|
|
288
|
+
selectedItemId={selectedItemIdRef.current}
|
|
289
|
+
/>
|
|
290
|
+
{SidebarFooterSlot ? (
|
|
291
|
+
<SidebarFooterSlot mini={isMini} {...slotProps?.sidebarFooter} />
|
|
292
|
+
) : null}
|
|
293
|
+
</Box>
|
|
294
|
+
</React.Fragment>
|
|
295
|
+
),
|
|
296
|
+
[
|
|
297
|
+
SidebarFooterSlot,
|
|
298
|
+
handleNavigationLinkClick,
|
|
299
|
+
hasDrawerTransitions,
|
|
300
|
+
isNavigationFullyExpanded,
|
|
301
|
+
navigation,
|
|
302
|
+
slotProps?.sidebarFooter
|
|
303
|
+
]
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const getDrawerSharedSx = React.useCallback(
|
|
307
|
+
(isMini: boolean, isTemporary: boolean) => {
|
|
308
|
+
const drawerWidth = isMini ? 64 : sidebarExpandedWidth;
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
width: drawerWidth,
|
|
312
|
+
flexShrink: 0,
|
|
313
|
+
...getDrawerWidthTransitionMixin(isNavigationExpanded),
|
|
314
|
+
...(isTemporary ? { position: "absolute" } : {}),
|
|
315
|
+
[`& .MuiDrawer-paper`]: {
|
|
316
|
+
position: "absolute",
|
|
317
|
+
width: drawerWidth,
|
|
318
|
+
boxSizing: "border-box",
|
|
319
|
+
backgroundImage: "none",
|
|
320
|
+
...getDrawerWidthTransitionMixin(isNavigationExpanded)
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
},
|
|
324
|
+
[isNavigationExpanded, sidebarExpandedWidth]
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const layoutRef = React.useRef<Element | null>(null);
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<Box
|
|
331
|
+
ref={layoutRef}
|
|
332
|
+
sx={{
|
|
333
|
+
position: "relative",
|
|
334
|
+
display: "flex",
|
|
335
|
+
overflow: "hidden",
|
|
336
|
+
height: "100vh",
|
|
337
|
+
width: "100vw",
|
|
338
|
+
...sx
|
|
339
|
+
}}
|
|
340
|
+
>
|
|
341
|
+
<AppBar color="inherit" position="absolute">
|
|
342
|
+
<Toolbar
|
|
343
|
+
sx={{ backgroundColor: "inherit", mx: { xs: -0.75, sm: -1.5 } }}
|
|
344
|
+
>
|
|
345
|
+
{!hideNavigation ? (
|
|
346
|
+
<React.Fragment>
|
|
347
|
+
<Box
|
|
348
|
+
sx={{
|
|
349
|
+
mr: { sm: disableCollapsibleSidebar ? 0 : 1 },
|
|
350
|
+
display: { md: "none" }
|
|
351
|
+
}}
|
|
352
|
+
>
|
|
353
|
+
{getMenuIcon(isMobileNavigationExpanded)}
|
|
354
|
+
</Box>
|
|
355
|
+
<Box
|
|
356
|
+
sx={{
|
|
357
|
+
display: {
|
|
358
|
+
xs: "none",
|
|
359
|
+
md: disableCollapsibleSidebar ? "none" : "block"
|
|
360
|
+
},
|
|
361
|
+
mr: disableCollapsibleSidebar ? 0 : 1
|
|
362
|
+
}}
|
|
363
|
+
>
|
|
364
|
+
{getMenuIcon(isDesktopNavigationExpanded)}
|
|
365
|
+
</Box>
|
|
366
|
+
</React.Fragment>
|
|
367
|
+
) : null}
|
|
368
|
+
|
|
369
|
+
<Box
|
|
370
|
+
sx={{
|
|
371
|
+
position: { xs: "absolute", md: "static" },
|
|
372
|
+
left: { xs: "50%", md: "auto" },
|
|
373
|
+
transform: { xs: "translateX(-50%)", md: "none" }
|
|
374
|
+
}}
|
|
375
|
+
>
|
|
376
|
+
<Link href="/" style={{ color: "inherit", textDecoration: "none" }}>
|
|
377
|
+
<Stack direction="row" alignItems="center">
|
|
378
|
+
{branding?.logo && (
|
|
379
|
+
<LogoContainer>{branding.logo}</LogoContainer>
|
|
380
|
+
)}
|
|
381
|
+
<Typography
|
|
382
|
+
variant="h6"
|
|
383
|
+
sx={{
|
|
384
|
+
color: (theme.vars ?? theme).palette.primary.main,
|
|
385
|
+
fontWeight: "700",
|
|
386
|
+
ml: 0.5,
|
|
387
|
+
whiteSpace: "nowrap"
|
|
388
|
+
}}
|
|
389
|
+
>
|
|
390
|
+
{applicationTitle}
|
|
391
|
+
</Typography>
|
|
392
|
+
</Stack>
|
|
393
|
+
</Link>
|
|
394
|
+
</Box>
|
|
395
|
+
<Box sx={{ flexGrow: 1 }} />
|
|
396
|
+
<Stack direction="row" spacing={1}>
|
|
397
|
+
<ToolbarActionsSlot {...slotProps?.toolbarActions} />
|
|
398
|
+
<ThemeSwitcher />
|
|
399
|
+
<ToolbarAccountSlot {...slotProps?.toolbarAccount} />
|
|
400
|
+
</Stack>
|
|
401
|
+
</Toolbar>
|
|
402
|
+
</AppBar>
|
|
403
|
+
|
|
404
|
+
{!hideNavigation ? (
|
|
405
|
+
<React.Fragment>
|
|
406
|
+
<Drawer
|
|
407
|
+
container={layoutRef.current}
|
|
408
|
+
variant="temporary"
|
|
409
|
+
open={isMobileNavigationExpanded}
|
|
410
|
+
onClose={handleSetNavigationExpanded(false)}
|
|
411
|
+
ModalProps={{
|
|
412
|
+
keepMounted: true // Better open performance on mobile.
|
|
413
|
+
}}
|
|
414
|
+
sx={{
|
|
415
|
+
display: {
|
|
416
|
+
xs: "block",
|
|
417
|
+
sm: disableCollapsibleSidebar ? "block" : "none",
|
|
418
|
+
md: "none"
|
|
419
|
+
},
|
|
420
|
+
...getDrawerSharedSx(false, true)
|
|
421
|
+
}}
|
|
422
|
+
>
|
|
423
|
+
{getDrawerContent(false, "phone")}
|
|
424
|
+
</Drawer>
|
|
425
|
+
<Drawer
|
|
426
|
+
variant="permanent"
|
|
427
|
+
sx={{
|
|
428
|
+
display: {
|
|
429
|
+
xs: "none",
|
|
430
|
+
sm: disableCollapsibleSidebar ? "none" : "block",
|
|
431
|
+
md: "none"
|
|
432
|
+
},
|
|
433
|
+
...getDrawerSharedSx(isMobileMini, false)
|
|
434
|
+
}}
|
|
435
|
+
>
|
|
436
|
+
{getDrawerContent(isMobileMini, "tablet")}
|
|
437
|
+
</Drawer>
|
|
438
|
+
<Drawer
|
|
439
|
+
variant="permanent"
|
|
440
|
+
sx={{
|
|
441
|
+
display: { xs: "none", md: "block" },
|
|
442
|
+
...getDrawerSharedSx(isDesktopMini, false)
|
|
443
|
+
}}
|
|
444
|
+
>
|
|
445
|
+
{getDrawerContent(isDesktopMini, "desktop")}
|
|
446
|
+
</Drawer>
|
|
447
|
+
</React.Fragment>
|
|
448
|
+
) : null}
|
|
449
|
+
|
|
450
|
+
<Box
|
|
451
|
+
sx={{
|
|
452
|
+
display: "flex",
|
|
453
|
+
flexDirection: "column",
|
|
454
|
+
flex: 1
|
|
455
|
+
}}
|
|
456
|
+
>
|
|
457
|
+
<Toolbar />
|
|
458
|
+
<Box
|
|
459
|
+
component="main"
|
|
460
|
+
sx={{
|
|
461
|
+
display: "flex",
|
|
462
|
+
flexDirection: "column",
|
|
463
|
+
flex: 1,
|
|
464
|
+
overflow: "auto"
|
|
465
|
+
}}
|
|
466
|
+
>
|
|
467
|
+
{children}
|
|
468
|
+
</Box>
|
|
469
|
+
</Box>
|
|
470
|
+
</Box>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
DashboardLayout.propTypes /* remove-proptypes */ = {
|
|
475
|
+
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
476
|
+
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
477
|
+
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
478
|
+
// └─────────────────────────────────────────────────────────────────────┘
|
|
479
|
+
/**
|
|
480
|
+
* The content of the dashboard.
|
|
481
|
+
*/
|
|
482
|
+
children: PropTypes.node,
|
|
483
|
+
/**
|
|
484
|
+
* Whether the sidebar should start collapsed in desktop size screens.
|
|
485
|
+
* @default false
|
|
486
|
+
*/
|
|
487
|
+
defaultSidebarCollapsed: PropTypes.bool,
|
|
488
|
+
/**
|
|
489
|
+
* Whether the sidebar should not be collapsible to a mini variant in desktop and tablet viewports.
|
|
490
|
+
* @default false
|
|
491
|
+
*/
|
|
492
|
+
disableCollapsibleSidebar: PropTypes.bool,
|
|
493
|
+
/**
|
|
494
|
+
* Whether the navigation bar and menu icon should be hidden
|
|
495
|
+
* @default false
|
|
496
|
+
*/
|
|
497
|
+
hideNavigation: PropTypes.bool,
|
|
498
|
+
/**
|
|
499
|
+
* Width of the sidebar when expanded.
|
|
500
|
+
* @default 320
|
|
501
|
+
*/
|
|
502
|
+
sidebarExpandedWidth: PropTypes.oneOfType([
|
|
503
|
+
PropTypes.number,
|
|
504
|
+
PropTypes.string
|
|
505
|
+
]),
|
|
506
|
+
/**
|
|
507
|
+
* The props used for each slot inside.
|
|
508
|
+
* @default {}
|
|
509
|
+
*/
|
|
510
|
+
slotProps: PropTypes.shape({
|
|
511
|
+
sidebarFooter: PropTypes.shape({
|
|
512
|
+
mini: PropTypes.bool.isRequired
|
|
513
|
+
}),
|
|
514
|
+
toolbarAccount: PropTypes.shape({
|
|
515
|
+
localeText: PropTypes.shape({
|
|
516
|
+
iconButtonAriaLabel: PropTypes.string,
|
|
517
|
+
signInLabel: PropTypes.string,
|
|
518
|
+
signOutLabel: PropTypes.string
|
|
519
|
+
}),
|
|
520
|
+
slotProps: PropTypes.shape({
|
|
521
|
+
popover: PropTypes.object,
|
|
522
|
+
popoverContent: PropTypes.object,
|
|
523
|
+
preview: PropTypes.object,
|
|
524
|
+
signInButton: PropTypes.object,
|
|
525
|
+
signOutButton: PropTypes.object
|
|
526
|
+
}),
|
|
527
|
+
slots: PropTypes.shape({
|
|
528
|
+
popover: PropTypes.elementType,
|
|
529
|
+
popoverContent: PropTypes.elementType,
|
|
530
|
+
preview: PropTypes.elementType,
|
|
531
|
+
signInButton: PropTypes.elementType,
|
|
532
|
+
signOutButton: PropTypes.elementType
|
|
533
|
+
})
|
|
534
|
+
}),
|
|
535
|
+
toolbarActions: PropTypes.object
|
|
536
|
+
}),
|
|
537
|
+
/**
|
|
538
|
+
* The components used for each slot inside.
|
|
539
|
+
* @default {}
|
|
540
|
+
*/
|
|
541
|
+
slots: PropTypes.shape({
|
|
542
|
+
sidebarFooter: PropTypes.elementType,
|
|
543
|
+
toolbarAccount: PropTypes.elementType,
|
|
544
|
+
toolbarActions: PropTypes.elementType
|
|
545
|
+
}),
|
|
546
|
+
/**
|
|
547
|
+
* The system prop that allows defining system overrides as well as additional CSS styles.
|
|
548
|
+
*/
|
|
549
|
+
sx: PropTypes.oneOfType([
|
|
550
|
+
PropTypes.arrayOf(
|
|
551
|
+
PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])
|
|
552
|
+
),
|
|
553
|
+
PropTypes.func,
|
|
554
|
+
PropTypes.object
|
|
555
|
+
])
|
|
556
|
+
} as any;
|
|
557
|
+
|
|
558
|
+
export { DashboardLayout };
|