@descope/web-components-ui 1.0.79 → 1.0.80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/dist/index.esm.js +927 -566
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/umd/387.js +1 -0
  4. package/dist/umd/988.js +1 -1
  5. package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -0
  6. package/dist/umd/descope-new-password-index-js.js +1 -0
  7. package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -1
  8. package/dist/umd/descope-password-field-index-js.js +1 -1
  9. package/dist/umd/descope-phone-field-descope-phone-field-internal-index-js.js +1 -1
  10. package/dist/umd/descope-phone-field-index-js.js +1 -1
  11. package/dist/umd/index.js +1 -1
  12. package/package.json +1 -1
  13. package/src/components/descope-new-password/NewPassword.js +129 -0
  14. package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +189 -0
  15. package/src/components/descope-new-password/descope-new-password-internal/componentName.js +3 -0
  16. package/src/components/descope-new-password/descope-new-password-internal/index.js +4 -0
  17. package/src/components/descope-new-password/index.js +6 -0
  18. package/src/components/descope-passcode/descope-passcode-internal/PasscodeInternal.js +3 -0
  19. package/src/components/descope-password-field/PasswordField.js +35 -36
  20. package/src/components/descope-phone-field/PhoneField.js +3 -2
  21. package/src/components/descope-phone-field/descope-phone-field-internal/PhoneFieldInternal.js +3 -0
  22. package/src/index.js +1 -0
  23. package/src/mixins/createProxy.js +1 -23
  24. package/src/mixins/inputEventsDispatchingMixin.js +15 -15
  25. package/src/mixins/inputValidationMixin.js +6 -2
  26. package/src/mixins/proxyInputMixin.js +6 -36
  27. package/src/theme/components/index.js +3 -1
  28. package/src/theme/components/newPassword.js +48 -0
  29. package/src/theme/components/passwordField.js +55 -3
@@ -0,0 +1,4 @@
1
+ import NewPasswordInternal from "./NewPasswordInternal"
2
+ import { componentName } from "./componentName"
3
+
4
+ customElements.define(componentName, NewPasswordInternal)
@@ -0,0 +1,6 @@
1
+ import NewPassword, { componentName } from './NewPassword';
2
+ import '../descope-text-field'
3
+ import '../descope-password-field'
4
+ import './descope-new-password-internal'
5
+
6
+ customElements.define(componentName, NewPassword);
@@ -172,6 +172,9 @@ class PasscodeInternal extends BaseInputClass {
172
172
 
173
173
  forwardAttrs(this, input, { includeAttrs: forwardAttributes })
174
174
  })
175
+
176
+ this.handleFocusEventsDispatching(this.inputs);
177
+ this.handleInputEventDispatching();
175
178
  }
176
179
 
