@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.
Files changed (27) hide show
  1. package/dist/cjs/index.cjs.js +209 -29
  2. package/dist/cjs/index.cjs.js.map +1 -1
  3. package/dist/index.esm.js +231 -63
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/umd/4978.js +1 -1
  6. package/dist/umd/DescopeDev.js +1 -1
  7. package/dist/umd/descope-divider-index-js.js +1 -1
  8. package/dist/umd/descope-enriched-text-index-js.js +1 -1
  9. package/dist/umd/descope-link-index-js.js +1 -1
  10. package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -1
  11. package/dist/umd/descope-new-password-index-js.js +1 -1
  12. package/dist/umd/descope-password-index-js.js +1 -1
  13. package/dist/umd/descope-text-index-js.js +1 -1
  14. package/dist/umd/descope-user-attribute-index-js.js +1 -1
  15. package/dist/umd/descope-user-auth-method-index-js.js +1 -1
  16. package/dist/umd/mapping-fields-descope-mappings-field-index-js.js +1 -1
  17. package/dist/umd/mapping-fields-descope-saml-group-mappings-index-js.js +1 -1
  18. package/package.json +1 -1
  19. package/src/components/descope-enriched-text/EnrichedTextClass.js +1 -0
  20. package/src/components/descope-link/LinkClass.js +1 -0
  21. package/src/components/descope-new-password/NewPasswordClass.js +27 -1
  22. package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +18 -30
  23. package/src/components/descope-password/PasswordClass.js +92 -15
  24. package/src/components/descope-password/helpers.js +62 -0
  25. package/src/components/descope-password/passwordDraggableMixin.js +16 -11
  26. package/src/components/descope-text/TextClass.js +1 -0
  27. 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: '> input:placeholder-shown' },
35
- revealButtonContainer: { selector: () => '::part(reveal-button)' },
36
- revealButtonIcon: { selector: () => '::part(reveal-button)::before' },
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
- inputValueTextColor: { ...inputElement, property: 'color' },
76
- inputPlaceholderTextColor: { ...inputElementPlaceholder, property: 'color' },
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
- vaadin-password-field > input {
200
+ :host ::slotted(input) {
121
201
  min-height: 0;
122
- -webkit-mask-image: none;
123
- }
124
- vaadin-password-field[readonly] > input:placeholder-shown {
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
- this.addEventListener('mousedown', (e) => {
11
+ super.init?.();
12
+
13
+ const ele = this.querySelector('input');
14
+
15
+ ele?.addEventListener('mousedown', (e) => {
12
16
  if (this.isDraggable && this.isReadOnly) {
13
- const inputEle = this.baseElement.querySelector('input');
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(() => inputEle.focus());
22
+ setTimeout(() => {
23
+ inputEle.focus();
24
+ });
18
25
 
19
26
  const onComplete = (_) => {
20
27
  inputEle.setAttribute('type', prevType);
21
-
22
- e.target.removeEventListener('mouseup', onComplete);
23
- e.target.removeEventListener('dragend', onComplete);
28
+ ele.removeAttribute('inert');
29
+ this.removeEventListener('mouseup', onComplete);
30
+ this.removeEventListener('dragend', onComplete);
24
31
  };
25
32
 
26
- e.target.addEventListener('mouseup', onComplete, { once: true });
27
- e.target.addEventListener('dragend', onComplete, { once: true });
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
 
@@ -13,6 +13,7 @@ class RawText extends createBaseClass({ componentName, baseSelector: ':host > sl
13
13
  <style>
14
14
  :host {
15
15
  display: inline-block;
16
+ line-height: 1em;
16
17
  }
17
18
  :host > slot {
18
19
  width: 100%;
@@ -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.inputElement;
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) {