@inf-monkeys-tech/monkeys-design 0.4.36 → 0.4.37
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/README.md +103 -0
- package/dist/components/login/index.d.mts +97 -1
- package/dist/components/login/index.d.ts +97 -1
- package/dist/components/login/index.js +262 -2
- package/dist/components/login/index.js.map +1 -1
- package/dist/components/login/index.mjs +262 -3
- package/dist/components/login/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +260 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +260 -1
- package/dist/index.mjs.map +1 -1
- package/dist/styles/login-page.scss +423 -0
- package/package.json +5 -2
- package/dist/styles/artist-login.scss +0 -375
package/README.md
CHANGED
|
@@ -68,6 +68,109 @@ export function Example() {
|
|
|
68
68
|
| `@inf-monkeys-tech/monkeys-design/palette` | palette 工具 |
|
|
69
69
|
| `@inf-monkeys-tech/monkeys-design/theme-system` | 主题解析与应用工具 |
|
|
70
70
|
|
|
71
|
+
## LoginPage
|
|
72
|
+
|
|
73
|
+
`LoginPage` 是通用登录页 UI 组件。组件库只负责页面结构和样式契约,不包含登录请求、OAuth、路由、租户判断、i18n 初始化或租户定制样式。
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import {
|
|
77
|
+
LoginPage,
|
|
78
|
+
type LoginPageMethodConfig,
|
|
79
|
+
} from '@inf-monkeys-tech/monkeys-design/components/login';
|
|
80
|
+
import '@inf-monkeys-tech/monkeys-design/styles/login-page.scss';
|
|
81
|
+
|
|
82
|
+
const methods: LoginPageMethodConfig[] = [
|
|
83
|
+
{
|
|
84
|
+
id: 'email',
|
|
85
|
+
label: 'Email',
|
|
86
|
+
fields: [],
|
|
87
|
+
submitLabel: 'Login',
|
|
88
|
+
onSubmit: (event) => event.preventDefault(),
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
export function Example() {
|
|
93
|
+
return (
|
|
94
|
+
<LoginPage
|
|
95
|
+
background={{ imageUrl: '', gradient: '' }}
|
|
96
|
+
logo={{ url: '', position: 'bottom', scale: 1 }}
|
|
97
|
+
primaryColor="#4D8F9D"
|
|
98
|
+
radius="12px"
|
|
99
|
+
toolbar={<div />}
|
|
100
|
+
title="Welcome"
|
|
101
|
+
methods={methods}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
默认背景规则:
|
|
108
|
+
|
|
109
|
+
- 配置了 `background.imageUrl` 或 `background.gradient` 时,使用配置背景。
|
|
110
|
+
- 未配置背景时,浅色模式使用白色和主题色渐变。
|
|
111
|
+
- 未配置背景时,`.dark` 深色模式使用黑色和主题色渐变。
|
|
112
|
+
|
|
113
|
+
宿主应用负责把全局主题传入 `primaryColor` 和 `radius`,组件会把它们作为 `--login-page-theme-primary-color` 和 `--login-page-theme-radius` 默认来源;页面级 `customCss` 仍可通过公开的 `--login-page-*` 变量做租户级覆盖。深浅色切换、语言切换等应用级控件通过 `toolbar` 传入。
|
|
114
|
+
|
|
115
|
+
### LoginPage CSS 契约
|
|
116
|
+
|
|
117
|
+
页面级自定义样式只能依赖 `data-login-page`、`data-login-part` 和公开 CSS 变量。不要依赖租户 id,不要新增登录页代码分支。
|
|
118
|
+
|
|
119
|
+
推荐优先覆盖变量:
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
[data-login-page] {
|
|
123
|
+
--login-page-panel-bg: rgb(255 255 255 / 0.92);
|
|
124
|
+
--login-page-panel-border: rgb(17 17 17 / 0.08);
|
|
125
|
+
--login-page-panel-shadow: 0 24px 60px rgb(0 0 0 / 0.08);
|
|
126
|
+
--login-page-control-bg: #ffffff;
|
|
127
|
+
--login-page-control-border: rgb(17 17 17 / 0.12);
|
|
128
|
+
--login-page-control-text: #111111;
|
|
129
|
+
--login-page-control-placeholder: #9f9fa9;
|
|
130
|
+
--login-page-form-width: 500px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.dark [data-login-page] {
|
|
134
|
+
--login-page-panel-bg: rgb(12 12 12 / 0.9);
|
|
135
|
+
--login-page-control-bg: #111111;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
公开部件:
|
|
140
|
+
|
|
141
|
+
```css
|
|
142
|
+
[data-login-part='root'] {}
|
|
143
|
+
[data-login-part='background'] {}
|
|
144
|
+
[data-login-part='toolbar'] {}
|
|
145
|
+
[data-login-part='logo'] {}
|
|
146
|
+
[data-login-part='logo-image'] {}
|
|
147
|
+
[data-login-part='panel'] {}
|
|
148
|
+
[data-login-part='back'] {}
|
|
149
|
+
[data-login-part='back-icon'] {}
|
|
150
|
+
[data-login-part='title'] {}
|
|
151
|
+
[data-login-part='tabs'] {}
|
|
152
|
+
[data-login-part='tab'] {}
|
|
153
|
+
[data-login-part='tab-icon'] {}
|
|
154
|
+
[data-login-part='form'] {}
|
|
155
|
+
[data-login-part='field'] {}
|
|
156
|
+
[data-login-part='input'] {}
|
|
157
|
+
[data-login-part='checkbox-label'] {}
|
|
158
|
+
[data-login-part='checkbox'] {}
|
|
159
|
+
[data-login-part='method-footer'] {}
|
|
160
|
+
[data-login-part='method-footer-action'] {}
|
|
161
|
+
[data-login-part='submit-button'] {}
|
|
162
|
+
[data-login-part='callout'] {}
|
|
163
|
+
[data-login-part='callout-title'] {}
|
|
164
|
+
[data-login-part='callout-description'] {}
|
|
165
|
+
[data-login-part='callout-detail'] {}
|
|
166
|
+
[data-login-part='callout-action'] {}
|
|
167
|
+
[data-login-part='external-methods'] {}
|
|
168
|
+
[data-login-part='external-label'] {}
|
|
169
|
+
[data-login-part='external-list'] {}
|
|
170
|
+
[data-login-part='external-button'] {}
|
|
171
|
+
[data-login-part='external-icon'] {}
|
|
172
|
+
```
|
|
173
|
+
|
|
71
174
|
## 基础组件
|
|
72
175
|
|
|
73
176
|
基础组件从 `components/base` 子路径导入:
|
|
@@ -1,5 +1,99 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
1
2
|
import React__default from 'react';
|
|
2
3
|
|
|
4
|
+
type LoginPageLogoLocation = 'top' | 'middle' | 'bottom';
|
|
5
|
+
interface LoginPageBackgroundConfig {
|
|
6
|
+
imageUrl?: string;
|
|
7
|
+
gradient?: string;
|
|
8
|
+
}
|
|
9
|
+
interface LoginPageLogoConfig {
|
|
10
|
+
url?: string;
|
|
11
|
+
alt?: string;
|
|
12
|
+
position?: LoginPageLogoLocation;
|
|
13
|
+
scale?: number;
|
|
14
|
+
}
|
|
15
|
+
interface LoginPageFieldConfig {
|
|
16
|
+
id?: string;
|
|
17
|
+
name: string;
|
|
18
|
+
type?: React__default.HTMLInputTypeAttribute;
|
|
19
|
+
value: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
autoComplete?: string;
|
|
22
|
+
inputMode?: React__default.HTMLAttributes<HTMLInputElement>['inputMode'];
|
|
23
|
+
maxLength?: number;
|
|
24
|
+
pattern?: string;
|
|
25
|
+
required?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
onChange: (value: string) => void;
|
|
28
|
+
}
|
|
29
|
+
interface LoginPageCheckboxConfig {
|
|
30
|
+
id: string;
|
|
31
|
+
label: React__default.ReactNode;
|
|
32
|
+
checked: boolean;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
onChange: (checked: boolean) => void;
|
|
35
|
+
}
|
|
36
|
+
interface LoginPageMethodConfig {
|
|
37
|
+
id: string;
|
|
38
|
+
label: React__default.ReactNode;
|
|
39
|
+
icon?: React__default.ReactNode;
|
|
40
|
+
fields: LoginPageFieldConfig[];
|
|
41
|
+
submitLabel: React__default.ReactNode;
|
|
42
|
+
loadingLabel?: React__default.ReactNode;
|
|
43
|
+
isLoading?: boolean;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
hidden?: boolean;
|
|
46
|
+
checkbox?: LoginPageCheckboxConfig;
|
|
47
|
+
footer?: React__default.ReactNode;
|
|
48
|
+
footerAction?: {
|
|
49
|
+
label: React__default.ReactNode;
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
onClick: () => void;
|
|
52
|
+
};
|
|
53
|
+
onSubmit: (event: React__default.FormEvent<HTMLFormElement>) => void;
|
|
54
|
+
}
|
|
55
|
+
interface LoginPageExternalMethodConfig {
|
|
56
|
+
id: string;
|
|
57
|
+
label: React__default.ReactNode;
|
|
58
|
+
icon?: React__default.ReactNode;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
onClick?: () => void;
|
|
61
|
+
render?: (button: React__default.ReactElement) => React__default.ReactNode;
|
|
62
|
+
}
|
|
63
|
+
interface LoginPageCalloutConfig {
|
|
64
|
+
tone?: 'info' | 'warning' | 'success' | 'danger';
|
|
65
|
+
title: React__default.ReactNode;
|
|
66
|
+
description?: React__default.ReactNode;
|
|
67
|
+
detail?: React__default.ReactNode;
|
|
68
|
+
action?: {
|
|
69
|
+
label: React__default.ReactNode;
|
|
70
|
+
disabled?: boolean;
|
|
71
|
+
onClick: () => void;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
interface LoginPageProps {
|
|
75
|
+
className?: string;
|
|
76
|
+
style?: React__default.CSSProperties;
|
|
77
|
+
background?: LoginPageBackgroundConfig;
|
|
78
|
+
logo?: LoginPageLogoConfig;
|
|
79
|
+
primaryColor?: string;
|
|
80
|
+
radius?: string;
|
|
81
|
+
customCss?: string;
|
|
82
|
+
toolbar?: React__default.ReactNode;
|
|
83
|
+
title?: React__default.ReactNode;
|
|
84
|
+
backAction?: {
|
|
85
|
+
label: React__default.ReactNode;
|
|
86
|
+
icon?: React__default.ReactNode;
|
|
87
|
+
onClick: () => void;
|
|
88
|
+
};
|
|
89
|
+
methods: LoginPageMethodConfig[];
|
|
90
|
+
activeMethodId?: string;
|
|
91
|
+
defaultMethodId?: string;
|
|
92
|
+
onMethodChange?: (methodId: string) => void;
|
|
93
|
+
externalLabel?: React__default.ReactNode;
|
|
94
|
+
externalMethods?: LoginPageExternalMethodConfig[];
|
|
95
|
+
callout?: LoginPageCalloutConfig;
|
|
96
|
+
}
|
|
3
97
|
interface LoginLayoutProps {
|
|
4
98
|
className?: string;
|
|
5
99
|
style?: React__default.CSSProperties;
|
|
@@ -76,6 +170,8 @@ interface PendingApprovalProps {
|
|
|
76
170
|
onBack?: () => void;
|
|
77
171
|
}
|
|
78
172
|
|
|
173
|
+
declare function LoginPage({ className, style, background, logo, primaryColor, radius, customCss, toolbar, title, backAction, methods, activeMethodId, defaultMethodId, onMethodChange, externalLabel, externalMethods, callout, }: LoginPageProps): react_jsx_runtime.JSX.Element;
|
|
174
|
+
|
|
79
175
|
declare const LoginLayout: React__default.FC<LoginLayoutProps>;
|
|
80
176
|
|
|
81
177
|
declare const EmailAuth: React__default.ForwardRefExoticComponent<EmailAuthProps & React__default.RefAttributes<HTMLFormElement>>;
|
|
@@ -88,4 +184,4 @@ declare const AuthDivider: React__default.FC<AuthDividerProps>;
|
|
|
88
184
|
|
|
89
185
|
declare const PendingApproval: React__default.FC<PendingApprovalProps>;
|
|
90
186
|
|
|
91
|
-
export { AuthDivider, type AuthDividerProps, EmailAuth, type EmailAuthProps, LoginLayout, type LoginLayoutProps, OAuthButton, type OAuthButtonProps, OIDCButton, type OIDCButtonProps, PendingApproval, type PendingApprovalProps };
|
|
187
|
+
export { AuthDivider, type AuthDividerProps, EmailAuth, type EmailAuthProps, LoginLayout, type LoginLayoutProps, LoginPage, type LoginPageBackgroundConfig, type LoginPageCalloutConfig, type LoginPageCheckboxConfig, type LoginPageExternalMethodConfig, type LoginPageFieldConfig, type LoginPageLogoConfig, type LoginPageLogoLocation, type LoginPageMethodConfig, type LoginPageProps, OAuthButton, type OAuthButtonProps, OIDCButton, type OIDCButtonProps, PendingApproval, type PendingApprovalProps };
|
|
@@ -1,5 +1,99 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
1
2
|
import React__default from 'react';
|
|
2
3
|
|
|
4
|
+
type LoginPageLogoLocation = 'top' | 'middle' | 'bottom';
|
|
5
|
+
interface LoginPageBackgroundConfig {
|
|
6
|
+
imageUrl?: string;
|
|
7
|
+
gradient?: string;
|
|
8
|
+
}
|
|
9
|
+
interface LoginPageLogoConfig {
|
|
10
|
+
url?: string;
|
|
11
|
+
alt?: string;
|
|
12
|
+
position?: LoginPageLogoLocation;
|
|
13
|
+
scale?: number;
|
|
14
|
+
}
|
|
15
|
+
interface LoginPageFieldConfig {
|
|
16
|
+
id?: string;
|
|
17
|
+
name: string;
|
|
18
|
+
type?: React__default.HTMLInputTypeAttribute;
|
|
19
|
+
value: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
autoComplete?: string;
|
|
22
|
+
inputMode?: React__default.HTMLAttributes<HTMLInputElement>['inputMode'];
|
|
23
|
+
maxLength?: number;
|
|
24
|
+
pattern?: string;
|
|
25
|
+
required?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
onChange: (value: string) => void;
|
|
28
|
+
}
|
|
29
|
+
interface LoginPageCheckboxConfig {
|
|
30
|
+
id: string;
|
|
31
|
+
label: React__default.ReactNode;
|
|
32
|
+
checked: boolean;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
onChange: (checked: boolean) => void;
|
|
35
|
+
}
|
|
36
|
+
interface LoginPageMethodConfig {
|
|
37
|
+
id: string;
|
|
38
|
+
label: React__default.ReactNode;
|
|
39
|
+
icon?: React__default.ReactNode;
|
|
40
|
+
fields: LoginPageFieldConfig[];
|
|
41
|
+
submitLabel: React__default.ReactNode;
|
|
42
|
+
loadingLabel?: React__default.ReactNode;
|
|
43
|
+
isLoading?: boolean;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
hidden?: boolean;
|
|
46
|
+
checkbox?: LoginPageCheckboxConfig;
|
|
47
|
+
footer?: React__default.ReactNode;
|
|
48
|
+
footerAction?: {
|
|
49
|
+
label: React__default.ReactNode;
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
onClick: () => void;
|
|
52
|
+
};
|
|
53
|
+
onSubmit: (event: React__default.FormEvent<HTMLFormElement>) => void;
|
|
54
|
+
}
|
|
55
|
+
interface LoginPageExternalMethodConfig {
|
|
56
|
+
id: string;
|
|
57
|
+
label: React__default.ReactNode;
|
|
58
|
+
icon?: React__default.ReactNode;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
onClick?: () => void;
|
|
61
|
+
render?: (button: React__default.ReactElement) => React__default.ReactNode;
|
|
62
|
+
}
|
|
63
|
+
interface LoginPageCalloutConfig {
|
|
64
|
+
tone?: 'info' | 'warning' | 'success' | 'danger';
|
|
65
|
+
title: React__default.ReactNode;
|
|
66
|
+
description?: React__default.ReactNode;
|
|
67
|
+
detail?: React__default.ReactNode;
|
|
68
|
+
action?: {
|
|
69
|
+
label: React__default.ReactNode;
|
|
70
|
+
disabled?: boolean;
|
|
71
|
+
onClick: () => void;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
interface LoginPageProps {
|
|
75
|
+
className?: string;
|
|
76
|
+
style?: React__default.CSSProperties;
|
|
77
|
+
background?: LoginPageBackgroundConfig;
|
|
78
|
+
logo?: LoginPageLogoConfig;
|
|
79
|
+
primaryColor?: string;
|
|
80
|
+
radius?: string;
|
|
81
|
+
customCss?: string;
|
|
82
|
+
toolbar?: React__default.ReactNode;
|
|
83
|
+
title?: React__default.ReactNode;
|
|
84
|
+
backAction?: {
|
|
85
|
+
label: React__default.ReactNode;
|
|
86
|
+
icon?: React__default.ReactNode;
|
|
87
|
+
onClick: () => void;
|
|
88
|
+
};
|
|
89
|
+
methods: LoginPageMethodConfig[];
|
|
90
|
+
activeMethodId?: string;
|
|
91
|
+
defaultMethodId?: string;
|
|
92
|
+
onMethodChange?: (methodId: string) => void;
|
|
93
|
+
externalLabel?: React__default.ReactNode;
|
|
94
|
+
externalMethods?: LoginPageExternalMethodConfig[];
|
|
95
|
+
callout?: LoginPageCalloutConfig;
|
|
96
|
+
}
|
|
3
97
|
interface LoginLayoutProps {
|
|
4
98
|
className?: string;
|
|
5
99
|
style?: React__default.CSSProperties;
|
|
@@ -76,6 +170,8 @@ interface PendingApprovalProps {
|
|
|
76
170
|
onBack?: () => void;
|
|
77
171
|
}
|
|
78
172
|
|
|
173
|
+
declare function LoginPage({ className, style, background, logo, primaryColor, radius, customCss, toolbar, title, backAction, methods, activeMethodId, defaultMethodId, onMethodChange, externalLabel, externalMethods, callout, }: LoginPageProps): react_jsx_runtime.JSX.Element;
|
|
174
|
+
|
|
79
175
|
declare const LoginLayout: React__default.FC<LoginLayoutProps>;
|
|
80
176
|
|
|
81
177
|
declare const EmailAuth: React__default.ForwardRefExoticComponent<EmailAuthProps & React__default.RefAttributes<HTMLFormElement>>;
|
|
@@ -88,4 +184,4 @@ declare const AuthDivider: React__default.FC<AuthDividerProps>;
|
|
|
88
184
|
|
|
89
185
|
declare const PendingApproval: React__default.FC<PendingApprovalProps>;
|
|
90
186
|
|
|
91
|
-
export { AuthDivider, type AuthDividerProps, EmailAuth, type EmailAuthProps, LoginLayout, type LoginLayoutProps, OAuthButton, type OAuthButtonProps, OIDCButton, type OIDCButtonProps, PendingApproval, type PendingApprovalProps };
|
|
187
|
+
export { AuthDivider, type AuthDividerProps, EmailAuth, type EmailAuthProps, LoginLayout, type LoginLayoutProps, LoginPage, type LoginPageBackgroundConfig, type LoginPageCalloutConfig, type LoginPageCheckboxConfig, type LoginPageExternalMethodConfig, type LoginPageFieldConfig, type LoginPageLogoConfig, type LoginPageLogoLocation, type LoginPageMethodConfig, type LoginPageProps, OAuthButton, type OAuthButtonProps, OIDCButton, type OIDCButtonProps, PendingApproval, type PendingApprovalProps };
|
|
@@ -1,13 +1,272 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
4
3
|
var React = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
|
|
6
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
7
|
|
|
8
8
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
9
9
|
|
|
10
|
-
// src/components/login/
|
|
10
|
+
// src/components/login/LoginPage.tsx
|
|
11
|
+
var LOGIN_LOGO_POSITIONS = ["top", "middle", "bottom"];
|
|
12
|
+
var normalizeCssValue = (value) => {
|
|
13
|
+
const trimmed = value?.trim();
|
|
14
|
+
return trimmed || void 0;
|
|
15
|
+
};
|
|
16
|
+
var createBackgroundImage = (gradient, imageUrl) => {
|
|
17
|
+
const resolvedGradient = normalizeCssValue(gradient);
|
|
18
|
+
const resolvedImageUrl = normalizeCssValue(imageUrl);
|
|
19
|
+
return [resolvedGradient, resolvedImageUrl ? `url(${JSON.stringify(resolvedImageUrl)})` : void 0].filter(Boolean).join(", ");
|
|
20
|
+
};
|
|
21
|
+
var normalizeLogoPosition = (position) => position && LOGIN_LOGO_POSITIONS.includes(position) ? position : "bottom";
|
|
22
|
+
var normalizeLogoScale = (scale) => typeof scale === "number" && Number.isFinite(scale) && scale > 0 ? scale : void 0;
|
|
23
|
+
function LoginPage({
|
|
24
|
+
className,
|
|
25
|
+
style,
|
|
26
|
+
background,
|
|
27
|
+
logo,
|
|
28
|
+
primaryColor,
|
|
29
|
+
radius,
|
|
30
|
+
customCss,
|
|
31
|
+
toolbar,
|
|
32
|
+
title,
|
|
33
|
+
backAction,
|
|
34
|
+
methods,
|
|
35
|
+
activeMethodId,
|
|
36
|
+
defaultMethodId,
|
|
37
|
+
onMethodChange,
|
|
38
|
+
externalLabel,
|
|
39
|
+
externalMethods = [],
|
|
40
|
+
callout
|
|
41
|
+
}) {
|
|
42
|
+
const availableMethods = React.useMemo(() => methods.filter((method) => !method.hidden), [methods]);
|
|
43
|
+
const fallbackMethodId = defaultMethodId ?? availableMethods[0]?.id;
|
|
44
|
+
const [internalMethodId, setInternalMethodId] = React.useState(fallbackMethodId);
|
|
45
|
+
const currentMethodId = activeMethodId ?? internalMethodId;
|
|
46
|
+
const activeMethod = availableMethods.find((method) => method.id === currentMethodId) ?? availableMethods[0];
|
|
47
|
+
const hasTabs = availableMethods.length > 1;
|
|
48
|
+
const backgroundImage = createBackgroundImage(background?.gradient, background?.imageUrl);
|
|
49
|
+
const backgroundMode = backgroundImage ? "custom" : "default";
|
|
50
|
+
const logoPosition = normalizeLogoPosition(logo?.position);
|
|
51
|
+
const logoScale = normalizeLogoScale(logo?.scale);
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
if (!availableMethods.length) {
|
|
54
|
+
setInternalMethodId(void 0);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!currentMethodId || !availableMethods.some((method) => method.id === currentMethodId)) {
|
|
58
|
+
setInternalMethodId(fallbackMethodId ?? availableMethods[0]?.id);
|
|
59
|
+
}
|
|
60
|
+
}, [availableMethods, currentMethodId, fallbackMethodId]);
|
|
61
|
+
const rootStyle = React.useMemo(
|
|
62
|
+
() => ({
|
|
63
|
+
...primaryColor ? { ["--login-page-theme-primary-color"]: primaryColor } : null,
|
|
64
|
+
...radius ? { ["--login-page-theme-radius"]: radius } : null,
|
|
65
|
+
...style
|
|
66
|
+
}),
|
|
67
|
+
[primaryColor, radius, style]
|
|
68
|
+
);
|
|
69
|
+
const handleMethodChange = (methodId) => {
|
|
70
|
+
if (activeMethodId === void 0) {
|
|
71
|
+
setInternalMethodId(methodId);
|
|
72
|
+
}
|
|
73
|
+
onMethodChange?.(methodId);
|
|
74
|
+
};
|
|
75
|
+
const renderExternalMethod = (method) => {
|
|
76
|
+
const button = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
77
|
+
"button",
|
|
78
|
+
{
|
|
79
|
+
type: "button",
|
|
80
|
+
className: "login-page__oauth-button",
|
|
81
|
+
"data-login-part": "external-button",
|
|
82
|
+
"data-login-method-id": method.id,
|
|
83
|
+
onClick: method.onClick,
|
|
84
|
+
disabled: method.disabled,
|
|
85
|
+
children: [
|
|
86
|
+
method.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "login-page__oauth-icon", "data-login-part": "external-icon", children: method.icon }) : null,
|
|
87
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: method.label })
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: method.render ? method.render(button) : button }, method.id);
|
|
92
|
+
};
|
|
93
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
94
|
+
"main",
|
|
95
|
+
{
|
|
96
|
+
className: ["login-page", className].filter(Boolean).join(" "),
|
|
97
|
+
"data-login-page": true,
|
|
98
|
+
"data-login-part": "root",
|
|
99
|
+
"data-login-background": backgroundMode,
|
|
100
|
+
style: rootStyle,
|
|
101
|
+
children: [
|
|
102
|
+
customCss ? /* @__PURE__ */ jsxRuntime.jsx("style", { "data-login-page-custom-css": true, children: customCss }) : null,
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
104
|
+
"div",
|
|
105
|
+
{
|
|
106
|
+
className: "login-page__background",
|
|
107
|
+
"data-login-part": "background",
|
|
108
|
+
"data-login-background": backgroundMode,
|
|
109
|
+
style: backgroundImage ? { backgroundImage } : void 0,
|
|
110
|
+
"aria-hidden": "true"
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
toolbar ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__toolbar", "data-login-part": "toolbar", children: toolbar }) : null,
|
|
114
|
+
logo?.url ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
115
|
+
"div",
|
|
116
|
+
{
|
|
117
|
+
className: `login-page__logo login-page__logo--${logoPosition}`,
|
|
118
|
+
"data-login-part": "logo",
|
|
119
|
+
"data-logo-position": logoPosition,
|
|
120
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
121
|
+
"img",
|
|
122
|
+
{
|
|
123
|
+
className: "login-page__logo-image",
|
|
124
|
+
"data-login-part": "logo-image",
|
|
125
|
+
src: logo.url,
|
|
126
|
+
alt: logo.alt ?? "",
|
|
127
|
+
style: logoScale ? { transform: `scale(${logoScale})` } : void 0
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
) : null,
|
|
132
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
133
|
+
"section",
|
|
134
|
+
{
|
|
135
|
+
className: "login-page__form",
|
|
136
|
+
"data-login-part": "panel",
|
|
137
|
+
"aria-label": typeof title === "string" ? title : void 0,
|
|
138
|
+
children: [
|
|
139
|
+
backAction ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "login-page__back", "data-login-part": "back", onClick: backAction.onClick, children: [
|
|
140
|
+
backAction.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "login-page__back-icon", "data-login-part": "back-icon", children: backAction.icon }) : null,
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: backAction.label })
|
|
142
|
+
] }) : null,
|
|
143
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "login-page__title", "data-login-part": "title", children: title }) : null,
|
|
144
|
+
hasTabs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__tabs", "data-login-part": "tabs", role: "tablist", children: availableMethods.map((method) => {
|
|
145
|
+
const selected = method.id === activeMethod?.id;
|
|
146
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
147
|
+
"button",
|
|
148
|
+
{
|
|
149
|
+
type: "button",
|
|
150
|
+
role: "tab",
|
|
151
|
+
"aria-selected": selected,
|
|
152
|
+
className: `login-page__tab ${selected ? "login-page__tab--active" : ""}`,
|
|
153
|
+
"data-login-part": "tab",
|
|
154
|
+
"data-login-method-id": method.id,
|
|
155
|
+
"data-active": selected ? "true" : "false",
|
|
156
|
+
onClick: () => handleMethodChange(method.id),
|
|
157
|
+
children: [
|
|
158
|
+
method.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "login-page__tab-icon", "data-login-part": "tab-icon", children: method.icon }) : null,
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: method.label })
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
method.id
|
|
163
|
+
);
|
|
164
|
+
}) }) : null,
|
|
165
|
+
activeMethod ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
166
|
+
"form",
|
|
167
|
+
{
|
|
168
|
+
className: "login-page__form-fields",
|
|
169
|
+
"data-login-part": "form",
|
|
170
|
+
"data-login-method-id": activeMethod.id,
|
|
171
|
+
onSubmit: activeMethod.onSubmit,
|
|
172
|
+
children: [
|
|
173
|
+
activeMethod.fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__field", "data-login-part": "field", "data-login-field-name": field.name, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
174
|
+
"input",
|
|
175
|
+
{
|
|
176
|
+
id: field.id,
|
|
177
|
+
name: field.name,
|
|
178
|
+
type: field.type ?? "text",
|
|
179
|
+
value: field.value,
|
|
180
|
+
placeholder: field.placeholder,
|
|
181
|
+
autoComplete: field.autoComplete,
|
|
182
|
+
inputMode: field.inputMode,
|
|
183
|
+
maxLength: field.maxLength,
|
|
184
|
+
pattern: field.pattern,
|
|
185
|
+
disabled: activeMethod.disabled || activeMethod.isLoading || field.disabled,
|
|
186
|
+
required: field.required,
|
|
187
|
+
className: "login-page__input",
|
|
188
|
+
"data-login-part": "input",
|
|
189
|
+
onChange: (event) => field.onChange(event.target.value)
|
|
190
|
+
}
|
|
191
|
+
) }, field.name)),
|
|
192
|
+
activeMethod.checkbox ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "login-page__remember", "data-login-part": "checkbox-label", htmlFor: activeMethod.checkbox.id, children: [
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
194
|
+
"input",
|
|
195
|
+
{
|
|
196
|
+
id: activeMethod.checkbox.id,
|
|
197
|
+
type: "checkbox",
|
|
198
|
+
className: "login-page__checkbox",
|
|
199
|
+
"data-login-part": "checkbox",
|
|
200
|
+
checked: activeMethod.checkbox.checked,
|
|
201
|
+
disabled: activeMethod.disabled || activeMethod.isLoading || activeMethod.checkbox.disabled,
|
|
202
|
+
onChange: (event) => activeMethod.checkbox?.onChange(event.target.checked)
|
|
203
|
+
}
|
|
204
|
+
),
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: activeMethod.checkbox.label })
|
|
206
|
+
] }) : null,
|
|
207
|
+
activeMethod.footer || activeMethod.footerAction ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "login-page__method-footer", "data-login-part": "method-footer", children: [
|
|
208
|
+
activeMethod.footer,
|
|
209
|
+
activeMethod.footerAction ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
210
|
+
"button",
|
|
211
|
+
{
|
|
212
|
+
type: "button",
|
|
213
|
+
className: "login-page__method-footer-action",
|
|
214
|
+
"data-login-part": "method-footer-action",
|
|
215
|
+
"data-login-method-id": activeMethod.id,
|
|
216
|
+
onClick: activeMethod.footerAction.onClick,
|
|
217
|
+
disabled: activeMethod.disabled || activeMethod.isLoading || activeMethod.footerAction.disabled,
|
|
218
|
+
children: activeMethod.footerAction.label
|
|
219
|
+
}
|
|
220
|
+
) : null
|
|
221
|
+
] }) : null,
|
|
222
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
223
|
+
"button",
|
|
224
|
+
{
|
|
225
|
+
type: "submit",
|
|
226
|
+
className: "login-page__submit",
|
|
227
|
+
"data-login-part": "submit-button",
|
|
228
|
+
disabled: activeMethod.disabled || activeMethod.isLoading,
|
|
229
|
+
children: activeMethod.isLoading && activeMethod.loadingLabel ? activeMethod.loadingLabel : activeMethod.submitLabel
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
) : null,
|
|
235
|
+
callout ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
236
|
+
"div",
|
|
237
|
+
{
|
|
238
|
+
className: `login-page__callout login-page__callout--${callout.tone ?? "info"}`,
|
|
239
|
+
"data-login-part": "callout",
|
|
240
|
+
"data-tone": callout.tone ?? "info",
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__callout-title", "data-login-part": "callout-title", children: callout.title }),
|
|
243
|
+
callout.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "login-page__callout-description", "data-login-part": "callout-description", children: callout.description }) : null,
|
|
244
|
+
callout.detail ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "login-page__callout-detail", "data-login-part": "callout-detail", children: callout.detail }) : null,
|
|
245
|
+
callout.action ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
246
|
+
"button",
|
|
247
|
+
{
|
|
248
|
+
type: "button",
|
|
249
|
+
className: "login-page__callout-action",
|
|
250
|
+
"data-login-part": "callout-action",
|
|
251
|
+
onClick: callout.action.onClick,
|
|
252
|
+
disabled: callout.action.disabled,
|
|
253
|
+
children: callout.action.label
|
|
254
|
+
}
|
|
255
|
+
) : null
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
) : null,
|
|
259
|
+
externalMethods.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "login-page__oauth-section", "data-login-part": "external-methods", children: [
|
|
260
|
+
externalLabel ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__oauth-label", "data-login-part": "external-label", children: externalLabel }) : null,
|
|
261
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "login-page__oauth-list", "data-login-part": "external-list", children: externalMethods.map(renderExternalMethod) })
|
|
262
|
+
] }) : null
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
11
270
|
var containerStyle = {
|
|
12
271
|
display: "flex",
|
|
13
272
|
alignItems: "center",
|
|
@@ -308,6 +567,7 @@ var PendingApproval = ({
|
|
|
308
567
|
exports.AuthDivider = AuthDivider;
|
|
309
568
|
exports.EmailAuth = EmailAuth;
|
|
310
569
|
exports.LoginLayout = LoginLayout;
|
|
570
|
+
exports.LoginPage = LoginPage;
|
|
311
571
|
exports.OAuthButton = OAuthButton;
|
|
312
572
|
exports.OIDCButton = OIDCButton;
|
|
313
573
|
exports.PendingApproval = PendingApproval;
|