@descope/web-components-ui 1.0.312 → 1.0.314
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/cjs/index.cjs.js +209 -29
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/index.esm.js +231 -63
- package/dist/index.esm.js.map +1 -1
- package/dist/umd/4978.js +1 -1
- package/dist/umd/DescopeDev.js +1 -1
- package/dist/umd/descope-divider-index-js.js +1 -1
- package/dist/umd/descope-enriched-text-index-js.js +1 -1
- package/dist/umd/descope-link-index-js.js +1 -1
- package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -1
- package/dist/umd/descope-new-password-index-js.js +1 -1
- package/dist/umd/descope-password-index-js.js +1 -1
- package/dist/umd/descope-text-index-js.js +1 -1
- package/dist/umd/descope-user-attribute-index-js.js +1 -1
- package/dist/umd/descope-user-auth-method-index-js.js +1 -1
- package/dist/umd/mapping-fields-descope-mappings-field-index-js.js +1 -1
- package/dist/umd/mapping-fields-descope-saml-group-mappings-index-js.js +1 -1
- package/package.json +1 -1
- package/src/components/descope-enriched-text/EnrichedTextClass.js +1 -0
- package/src/components/descope-link/LinkClass.js +1 -0
- package/src/components/descope-new-password/NewPasswordClass.js +27 -1
- package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +18 -30
- package/src/components/descope-password/PasswordClass.js +92 -15
- package/src/components/descope-password/helpers.js +62 -0
- package/src/components/descope-password/passwordDraggableMixin.js +16 -11
- package/src/components/descope-text/TextClass.js +1 -0
- package/src/mixins/inputValidationMixin.js +12 -1
@@ -6,16 +6,86 @@ import {
|
|
6
6
|
componentNameValidationMixin,
|
7
7
|
} from '../../mixins';
|
8
8
|
import { compose } from '../../helpers';
|
9
|
-
import { getComponentName } from '../../helpers/componentHelpers';
|
9
|
+
import { getComponentName, syncAttrs } from '../../helpers/componentHelpers';
|
10
10
|
import passwordDraggableMixin from './passwordDraggableMixin';
|
11
11
|
import {
|
12
12
|
resetInputLabelPosition,
|
13
13
|
resetInputCursor,
|
14
14
|
useHostExternalPadding,
|
15
15
|
} from '../../helpers/themeHelpers/resetHelpers';
|
16
|
+
import {
|
17
|
+
applyExternalInputStyles,
|
18
|
+
createExternalInputEle,
|
19
|
+
createExternalInputSlot,
|
20
|
+
} from './helpers';
|
16
21
|
|
17
22
|
export const componentName = getComponentName('password');
|
18
23
|
|
24
|
+
const customMixin = (superclass) =>
|
25
|
+
class PasswordFieldMixinClass extends superclass {
|
26
|
+
init() {
|
27
|
+
super.init?.();
|
28
|
+
|
29
|
+
// reset vaadin's checkValidity
|
30
|
+
this.baseElement.checkValidity = () => {};
|
31
|
+
// set safety attribute `external-input`
|
32
|
+
this.setAttribute('external-input', 'true');
|
33
|
+
|
34
|
+
// use original input element as reference
|
35
|
+
const origInput = this.baseElement.querySelector('input');
|
36
|
+
|
37
|
+
// create external slot
|
38
|
+
const externalInputSlot = createExternalInputSlot('external-input', 'suffix');
|
39
|
+
// append external slot to base element
|
40
|
+
this.baseElement.appendChild(externalInputSlot);
|
41
|
+
|
42
|
+
// create external input
|
43
|
+
const externalInput = createExternalInputEle('external-input', this.getAutocompleteType());
|
44
|
+
|
45
|
+
// apply original input's styles to external input
|
46
|
+
setTimeout(() => {
|
47
|
+
applyExternalInputStyles(origInput, externalInput);
|
48
|
+
});
|
49
|
+
|
50
|
+
// set external input events
|
51
|
+
this.handleExternalInputEvents(externalInput);
|
52
|
+
|
53
|
+
// sync input stateful attributes: `type` (for visibility state change) and `readonly`
|
54
|
+
syncAttrs(origInput, externalInput, { includeAttrs: ['type', 'readonly'] });
|
55
|
+
|
56
|
+
origInput.addEventListener('focus', (e) => {
|
57
|
+
e.preventDefault();
|
58
|
+
if (e.isTrusted) {
|
59
|
+
externalInput.focus();
|
60
|
+
}
|
61
|
+
});
|
62
|
+
|
63
|
+
this.addEventListener('focus', (e) => {
|
64
|
+
e.preventDefault();
|
65
|
+
this.focus();
|
66
|
+
});
|
67
|
+
|
68
|
+
// append external input to component's DOM
|
69
|
+
this.appendChild(externalInput);
|
70
|
+
}
|
71
|
+
|
72
|
+
getAutocompleteType() {
|
73
|
+
return this.getAttribute('autocomplete') || 'current-password';
|
74
|
+
}
|
75
|
+
|
76
|
+
handleExternalInputEvents(inputEle) {
|
77
|
+
// sync value of insible input back to original input
|
78
|
+
inputEle.addEventListener('input', (e) => {
|
79
|
+
this.value = e.target.value;
|
80
|
+
});
|
81
|
+
|
82
|
+
// sync `focused` attribute on host when focusing on external input
|
83
|
+
inputEle.addEventListener('focus', () => {
|
84
|
+
this.setAttribute('focused', 'true');
|
85
|
+
});
|
86
|
+
}
|
87
|
+
};
|
88
|
+
|
19
89
|
const {
|
20
90
|
host,
|
21
91
|
inputField,
|
@@ -31,9 +101,9 @@ const {
|
|
31
101
|
host: { selector: () => ':host' },
|
32
102
|
inputField: { selector: '::part(input-field)' },
|
33
103
|
inputElement: { selector: '> input' },
|
34
|
-
inputElementPlaceholder: { selector: '
|
35
|
-
revealButtonContainer: { selector:
|
36
|
-
revealButtonIcon: { selector:
|
104
|
+
inputElementPlaceholder: { selector: () => ':host input:placeholder-shown' },
|
105
|
+
revealButtonContainer: { selector: '::part(reveal-button)' },
|
106
|
+
revealButtonIcon: { selector: '::part(reveal-button)::before' },
|
37
107
|
label: { selector: '::part(label)' },
|
38
108
|
requiredIndicator: { selector: '[required]::part(required-indicator)::after' },
|
39
109
|
helperText: { selector: '::part(helper-text)' },
|
@@ -72,8 +142,14 @@ export const PasswordClass = compose(
|
|
72
142
|
labelRequiredIndicator: { ...requiredIndicator, property: 'content' },
|
73
143
|
errorMessageTextColor: { ...errorMessage, property: 'color' },
|
74
144
|
|
75
|
-
|
76
|
-
|
145
|
+
inputPlaceholderTextColor: [
|
146
|
+
{ ...inputElementPlaceholder, property: 'color' },
|
147
|
+
{ selector: () => ':host ::slotted(input:placeholder-shown)', property: 'color' },
|
148
|
+
],
|
149
|
+
inputValueTextColor: [
|
150
|
+
{ ...inputElement, property: 'color' },
|
151
|
+
{ selector: () => ':host ::slotted(input)', property: 'color' },
|
152
|
+
],
|
77
153
|
|
78
154
|
revealButtonOffset: [
|
79
155
|
{ ...revealButtonContainer, property: 'margin-right' },
|
@@ -86,7 +162,8 @@ export const PasswordClass = compose(
|
|
86
162
|
draggableMixin,
|
87
163
|
proxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
|
88
164
|
componentNameValidationMixin,
|
89
|
-
passwordDraggableMixin
|
165
|
+
passwordDraggableMixin,
|
166
|
+
customMixin
|
90
167
|
)(
|
91
168
|
createProxy({
|
92
169
|
slots: ['', 'suffix'],
|
@@ -97,6 +174,7 @@ export const PasswordClass = compose(
|
|
97
174
|
max-width: 100%;
|
98
175
|
min-width: 10em;
|
99
176
|
box-sizing: border-box;
|
177
|
+
position: relative;
|
100
178
|
}
|
101
179
|
${useHostExternalPadding(PasswordClass.cssVarList)}
|
102
180
|
${resetInputCursor('vaadin-password-field')}
|
@@ -108,7 +186,9 @@ export const PasswordClass = compose(
|
|
108
186
|
padding: 0;
|
109
187
|
}
|
110
188
|
vaadin-password-field > input {
|
189
|
+
-webkit-mask-image: none;
|
111
190
|
box-sizing: border-box;
|
191
|
+
opacity: 1;
|
112
192
|
}
|
113
193
|
vaadin-password-field::part(input-field) {
|
114
194
|
box-sizing: border-box;
|
@@ -117,12 +197,11 @@ export const PasswordClass = compose(
|
|
117
197
|
vaadin-password-field[focus-ring]::part(input-field) {
|
118
198
|
box-shadow: none;
|
119
199
|
}
|
120
|
-
|
200
|
+
:host ::slotted(input) {
|
121
201
|
min-height: 0;
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
opacity: 1;
|
202
|
+
}
|
203
|
+
:host([readonly]) ::slotted(input:placeholder-shown) {
|
204
|
+
opacity: 0;
|
126
205
|
}
|
127
206
|
vaadin-password-field::before {
|
128
207
|
height: initial;
|
@@ -133,11 +212,9 @@ export const PasswordClass = compose(
|
|
133
212
|
vaadin-password-field-button {
|
134
213
|
cursor: pointer;
|
135
214
|
}
|
136
|
-
|
137
|
-
[readonly] vaadin-password-field-button {
|
215
|
+
:host([readonly]) vaadin-password-field-button {
|
138
216
|
pointer-events: none;
|
139
217
|
}
|
140
|
-
|
141
218
|
vaadin-password-field-button[focus-ring] {
|
142
219
|
box-shadow: 0 0 0 2px var(${PasswordClass.cssVarList.inputOutlineColor});
|
143
220
|
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
// since on load we can only sample the color of the placeholder,
|
2
|
+
// we need to temporarily populate the input in order to sample the value color
|
3
|
+
const getValueColor = (ele, computedStyle) => {
|
4
|
+
// eslint-disable-next-line no-param-reassign
|
5
|
+
ele.value = '_';
|
6
|
+
|
7
|
+
const valueColor = computedStyle.getPropertyValue('color');
|
8
|
+
|
9
|
+
// eslint-disable-next-line no-param-reassign
|
10
|
+
ele.value = '';
|
11
|
+
|
12
|
+
return valueColor;
|
13
|
+
};
|
14
|
+
|
15
|
+
export const createExternalInputSlot = (slotName, targetSlotName) => {
|
16
|
+
const slotEle = document.createElement('slot');
|
17
|
+
|
18
|
+
slotEle.setAttribute('name', slotName);
|
19
|
+
slotEle.setAttribute('slot', targetSlotName);
|
20
|
+
|
21
|
+
return slotEle;
|
22
|
+
};
|
23
|
+
|
24
|
+
export const createExternalInputEle = (targetSlotName, autocompleteType) => {
|
25
|
+
const inputEle = document.createElement('input');
|
26
|
+
|
27
|
+
inputEle.setAttribute('slot', targetSlotName);
|
28
|
+
inputEle.setAttribute('type', 'password');
|
29
|
+
inputEle.setAttribute('data-hidden-input', 'true');
|
30
|
+
inputEle.setAttribute('autocomplete', autocompleteType);
|
31
|
+
|
32
|
+
return inputEle;
|
33
|
+
};
|
34
|
+
|
35
|
+
export const applyExternalInputStyles = (sourceInputEle, targetInputEle) => {
|
36
|
+
const computedStyle = getComputedStyle(sourceInputEle);
|
37
|
+
const height = computedStyle.getPropertyValue('height');
|
38
|
+
const paddingLeft = computedStyle.getPropertyValue('padding-left');
|
39
|
+
const paddingRight = computedStyle.getPropertyValue('padding-right');
|
40
|
+
const fontSize = computedStyle.getPropertyValue('font-size');
|
41
|
+
const fontFamily = computedStyle.getPropertyValue('font-family');
|
42
|
+
const letterSpacing = computedStyle.getPropertyValue('letter-spacing');
|
43
|
+
const caretColor = computedStyle.getPropertyValue('caret-color');
|
44
|
+
const valueColor = getValueColor(sourceInputEle, computedStyle);
|
45
|
+
|
46
|
+
// set external input style (and lock it with `all: unset` and `!important` all around)
|
47
|
+
// eslint-disable-next-line no-param-reassign
|
48
|
+
targetInputEle.style = `
|
49
|
+
all: unset !important;
|
50
|
+
position: absolute !important;
|
51
|
+
width: calc(100% - 3em) !important;
|
52
|
+
background-color: transparent !important;
|
53
|
+
color: ${valueColor} !important;
|
54
|
+
height: ${height} !important;
|
55
|
+
left: ${paddingLeft} !important;
|
56
|
+
right: ${paddingRight} !important;
|
57
|
+
font-size: ${fontSize} !important;
|
58
|
+
font-family: ${fontFamily} !important;
|
59
|
+
letter-spacing: ${letterSpacing} !important;
|
60
|
+
caret-color: ${caretColor} !important;
|
61
|
+
`;
|
62
|
+
};
|
@@ -8,27 +8,32 @@ const passwordDraggableMixin = (superclass) =>
|
|
8
8
|
// there is an issue in Chrome that input field with type password cannot be D&D
|
9
9
|
// so in case the input is draggable & readonly, we are changing the input type to "text" before dragging
|
10
10
|
// and return the original type when done
|
11
|
-
|
11
|
+
super.init?.();
|
12
|
+
|
13
|
+
const ele = this.querySelector('input');
|
14
|
+
|
15
|
+
ele?.addEventListener('mousedown', (e) => {
|
12
16
|
if (this.isDraggable && this.isReadOnly) {
|
13
|
-
|
14
|
-
const prevType = inputEle.getAttribute('type');
|
17
|
+
ele.setAttribute('inert', 'true');
|
15
18
|
|
19
|
+
const inputEle = e.target;
|
20
|
+
const prevType = inputEle.getAttribute('type');
|
16
21
|
inputEle.setAttribute('type', 'text');
|
17
|
-
setTimeout(() =>
|
22
|
+
setTimeout(() => {
|
23
|
+
inputEle.focus();
|
24
|
+
});
|
18
25
|
|
19
26
|
const onComplete = (_) => {
|
20
27
|
inputEle.setAttribute('type', prevType);
|
21
|
-
|
22
|
-
|
23
|
-
|
28
|
+
ele.removeAttribute('inert');
|
29
|
+
this.removeEventListener('mouseup', onComplete);
|
30
|
+
this.removeEventListener('dragend', onComplete);
|
24
31
|
};
|
25
32
|
|
26
|
-
|
27
|
-
|
33
|
+
this.addEventListener('dragend', onComplete, { once: true });
|
34
|
+
this.addEventListener('mouseup', onComplete, { once: true });
|
28
35
|
}
|
29
36
|
});
|
30
|
-
|
31
|
-
super.init?.();
|
32
37
|
}
|
33
38
|
};
|
34
39
|
|
@@ -8,8 +8,13 @@ const errorAttributes = {
|
|
8
8
|
tooShort: 'data-errormessage-pattern-mismatch-too-short',
|
9
9
|
tooLong: 'data-errormessage-pattern-mismatch-too-long',
|
10
10
|
};
|
11
|
+
|
12
|
+
const validationTargetSymbol = Symbol('validationTarget');
|
13
|
+
|
11
14
|
export const inputValidationMixin = (superclass) =>
|
12
15
|
class InputValidationMixinClass extends superclass {
|
16
|
+
#validationTarget = validationTargetSymbol;
|
17
|
+
|
13
18
|
static get observedAttributes() {
|
14
19
|
return [...(superclass.observedAttributes || []), ...observedAttributes];
|
15
20
|
}
|
@@ -126,7 +131,13 @@ export const inputValidationMixin = (superclass) =>
|
|
126
131
|
}
|
127
132
|
|
128
133
|
get validationTarget() {
|
129
|
-
return this
|
134
|
+
return this.#validationTarget === validationTargetSymbol
|
135
|
+
? this.inputElement
|
136
|
+
: this.#validationTarget;
|
137
|
+
}
|
138
|
+
|
139
|
+
set validationTarget(val) {
|
140
|
+
this.#validationTarget = val;
|
130
141
|
}
|
131
142
|
|
132
143
|
setCustomValidity(errorMessage) {
|