@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,189 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import Avatar, { AvatarProps } from "@mui/material/Avatar";
|
|
4
|
+
import Typography from "@mui/material/Typography";
|
|
5
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
6
|
+
import Stack from "@mui/material/Stack";
|
|
7
|
+
import IconButton, { IconButtonProps } from "@mui/material/IconButton";
|
|
8
|
+
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
|
9
|
+
import { SessionContext } from "../AppProvider";
|
|
10
|
+
import { useLocaleText } from "../shared/locales/LocaleContext";
|
|
11
|
+
|
|
12
|
+
export type AccountPreviewVariant = "condensed" | "expanded";
|
|
13
|
+
|
|
14
|
+
export interface AccountPreviewSlots {
|
|
15
|
+
/**
|
|
16
|
+
* The component used for the Avatar
|
|
17
|
+
* @default Avatar
|
|
18
|
+
*/
|
|
19
|
+
avatar?: React.ElementType;
|
|
20
|
+
/**
|
|
21
|
+
* The component used for the overflow icon button in the expanded variant
|
|
22
|
+
* @default IconButton
|
|
23
|
+
*/
|
|
24
|
+
moreIconButton?: React.ElementType;
|
|
25
|
+
/**
|
|
26
|
+
* The component used for the avatar icon button in the condensed variant
|
|
27
|
+
* @default IconButton
|
|
28
|
+
*/
|
|
29
|
+
avatarIconButton?: React.ElementType;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AccountPreviewProps {
|
|
33
|
+
/**
|
|
34
|
+
* The components used for each slot inside.
|
|
35
|
+
*/
|
|
36
|
+
slots?: AccountPreviewSlots;
|
|
37
|
+
/**
|
|
38
|
+
* The props used for each slot inside.
|
|
39
|
+
*/
|
|
40
|
+
slotProps?: {
|
|
41
|
+
avatar?: AvatarProps;
|
|
42
|
+
moreIconButton?: IconButtonProps;
|
|
43
|
+
avatarIconButton?: IconButtonProps;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The type of account details to display.
|
|
47
|
+
* @property {'condensed'} condensed - Shows only the user's avatar.
|
|
48
|
+
* @property {'expanded'} expanded - Displays the user's avatar, name, and email if available.
|
|
49
|
+
* @default 'condensed'
|
|
50
|
+
*/
|
|
51
|
+
variant?: AccountPreviewVariant;
|
|
52
|
+
/**
|
|
53
|
+
* The handler used when the preview is expanded
|
|
54
|
+
*/
|
|
55
|
+
handleClick?: React.MouseEventHandler<HTMLElement>;
|
|
56
|
+
/**
|
|
57
|
+
* The state of the Account popover
|
|
58
|
+
* @default false
|
|
59
|
+
*/
|
|
60
|
+
open?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The AccountPreview component displays user account information.
|
|
65
|
+
*
|
|
66
|
+
* Demos:
|
|
67
|
+
*
|
|
68
|
+
* - [Account](https://mui.com/toolpad/core/react-account/)
|
|
69
|
+
*
|
|
70
|
+
* API:
|
|
71
|
+
*
|
|
72
|
+
* - [AccountPreview API](https://mui.com/toolpad/core/api/account-preview)
|
|
73
|
+
*/
|
|
74
|
+
function AccountPreview(props: AccountPreviewProps) {
|
|
75
|
+
const { slots, variant = "condensed", slotProps, open, handleClick } = props;
|
|
76
|
+
const session = React.useContext(SessionContext);
|
|
77
|
+
const localeText = useLocaleText();
|
|
78
|
+
|
|
79
|
+
if (!session || !session.user) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const avatarContent = slots?.avatar ? (
|
|
84
|
+
<slots.avatar />
|
|
85
|
+
) : (
|
|
86
|
+
<Avatar
|
|
87
|
+
src={session.user?.image || ""}
|
|
88
|
+
alt={session.user?.name || session.user?.email || ""}
|
|
89
|
+
sx={{
|
|
90
|
+
height: variant === "expanded" ? 48 : 32,
|
|
91
|
+
width: variant === "expanded" ? 48 : 32
|
|
92
|
+
}}
|
|
93
|
+
{...slotProps?.avatar}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (variant === "expanded") {
|
|
98
|
+
return (
|
|
99
|
+
<Stack
|
|
100
|
+
direction="row"
|
|
101
|
+
justifyContent="flex-start"
|
|
102
|
+
spacing={2}
|
|
103
|
+
padding={2}
|
|
104
|
+
>
|
|
105
|
+
{avatarContent}
|
|
106
|
+
<Stack direction="column" justifyContent="space-evenly">
|
|
107
|
+
<Typography variant="body2" fontWeight="bolder" noWrap>
|
|
108
|
+
{session.user?.name}
|
|
109
|
+
</Typography>
|
|
110
|
+
<Typography variant="caption" noWrap>
|
|
111
|
+
{session.user?.email}
|
|
112
|
+
</Typography>
|
|
113
|
+
</Stack>
|
|
114
|
+
{handleClick &&
|
|
115
|
+
(slots?.moreIconButton ? (
|
|
116
|
+
<slots.moreIconButton />
|
|
117
|
+
) : (
|
|
118
|
+
<IconButton
|
|
119
|
+
size="small"
|
|
120
|
+
onClick={handleClick}
|
|
121
|
+
{...slotProps?.moreIconButton}
|
|
122
|
+
sx={{ alignSelf: "flex-start", ...slotProps?.moreIconButton?.sx }}
|
|
123
|
+
>
|
|
124
|
+
<MoreVertIcon fontSize="small" />
|
|
125
|
+
</IconButton>
|
|
126
|
+
))}
|
|
127
|
+
</Stack>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<Tooltip title={session.user.name ?? "Account"}>
|
|
133
|
+
{slots?.avatarIconButton ? (
|
|
134
|
+
<slots.avatarIconButton />
|
|
135
|
+
) : (
|
|
136
|
+
<IconButton
|
|
137
|
+
onClick={handleClick}
|
|
138
|
+
aria-label={localeText.iconButtonAriaLabel || "Current User"}
|
|
139
|
+
size="small"
|
|
140
|
+
aria-controls={open ? "account-menu" : undefined}
|
|
141
|
+
aria-haspopup="true"
|
|
142
|
+
aria-expanded={open ? "true" : undefined}
|
|
143
|
+
{...slotProps?.avatarIconButton}
|
|
144
|
+
>
|
|
145
|
+
{avatarContent}
|
|
146
|
+
</IconButton>
|
|
147
|
+
)}
|
|
148
|
+
</Tooltip>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
AccountPreview.propTypes /* remove-proptypes */ = {
|
|
153
|
+
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
154
|
+
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
155
|
+
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
156
|
+
// └─────────────────────────────────────────────────────────────────────┘
|
|
157
|
+
/**
|
|
158
|
+
* The handler used when the preview is expanded
|
|
159
|
+
*/
|
|
160
|
+
handleClick: PropTypes.func,
|
|
161
|
+
/**
|
|
162
|
+
* The state of the Account popover
|
|
163
|
+
* @default false
|
|
164
|
+
*/
|
|
165
|
+
open: PropTypes.bool,
|
|
166
|
+
/**
|
|
167
|
+
* The props used for each slot inside.
|
|
168
|
+
*/
|
|
169
|
+
slotProps: PropTypes.shape({
|
|
170
|
+
avatar: PropTypes.object,
|
|
171
|
+
avatarIconButton: PropTypes.object,
|
|
172
|
+
moreIconButton: PropTypes.object
|
|
173
|
+
}),
|
|
174
|
+
/**
|
|
175
|
+
* The components used for each slot inside.
|
|
176
|
+
*/
|
|
177
|
+
slots: PropTypes.shape({
|
|
178
|
+
avatar: PropTypes.elementType
|
|
179
|
+
}),
|
|
180
|
+
/**
|
|
181
|
+
* The type of account details to display.
|
|
182
|
+
* @property {'condensed'} condensed - Shows only the user's avatar.
|
|
183
|
+
* @property {'expanded'} expanded - Displays the user's avatar, name, and email if available.
|
|
184
|
+
* @default 'condensed'
|
|
185
|
+
*/
|
|
186
|
+
variant: PropTypes.oneOf(["condensed", "expanded"])
|
|
187
|
+
} as any;
|
|
188
|
+
|
|
189
|
+
export { AccountPreview };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Button, { ButtonProps } from "@mui/material/Button";
|
|
3
|
+
import { AuthenticationContext } from "../AppProvider/AppProvider";
|
|
4
|
+
import { useLocaleText } from "../shared/locales/LocaleContext";
|
|
5
|
+
|
|
6
|
+
export /**
|
|
7
|
+
*
|
|
8
|
+
* Demos:
|
|
9
|
+
*
|
|
10
|
+
* - [Account](https://mui.com/toolpad/core/react-account/)
|
|
11
|
+
*
|
|
12
|
+
* API:
|
|
13
|
+
*
|
|
14
|
+
* - [SignInButton API](https://mui.com/toolpad/core/api/sign-in-button)
|
|
15
|
+
*/ function SignInButton(props: ButtonProps) {
|
|
16
|
+
const authentication = React.useContext(AuthenticationContext);
|
|
17
|
+
const localeText = useLocaleText();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Button
|
|
21
|
+
disableElevation
|
|
22
|
+
variant="contained"
|
|
23
|
+
size="small"
|
|
24
|
+
onClick={authentication?.signIn}
|
|
25
|
+
sx={{
|
|
26
|
+
textTransform: "capitalize",
|
|
27
|
+
filter: "opacity(0.9)",
|
|
28
|
+
transition: "filter 0.2s ease-in",
|
|
29
|
+
"&:hover": {
|
|
30
|
+
filter: "opacity(1)"
|
|
31
|
+
}
|
|
32
|
+
}}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
{localeText?.signInLabel || "Sign In"}
|
|
36
|
+
</Button>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Button, { ButtonProps } from "@mui/material/Button";
|
|
3
|
+
import LogoutIcon from "@mui/icons-material/Logout";
|
|
4
|
+
import { AuthenticationContext } from "../AppProvider/AppProvider";
|
|
5
|
+
import { useLocaleText } from "../shared/locales/LocaleContext";
|
|
6
|
+
|
|
7
|
+
export type SignOutButtonProps = ButtonProps;
|
|
8
|
+
|
|
9
|
+
export /**
|
|
10
|
+
*
|
|
11
|
+
* Demos:
|
|
12
|
+
*
|
|
13
|
+
* - [Account](https://mui.com/toolpad/core/react-account/)
|
|
14
|
+
*
|
|
15
|
+
* API:
|
|
16
|
+
*
|
|
17
|
+
* - [SignOutButton API](https://mui.com/toolpad/core/api/sign-out-button)
|
|
18
|
+
*/ function SignOutButton(props: SignOutButtonProps) {
|
|
19
|
+
const authentication = React.useContext(AuthenticationContext);
|
|
20
|
+
const localeText = useLocaleText();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Button
|
|
24
|
+
disabled={!authentication}
|
|
25
|
+
variant="outlined"
|
|
26
|
+
size="small"
|
|
27
|
+
disableElevation
|
|
28
|
+
onClick={authentication?.signOut}
|
|
29
|
+
sx={{
|
|
30
|
+
textTransform: "capitalize",
|
|
31
|
+
fontWeight: "normal",
|
|
32
|
+
filter: "opacity(0.9)",
|
|
33
|
+
transition: "filter 0.2s ease-in",
|
|
34
|
+
"&:hover": {
|
|
35
|
+
filter: "opacity(1)"
|
|
36
|
+
}
|
|
37
|
+
}}
|
|
38
|
+
startIcon={<LogoutIcon />}
|
|
39
|
+
{...props}
|
|
40
|
+
>
|
|
41
|
+
{localeText.signOutLabel}
|
|
42
|
+
</Button>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { describe, test, expect } from "vitest";
|
|
7
|
+
import { render, screen } from "@testing-library/react";
|
|
8
|
+
import { createTheme } from "@mui/material/styles";
|
|
9
|
+
import { AppProvider } from "./AppProviderComponent";
|
|
10
|
+
|
|
11
|
+
describe("AppProvider", () => {
|
|
12
|
+
test("renders content correctly", async () => {
|
|
13
|
+
render(<AppProvider>Hello world</AppProvider>);
|
|
14
|
+
|
|
15
|
+
expect(screen.getByText("Hello world")).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("renders content correctly when using legacy theme", async () => {
|
|
19
|
+
const legacyTheme = createTheme();
|
|
20
|
+
|
|
21
|
+
render(<AppProvider theme={legacyTheme}>Hello world</AppProvider>);
|
|
22
|
+
|
|
23
|
+
expect(screen.getByText("Hello world")).toBeTruthy();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Theme } from "@mui/material/styles";
|
|
4
|
+
|
|
5
|
+
export interface NavigateOptions {
|
|
6
|
+
history?: "auto" | "push" | "replace";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Navigate {
|
|
10
|
+
(url: string | URL, options?: NavigateOptions): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Abstract router used by Toolpad components.
|
|
15
|
+
*/
|
|
16
|
+
export interface Router {
|
|
17
|
+
pathname: string;
|
|
18
|
+
searchParams: URLSearchParams;
|
|
19
|
+
navigate: Navigate;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Branding {
|
|
23
|
+
title?: string;
|
|
24
|
+
logo?: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface NavigationPageItem {
|
|
28
|
+
kind?: "page";
|
|
29
|
+
segment?: string;
|
|
30
|
+
title?: string;
|
|
31
|
+
icon?: React.ReactNode;
|
|
32
|
+
pattern?: string;
|
|
33
|
+
action?: React.ReactNode;
|
|
34
|
+
children?: Navigation;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface NavigationSubheaderItem {
|
|
38
|
+
kind: "header";
|
|
39
|
+
title: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface NavigationDividerItem {
|
|
43
|
+
kind: "divider";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type NavigationItem =
|
|
47
|
+
| NavigationPageItem
|
|
48
|
+
| NavigationSubheaderItem
|
|
49
|
+
| NavigationDividerItem;
|
|
50
|
+
|
|
51
|
+
export type Navigation = NavigationItem[];
|
|
52
|
+
|
|
53
|
+
export interface Session {
|
|
54
|
+
user?: {
|
|
55
|
+
id?: string | null;
|
|
56
|
+
name?: string | null;
|
|
57
|
+
image?: string | null;
|
|
58
|
+
email?: string | null;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface Authentication {
|
|
63
|
+
signIn: () => void;
|
|
64
|
+
signOut: () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const AuthenticationContext = React.createContext<Authentication | null>(
|
|
68
|
+
null
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export const SessionContext = React.createContext<Session | null>(null);
|
|
72
|
+
|
|
73
|
+
export type AppTheme = Theme | { light: Theme; dark: Theme };
|
|
74
|
+
|
|
75
|
+
export interface AppProviderProps {
|
|
76
|
+
/**
|
|
77
|
+
* The content of the app provider.
|
|
78
|
+
*/
|
|
79
|
+
children: React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* [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.
|
|
82
|
+
* @default createTheme()
|
|
83
|
+
*/
|
|
84
|
+
theme?: AppTheme;
|
|
85
|
+
/**
|
|
86
|
+
* Branding options for the app.
|
|
87
|
+
* @default null
|
|
88
|
+
*/
|
|
89
|
+
branding?: Branding | null;
|
|
90
|
+
/**
|
|
91
|
+
* Navigation definition for the app.
|
|
92
|
+
* @default []
|
|
93
|
+
*/
|
|
94
|
+
navigation?: Navigation;
|
|
95
|
+
/**
|
|
96
|
+
* Router implementation used inside Toolpad components.
|
|
97
|
+
* @default null
|
|
98
|
+
*/
|
|
99
|
+
router?: Router;
|
|
100
|
+
/**
|
|
101
|
+
* Session info about the current user.
|
|
102
|
+
* @default null
|
|
103
|
+
*/
|
|
104
|
+
session?: Session | null;
|
|
105
|
+
/**
|
|
106
|
+
* Authentication methods.
|
|
107
|
+
* @default null
|
|
108
|
+
*/
|
|
109
|
+
authentication?: Authentication | null;
|
|
110
|
+
/**
|
|
111
|
+
* The window where the application is rendered.
|
|
112
|
+
* This is needed when rendering the app inside an iframe, for example.
|
|
113
|
+
* @default window
|
|
114
|
+
*/
|
|
115
|
+
window?: Window;
|
|
116
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import {
|
|
4
|
+
BrandingContext,
|
|
5
|
+
NavigationContext,
|
|
6
|
+
RouterContext,
|
|
7
|
+
WindowContext
|
|
8
|
+
} from "../shared/context";
|
|
9
|
+
import { AppThemeProvider } from "./AppThemeProvider";
|
|
10
|
+
import { createTheme as createMuiTheme, Theme } from "@mui/material/styles";
|
|
11
|
+
import {
|
|
12
|
+
AppProviderProps,
|
|
13
|
+
AuthenticationContext,
|
|
14
|
+
SessionContext
|
|
15
|
+
} from "./AppProvider";
|
|
16
|
+
|
|
17
|
+
function createTheme(): Theme {
|
|
18
|
+
return createMuiTheme({
|
|
19
|
+
cssVariables: {
|
|
20
|
+
colorSchemeSelector: "data-toolpad-color-scheme"
|
|
21
|
+
},
|
|
22
|
+
colorSchemes: { dark: true }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* Demos:
|
|
29
|
+
*
|
|
30
|
+
* - [App Provider](https://mui.com/toolpad/core/react-app-provider/)
|
|
31
|
+
* - [Dashboard Layout](https://mui.com/toolpad/core/react-dashboard-layout/)
|
|
32
|
+
*
|
|
33
|
+
* API:
|
|
34
|
+
*
|
|
35
|
+
* - [AppProvider API](https://mui.com/toolpad/core/api/app-provider)
|
|
36
|
+
*/
|
|
37
|
+
function AppProvider(props: AppProviderProps) {
|
|
38
|
+
const {
|
|
39
|
+
children,
|
|
40
|
+
theme = createTheme(),
|
|
41
|
+
branding = null,
|
|
42
|
+
navigation = [],
|
|
43
|
+
router = null,
|
|
44
|
+
authentication = null,
|
|
45
|
+
session = null,
|
|
46
|
+
window: appWindow
|
|
47
|
+
} = props;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<WindowContext.Provider value={appWindow}>
|
|
51
|
+
<AuthenticationContext.Provider value={authentication}>
|
|
52
|
+
<SessionContext.Provider value={session}>
|
|
53
|
+
<RouterContext.Provider value={router}>
|
|
54
|
+
<AppThemeProvider theme={theme} window={appWindow}>
|
|
55
|
+
<BrandingContext.Provider value={branding}>
|
|
56
|
+
<NavigationContext.Provider value={navigation}>
|
|
57
|
+
{children}
|
|
58
|
+
</NavigationContext.Provider>
|
|
59
|
+
</BrandingContext.Provider>
|
|
60
|
+
</AppThemeProvider>
|
|
61
|
+
</RouterContext.Provider>
|
|
62
|
+
</SessionContext.Provider>
|
|
63
|
+
</AuthenticationContext.Provider>
|
|
64
|
+
</WindowContext.Provider>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
AppProvider.propTypes /* remove-proptypes */ = {
|
|
69
|
+
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
|
70
|
+
// │ These PropTypes are generated from the TypeScript type definitions. │
|
|
71
|
+
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
|
72
|
+
// └─────────────────────────────────────────────────────────────────────┘
|
|
73
|
+
/**
|
|
74
|
+
* Authentication methods.
|
|
75
|
+
* @default null
|
|
76
|
+
*/
|
|
77
|
+
authentication: PropTypes.shape({
|
|
78
|
+
signIn: PropTypes.func.isRequired,
|
|
79
|
+
signOut: PropTypes.func.isRequired
|
|
80
|
+
}),
|
|
81
|
+
/**
|
|
82
|
+
* Branding options for the app.
|
|
83
|
+
* @default null
|
|
84
|
+
*/
|
|
85
|
+
branding: PropTypes.shape({
|
|
86
|
+
logo: PropTypes.node,
|
|
87
|
+
title: PropTypes.string
|
|
88
|
+
}),
|
|
89
|
+
/**
|
|
90
|
+
* The content of the app provider.
|
|
91
|
+
*/
|
|
92
|
+
children: PropTypes.node,
|
|
93
|
+
/**
|
|
94
|
+
* Navigation definition for the app.
|
|
95
|
+
* @default []
|
|
96
|
+
*/
|
|
97
|
+
navigation: PropTypes.arrayOf(
|
|
98
|
+
PropTypes.oneOfType([
|
|
99
|
+
PropTypes.shape({
|
|
100
|
+
action: PropTypes.node,
|
|
101
|
+
children: PropTypes.arrayOf(
|
|
102
|
+
PropTypes.oneOfType([
|
|
103
|
+
PropTypes.object,
|
|
104
|
+
PropTypes.shape({
|
|
105
|
+
kind: PropTypes.oneOf(["header"]).isRequired,
|
|
106
|
+
title: PropTypes.string.isRequired
|
|
107
|
+
}),
|
|
108
|
+
PropTypes.shape({
|
|
109
|
+
kind: PropTypes.oneOf(["divider"]).isRequired
|
|
110
|
+
})
|
|
111
|
+
]).isRequired
|
|
112
|
+
),
|
|
113
|
+
icon: PropTypes.node,
|
|
114
|
+
kind: PropTypes.oneOf(["page"]),
|
|
115
|
+
pattern: PropTypes.string,
|
|
116
|
+
segment: PropTypes.string,
|
|
117
|
+
title: PropTypes.string
|
|
118
|
+
}),
|
|
119
|
+
PropTypes.shape({
|
|
120
|
+
kind: PropTypes.oneOf(["header"]).isRequired,
|
|
121
|
+
title: PropTypes.string.isRequired
|
|
122
|
+
}),
|
|
123
|
+
PropTypes.shape({
|
|
124
|
+
kind: PropTypes.oneOf(["divider"]).isRequired
|
|
125
|
+
})
|
|
126
|
+
]).isRequired
|
|
127
|
+
),
|
|
128
|
+
/**
|
|
129
|
+
* Router implementation used inside Toolpad components.
|
|
130
|
+
* @default null
|
|
131
|
+
*/
|
|
132
|
+
router: PropTypes.shape({
|
|
133
|
+
navigate: PropTypes.func.isRequired,
|
|
134
|
+
pathname: PropTypes.string.isRequired,
|
|
135
|
+
searchParams: PropTypes.instanceOf(URLSearchParams).isRequired
|
|
136
|
+
}),
|
|
137
|
+
/**
|
|
138
|
+
* Session info about the current user.
|
|
139
|
+
* @default null
|
|
140
|
+
*/
|
|
141
|
+
session: PropTypes.shape({
|
|
142
|
+
user: PropTypes.shape({
|
|
143
|
+
email: PropTypes.string,
|
|
144
|
+
id: PropTypes.string,
|
|
145
|
+
image: PropTypes.string,
|
|
146
|
+
name: PropTypes.string
|
|
147
|
+
})
|
|
148
|
+
}),
|
|
149
|
+
/**
|
|
150
|
+
* [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.
|
|
151
|
+
* @default createTheme()
|
|
152
|
+
*/
|
|
153
|
+
theme: PropTypes.object,
|
|
154
|
+
/**
|
|
155
|
+
* The window where the application is rendered.
|
|
156
|
+
* This is needed when rendering the app inside an iframe, for example.
|
|
157
|
+
* @default window
|
|
158
|
+
*/
|
|
159
|
+
window: PropTypes.object
|
|
160
|
+
} as any;
|
|
161
|
+
|
|
162
|
+
export { AppProvider };
|