@vaadin/login 24.2.0-dev.e9803eea7 → 24.2.0-rc1
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/package.json +17 -11
- package/src/vaadin-login-form-mixin.d.ts +18 -0
- package/src/vaadin-login-form-mixin.js +127 -0
- package/src/vaadin-login-form-wrapper-styles.d.ts +8 -0
- package/src/vaadin-login-form-wrapper-styles.js +32 -0
- package/src/vaadin-login-form-wrapper.js +13 -27
- package/src/vaadin-login-form.d.ts +2 -4
- package/src/vaadin-login-form.js +12 -91
- package/src/vaadin-login-overlay-mixin.d.ts +29 -0
- package/src/vaadin-login-overlay-mixin.js +167 -0
- package/src/vaadin-login-overlay-wrapper-styles.d.ts +8 -0
- package/src/vaadin-login-overlay-wrapper-styles.js +35 -0
- package/src/vaadin-login-overlay-wrapper.js +30 -64
- package/src/vaadin-login-overlay.d.ts +8 -19
- package/src/vaadin-login-overlay.js +11 -137
- package/theme/lumo/vaadin-login-form-wrapper-styles.js +5 -0
- package/theme/lumo/vaadin-login-form.js +0 -1
- package/theme/lumo/vaadin-login-overlay-styles.js +3 -2
- package/theme/lumo/vaadin-login-overlay.js +0 -1
- package/theme/material/vaadin-login-form-wrapper-styles.js +13 -1
- package/theme/material/vaadin-login-form.js +0 -1
- package/theme/material/vaadin-login-overlay-styles.js +1 -4
- package/theme/material/vaadin-login-overlay.js +0 -1
- package/web-types.json +372 -0
- package/web-types.lit.json +209 -0
- package/theme/lumo/vaadin-login-form-styles.js +0 -13
- package/theme/material/vaadin-login-form-styles.js +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/login",
|
|
3
|
-
"version": "24.2.0-
|
|
3
|
+
"version": "24.2.0-rc1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"type": "module",
|
|
22
22
|
"files": [
|
|
23
23
|
"src",
|
|
24
|
+
"!src/vaadin-lit-login-form-wrapper.js",
|
|
25
|
+
"!src/vaadin-lit-login-form.d.ts",
|
|
26
|
+
"!src/vaadin-lit-login-form.js",
|
|
27
|
+
"!src/vaadin-lit-login-overlay-wrapper.js",
|
|
28
|
+
"!src/vaadin-lit-login-overlay.d.ts",
|
|
29
|
+
"!src/vaadin-lit-login-overlay.js",
|
|
24
30
|
"theme",
|
|
25
31
|
"vaadin-*.d.ts",
|
|
26
32
|
"vaadin-*.js",
|
|
@@ -37,23 +43,23 @@
|
|
|
37
43
|
"dependencies": {
|
|
38
44
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
39
45
|
"@polymer/polymer": "^3.0.0",
|
|
40
|
-
"@vaadin/button": "24.2.0-
|
|
41
|
-
"@vaadin/component-base": "24.2.0-
|
|
42
|
-
"@vaadin/overlay": "24.2.0-
|
|
43
|
-
"@vaadin/password-field": "24.2.0-
|
|
44
|
-
"@vaadin/text-field": "24.2.0-
|
|
45
|
-
"@vaadin/vaadin-lumo-styles": "24.2.0-
|
|
46
|
-
"@vaadin/vaadin-material-styles": "24.2.0-
|
|
47
|
-
"@vaadin/vaadin-themable-mixin": "24.2.0-
|
|
46
|
+
"@vaadin/button": "24.2.0-rc1",
|
|
47
|
+
"@vaadin/component-base": "24.2.0-rc1",
|
|
48
|
+
"@vaadin/overlay": "24.2.0-rc1",
|
|
49
|
+
"@vaadin/password-field": "24.2.0-rc1",
|
|
50
|
+
"@vaadin/text-field": "24.2.0-rc1",
|
|
51
|
+
"@vaadin/vaadin-lumo-styles": "24.2.0-rc1",
|
|
52
|
+
"@vaadin/vaadin-material-styles": "24.2.0-rc1",
|
|
53
|
+
"@vaadin/vaadin-themable-mixin": "24.2.0-rc1"
|
|
48
54
|
},
|
|
49
55
|
"devDependencies": {
|
|
50
56
|
"@esm-bundle/chai": "^4.3.4",
|
|
51
|
-
"@vaadin/testing-helpers": "^0.
|
|
57
|
+
"@vaadin/testing-helpers": "^0.5.0",
|
|
52
58
|
"sinon": "^13.0.2"
|
|
53
59
|
},
|
|
54
60
|
"web-types": [
|
|
55
61
|
"web-types.json",
|
|
56
62
|
"web-types.lit.json"
|
|
57
63
|
],
|
|
58
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "012bef350bbf29865748f4c78338dd17c6f61a74"
|
|
59
65
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2018 - 2023 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
+
import type { LoginMixinClass } from './vaadin-login-mixin.js';
|
|
8
|
+
|
|
9
|
+
export declare function LoginFormMixin<T extends Constructor<HTMLElement>>(
|
|
10
|
+
base: T,
|
|
11
|
+
): Constructor<LoginFormMixinClass> & Constructor<LoginMixinClass> & T;
|
|
12
|
+
|
|
13
|
+
export declare class LoginFormMixinClass {
|
|
14
|
+
/**
|
|
15
|
+
* Submits the form.
|
|
16
|
+
*/
|
|
17
|
+
submit(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2018 - 2023 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { LoginMixin } from './vaadin-login-mixin.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @polymerMixin
|
|
10
|
+
* @mixes LoginMixin
|
|
11
|
+
*/
|
|
12
|
+
export const LoginFormMixin = (superClass) =>
|
|
13
|
+
class LoginFormMixin extends LoginMixin(superClass) {
|
|
14
|
+
static get observers() {
|
|
15
|
+
return ['_errorChanged(error)'];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get _customFields() {
|
|
19
|
+
return [...this.$.vaadinLoginFormWrapper.children].filter((node) => {
|
|
20
|
+
return node.getAttribute('slot') === 'custom-form-area' && node.hasAttribute('name');
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** @protected */
|
|
25
|
+
async connectedCallback() {
|
|
26
|
+
super.connectedCallback();
|
|
27
|
+
|
|
28
|
+
if (!this.noAutofocus) {
|
|
29
|
+
// Wait for the form to fully render.
|
|
30
|
+
await new Promise(requestAnimationFrame);
|
|
31
|
+
this.$.vaadinLoginUsername.focus();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @private */
|
|
36
|
+
_errorChanged() {
|
|
37
|
+
if (this.error && !this._preventAutoEnable) {
|
|
38
|
+
this.disabled = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Submits the form.
|
|
44
|
+
*/
|
|
45
|
+
submit() {
|
|
46
|
+
const userName = this.$.vaadinLoginUsername;
|
|
47
|
+
const password = this.$.vaadinLoginPassword;
|
|
48
|
+
|
|
49
|
+
if (this.disabled || !(userName.validate() && password.validate())) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.error = false;
|
|
54
|
+
this.disabled = true;
|
|
55
|
+
|
|
56
|
+
const detail = {
|
|
57
|
+
username: userName.value,
|
|
58
|
+
password: password.value,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const fields = this._customFields;
|
|
62
|
+
if (fields.length) {
|
|
63
|
+
detail.custom = {};
|
|
64
|
+
|
|
65
|
+
fields.forEach((field) => {
|
|
66
|
+
detail.custom[field.name] = field.value;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const loginEventDetails = {
|
|
71
|
+
bubbles: true,
|
|
72
|
+
cancelable: true,
|
|
73
|
+
detail,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const firedEvent = this.dispatchEvent(new CustomEvent('login', loginEventDetails));
|
|
77
|
+
if (this.action && firedEvent) {
|
|
78
|
+
const csrfMetaName = document.querySelector('meta[name=_csrf_parameter]');
|
|
79
|
+
const csrfMetaValue = document.querySelector('meta[name=_csrf]');
|
|
80
|
+
if (csrfMetaName && csrfMetaValue) {
|
|
81
|
+
this.$.csrf.name = csrfMetaName.content;
|
|
82
|
+
this.$.csrf.value = csrfMetaValue.content;
|
|
83
|
+
}
|
|
84
|
+
this.querySelector('form').submit();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** @protected */
|
|
89
|
+
_onFormData(event) {
|
|
90
|
+
const { formData } = event;
|
|
91
|
+
|
|
92
|
+
if (this._customFields.length) {
|
|
93
|
+
this._customFields.forEach((field) => {
|
|
94
|
+
formData.append(field.name, field.value);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @protected */
|
|
100
|
+
_handleInputKeydown(e) {
|
|
101
|
+
if (e.key === 'Enter') {
|
|
102
|
+
const { currentTarget: inputActive } = e;
|
|
103
|
+
const nextInput =
|
|
104
|
+
inputActive.id === 'vaadinLoginUsername' ? this.$.vaadinLoginPassword : this.$.vaadinLoginUsername;
|
|
105
|
+
if (inputActive.validate()) {
|
|
106
|
+
if (nextInput.checkValidity()) {
|
|
107
|
+
this.submit();
|
|
108
|
+
} else {
|
|
109
|
+
nextInput.focus();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** @protected */
|
|
116
|
+
_handleInputKeyup(e) {
|
|
117
|
+
const input = e.currentTarget;
|
|
118
|
+
if (e.key === 'Tab' && input instanceof HTMLInputElement) {
|
|
119
|
+
input.select();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @protected */
|
|
124
|
+
_onForgotPasswordClick() {
|
|
125
|
+
this.dispatchEvent(new CustomEvent('forgot-password'));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2018 - 2023 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { css } from 'lit';
|
|
7
|
+
|
|
8
|
+
export const loginFormWrapperStyles = css`
|
|
9
|
+
:host {
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
display: inline-block;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:host([hidden]) {
|
|
15
|
+
display: none !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[part='form'] {
|
|
19
|
+
flex: 1;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[part='form-title'] {
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
[part='error-message'] {
|
|
30
|
+
position: relative;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
7
|
-
import {
|
|
7
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
8
|
+
import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
9
|
+
import { loginFormWrapperStyles } from './vaadin-login-form-wrapper-styles.js';
|
|
10
|
+
|
|
11
|
+
registerStyles('vaadin-login-form-wrapper', loginFormWrapperStyles, {
|
|
12
|
+
moduleId: 'vaadin-login-form-wrapper-styles',
|
|
13
|
+
});
|
|
8
14
|
|
|
9
15
|
/**
|
|
10
16
|
* An element used internally by `<vaadin-login-form>`. Not intended to be used separately.
|
|
@@ -16,31 +22,6 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
16
22
|
class LoginFormWrapper extends ThemableMixin(PolymerElement) {
|
|
17
23
|
static get template() {
|
|
18
24
|
return html`
|
|
19
|
-
<style>
|
|
20
|
-
:host {
|
|
21
|
-
overflow: hidden;
|
|
22
|
-
display: inline-block;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
:host([hidden]) {
|
|
26
|
-
display: none !important;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
[part='form'] {
|
|
30
|
-
flex: 1;
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: column;
|
|
33
|
-
box-sizing: border-box;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
[part='form-title'] {
|
|
37
|
-
margin: 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
[part='error-message'] {
|
|
41
|
-
position: relative;
|
|
42
|
-
}
|
|
43
|
-
</style>
|
|
44
25
|
<section part="form">
|
|
45
26
|
<h2 part="form-title">[[i18n.form.title]]</h2>
|
|
46
27
|
<div part="error-message" hidden$="[[!error]]">
|
|
@@ -50,9 +31,14 @@ class LoginFormWrapper extends ThemableMixin(PolymerElement) {
|
|
|
50
31
|
|
|
51
32
|
<slot name="form"></slot>
|
|
52
33
|
|
|
34
|
+
<slot name="custom-form-area"></slot>
|
|
35
|
+
|
|
36
|
+
<slot name="submit"></slot>
|
|
37
|
+
|
|
53
38
|
<slot name="forgot-password"></slot>
|
|
54
39
|
|
|
55
40
|
<div part="footer">
|
|
41
|
+
<slot name="footer"></slot>
|
|
56
42
|
<p>[[i18n.additionalInformation]]</p>
|
|
57
43
|
</div>
|
|
58
44
|
</section>
|
|
@@ -86,6 +72,6 @@ class LoginFormWrapper extends ThemableMixin(PolymerElement) {
|
|
|
86
72
|
}
|
|
87
73
|
}
|
|
88
74
|
|
|
89
|
-
|
|
75
|
+
defineCustomElement(LoginFormWrapper);
|
|
90
76
|
|
|
91
77
|
export { LoginFormWrapper };
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
7
7
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
8
|
-
import {
|
|
8
|
+
import { LoginFormMixin } from './vaadin-login-form-mixin.js';
|
|
9
9
|
export { LoginI18n } from './vaadin-login-mixin.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -69,9 +69,7 @@ export interface LoginFormEventMap extends HTMLElementEventMap, LoginFormCustomE
|
|
|
69
69
|
* @fires {CustomEvent} forgot-password - Fired when user clicks on the "Forgot password" button.
|
|
70
70
|
* @fires {CustomEvent} login - Fired when a user submits the login.
|
|
71
71
|
*/
|
|
72
|
-
declare class LoginForm extends ElementMixin(ThemableMixin(
|
|
73
|
-
submit(): void;
|
|
74
|
-
|
|
72
|
+
declare class LoginForm extends LoginFormMixin(ElementMixin(ThemableMixin(HTMLElement))) {
|
|
75
73
|
addEventListener<K extends keyof LoginFormEventMap>(
|
|
76
74
|
type: K,
|
|
77
75
|
listener: (this: LoginForm, ev: LoginFormEventMap[K]) => void,
|
package/src/vaadin-login-form.js
CHANGED
|
@@ -8,9 +8,10 @@ import '@vaadin/text-field/src/vaadin-text-field.js';
|
|
|
8
8
|
import '@vaadin/password-field/src/vaadin-password-field.js';
|
|
9
9
|
import './vaadin-login-form-wrapper.js';
|
|
10
10
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
11
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
11
12
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
12
13
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
13
|
-
import {
|
|
14
|
+
import { LoginFormMixin } from './vaadin-login-form-mixin.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* `<vaadin-login-form>` is a Web Component providing an easy way to require users
|
|
@@ -46,12 +47,13 @@ import { LoginMixin } from './vaadin-login-mixin.js';
|
|
|
46
47
|
* @fires {CustomEvent} forgot-password - Fired when user clicks on the "Forgot password" button.
|
|
47
48
|
* @fires {CustomEvent} login - Fired when a user submits the login.
|
|
48
49
|
*
|
|
50
|
+
* @customElement
|
|
49
51
|
* @extends HTMLElement
|
|
50
52
|
* @mixes ElementMixin
|
|
51
53
|
* @mixes ThemableMixin
|
|
52
|
-
* @mixes
|
|
54
|
+
* @mixes LoginFormMixin
|
|
53
55
|
*/
|
|
54
|
-
class LoginForm extends
|
|
56
|
+
class LoginForm extends LoginFormMixin(ElementMixin(ThemableMixin(PolymerElement))) {
|
|
55
57
|
static get template() {
|
|
56
58
|
return html`
|
|
57
59
|
<style>
|
|
@@ -59,8 +61,8 @@ class LoginForm extends LoginMixin(ElementMixin(ThemableMixin(PolymerElement)))
|
|
|
59
61
|
width: 100%;
|
|
60
62
|
}
|
|
61
63
|
</style>
|
|
62
|
-
<vaadin-login-form-wrapper theme$="[[_theme]]" error="[[error]]" i18n="[[i18n]]">
|
|
63
|
-
<form method="POST" action$="[[action]]" slot="form">
|
|
64
|
+
<vaadin-login-form-wrapper id="vaadinLoginFormWrapper" theme$="[[_theme]]" error="[[error]]" i18n="[[i18n]]">
|
|
65
|
+
<form method="POST" action$="[[action]]" on-formdata="_onFormData" slot="form">
|
|
64
66
|
<input id="csrf" type="hidden" />
|
|
65
67
|
<vaadin-text-field
|
|
66
68
|
name="username"
|
|
@@ -89,12 +91,12 @@ class LoginForm extends LoginMixin(ElementMixin(ThemableMixin(PolymerElement)))
|
|
|
89
91
|
>
|
|
90
92
|
<input type="password" slot="input" on-keyup="_handleInputKeyup" />
|
|
91
93
|
</vaadin-password-field>
|
|
92
|
-
|
|
93
|
-
<vaadin-button theme="primary contained submit" on-click="submit" disabled$="[[disabled]]">
|
|
94
|
-
[[i18n.form.submit]]
|
|
95
|
-
</vaadin-button>
|
|
96
94
|
</form>
|
|
97
95
|
|
|
96
|
+
<vaadin-button slot="submit" theme="primary contained submit" on-click="submit" disabled$="[[disabled]]">
|
|
97
|
+
[[i18n.form.submit]]
|
|
98
|
+
</vaadin-button>
|
|
99
|
+
|
|
98
100
|
<vaadin-button
|
|
99
101
|
slot="forgot-password"
|
|
100
102
|
theme="tertiary small"
|
|
@@ -111,19 +113,6 @@ class LoginForm extends LoginMixin(ElementMixin(ThemableMixin(PolymerElement)))
|
|
|
111
113
|
return 'vaadin-login-form';
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
static get observers() {
|
|
115
|
-
return ['_errorChanged(error)'];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** @protected */
|
|
119
|
-
connectedCallback() {
|
|
120
|
-
super.connectedCallback();
|
|
121
|
-
|
|
122
|
-
if (!this.noAutofocus) {
|
|
123
|
-
this.$.vaadinLoginUsername.focus();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
116
|
/**
|
|
128
117
|
* @param {StampedTemplate} dom
|
|
129
118
|
* @return {null}
|
|
@@ -132,76 +121,8 @@ class LoginForm extends LoginMixin(ElementMixin(ThemableMixin(PolymerElement)))
|
|
|
132
121
|
_attachDom(dom) {
|
|
133
122
|
this.appendChild(dom);
|
|
134
123
|
}
|
|
135
|
-
|
|
136
|
-
/** @private */
|
|
137
|
-
_errorChanged() {
|
|
138
|
-
if (this.error && !this._preventAutoEnable) {
|
|
139
|
-
this.disabled = false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
submit() {
|
|
144
|
-
const userName = this.$.vaadinLoginUsername;
|
|
145
|
-
const password = this.$.vaadinLoginPassword;
|
|
146
|
-
|
|
147
|
-
if (this.disabled || !(userName.validate() && password.validate())) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.error = false;
|
|
152
|
-
this.disabled = true;
|
|
153
|
-
|
|
154
|
-
const loginEventDetails = {
|
|
155
|
-
bubbles: true,
|
|
156
|
-
cancelable: true,
|
|
157
|
-
detail: {
|
|
158
|
-
username: userName.value,
|
|
159
|
-
password: password.value,
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const firedEvent = this.dispatchEvent(new CustomEvent('login', loginEventDetails));
|
|
164
|
-
if (this.action && firedEvent) {
|
|
165
|
-
const csrfMetaName = document.querySelector('meta[name=_csrf_parameter]');
|
|
166
|
-
const csrfMetaValue = document.querySelector('meta[name=_csrf]');
|
|
167
|
-
if (csrfMetaName && csrfMetaValue) {
|
|
168
|
-
this.$.csrf.name = csrfMetaName.content;
|
|
169
|
-
this.$.csrf.value = csrfMetaValue.content;
|
|
170
|
-
}
|
|
171
|
-
this.querySelector('form').submit();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** @private */
|
|
176
|
-
_handleInputKeydown(e) {
|
|
177
|
-
if (e.key === 'Enter') {
|
|
178
|
-
const { currentTarget: inputActive } = e;
|
|
179
|
-
const nextInput =
|
|
180
|
-
inputActive.id === 'vaadinLoginUsername' ? this.$.vaadinLoginPassword : this.$.vaadinLoginUsername;
|
|
181
|
-
if (inputActive.validate()) {
|
|
182
|
-
if (nextInput.checkValidity()) {
|
|
183
|
-
this.submit();
|
|
184
|
-
} else {
|
|
185
|
-
nextInput.focus();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** @private */
|
|
192
|
-
_handleInputKeyup(e) {
|
|
193
|
-
const input = e.currentTarget;
|
|
194
|
-
if (e.key === 'Tab' && input instanceof HTMLInputElement) {
|
|
195
|
-
input.select();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/** @private */
|
|
200
|
-
_onForgotPasswordClick() {
|
|
201
|
-
this.dispatchEvent(new CustomEvent('forgot-password'));
|
|
202
|
-
}
|
|
203
124
|
}
|
|
204
125
|
|
|
205
|
-
|
|
126
|
+
defineCustomElement(LoginForm);
|
|
206
127
|
|
|
207
128
|
export { LoginForm };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2018 - 2023 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
+
import type { OverlayClassMixinClass } from '@vaadin/component-base/src/overlay-class-mixin.js';
|
|
8
|
+
import type { LoginMixinClass } from './vaadin-login-mixin.js';
|
|
9
|
+
|
|
10
|
+
export declare function LoginOverlayMixin<T extends Constructor<HTMLElement>>(
|
|
11
|
+
base: T,
|
|
12
|
+
): Constructor<LoginMixinClass> & Constructor<LoginOverlayMixinClass> & Constructor<OverlayClassMixinClass> & T;
|
|
13
|
+
|
|
14
|
+
export declare class LoginOverlayMixinClass {
|
|
15
|
+
/**
|
|
16
|
+
* Defines the application description
|
|
17
|
+
*/
|
|
18
|
+
description: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* True if the overlay is currently displayed.
|
|
22
|
+
*/
|
|
23
|
+
opened: boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Defines the application title
|
|
27
|
+
*/
|
|
28
|
+
title: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2018 - 2023 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
|
|
7
|
+
import { LoginMixin } from './vaadin-login-mixin.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @polymerMixin
|
|
11
|
+
* @mixes LoginMixin
|
|
12
|
+
* @mixes OverlayClassMixin
|
|
13
|
+
*/
|
|
14
|
+
export const LoginOverlayMixin = (superClass) =>
|
|
15
|
+
class LoginOverlayMixin extends OverlayClassMixin(LoginMixin(superClass)) {
|
|
16
|
+
static get properties() {
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* Defines the application description
|
|
20
|
+
* @type {string}
|
|
21
|
+
*/
|
|
22
|
+
description: {
|
|
23
|
+
type: String,
|
|
24
|
+
value: 'Application description',
|
|
25
|
+
notify: true,
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* True if the overlay is currently displayed.
|
|
30
|
+
* @type {boolean}
|
|
31
|
+
*/
|
|
32
|
+
opened: {
|
|
33
|
+
type: Boolean,
|
|
34
|
+
value: false,
|
|
35
|
+
observer: '_onOpenedChange',
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Defines the application title
|
|
40
|
+
* @type {string}
|
|
41
|
+
*/
|
|
42
|
+
title: {
|
|
43
|
+
type: String,
|
|
44
|
+
value: 'App name',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static get observers() {
|
|
50
|
+
return ['__i18nChanged(i18n)'];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @protected */
|
|
54
|
+
ready() {
|
|
55
|
+
super.ready();
|
|
56
|
+
|
|
57
|
+
this._overlayElement = this.$.vaadinLoginOverlayWrapper;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @protected */
|
|
61
|
+
connectedCallback() {
|
|
62
|
+
super.connectedCallback();
|
|
63
|
+
|
|
64
|
+
// Restore opened state if overlay was open when disconnecting
|
|
65
|
+
if (this.__restoreOpened) {
|
|
66
|
+
this.opened = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @protected */
|
|
71
|
+
disconnectedCallback() {
|
|
72
|
+
super.disconnectedCallback();
|
|
73
|
+
|
|
74
|
+
// Close overlay and memorize opened state
|
|
75
|
+
this.__restoreOpened = this.opened;
|
|
76
|
+
this.opened = false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @private */
|
|
80
|
+
__i18nChanged(i18n) {
|
|
81
|
+
const header = i18n && i18n.header;
|
|
82
|
+
if (!header) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.title = header.title;
|
|
86
|
+
this.description = header.description;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @protected */
|
|
90
|
+
_preventClosingLogin(e) {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {!Event} e
|
|
96
|
+
* @protected
|
|
97
|
+
*/
|
|
98
|
+
_retargetEvent(e) {
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
const { detail, composed, cancelable, bubbles } = e;
|
|
101
|
+
|
|
102
|
+
const firedEvent = this.dispatchEvent(new CustomEvent(e.type, { bubbles, cancelable, composed, detail }));
|
|
103
|
+
// Check if `eventTarget.preventDefault()` was called to prevent default in the original event
|
|
104
|
+
if (!firedEvent) {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** @private */
|
|
110
|
+
async _onOpenedChange() {
|
|
111
|
+
const form = this.$.vaadinLoginForm;
|
|
112
|
+
|
|
113
|
+
// Wait for initial render on overlay initialization
|
|
114
|
+
if (!form.$ && this.updateComplete) {
|
|
115
|
+
await this.updateComplete;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!this.opened) {
|
|
119
|
+
form.$.vaadinLoginUsername.value = '';
|
|
120
|
+
form.$.vaadinLoginPassword.value = '';
|
|
121
|
+
this.disabled = false;
|
|
122
|
+
|
|
123
|
+
if (this._undoTitleTeleport) {
|
|
124
|
+
this._undoTitleTeleport();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (this._undoFieldsTeleport) {
|
|
128
|
+
this._undoFieldsTeleport();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this._undoFooterTeleport) {
|
|
132
|
+
this._undoFooterTeleport();
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
this._undoTitleTeleport = this._teleport('title', this.$.vaadinLoginOverlayWrapper);
|
|
136
|
+
|
|
137
|
+
this._undoFieldsTeleport = this._teleport(
|
|
138
|
+
'custom-form-area',
|
|
139
|
+
form.$.vaadinLoginFormWrapper,
|
|
140
|
+
form.querySelector('vaadin-button'),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
this._undoFooterTeleport = this._teleport('footer', form.$.vaadinLoginFormWrapper);
|
|
144
|
+
|
|
145
|
+
// Overlay sets pointerEvents on body to `none`, which breaks LastPass popup
|
|
146
|
+
// Reverting it back to the previous state
|
|
147
|
+
// https://github.com/vaadin/vaadin-overlay/blob/041cde4481b6262eac68d3a699f700216d897373/src/vaadin-overlay.html#L660
|
|
148
|
+
document.body.style.pointerEvents = this.$.vaadinLoginOverlayWrapper._previousDocumentPointerEvents;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** @private */
|
|
153
|
+
_teleport(slot, target, refNode) {
|
|
154
|
+
const teleported = [...this.querySelectorAll(`[slot="${slot}"]`)].map((el) => {
|
|
155
|
+
if (refNode) {
|
|
156
|
+
target.insertBefore(el, refNode);
|
|
157
|
+
} else {
|
|
158
|
+
target.appendChild(el);
|
|
159
|
+
}
|
|
160
|
+
return el;
|
|
161
|
+
});
|
|
162
|
+
// Function to undo the teleport
|
|
163
|
+
return () => {
|
|
164
|
+
this.append(...teleported);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|