177
180
  attributeChangedCallback(attrName, oldValue, newValue) {
@@ -5,7 +5,6 @@ import {
5
5
  proxyInputMixin,
6
6
  componentNameValidationMixin
7
7
  } from '../../mixins';
8
- import textFieldMappings from '../descope-text-field/textFieldMappings';
9
8
  import { compose } from '../../helpers';
10
9
  import { getComponentName } from '../../helpers/componentHelpers';
11
10
 
@@ -13,16 +12,37 @@ export const componentName = getComponentName('password-field');
13
12
 
14
13
  let overrides = ``;
15
14
 
15
+ const { host, inputWrapper, inputElement, inputElementPlaceholder, revealButton, label, requiredIndicator } = {
16
+ host: () => ':host',
17
+ inputWrapper: { selector: '::part(input-field)' },
18
+ inputElement: { selector: '> input' },
19
+ inputElementPlaceholder: { selector: '> input:placeholder-shown' },
20
+ revealButton: { selector: 'vaadin-password-field-button' },
21
+ label: { selector: '> label' },
22
+ requiredIndicator: { selector: '::part(required-indicator)::after' },
23
+ }
24
+
16
25
  const PasswordField = compose(
17
26
  createStyleMixin({
18
27
  mappings: {
19
- ...textFieldMappings,
20
- revealCursor: [
21
- {
22
- selector: '::part(reveal-button)::before',
23
- property: 'cursor'
24
- }
25
- ]
28
+ wrapperBorderStyle: { ...inputWrapper, property: 'border-style' },
29
+ wrapperBorderWidth: { ...inputWrapper, property: 'border-width' },
30
+ wrapperBorderColor: { ...inputWrapper, property: 'border-color' },
31
+ wrapperBorderRadius: { ...inputWrapper, property: 'border-radius' },
32
+ labelTextColor: [
33
+ { ...label, property: 'color' },
34
+ { ...requiredIndicator, property: 'color' }
35
+ ],
36
+ inputTextColor: [{ ...inputElement, property: 'color' }],
37
+ placeholderTextColor: { ...inputElementPlaceholder, property: 'color' },
38
+ fontSize: [{}, host],
39
+ height: inputWrapper,
40
+ padding: inputWrapper,
41
+ pointerCursor: [
42
+ { ...revealButton, property: 'cursor' },
43
+ { ...label, property: 'cursor' },
44
+ { ...requiredIndicator, property: 'cursor' }
45
+ ],
26
46
  }
27
47
  }),
28
48
  draggableMixin,
@@ -43,38 +63,17 @@ overrides = `
43
63
  display: inline-block;
44
64
  }
45
65
  vaadin-password-field {
46
- margin: 0;
66
+ width: 100%;
47
67
  padding: 0;
48
68
  }
49
69
  vaadin-password-field::part(input-field) {
50
- overflow: hidden;
51
- }
52
- vaadin-password-field[readonly] > input:placeholder-shown {
53
- opacity: 1;
54
- }
55
- vaadin-password-field input:-webkit-autofill,
56
- vaadin-password-field input:-webkit-autofill::first-line,
57
- vaadin-password-field input:-webkit-autofill:hover,
58
- vaadin-password-field input:-webkit-autofill:active,
59
- vaadin-password-field input:-webkit-autofill:focus {
60
- -webkit-text-fill-color: var(${PasswordField.cssVarList.color});
61
- box-shadow: 0 0 0 var(${PasswordField.cssVarList.height}) var(${PasswordField.cssVarList.backgroundColor}) inset;
62
- }
63
- vaadin-password-field > label,
64
- vaadin-password-field::part(input-field) {
65
- cursor: pointer;
66
- color: var(${PasswordField.cssVarList.color});
67
- }
68
- vaadin-password-field::part(input-field):focus {
69
- cursor: text;
70
- }
71
- vaadin-password-field[required]::part(required-indicator)::after {
72
- font-size: "12px";
73
- content: "*";
74
- color: var(${PasswordField.cssVarList.color});
70
+ background: transparent;
75
71
  }
76
- vaadin-password-field[readonly]::part(input-field)::after {
77
- border: 0 solid;
72
+ vaadin-password-field::part(input-field)::after {
73
+ opacity: 0;
74
+ }
75
+ vaadin-password-field::before {
76
+ height: initial;
78
77
  }
79
78
  `;
80
79
 
@@ -7,7 +7,6 @@ import {
7
7
  draggableMixin,
8
8
  proxyInputMixin
9
9
  } from '../../mixins';
10
-
11
10
  import TextField from '../descope-text-field/TextField';
12
11
  import ComboBox from '../descope-combo-box/ComboBox';
13
12
 
@@ -54,6 +53,7 @@ const customMixin = (superclass) =>
54
53
  };
55
54
 
56
55
  const {
56
+ host,
57
57
  inputWrapper,
58
58
  countryCodeInput,
59
59
  phoneInput,
@@ -61,6 +61,7 @@ const {
61
61
  requiredIndicator,
62
62
  separator
63
63
  } = {
64
+ host: { selector: () => ':host' },
64
65
  inputWrapper: { selector: '::part(input-field)' },
65
66
  phoneInput: { selector: () => 'descope-text-field' },
66
67
  countryCodeInput: { selector: () => 'descope-combo-box' },
@@ -72,7 +73,7 @@ const {
72
73
  const PhoneField = compose(
73
74
  createStyleMixin({
74
75
  mappings: {
75
- componentWidth: { selector: () => ':host', property: 'width' },
76
+ componentWidth: { ...host, property: 'width' },
76
77
 
77
78
  wrapperBorderStyle: [
78
79
  { ...inputWrapper, property: 'border-style' },
@@ -160,6 +160,9 @@ class PhoneFieldInternal extends BaseInputClass {
160
160
  .join('');
161
161
  e.target.value = sanitizedInput;
162
162
  });
163
+
164
+ this.handleFocusEventsDispatching(this.inputs)
165
+ this.handleInputEventDispatching()
163
166
  }
164
167
 
165
168
  attributeChangedCallback(attrName, oldValue, newValue) {
package/src/index.js CHANGED
@@ -17,6 +17,7 @@ import './components/descope-text-area';
17
17
  import './components/descope-text-field';
18
18
  import './components/descope-image';
19
19
  import './components/descope-phone-field';
20
+ import './components/descope-new-password';
20
21
 
21
22
  export {
22
23
  globalsThemeToStyle,
@@ -17,7 +17,7 @@ export const createProxy = ({
17
17
  #dispatchFocus = createDispatchEvent.bind(this, 'focus')
18
18
 
19
19
  constructor() {
20
- super().attachShadow({ mode: 'open' }).innerHTML = `
20
+ super().attachShadow({ mode: 'open', delegatesFocus: true }).innerHTML = `
21
21
  <style id="create-proxy">${isFunction(style) ? style() : style
22
22
  }</style>
23
23
  <${wrappedEleName}>
@@ -27,8 +27,6 @@ export const createProxy = ({
27
27
  `;
28
28
  }
29
29
 
30
- focus = () => this.baseElement.focus()
31
-
32
30
  init() {
33
31
  super.init?.();
34
32
 
@@ -40,30 +38,10 @@ export const createProxy = ({
40
38
  this.#dispatchFocus()
41
39
  })
42
40
 
43
- this.addEventListener('focus', (e) => {
44
- // if we got a focus event we want to focus the proxy element
45
- if (e.isTrusted) {
46
- this.focus();
47
- }
48
- })
49
41
 
50
42
  // this is needed for components that uses props, such as combo box
51
43
  forwardProps(this, this.baseElement, includeForwardProps)
52
44
 
53
- // `onkeydown` is set on `baseElement` support proper tab-index navigation
54
- // this support is needed since both proxy host and element catch `focus`/`blur` event
55
- // which causes faulty behavior.
56
- // we need this to happen only when the proxy component is in the light DOM,
57
- // otherwise it will focus the nested proxy element
58
- this.baseElement.onkeydown = (e) => {
59
- if (e.shiftKey && e.keyCode === 9 && this.getRootNode() === document) {
60
- this.removeAttribute('tabindex');
61
- // We want to defer the action of setting the tab index back
62
- // so it will happen after focusing the previous element
63
- setTimeout(() => this.setAttribute('tabindex', '0'), 0);
64
- }
65
- };
66
-
67
45
  syncAttrs(this.baseElement, this, {
68
46
  excludeAttrs: excludeAttrsSync,
69
47
  includeAttrs: includeAttrsSync
@@ -3,8 +3,6 @@ import { createDispatchEvent } from "../helpers/mixinsHelpers";
3
3
  export const inputEventsDispatchingMixin = (superclass) => class InputEventsDispatchingMixinClass extends superclass {
4
4
  init() {
5
5
  this.#blockNativeEvents();
6
- this.#handleFocusEventsDispatching();
7
- this.#handleInputEventDispatching();
8
6
 
9
7
  super.init?.();
10
8
  }
@@ -18,29 +16,28 @@ export const inputEventsDispatchingMixin = (superclass) => class InputEventsDisp
18
16
  })
19
17
  }
20
18
 
21
- #handleFocusEventsDispatching() {
19
+ handleFocusEventsDispatching(inputs) {
22
20
  let timerId
23
21
 
24
22
  // in order to simulate blur & focusout on root input element
25
23
  // we are checking if focus on one of the inner elements happened immediately after blur
26
24
  // if not, the component is no longer focused and we should dispatch blur & focusout
27
- this.addEventListener('focusout', (e) => {
28
- if (e.isTrusted) {
25
+ inputs?.forEach(input => {
26
+ input?.addEventListener('focusout', (e) => {
29
27
  e.stopImmediatePropagation();
30
28
  timerId = setTimeout(() => {
31
29
  timerId = null
30
+
32
31
  createDispatchEvent.call(this, 'blur');
33
32
  createDispatchEvent.call(this, 'focusout', { bubbles: true });
34
33
  });
35
- }
36
- })
34
+ })
37
35
 
38
- // in order to simulate focus & focusin on the root input element
39
- // we are holding a timer id and clearing it on focusin
40
- // if there is a timer id, it means that the root input is still focused
41
- // otherwise, it was not focused before, and we should dispatch focus & focusin
42
- this.addEventListener('focusin', (e) => {
43
- if (e.isTrusted) {
36
+ // in order to simulate focus & focusin on the root input element
37
+ // we are holding a timer id and clearing it on focusin
38
+ // if there is a timer id, it means that the root input is still focused
39
+ // otherwise, it was not focused before, and we should dispatch focus & focusin
40
+ const onFocus = (e) => {
44
41
  e.stopImmediatePropagation();
45
42
  clearTimeout(timerId)
46
43
  if (!timerId) {
@@ -48,13 +45,17 @@ export const inputEventsDispatchingMixin = (superclass) => class InputEventsDisp
48
45
  createDispatchEvent.call(this, 'focusin', { bubbles: true });
49
46
  }
50
47
  }
48
+
49
+ // some components are not dispatching focusin but only focus
50
+ input?.addEventListener('focusin', onFocus)
51
+ input?.addEventListener('focus', onFocus)
51
52
  })
52
53
  }
53
54
 
54
55
  // we want to block the input events from propagating in case the value of the root input wasn't change
55
56
  // this can happen if we are sanitizing characters on the internal inputs and do not want it to affect the root input element value
56
57
  // in this case, on each input event, we are comparing the root input value to the previous one, and only if it does not match, we are allowing the input event to propagate
57
- #handleInputEventDispatching() {
58
+ handleInputEventDispatching() {
58
59
  let previousRootComponentValue = this.value
59
60
 
60
61
  this.addEventListener('input', (e) => {
@@ -66,6 +67,5 @@ export const inputEventsDispatchingMixin = (superclass) => class InputEventsDisp
66
67
  previousRootComponentValue = this.value
67
68
  }
68
69
  });
69
-
70
70
  }
71
71
  }
@@ -68,7 +68,7 @@ export const inputValidationMixin = (superclass) => class InputValidationMixinCl
68
68
 
69
69
  #setValidity() {
70
70
  const validity = this.getValidity()
71
- this.#internals.setValidity(validity, this.getErrorMessage(validity))
71
+ this.#internals.setValidity(validity, this.getErrorMessage(validity), this.validationTarget)
72
72
  }
73
73
 
74
74
  get validationMessage() {
@@ -91,9 +91,13 @@ export const inputValidationMixin = (superclass) => class InputValidationMixinCl
91
91
  return this.#internals.validity
92
92
  }
93
93
 
94
+ get validationTarget () {
95
+ return this.inputElement
96
+ }
97
+
94
98
  setCustomValidity(errorMessage) {
95
99
  if (errorMessage) {
96
- this.#internals.setValidity({ customError: true }, errorMessage)
100
+ this.#internals.setValidity({ customError: true }, errorMessage, this.validationTarget)
97
101
  } else {
98
102
  this.#internals.setValidity({})
99
103
  this.#setValidity()
@@ -64,21 +64,6 @@ export const proxyInputMixin = (superclass) =>
64
64
  return this.inputElement.validity
65
65
  }
66
66
 
67
- reportValidityOnInternalInput() {
68
- setTimeout(() => {
69
- this.inputElement.focus();
70
- this.inputElement.reportValidity()
71
- })
72
- }
73
-
74
- // we want reportValidity to behave like form submission
75
- reportValidity() {
76
- if (!this.checkValidity()) {
77
- this.setAttribute('invalid', 'true');
78
- this.reportValidityOnInternalInput();
79
- }
80
- }
81
-
82
67
  handleInternalInputErrorMessage() {
83
68
  if (!this.inputElement.checkValidity()) {
84
69
  this.inputElement.setCustomValidity(this.validationMessage)
@@ -120,30 +105,15 @@ export const proxyInputMixin = (superclass) =>
120
105
  }
121
106
  })
122
107
 
123
- this.addEventListener('focus', (e) => {
124
- // when clicking on the form submit button and the input is invalid, we want it to appear as invalid
125
- // this is a best effort, we cannot identify it for sure without listening to the form submission event
126
- // this will also be triggered when the focus is moving from the submit button to the input by pressing TAB key
127
- if (e.relatedTarget?.form && e.relatedTarget?.form === this.form && e.relatedTarget?.nodeName === 'BUTTON') {
128
- if (!this.checkValidity()) {
129
- this.setAttribute('invalid', 'true');
130
- }
131
-
132
- if (this.hasAttribute('invalid')) {
133
- this.reportValidityOnInternalInput()
134
- }
108
+
109
+ this.addEventListener('invalid', () => {
110
+ if (!this.checkValidity()) {
111
+ this.setAttribute('invalid', 'true');
135
112
  }
113
+ this.#handleErrorMessage()
136
114
  })
137
115
 
138
- this.addEventListener('invalid', this.#handleErrorMessage)
139
-
140
- this.handleInternalInputErrorMessage()
141
-
142
- // this is needed in order to make sure the form input validation is working
143
- // we do not want it to happen when the component is nested
144
- if (!this.hasAttribute('tabindex') && this.getRootNode() === document) {
145
- this.setAttribute('tabindex', 0);
146
- }
116
+ this.handleInternalInputErrorMessage();
147
117
 
148
118
  // sync properties
149
119
  propertyObserver(this, this.inputElement, 'value');
@@ -16,6 +16,7 @@ import { loaderRadial, loaderLinear } from './loader';
16
16
  import comboBox from './comboBox';
17
17
  import image from './image';
18
18
  import phoneField from './phoneField';
19
+ import newPassword from './newPassword';
19
20
 
20
21
  export default {
21
22
  button,
@@ -36,5 +37,6 @@ export default {
36
37
  loaderLinear,
37
38
  comboBox,
38
39
  image,
39
- phoneField
40
+ phoneField,
41
+ newPassword,
40
42
  };
@@ -0,0 +1,48 @@
1
+ import globals from '../globals';
2
+ import { getThemeRefs } from '../../helpers/themeHelpers';
3
+ import NewPassword from '../../components/descope-new-password/NewPassword';
4
+
5
+ const globalRefs = getThemeRefs(globals);
6
+
7
+ const vars = NewPassword.cssVarList;
8
+
9
+ const newPassword = {
10
+ _required: {
11
+ [vars.requiredContent]: "'*'",
12
+ },
13
+
14
+ [vars.inputLabelTextColor]: globalRefs.colors.surface.contrast,
15
+ [vars.inputTextColor]: globalRefs.colors.surface.contrast,
16
+ [vars.placeholderTextColor]: globalRefs.colors.surface.main,
17
+ [vars.inputsGap]: '1em',
18
+
19
+ size: {
20
+ xs: {
21
+ [vars.fieldsMargin]: '0',
22
+ },
23
+ sm: {
24
+ [vars.fieldsMargin]: '0',
25
+ },
26
+ md: {
27
+ [vars.fieldsMargin]: '0.5em',
28
+ },
29
+ lg: {
30
+ [vars.fieldsMargin]: '1em',
31
+ },
32
+ xl: {
33
+ [vars.fieldsMargin]: '2em',
34
+ },
35
+ },
36
+
37
+ _fullWidth: {
38
+ [vars.componentWidth]: '100%'
39
+ },
40
+
41
+ _invalid: {
42
+ [vars.inputLabelTextColor]: globalRefs.colors.error.main,
43
+ [vars.inputTextColor]: globalRefs.colors.error.main,
44
+ [vars.placeholderTextColor]: globalRefs.colors.error.light,
45
+ }
46
+ };
47
+
48
+ export default newPassword;
@@ -1,11 +1,63 @@
1
1
  import PasswordField from '../../components/descope-password-field/PasswordField';
2
- import { textField } from './textField';
2
+ import globals from '../globals';
3
+ import { getThemeRefs } from '../../helpers/themeHelpers';
4
+
5
+ const globalRefs = getThemeRefs(globals);
3
6
 
4
7
  const vars = PasswordField.cssVarList;
5
8
 
6
9
  const passwordField = {
7
- ...textField(vars),
8
- [vars.revealCursor]: 'pointer'
10
+ [vars.wrapperBorderStyle]: 'solid',
11
+ [vars.wrapperBorderWidth]: '1px',
12
+ [vars.wrapperBorderColor]: 'transparent',
13
+ [vars.wrapperBorderRadius]: globalRefs.radius.sm,
14
+
15
+ [vars.labelTextColor]: globalRefs.colors.surface.contrast,
16
+ [vars.inputTextColor]: globalRefs.colors.surface.contrast,
17
+ [vars.placeholderTextColor]: globalRefs.colors.surface.main,
18
+
19
+ [vars.pointerCursor]: 'pointer',
20
+
21
+ [vars.padding]: `0`,
22
+
23
+ size: {
24
+ xs: {
25
+ [vars.height]: '14px',
26
+ [vars.fontSize]: '8px',
27
+ },
28
+ sm: {
29
+ [vars.height]: '20px',
30
+ [vars.fontSize]: '10px',
31
+ },
32
+ md: {
33
+ [vars.height]: '30px',
34
+ [vars.fontSize]: '14px',
35
+ },
36
+ lg: {
37
+ [vars.height]: '40px',
38
+ [vars.fontSize]: '20px',
39
+ },
40
+ xl: {
41
+ [vars.height]: '50px',
42
+ [vars.fontSize]: '25px',
43
+ }
44
+ },
45
+
46
+ _bordered: {
47
+ [vars.padding]: `0 0.5em`,
48
+ [vars.wrapperBorderColor]: globalRefs.colors.surface.main
49
+ },
50
+
51
+ _fullWidth: {
52
+ [vars.width]: '100%'
53
+ },
54
+
55
+ _invalid: {
56
+ [vars.labelTextColor]: globalRefs.colors.error.main,
57
+ [vars.inputTextColor]: globalRefs.colors.error.main,
58
+ [vars.placeholderTextColor]: globalRefs.colors.error.light,
59
+ [vars.wrapperBorderColor]: globalRefs.colors.error.main
60
+ },
9
61
  };
10
62
 
11
63
  export default passwordField;