@descope/web-components-ui 1.0.312 → 1.0.314

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.
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) {