@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.
Files changed (202) hide show
  1. package/.github/workflows/main.yml +49 -0
  2. package/.vscode/settings.json +3 -0
  3. package/LICENSE +21 -0
  4. package/README.md +11 -0
  5. package/build/src/Account/Account.d.ts +71 -0
  6. package/build/src/Account/Account.js +117 -0
  7. package/build/src/Account/Account.test.d.ts +1 -0
  8. package/build/src/Account/Account.test.js +35 -0
  9. package/build/src/Account/AccountPopoverFooter.d.ts +6 -0
  10. package/build/src/Account/AccountPopoverFooter.js +21 -0
  11. package/build/src/Account/AccountPopoverHeader.d.ts +6 -0
  12. package/build/src/Account/AccountPopoverHeader.js +15 -0
  13. package/build/src/Account/AccountPreview.d.ts +67 -0
  14. package/build/src/Account/AccountPreview.js +76 -0
  15. package/build/src/Account/AccountPreview.test.d.ts +1 -0
  16. package/build/src/Account/AccountPreview.test.js +47 -0
  17. package/build/src/Account/SignInButton.d.ts +2 -0
  18. package/build/src/Account/SignInButton.js +26 -0
  19. package/build/src/Account/SignOutButton.d.ts +3 -0
  20. package/build/src/Account/SignOutButton.js +28 -0
  21. package/build/src/Account/index.d.ts +6 -0
  22. package/build/src/Account/index.js +6 -0
  23. package/build/src/AppProvider/AppProvider.d.ts +98 -0
  24. package/build/src/AppProvider/AppProvider.js +4 -0
  25. package/build/src/AppProvider/AppProvider.test.d.ts +4 -0
  26. package/build/src/AppProvider/AppProvider.test.js +16 -0
  27. package/build/src/AppProvider/AppProviderComponent.d.ts +17 -0
  28. package/build/src/AppProvider/AppProviderComponent.js +120 -0
  29. package/build/src/AppProvider/AppThemeProvider.d.ts +12 -0
  30. package/build/src/AppProvider/AppThemeProvider.js +73 -0
  31. package/build/src/AppProvider/index.d.ts +1 -0
  32. package/build/src/AppProvider/index.js +1 -0
  33. package/build/src/DashboardLayout/DashboardLayout.d.ts +83 -0
  34. package/build/src/DashboardLayout/DashboardLayout.js +286 -0
  35. package/build/src/DashboardLayout/DashboardLayout.test.d.ts +1 -0
  36. package/build/src/DashboardLayout/DashboardLayout.test.js +291 -0
  37. package/build/src/DashboardLayout/DashboardSidebarSubNavigation.d.ts +16 -0
  38. package/build/src/DashboardLayout/DashboardSidebarSubNavigation.js +149 -0
  39. package/build/src/DashboardLayout/ThemeSwitcher.d.ts +5 -0
  40. package/build/src/DashboardLayout/ThemeSwitcher.js +40 -0
  41. package/build/src/DashboardLayout/ToolbarActions.d.ts +5 -0
  42. package/build/src/DashboardLayout/ToolbarActions.js +9 -0
  43. package/build/src/DashboardLayout/index.d.ts +2 -0
  44. package/build/src/DashboardLayout/index.js +3 -0
  45. package/build/src/DashboardLayout/utils.d.ts +8 -0
  46. package/build/src/DashboardLayout/utils.js +16 -0
  47. package/build/src/PageContainer/PageContainer.d.ts +66 -0
  48. package/build/src/PageContainer/PageContainer.js +97 -0
  49. package/build/src/PageContainer/PageContainer.test.d.ts +1 -0
  50. package/build/src/PageContainer/PageContainer.test.js +127 -0
  51. package/build/src/PageContainer/PageContainerToolbar.d.ts +16 -0
  52. package/build/src/PageContainer/PageContainerToolbar.js +24 -0
  53. package/build/src/PageContainer/PageContainerToolbar.test.d.ts +1 -0
  54. package/build/src/PageContainer/PageContainerToolbar.test.js +10 -0
  55. package/build/src/PageContainer/index.d.ts +2 -0
  56. package/build/src/PageContainer/index.js +2 -0
  57. package/build/src/index.d.ts +8 -0
  58. package/build/src/index.js +8 -0
  59. package/build/src/nextjs/AppProvider.d.ts +6 -0
  60. package/build/src/nextjs/AppProvider.js +16 -0
  61. package/build/src/nextjs/AppProvider.test.d.ts +1 -0
  62. package/build/src/nextjs/AppProvider.test.js +36 -0
  63. package/build/src/nextjs/AppProviderNextApp.d.ts +5 -0
  64. package/build/src/nextjs/AppProviderNextApp.js +27 -0
  65. package/build/src/nextjs/AppProviderNextPages.d.ts +5 -0
  66. package/build/src/nextjs/AppProviderNextPages.js +37 -0
  67. package/build/src/nextjs/index.d.ts +1 -0
  68. package/build/src/nextjs/index.js +1 -0
  69. package/build/src/persistence/codec.d.ts +47 -0
  70. package/build/src/persistence/codec.js +57 -0
  71. package/build/src/persistence/index.d.ts +1 -0
  72. package/build/src/persistence/index.js +1 -0
  73. package/build/src/persistence/useStorageState.d.ts +50 -0
  74. package/build/src/persistence/useStorageState.js +116 -0
  75. package/build/src/persistence/useStorageState.test.d.ts +1 -0
  76. package/build/src/persistence/useStorageState.test.js +61 -0
  77. package/build/src/react-router-dom/AppProvider.d.ts +6 -0
  78. package/build/src/react-router-dom/AppProvider.js +29 -0
  79. package/build/src/react-router-dom/AppProvider.test.d.ts +1 -0
  80. package/build/src/react-router-dom/AppProvider.test.js +12 -0
  81. package/build/src/react-router-dom/index.d.ts +1 -0
  82. package/build/src/react-router-dom/index.js +1 -0
  83. package/build/src/shared/Link.d.ts +8 -0
  84. package/build/src/shared/Link.js +19 -0
  85. package/build/src/shared/branding.d.ts +1 -0
  86. package/build/src/shared/branding.js +6 -0
  87. package/build/src/shared/components.d.ts +5 -0
  88. package/build/src/shared/components.js +23 -0
  89. package/build/src/shared/context.d.ts +12 -0
  90. package/build/src/shared/context.js +10 -0
  91. package/build/src/shared/locales/LocaleContext.d.ts +19 -0
  92. package/build/src/shared/locales/LocaleContext.js +18 -0
  93. package/build/src/shared/locales/en.d.ts +6 -0
  94. package/build/src/shared/locales/en.js +8 -0
  95. package/build/src/shared/navigation.d.ts +16 -0
  96. package/build/src/shared/navigation.js +129 -0
  97. package/build/src/useActivePage/index.d.ts +1 -0
  98. package/build/src/useActivePage/index.js +1 -0
  99. package/build/src/useActivePage/useActivePage.d.ts +11 -0
  100. package/build/src/useActivePage/useActivePage.js +48 -0
  101. package/build/src/useLocalStorageState/index.d.ts +1 -0
  102. package/build/src/useLocalStorageState/index.js +1 -0
  103. package/build/src/useLocalStorageState/useLocalStorageState.d.ts +2 -0
  104. package/build/src/useLocalStorageState/useLocalStorageState.js +14 -0
  105. package/build/src/useSessionStorageState/index.d.ts +1 -0
  106. package/build/src/useSessionStorageState/index.js +1 -0
  107. package/build/src/useSessionStorageState/useSessionStorageState.d.ts +2 -0
  108. package/build/src/useSessionStorageState/useSessionStorageState.js +14 -0
  109. package/build/src/utils/collections.d.ts +44 -0
  110. package/build/src/utils/collections.js +43 -0
  111. package/build/src/utils/describeConformance.d.ts +7 -0
  112. package/build/src/utils/describeConformance.js +3 -0
  113. package/build/src/utils/events.d.ts +27 -0
  114. package/build/src/utils/events.js +54 -0
  115. package/build/src/utils/hooks/index.d.ts +2 -0
  116. package/build/src/utils/hooks/index.js +2 -0
  117. package/build/src/utils/hooks/useBoolean.d.ts +11 -0
  118. package/build/src/utils/hooks/useBoolean.js +11 -0
  119. package/build/src/utils/hooks/useDebounced.d.ts +8 -0
  120. package/build/src/utils/hooks/useDebounced.js +28 -0
  121. package/build/src/utils/hooks/useDebouncedHandler.d.ts +12 -0
  122. package/build/src/utils/hooks/useDebouncedHandler.js +41 -0
  123. package/build/src/utils/hooks/useLatest.d.ts +6 -0
  124. package/build/src/utils/hooks/useLatest.js +9 -0
  125. package/build/src/utils/hooks/usePageTitle.d.ts +4 -0
  126. package/build/src/utils/hooks/usePageTitle.js +13 -0
  127. package/build/src/utils/hooks/useSsr.d.ts +4 -0
  128. package/build/src/utils/hooks/useSsr.js +16 -0
  129. package/build/src/utils/hooks/useStorageState.d.ts +10 -0
  130. package/build/src/utils/hooks/useStorageState.js +51 -0
  131. package/build/src/utils/warnOnce.d.ts +5 -0
  132. package/build/src/utils/warnOnce.js +11 -0
  133. package/build/vitest.setup.d.ts +1 -0
  134. package/build/vitest.setup.js +19 -0
  135. package/package.json +60 -0
  136. package/src/Account/Account.test.tsx +56 -0
  137. package/src/Account/Account.tsx +226 -0
  138. package/src/Account/AccountPopoverFooter.tsx +33 -0
  139. package/src/Account/AccountPopoverHeader.tsx +20 -0
  140. package/src/Account/AccountPreview.test.tsx +79 -0
  141. package/src/Account/AccountPreview.tsx +189 -0
  142. package/src/Account/SignInButton.tsx +38 -0
  143. package/src/Account/SignOutButton.tsx +44 -0
  144. package/src/Account/index.ts +6 -0
  145. package/src/AppProvider/AppProvider.test.tsx +25 -0
  146. package/src/AppProvider/AppProvider.tsx +116 -0
  147. package/src/AppProvider/AppProviderComponent.tsx +162 -0
  148. package/src/AppProvider/AppThemeProvider.tsx +177 -0
  149. package/src/AppProvider/index.ts +1 -0
  150. package/src/DashboardLayout/DashboardLayout.test.tsx +429 -0
  151. package/src/DashboardLayout/DashboardLayout.tsx +558 -0
  152. package/src/DashboardLayout/DashboardSidebarSubNavigation.tsx +301 -0
  153. package/src/DashboardLayout/ThemeSwitcher.tsx +81 -0
  154. package/src/DashboardLayout/ToolbarActions.tsx +11 -0
  155. package/src/DashboardLayout/index.ts +4 -0
  156. package/src/DashboardLayout/utils.ts +23 -0
  157. package/src/PageContainer/PageContainer.test.tsx +194 -0
  158. package/src/PageContainer/PageContainer.tsx +201 -0
  159. package/src/PageContainer/PageContainerToolbar.test.tsx +11 -0
  160. package/src/PageContainer/PageContainerToolbar.tsx +31 -0
  161. package/src/PageContainer/index.ts +2 -0
  162. package/src/index.ts +15 -0
  163. package/src/nextjs/AppProvider.test.tsx +48 -0
  164. package/src/nextjs/AppProvider.tsx +18 -0
  165. package/src/nextjs/AppProviderNextApp.tsx +37 -0
  166. package/src/nextjs/AppProviderNextPages.tsx +52 -0
  167. package/src/nextjs/index.tsx +1 -0
  168. package/src/persistence/codec.tsx +81 -0
  169. package/src/persistence/index.ts +1 -0
  170. package/src/persistence/useStorageState.test.tsx +101 -0
  171. package/src/persistence/useStorageState.tsx +244 -0
  172. package/src/react-router-dom/AppProvider.test.tsx +17 -0
  173. package/src/react-router-dom/AppProvider.tsx +40 -0
  174. package/src/react-router-dom/index.tsx +1 -0
  175. package/src/shared/Link.tsx +37 -0
  176. package/src/shared/branding.ts +7 -0
  177. package/src/shared/components.tsx +46 -0
  178. package/src/shared/context.ts +21 -0
  179. package/src/shared/locales/LocaleContext.tsx +44 -0
  180. package/src/shared/locales/en.tsx +9 -0
  181. package/src/shared/navigation.tsx +197 -0
  182. package/src/useActivePage/index.ts +1 -0
  183. package/src/useActivePage/useActivePage.ts +66 -0
  184. package/src/useLocalStorageState/index.ts +1 -0
  185. package/src/useLocalStorageState/useLocalStorageState.tsx +23 -0
  186. package/src/useSessionStorageState/index.tsx +1 -0
  187. package/src/useSessionStorageState/useSessionStorageState.tsx +23 -0
  188. package/src/utils/collections.ts +125 -0
  189. package/src/utils/describeConformance.ts +14 -0
  190. package/src/utils/events.ts +81 -0
  191. package/src/utils/hooks/index.ts +2 -0
  192. package/src/utils/hooks/useBoolean.ts +12 -0
  193. package/src/utils/hooks/useDebounced.ts +39 -0
  194. package/src/utils/hooks/useDebouncedHandler.ts +71 -0
  195. package/src/utils/hooks/useLatest.ts +16 -0
  196. package/src/utils/hooks/usePageTitle.ts +14 -0
  197. package/src/utils/hooks/useSsr.ts +24 -0
  198. package/src/utils/hooks/useStorageState.ts +130 -0
  199. package/src/utils/warnOnce.ts +12 -0
  200. package/tsconfig.json +19 -0
  201. package/vite.config.ts +27 -0
  202. 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 };