@etsoo/toolpad 1.0.9 → 1.0.11
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/build/Account/Account.d.ts +0 -3
- package/build/Account/Account.js +0 -41
- package/build/Account/AccountPreview.d.ts +0 -3
- package/build/Account/AccountPreview.js +0 -37
- package/build/AppProvider/AppProvider.d.ts +2 -1
- package/build/AppProvider/AppProviderComponent.d.ts +0 -3
- package/build/AppProvider/AppProviderComponent.js +0 -90
- package/build/DashboardLayout/DashboardLayout.d.ts +0 -3
- package/build/DashboardLayout/DashboardLayout.js +0 -82
- package/build/DashboardLayout/DashboardSidebarSubNavigation.js +4 -6
- package/build/DashboardLayout/TitleBar.js +5 -2
- package/build/PageContainer/PageContainer.d.ts +11 -16
- package/build/PageContainer/PageContainer.js +43 -40
- package/build/PageContainer/PageContainer.test.js +40 -30
- package/build/shared/navigation.js +15 -7
- package/build/useActivePage/useActivePage.d.ts +1 -4
- package/build/useActivePage/useActivePage.js +2 -3
- package/package.json +1 -3
- package/src/Account/Account.tsx +0 -42
- package/src/Account/AccountPreview.tsx +0 -38
- package/src/AppProvider/AppProvider.tsx +1 -1
- package/src/AppProvider/AppProviderComponent.tsx +0 -95
- package/src/DashboardLayout/DashboardLayout.tsx +0 -87
- package/src/DashboardLayout/DashboardSidebarSubNavigation.tsx +4 -15
- package/src/DashboardLayout/TitleBar.tsx +12 -10
- package/src/PageContainer/PageContainer.test.tsx +88 -59
- package/src/PageContainer/PageContainer.tsx +73 -65
- package/src/shared/navigation.tsx +15 -8
- package/src/useActivePage/useActivePage.ts +3 -7
|
@@ -60,7 +60,4 @@ export interface AccountProps {
|
|
|
60
60
|
* - [Account API](https://mui.com/toolpad/core/api/account)
|
|
61
61
|
*/
|
|
62
62
|
declare function Account(props: AccountProps): import("react/jsx-runtime").JSX.Element | null;
|
|
63
|
-
declare namespace Account {
|
|
64
|
-
var propTypes: any;
|
|
65
|
-
}
|
|
66
63
|
export { Account };
|
package/build/Account/Account.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
3
|
import Popover from "@mui/material/Popover";
|
|
5
4
|
import Divider from "@mui/material/Divider";
|
|
6
5
|
import Stack from "@mui/material/Stack";
|
|
@@ -64,44 +63,4 @@ function Account(props) {
|
|
|
64
63
|
...slotProps?.popover?.slotProps
|
|
65
64
|
}, children: slots?.popoverContent ? (_jsx(slots.popoverContent, { ...slotProps?.popoverContent })) : (_jsxs(Stack, { direction: "column", ...slotProps?.popoverContent, children: [_jsx(AccountPopoverHeader, { children: _jsx(AccountPreview, { variant: "expanded" }) }), _jsx(Divider, {}), _jsx(AccountPopoverFooter, { children: _jsx(SignOutButton, { ...slotProps?.signOutButton }) })] })) }))] }));
|
|
66
65
|
}
|
|
67
|
-
Account.propTypes /* remove-proptypes */ = {
|
|
68
|
-
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
69
|
-
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
70
|
-
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
71
|
-
// └─────────────────────────────────────────────────────────────────────┘
|
|
72
|
-
/**
|
|
73
|
-
* The props used for each slot inside.
|
|
74
|
-
*/
|
|
75
|
-
slotProps: PropTypes.shape({
|
|
76
|
-
popover: PropTypes.object,
|
|
77
|
-
popoverContent: PropTypes.object,
|
|
78
|
-
preview: PropTypes.shape({
|
|
79
|
-
handleClick: PropTypes.func,
|
|
80
|
-
open: PropTypes.bool,
|
|
81
|
-
slotProps: PropTypes.shape({
|
|
82
|
-
avatar: PropTypes.object,
|
|
83
|
-
avatarIconButton: PropTypes.object,
|
|
84
|
-
moreIconButton: PropTypes.object
|
|
85
|
-
}),
|
|
86
|
-
slots: PropTypes.shape({
|
|
87
|
-
avatar: PropTypes.elementType,
|
|
88
|
-
avatarIconButton: PropTypes.elementType,
|
|
89
|
-
moreIconButton: PropTypes.elementType
|
|
90
|
-
}),
|
|
91
|
-
variant: PropTypes.oneOf(["condensed", "expanded"])
|
|
92
|
-
}),
|
|
93
|
-
signInButton: PropTypes.object,
|
|
94
|
-
signOutButton: PropTypes.object
|
|
95
|
-
}),
|
|
96
|
-
/**
|
|
97
|
-
* The components used for each slot inside.
|
|
98
|
-
*/
|
|
99
|
-
slots: PropTypes.shape({
|
|
100
|
-
popover: PropTypes.elementType,
|
|
101
|
-
popoverContent: PropTypes.elementType,
|
|
102
|
-
preview: PropTypes.elementType,
|
|
103
|
-
signInButton: PropTypes.elementType,
|
|
104
|
-
signOutButton: PropTypes.elementType
|
|
105
|
-
})
|
|
106
|
-
};
|
|
107
66
|
export { Account };
|
|
@@ -61,7 +61,4 @@ export interface AccountPreviewProps {
|
|
|
61
61
|
* - [AccountPreview API](https://mui.com/toolpad/core/api/account-preview)
|
|
62
62
|
*/
|
|
63
63
|
declare function AccountPreview(props: AccountPreviewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
64
|
-
declare namespace AccountPreview {
|
|
65
|
-
var propTypes: any;
|
|
66
|
-
}
|
|
67
64
|
export { AccountPreview };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
3
|
import Avatar from "@mui/material/Avatar";
|
|
5
4
|
import Typography from "@mui/material/Typography";
|
|
6
5
|
import Tooltip from "@mui/material/Tooltip";
|
|
@@ -56,40 +55,4 @@ function AccountPreview(props) {
|
|
|
56
55
|
}
|
|
57
56
|
return (_jsx(Tooltip, { title: session.user.name ?? "Account", children: slots?.avatarIconButton ? (_jsx(slots.avatarIconButton, {})) : (_jsx(IconButton, { onClick: handleClick, "aria-label": localeText.accountIconButtonAriaLabel, size: "small", "aria-controls": open ? "account-menu" : undefined, "aria-haspopup": "true", "aria-expanded": open ? "true" : undefined, ...slotProps?.avatarIconButton, children: avatarContent })) }));
|
|
58
57
|
}
|
|
59
|
-
AccountPreview.propTypes /* remove-proptypes */ = {
|
|
60
|
-
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
61
|
-
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
62
|
-
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
63
|
-
// └─────────────────────────────────────────────────────────────────────┘
|
|
64
|
-
/**
|
|
65
|
-
* The handler used when the preview is expanded
|
|
66
|
-
*/
|
|
67
|
-
handleClick: PropTypes.func,
|
|
68
|
-
/**
|
|
69
|
-
* The state of the Account popover
|
|
70
|
-
* @default false
|
|
71
|
-
*/
|
|
72
|
-
open: PropTypes.bool,
|
|
73
|
-
/**
|
|
74
|
-
* The props used for each slot inside.
|
|
75
|
-
*/
|
|
76
|
-
slotProps: PropTypes.shape({
|
|
77
|
-
avatar: PropTypes.object,
|
|
78
|
-
avatarIconButton: PropTypes.object,
|
|
79
|
-
moreIconButton: PropTypes.object
|
|
80
|
-
}),
|
|
81
|
-
/**
|
|
82
|
-
* The components used for each slot inside.
|
|
83
|
-
*/
|
|
84
|
-
slots: PropTypes.shape({
|
|
85
|
-
avatar: PropTypes.elementType
|
|
86
|
-
}),
|
|
87
|
-
/**
|
|
88
|
-
* The type of account details to display.
|
|
89
|
-
* @property {'condensed'} condensed - Shows only the user's avatar.
|
|
90
|
-
* @property {'expanded'} expanded - Displays the user's avatar, name, and email if available.
|
|
91
|
-
* @default 'condensed'
|
|
92
|
-
*/
|
|
93
|
-
variant: PropTypes.oneOf(["condensed", "expanded"])
|
|
94
|
-
};
|
|
95
58
|
export { AccountPreview };
|
|
@@ -16,7 +16,7 @@ export interface Router {
|
|
|
16
16
|
navigate: Navigate;
|
|
17
17
|
}
|
|
18
18
|
export interface Branding {
|
|
19
|
-
title?:
|
|
19
|
+
title?: React.ReactNode | [string, (handler: React.MouseEvent<HTMLSpanElement>) => void];
|
|
20
20
|
logo?: React.ReactNode;
|
|
21
21
|
}
|
|
22
22
|
export interface NavigationPageItem {
|
|
@@ -27,6 +27,7 @@ export interface NavigationPageItem {
|
|
|
27
27
|
pattern?: string;
|
|
28
28
|
action?: React.ReactNode;
|
|
29
29
|
children?: Navigation;
|
|
30
|
+
subs?: string[];
|
|
30
31
|
}
|
|
31
32
|
export interface NavigationSubheaderItem {
|
|
32
33
|
kind: "header";
|
|
@@ -11,7 +11,4 @@ import { AppProviderProps } from "./AppProvider";
|
|
|
11
11
|
* - [AppProvider API](https://mui.com/toolpad/core/api/app-provider)
|
|
12
12
|
*/
|
|
13
13
|
declare function AppProvider(props: AppProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
-
declare namespace AppProvider {
|
|
15
|
-
var propTypes: any;
|
|
16
|
-
}
|
|
17
14
|
export { AppProvider };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
3
|
import { BrandingContext, NavigationContext, RouterContext, WindowContext } from "../shared/context";
|
|
5
4
|
import { AppThemeProvider } from "./AppThemeProvider";
|
|
6
5
|
import { createTheme as createMuiTheme } from "@mui/material/styles";
|
|
@@ -29,93 +28,4 @@ function AppProvider(props) {
|
|
|
29
28
|
const { children, theme = createTheme(), branding = null, localeText, navigation = [], router = null, authentication = null, session = null, window: appWindow } = props;
|
|
30
29
|
return (_jsx(WindowContext.Provider, { value: appWindow, children: _jsx(AuthenticationContext.Provider, { value: authentication, children: _jsx(SessionContext.Provider, { value: session, children: _jsx(RouterContext.Provider, { value: router, children: _jsx(AppThemeProvider, { theme: theme, window: appWindow, children: _jsx(LocaleProvider, { localeText: localeText, children: _jsx(BrandingContext.Provider, { value: branding, children: _jsx(NavigationContext.Provider, { value: navigation, children: children }) }) }) }) }) }) }) }));
|
|
31
30
|
}
|
|
32
|
-
AppProvider.propTypes /* remove-proptypes */ = {
|
|
33
|
-
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
34
|
-
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
35
|
-
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
36
|
-
// └─────────────────────────────────────────────────────────────────────┘
|
|
37
|
-
/**
|
|
38
|
-
* Authentication methods.
|
|
39
|
-
* @default null
|
|
40
|
-
*/
|
|
41
|
-
authentication: PropTypes.shape({
|
|
42
|
-
signIn: PropTypes.func.isRequired,
|
|
43
|
-
signOut: PropTypes.func.isRequired
|
|
44
|
-
}),
|
|
45
|
-
/**
|
|
46
|
-
* Branding options for the app.
|
|
47
|
-
* @default null
|
|
48
|
-
*/
|
|
49
|
-
branding: PropTypes.shape({
|
|
50
|
-
logo: PropTypes.node,
|
|
51
|
-
title: PropTypes.node
|
|
52
|
-
}),
|
|
53
|
-
/**
|
|
54
|
-
* The content of the app provider.
|
|
55
|
-
*/
|
|
56
|
-
children: PropTypes.node,
|
|
57
|
-
/**
|
|
58
|
-
* Navigation definition for the app.
|
|
59
|
-
* @default []
|
|
60
|
-
*/
|
|
61
|
-
navigation: PropTypes.arrayOf(PropTypes.oneOfType([
|
|
62
|
-
PropTypes.shape({
|
|
63
|
-
action: PropTypes.node,
|
|
64
|
-
children: PropTypes.arrayOf(PropTypes.oneOfType([
|
|
65
|
-
PropTypes.object,
|
|
66
|
-
PropTypes.shape({
|
|
67
|
-
kind: PropTypes.oneOf(["header"]).isRequired,
|
|
68
|
-
title: PropTypes.string.isRequired
|
|
69
|
-
}),
|
|
70
|
-
PropTypes.shape({
|
|
71
|
-
kind: PropTypes.oneOf(["divider"]).isRequired
|
|
72
|
-
})
|
|
73
|
-
]).isRequired),
|
|
74
|
-
icon: PropTypes.node,
|
|
75
|
-
kind: PropTypes.oneOf(["page"]),
|
|
76
|
-
pattern: PropTypes.string,
|
|
77
|
-
segment: PropTypes.string,
|
|
78
|
-
title: PropTypes.string
|
|
79
|
-
}),
|
|
80
|
-
PropTypes.shape({
|
|
81
|
-
kind: PropTypes.oneOf(["header"]).isRequired,
|
|
82
|
-
title: PropTypes.string.isRequired
|
|
83
|
-
}),
|
|
84
|
-
PropTypes.shape({
|
|
85
|
-
kind: PropTypes.oneOf(["divider"]).isRequired
|
|
86
|
-
})
|
|
87
|
-
]).isRequired),
|
|
88
|
-
/**
|
|
89
|
-
* Router implementation used inside Toolpad components.
|
|
90
|
-
* @default null
|
|
91
|
-
*/
|
|
92
|
-
router: PropTypes.shape({
|
|
93
|
-
navigate: PropTypes.func.isRequired,
|
|
94
|
-
pathname: PropTypes.string.isRequired,
|
|
95
|
-
searchParams: PropTypes.instanceOf(URLSearchParams).isRequired
|
|
96
|
-
}),
|
|
97
|
-
/**
|
|
98
|
-
* Session info about the current user.
|
|
99
|
-
* @default null
|
|
100
|
-
*/
|
|
101
|
-
session: PropTypes.shape({
|
|
102
|
-
user: PropTypes.shape({
|
|
103
|
-
email: PropTypes.string,
|
|
104
|
-
id: PropTypes.string,
|
|
105
|
-
image: PropTypes.string,
|
|
106
|
-
name: PropTypes.string
|
|
107
|
-
})
|
|
108
|
-
}),
|
|
109
|
-
/**
|
|
110
|
-
* [Theme or themes](https://mui.com/toolpad/core/react-app-provider/#theming) to be used by the app in light/dark mode. A [CSS variables theme](https://mui.com/material-ui/customization/css-theme-variables/overview/) is recommended.
|
|
111
|
-
* @default createTheme()
|
|
112
|
-
*/
|
|
113
|
-
theme: PropTypes.object,
|
|
114
|
-
/**
|
|
115
|
-
* The window where the application is rendered.
|
|
116
|
-
* This is needed when rendering the app inside an iframe, for example.
|
|
117
|
-
* @default window
|
|
118
|
-
*/
|
|
119
|
-
window: PropTypes.object
|
|
120
|
-
};
|
|
121
31
|
export { AppProvider };
|
|
@@ -88,7 +88,4 @@ export interface DashboardLayoutProps {
|
|
|
88
88
|
* - [DashboardLayout API](https://mui.com/toolpad/core/api/dashboard-layout)
|
|
89
89
|
*/
|
|
90
90
|
declare function DashboardLayout(props: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
91
|
-
declare namespace DashboardLayout {
|
|
92
|
-
var propTypes: any;
|
|
93
|
-
}
|
|
94
91
|
export { DashboardLayout };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import PropTypes from "prop-types";
|
|
5
4
|
import { styled, useTheme } from "@mui/material";
|
|
6
5
|
import MuiAppBar from "@mui/material/AppBar";
|
|
7
6
|
import Box from "@mui/material/Box";
|
|
@@ -191,85 +190,4 @@ function DashboardLayout(props) {
|
|
|
191
190
|
overflow: "auto"
|
|
192
191
|
}, children: children })] })] }));
|
|
193
192
|
}
|
|
194
|
-
DashboardLayout.propTypes /* remove-proptypes */ = {
|
|
195
|
-
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
196
|
-
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
197
|
-
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
198
|
-
// └─────────────────────────────────────────────────────────────────────┘
|
|
199
|
-
/**
|
|
200
|
-
* The content of the dashboard.
|
|
201
|
-
*/
|
|
202
|
-
children: PropTypes.node,
|
|
203
|
-
/**
|
|
204
|
-
* Whether the sidebar should start collapsed in desktop size screens.
|
|
205
|
-
* @default false
|
|
206
|
-
*/
|
|
207
|
-
defaultSidebarCollapsed: PropTypes.bool,
|
|
208
|
-
/**
|
|
209
|
-
* Whether the sidebar should not be collapsible to a mini variant in desktop and tablet viewports.
|
|
210
|
-
* @default false
|
|
211
|
-
*/
|
|
212
|
-
disableCollapsibleSidebar: PropTypes.bool,
|
|
213
|
-
/**
|
|
214
|
-
* Whether the navigation bar and menu icon should be hidden
|
|
215
|
-
* @default false
|
|
216
|
-
*/
|
|
217
|
-
hideNavigation: PropTypes.bool,
|
|
218
|
-
/**
|
|
219
|
-
* Width of the sidebar when expanded.
|
|
220
|
-
* @default 320
|
|
221
|
-
*/
|
|
222
|
-
sidebarExpandedWidth: PropTypes.oneOfType([
|
|
223
|
-
PropTypes.number,
|
|
224
|
-
PropTypes.string
|
|
225
|
-
]),
|
|
226
|
-
/**
|
|
227
|
-
* The props used for each slot inside.
|
|
228
|
-
* @default {}
|
|
229
|
-
*/
|
|
230
|
-
slotProps: PropTypes.shape({
|
|
231
|
-
sidebarFooter: PropTypes.shape({
|
|
232
|
-
mini: PropTypes.bool.isRequired
|
|
233
|
-
}),
|
|
234
|
-
toolbarAccount: PropTypes.shape({
|
|
235
|
-
localeText: PropTypes.shape({
|
|
236
|
-
iconButtonAriaLabel: PropTypes.string,
|
|
237
|
-
signInLabel: PropTypes.string,
|
|
238
|
-
signOutLabel: PropTypes.string
|
|
239
|
-
}),
|
|
240
|
-
slotProps: PropTypes.shape({
|
|
241
|
-
popover: PropTypes.object,
|
|
242
|
-
popoverContent: PropTypes.object,
|
|
243
|
-
preview: PropTypes.object,
|
|
244
|
-
signInButton: PropTypes.object,
|
|
245
|
-
signOutButton: PropTypes.object
|
|
246
|
-
}),
|
|
247
|
-
slots: PropTypes.shape({
|
|
248
|
-
popover: PropTypes.elementType,
|
|
249
|
-
popoverContent: PropTypes.elementType,
|
|
250
|
-
preview: PropTypes.elementType,
|
|
251
|
-
signInButton: PropTypes.elementType,
|
|
252
|
-
signOutButton: PropTypes.elementType
|
|
253
|
-
})
|
|
254
|
-
}),
|
|
255
|
-
toolbarActions: PropTypes.object
|
|
256
|
-
}),
|
|
257
|
-
/**
|
|
258
|
-
* The components used for each slot inside.
|
|
259
|
-
* @default {}
|
|
260
|
-
*/
|
|
261
|
-
slots: PropTypes.shape({
|
|
262
|
-
sidebarFooter: PropTypes.elementType,
|
|
263
|
-
toolbarAccount: PropTypes.elementType,
|
|
264
|
-
toolbarActions: PropTypes.elementType
|
|
265
|
-
}),
|
|
266
|
-
/**
|
|
267
|
-
* The system prop that allows defining system overrides as well as additional CSS styles.
|
|
268
|
-
*/
|
|
269
|
-
sx: PropTypes.oneOfType([
|
|
270
|
-
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])),
|
|
271
|
-
PropTypes.func,
|
|
272
|
-
PropTypes.object
|
|
273
|
-
])
|
|
274
|
-
};
|
|
275
193
|
export { DashboardLayout };
|
|
@@ -97,12 +97,10 @@ function DashboardSidebarSubNavigation({ subNavigation, basePath = "", depth = 0
|
|
|
97
97
|
const isNestedNavigationExpanded = expandedSidebarItemIds.includes(navigationItemId);
|
|
98
98
|
const nestedNavigationCollapseIcon = isNestedNavigationExpanded ? (_jsx(ExpandLessIcon, {})) : (_jsx(ExpandMoreIcon, {}));
|
|
99
99
|
const listItemIconSize = 34;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
console.warn(`Duplicate selected path in navigation: ${navigationItemFullPath}`);
|
|
105
|
-
}
|
|
100
|
+
// If the item is selected, we don't want to select more
|
|
101
|
+
const isSelected = selectedItemId
|
|
102
|
+
? false
|
|
103
|
+
: isPageItemSelected(navigationItem, basePath, pathname);
|
|
106
104
|
if (isSelected && !selectedItemId) {
|
|
107
105
|
selectedItemId = navigationItemId;
|
|
108
106
|
}
|
|
@@ -42,7 +42,10 @@ export function TitleBar() {
|
|
|
42
42
|
}
|
|
43
43
|
return [title, false];
|
|
44
44
|
}, [title]);
|
|
45
|
-
if (
|
|
45
|
+
if (hasLink) {
|
|
46
|
+
return (_jsx(Link, { href: "/", style: { color: "inherit", textDecoration: "none" }, children: _jsxs(Stack, { direction: "row", alignItems: "center", children: [branding?.logo && _jsx(LogoContainer, { children: branding.logo }), titleUI] }) }));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
46
49
|
return titleUI;
|
|
47
|
-
|
|
50
|
+
}
|
|
48
51
|
}
|
|
@@ -21,20 +21,18 @@ export interface Breadcrumb {
|
|
|
21
21
|
*/
|
|
22
22
|
path: string;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
* @deprecated Use `Breadcrumb` instead.
|
|
26
|
-
*/
|
|
27
|
-
export type BreadCrumb = Breadcrumb;
|
|
28
|
-
export interface PageContainerProps extends ContainerProps {
|
|
29
|
-
children?: React.ReactNode;
|
|
30
|
-
/**
|
|
31
|
-
* The title of the page. Leave blank to use the active page title.
|
|
32
|
-
*/
|
|
24
|
+
export type PageData = {
|
|
33
25
|
title?: string;
|
|
34
|
-
|
|
35
|
-
* The breadcrumbs of the page. Leave blank to use the active page breadcrumbs.
|
|
36
|
-
*/
|
|
26
|
+
page?: string;
|
|
37
27
|
breadcrumbs?: Breadcrumb[];
|
|
28
|
+
};
|
|
29
|
+
type PageDataAction = PageData | true;
|
|
30
|
+
export declare const PageDataContext: React.Context<{
|
|
31
|
+
state: PageData;
|
|
32
|
+
dispatch: React.Dispatch<PageDataAction>;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function PageDataContextProvider(props: React.PropsWithChildren<PageData>): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export type PageContainerProps = React.PropsWithChildren<ContainerProps & {
|
|
38
36
|
/**
|
|
39
37
|
* The components used for each slot inside.
|
|
40
38
|
*/
|
|
@@ -43,7 +41,7 @@ export interface PageContainerProps extends ContainerProps {
|
|
|
43
41
|
* The props used for each slot inside.
|
|
44
42
|
*/
|
|
45
43
|
slotProps?: PageContainerSlotProps;
|
|
46
|
-
}
|
|
44
|
+
}>;
|
|
47
45
|
/**
|
|
48
46
|
* A container component to provide a title and breadcrumbs for your pages.
|
|
49
47
|
*
|
|
@@ -56,7 +54,4 @@ export interface PageContainerProps extends ContainerProps {
|
|
|
56
54
|
* - [PageContainer API](https://mui.com/toolpad/core/api/page-container)
|
|
57
55
|
*/
|
|
58
56
|
declare function PageContainer(props: PageContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
59
|
-
declare namespace PageContainer {
|
|
60
|
-
var propTypes: any;
|
|
61
|
-
}
|
|
62
57
|
export { PageContainer };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
3
|
+
import * as React from "react";
|
|
4
4
|
import Breadcrumbs from "@mui/material/Breadcrumbs";
|
|
5
5
|
import Container from "@mui/material/Container";
|
|
6
6
|
import Link from "@mui/material/Link";
|
|
@@ -18,6 +18,29 @@ const PageContentHeader = styled("div")(({ theme }) => ({
|
|
|
18
18
|
justifyContent: "space-between",
|
|
19
19
|
gap: theme.spacing(2)
|
|
20
20
|
}));
|
|
21
|
+
export const PageDataContext = React.createContext({ state: {}, dispatch: (value) => value });
|
|
22
|
+
function reducer(state, action) {
|
|
23
|
+
if (action === true) {
|
|
24
|
+
// Reset the state
|
|
25
|
+
if (state.breadcrumbs == null &&
|
|
26
|
+
state.title == null &&
|
|
27
|
+
state.page == null) {
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { ...state, ...action };
|
|
35
|
+
}
|
|
36
|
+
export function PageDataContextProvider(props) {
|
|
37
|
+
// Destruct
|
|
38
|
+
const { title, breadcrumbs, ...rest } = props;
|
|
39
|
+
// useReducer hook to manage state with our reducer function and initial state
|
|
40
|
+
const [state, dispatch] = React.useReducer(reducer, { title, breadcrumbs });
|
|
41
|
+
// Provide the state and dispatch function to the context value
|
|
42
|
+
return _jsx(PageDataContext.Provider, { value: { state, dispatch }, ...rest });
|
|
43
|
+
}
|
|
21
44
|
/**
|
|
22
45
|
* A container component to provide a title and breadcrumbs for your pages.
|
|
23
46
|
*
|
|
@@ -30,11 +53,26 @@ const PageContentHeader = styled("div")(({ theme }) => ({
|
|
|
30
53
|
* - [PageContainer API](https://mui.com/toolpad/core/api/page-container)
|
|
31
54
|
*/
|
|
32
55
|
function PageContainer(props) {
|
|
33
|
-
const { children, slots, slotProps,
|
|
56
|
+
const { children, slots, slotProps, ...rest } = props;
|
|
57
|
+
const loaded = React.useRef(false);
|
|
58
|
+
const { state, dispatch } = React.useContext(PageDataContext);
|
|
34
59
|
const activePage = useActivePage();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
60
|
+
React.useLayoutEffect(() => {
|
|
61
|
+
if (loaded.current) {
|
|
62
|
+
dispatch(true);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
loaded.current = true;
|
|
66
|
+
}
|
|
67
|
+
}, [activePage?.sourcePath]);
|
|
68
|
+
let resolvedBreadcrumbs = state.breadcrumbs ?? activePage?.breadcrumbs ?? [];
|
|
69
|
+
const title = state.title ?? activePage?.title ?? "";
|
|
70
|
+
if (state.page) {
|
|
71
|
+
resolvedBreadcrumbs = [
|
|
72
|
+
...resolvedBreadcrumbs,
|
|
73
|
+
{ title: state.page, path: "#" }
|
|
74
|
+
];
|
|
75
|
+
}
|
|
38
76
|
const ToolbarComponent = props?.slots?.toolbar ?? PageContainerToolbar;
|
|
39
77
|
const toolbarSlotProps = useSlotProps({
|
|
40
78
|
elementType: ToolbarComponent,
|
|
@@ -48,39 +86,4 @@ function PageContainer(props) {
|
|
|
48
86
|
})
|
|
49
87
|
: null }), _jsxs(PageContentHeader, { children: [title ? _jsx(Typography, { variant: "h4", children: title }) : null, _jsx(ToolbarComponent, { ...toolbarSlotProps })] })] }), _jsx("div", { children: children })] }) }));
|
|
50
88
|
}
|
|
51
|
-
PageContainer.propTypes /* remove-proptypes */ = {
|
|
52
|
-
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
53
|
-
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
54
|
-
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
55
|
-
// └─────────────────────────────────────────────────────────────────────┘
|
|
56
|
-
/**
|
|
57
|
-
* The breadcrumbs of the page. Leave blank to use the active page breadcrumbs.
|
|
58
|
-
*/
|
|
59
|
-
breadcrumbs: PropTypes.arrayOf(PropTypes.shape({
|
|
60
|
-
path: PropTypes.string.isRequired,
|
|
61
|
-
title: PropTypes.string.isRequired
|
|
62
|
-
})),
|
|
63
|
-
/**
|
|
64
|
-
* @ignore
|
|
65
|
-
*/
|
|
66
|
-
children: PropTypes.node,
|
|
67
|
-
/**
|
|
68
|
-
* The props used for each slot inside.
|
|
69
|
-
*/
|
|
70
|
-
slotProps: PropTypes.shape({
|
|
71
|
-
toolbar: PropTypes.shape({
|
|
72
|
-
children: PropTypes.node
|
|
73
|
-
}).isRequired
|
|
74
|
-
}),
|
|
75
|
-
/**
|
|
76
|
-
* The components used for each slot inside.
|
|
77
|
-
*/
|
|
78
|
-
slots: PropTypes.shape({
|
|
79
|
-
toolbar: PropTypes.elementType
|
|
80
|
-
}),
|
|
81
|
-
/**
|
|
82
|
-
* The title of the page. Leave blank to use the active page title.
|
|
83
|
-
*/
|
|
84
|
-
title: PropTypes.string
|
|
85
|
-
};
|
|
86
89
|
export { PageContainer };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { expect, describe, test, vi } from "vitest";
|
|
3
|
-
import { render, within, screen } from "@testing-library/react";
|
|
3
|
+
import { render, within, screen, act } from "@testing-library/react";
|
|
4
4
|
import { userEvent } from "@testing-library/user-event";
|
|
5
|
-
import { PageContainer } from "./PageContainer";
|
|
5
|
+
import { PageContainer, PageDataContextProvider } from "./PageContainer";
|
|
6
6
|
import describeConformance from "../utils/describeConformance";
|
|
7
7
|
import { AppProvider } from "../AppProvider/AppProviderComponent";
|
|
8
8
|
describe("PageContainer", () => {
|
|
@@ -13,16 +13,18 @@ describe("PageContainer", () => {
|
|
|
13
13
|
}
|
|
14
14
|
}));
|
|
15
15
|
test("renders page container correctly", async () => {
|
|
16
|
-
const user =
|
|
16
|
+
const user = userEvent.setup();
|
|
17
17
|
const router = {
|
|
18
18
|
pathname: "/orders",
|
|
19
19
|
searchParams: new URLSearchParams(),
|
|
20
20
|
navigate: vi.fn()
|
|
21
21
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
act(() => {
|
|
23
|
+
render(_jsx(AppProvider, { navigation: [
|
|
24
|
+
{ segment: "", title: "Home" },
|
|
25
|
+
{ segment: "orders", title: "Orders" }
|
|
26
|
+
], router: router, children: _jsx(PageDataContextProvider, { children: _jsx(PageContainer, {}) }) }));
|
|
27
|
+
});
|
|
26
28
|
const breadcrumbs = screen.getByRole("navigation", { name: "breadcrumb" });
|
|
27
29
|
const homeLink = within(breadcrumbs).getByRole("link", { name: "Home" });
|
|
28
30
|
await user.click(homeLink);
|
|
@@ -51,23 +53,27 @@ describe("PageContainer", () => {
|
|
|
51
53
|
navigate: vi.fn()
|
|
52
54
|
};
|
|
53
55
|
const branding = { title: "ACME" };
|
|
54
|
-
|
|
56
|
+
act(() => {
|
|
57
|
+
render(_jsx(AppProvider, { branding: branding, navigation: navigation, router: router, children: _jsx(PageDataContextProvider, { children: _jsx(PageContainer, {}) }) }));
|
|
58
|
+
});
|
|
55
59
|
const breadcrumbs = screen.getByRole("navigation", { name: "breadcrumb" });
|
|
56
60
|
expect(within(breadcrumbs).getByText("ACME")).toBeTruthy();
|
|
57
61
|
expect(within(breadcrumbs).getByText("Home")).toBeTruthy();
|
|
58
62
|
expect(within(breadcrumbs).getByText("Orders")).toBeTruthy();
|
|
59
63
|
});
|
|
60
64
|
test("renders dynamic correctly", async () => {
|
|
61
|
-
const user =
|
|
65
|
+
const user = userEvent.setup();
|
|
62
66
|
const router = {
|
|
63
67
|
pathname: "/orders/123",
|
|
64
68
|
searchParams: new URLSearchParams(),
|
|
65
69
|
navigate: vi.fn()
|
|
66
70
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
act(() => {
|
|
72
|
+
render(_jsx(AppProvider, { navigation: [
|
|
73
|
+
{ segment: "", title: "Home" },
|
|
74
|
+
{ segment: "orders", title: "Orders", pattern: "orders/:id" }
|
|
75
|
+
], router: router, children: _jsx(PageDataContextProvider, { children: _jsx(PageContainer, {}) }) }));
|
|
76
|
+
});
|
|
71
77
|
const breadcrumbs = screen.getByRole("navigation", { name: "breadcrumb" });
|
|
72
78
|
const homeLink = within(breadcrumbs).getByRole("link", { name: "Home" });
|
|
73
79
|
await user.click(homeLink);
|
|
@@ -82,29 +88,33 @@ describe("PageContainer", () => {
|
|
|
82
88
|
searchParams: new URLSearchParams(),
|
|
83
89
|
navigate: vi.fn()
|
|
84
90
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
act(() => {
|
|
92
|
+
render(_jsx(AppProvider, { navigation: [
|
|
93
|
+
{
|
|
94
|
+
segment: "users",
|
|
95
|
+
title: "Users",
|
|
96
|
+
children: [
|
|
97
|
+
{
|
|
98
|
+
segment: "invoices",
|
|
99
|
+
title: "Invoices",
|
|
100
|
+
pattern: "invoices/:id"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
], router: router, children: _jsx(PageDataContextProvider, { children: _jsx(PageContainer, {}) }) }));
|
|
105
|
+
});
|
|
98
106
|
const breadcrumbs = screen.getByRole("navigation", { name: "breadcrumb" });
|
|
99
107
|
const homeLink = within(breadcrumbs).getByRole("link", { name: "Users" });
|
|
100
108
|
expect(homeLink.getAttribute("href")).toBe("/users");
|
|
101
109
|
expect(within(breadcrumbs).getByText("Invoices")).toBeTruthy();
|
|
102
110
|
});
|
|
103
111
|
test("renders custom breadcrumbs", async () => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
act(() => {
|
|
113
|
+
render(_jsx(PageDataContextProvider, { breadcrumbs: [
|
|
114
|
+
{ title: "Hello", path: "/hello" },
|
|
115
|
+
{ title: "World", path: "/world" }
|
|
116
|
+
], children: _jsx(PageContainer, {}) }));
|
|
117
|
+
});
|
|
108
118
|
const breadcrumbs = screen.getByRole("navigation", { name: "breadcrumb" });
|
|
109
119
|
const helloLink = within(breadcrumbs).getByRole("link", { name: "Hello" });
|
|
110
120
|
expect(helloLink.getAttribute("href")).toBe("/hello");
|