@descope/web-components-ui 1.0.60 → 1.0.62

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/dist/cjs/index.cjs.js.map +1 -1
  2. package/dist/index.esm.js +395 -185
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/umd/442.js +1 -0
  5. package/dist/umd/942.js +1 -1
  6. package/dist/umd/descope-button-index-js.js +1 -1
  7. package/dist/umd/descope-checkbox-index-js.js +1 -1
  8. package/dist/umd/descope-combo-index-js.js +1 -1
  9. package/dist/umd/descope-container-index-js.js +1 -1
  10. package/dist/umd/descope-date-picker-index-js.js +1 -1
  11. package/dist/umd/descope-divider-index-js.js +1 -1
  12. package/dist/umd/descope-email-field-index-js.js +1 -1
  13. package/dist/umd/descope-link-index-js.js +1 -1
  14. package/dist/umd/descope-loader-linear-index-js.js +1 -1
  15. package/dist/umd/descope-loader-radial-index-js.js +1 -1
  16. package/dist/umd/descope-logo-index-js.js +1 -1
  17. package/dist/umd/descope-number-field-index-js.js +1 -1
  18. package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -1
  19. package/dist/umd/descope-passcode-index-js.js +1 -1
  20. package/dist/umd/descope-password-field-index-js.js +1 -1
  21. package/dist/umd/descope-switch-toggle-index-js.js +1 -1
  22. package/dist/umd/descope-text-area-index-js.js +1 -1
  23. package/dist/umd/descope-text-field-index-js.js +1 -1
  24. package/dist/umd/descope-text-index-js.js +1 -1
  25. package/dist/umd/index.js +1 -1
  26. package/package.json +1 -1
  27. package/src/baseClasses/BaseInputClass.js +3 -0
  28. package/src/components/descope-checkbox/Checkbox.js +2 -2
  29. package/src/components/descope-combo/index.js +1 -1
  30. package/src/components/descope-container/Container.js +1 -1
  31. package/src/components/descope-divider/Divider.js +1 -1
  32. package/src/components/descope-email-field/EmailField.js +2 -2
  33. package/src/components/descope-link/Link.js +1 -1
  34. package/src/components/descope-loader-linear/LoaderLinear.js +1 -1
  35. package/src/components/descope-loader-radial/LoaderRadial.js +1 -1
  36. package/src/components/descope-logo/Logo.js +1 -1
  37. package/src/components/descope-number-field/NumberField.js +2 -2
  38. package/src/components/descope-passcode/Passcode.js +2 -2
  39. package/src/components/descope-passcode/descope-passcode-internal/PasscodeInternal.js +42 -70
  40. package/src/components/descope-password-field/PasswordField.js +2 -2
  41. package/src/components/descope-switch-toggle/SwitchToggle.js +2 -2
  42. package/src/components/descope-text/Text.js +1 -1
  43. package/src/components/descope-text-area/TextArea.js +2 -2
  44. package/src/components/descope-text-field/TextField.js +2 -2
  45. package/src/componentsHelpers/compose.js +3 -0
  46. package/src/componentsHelpers/createProxy/index.js +2 -2
  47. package/src/componentsHelpers/enforceNestingElementsStylesMixin.js +67 -59
  48. package/src/componentsHelpers/index.js +2 -6
  49. package/src/componentsHelpers/inputMixin.js +173 -94
  50. package/src/componentsHelpers/proxyInputMixin.js +152 -0
  51. package/src/theme/components/textField.js +1 -1
  52. package/dist/umd/832.js +0 -1
  53. /package/src/{components → baseClasses}/DescopeBaseClass.js +0 -0
@@ -1,16 +1,16 @@
1
+ import BaseInputClass from '../../../baseClasses/BaseInputClass';
1
2
  import { getComponentName } from '../../../componentsHelpers';
2
3
  import { getSanitizedCharacters, focusElement } from './helpers';
3
4
 
4
5
  export const componentName = getComponentName('passcode-internal');
5
6
 
6
- class PasscodeInternal extends HTMLElement {
7
+ class PasscodeInternal extends BaseInputClass {
7
8
  static get observedAttributes() {
8
9
  return [
10
+ ...BaseInputClass.observedAttributes,
9
11
  'disabled',
10
12
  'bordered',
11
- 'size',
12
- 'required',
13
- 'pattern'
13
+ 'size'
14
14
  ];
15
15
  }
16
16
 
@@ -18,12 +18,6 @@ class PasscodeInternal extends HTMLElement {
18
18
  return componentName;
19
19
  }
20
20
 
21
- static get formAssociated() {
22
- return true;
23
- }
24
-
25
- #internals
26
-
27
21
  constructor() {
28
22
  super();
29
23
  const template = document.createElement('template');
@@ -47,23 +41,9 @@ class PasscodeInternal extends HTMLElement {
47
41
 
48
42
  this.baseSelector = ':host > div';
49
43
 
50
- this.#internals = this.attachInternals();
51
-
52
44
  this.inputs = Array.from(this.querySelectorAll('descope-text-field'))
53
45
  }
54
46
 
55
- checkValidity() {
56
- // we need to toggle the has-error-message so the text inside the digits will become red when there is an error
57
- if (this.#internals.validity.valid) {
58
- this.inputs.forEach(input => input.removeAttribute('has-error-message'))
59
- } else {
60
- this.inputs.forEach(input => input.setAttribute('has-error-message', 'true'))
61
- // we need to call it so the has-error-message with have the correct format (="true")
62
- this.oninvalid?.()
63
- }
64
- return this.#internals.validity.valid
65
- }
66
-
67
47
  get digits() {
68
48
  return Number.parseInt(this.getAttribute('digits')) || 6
69
49
  }
@@ -72,59 +52,54 @@ class PasscodeInternal extends HTMLElement {
72
52
  return this.inputs.map(({ value }) => value).join('')
73
53
  }
74
54
 
75
- set value(val) { }
55
+ set value(val) {
56
+ if(val === this.value) return;
76
57
 
77
- get isRequired() {
78
- return this.hasAttribute('required') && this.getAttribute('required') !== 'false'
58
+ const charArr = getSanitizedCharacters(val);
59
+
60
+ if (charArr.length) {
61
+ this.fillDigits(charArr, this.inputs[0]);
62
+ }
79
63
  }
80
64
 
81
65
  get pattern() {
82
66
  return `^$|^\\d{${this.digits},}$`
83
67
  }
84
68
 
85
- get valueMissingErrMsg() {
86
- return 'Please fill out this field.'
87
- }
88
-
89
- get patternMismatchErrMsg() {
90
- return `Must be a ${this.digits} digits number.`
91
- }
92
-
93
- get validity() {
94
- return this.#internals.validity;
95
- }
96
-
97
- get validationMessage() {
98
- return this.#internals.validationMessage;
99
- }
100
-
101
- reportValidity() {
102
- this.#internals.reportValidity()
69
+ handleInputsInvalid() {
70
+ setTimeout(() => {
71
+ if (this.hasAttribute('invalid')) {
72
+ this.inputs.forEach(input => input.setAttribute('invalid', 'true'))
73
+ }
74
+ })
103
75
  }
104
76
 
105
- formAssociatedCallback() {
106
- this.setValidity?.();
77
+ handleInputsValid() {
78
+ this.inputs.forEach(input => input.removeAttribute('invalid'))
107
79
  }
108
80
 
109
- setValidity = () => {
81
+ getValidity() {
110
82
  if (this.isRequired && !this.value) {
111
- this.#internals.setValidity({ valueMissing: true }, this.valueMissingErrMsg);
83
+ return { valueMissing: true };
112
84
  }
113
85
  else if (this.pattern && !new RegExp(this.pattern).test(this.value)) {
114
- this.#internals.setValidity({ patternMismatch: true }, this.patternMismatchErrMsg);
86
+ return { patternMismatch: true };
115
87
  }
116
88
  else {
117
- this.#internals.setValidity({})
89
+ return {}
118
90
  }
119
91
  };
120
92
 
93
+ handleFocus() {
94
+ this.inputs[0].focus();
95
+ }
96
+
121
97
  async connectedCallback() {
122
- this.setValidity();
98
+ super.connectedCallback();
123
99
  this.initInputs()
124
100
 
125
- this.onfocus = () => {
126
- this.inputs[0].focus();
127
- }
101
+ this.addEventListener('invalid', this.handleInputsInvalid)
102
+ this.addEventListener('valid', this.handleInputsValid)
128
103
  }
129
104
 
130
105
  getInputIdx(inputEle) {
@@ -155,6 +130,10 @@ class PasscodeInternal extends HTMLElement {
155
130
  !currentInput.hasAttribute('focused') && focusElement(currentInput);
156
131
  };
157
132
 
133
+ handleBlur() {
134
+ this.handleInputsInvalid()
135
+ }
136
+
158
137
  initInputs() {
159
138
  this.inputs.forEach((input) => {
160
139
 
@@ -163,7 +142,7 @@ class PasscodeInternal extends HTMLElement {
163
142
  // if not, the component is no longer focused and we should simulate blur
164
143
  input.addEventListener('blur', () => {
165
144
  const timerId = setTimeout(() => {
166
- this.dispatchEvent(new Event('blur'))
145
+ this.dispatchBlur()
167
146
  });
168
147
 
169
148
  this.inputs.forEach((ele) =>
@@ -171,13 +150,13 @@ class PasscodeInternal extends HTMLElement {
171
150
  );
172
151
  })
173
152
 
174
- input.oninput = (e) => {
153
+ input.oninput = () => {
175
154
  const charArr = getSanitizedCharacters(input.value);
176
155
 
177
156
  if (!charArr.length) input.value = ''; // if we got an invalid value we want to clear the input
178
157
  else this.fillDigits(charArr, input);
179
158
 
180
- this.setValidity();
159
+ this.dispatchInput()
181
160
  };
182
161
 
183
162
  input.onkeydown = ({ key }) => {
@@ -190,27 +169,21 @@ class PasscodeInternal extends HTMLElement {
190
169
  !prevInput.hasAttribute('focused') && setTimeout(() => {
191
170
  focusElement(prevInput);
192
171
  });
172
+
173
+ this.dispatchInput()
193
174
  } else if (key.match(/^(\d)$/g)) { // if input is a digit
194
175
  input.value = ''; // we are clearing the previous value so we can override it with the new value
195
176
  }
196
177
 
197
- this.setValidity()
198
178
  };
199
179
  })
200
180
  }
201
181
 
202
- attributeChangedCallback(
203
- attrName,
204
- oldValue,
205
- newValue
206
- ) {
207
- const validationRelatedAttributes = ['required', 'pattern'];
182
+ attributeChangedCallback(attrName, oldValue, newValue) {
183
+ super.attributeChangedCallback(attrName, oldValue, newValue)
208
184
 
209
185
  if (oldValue !== newValue) {
210
- if (validationRelatedAttributes.includes(attrName)) {
211
- this.setValidity()
212
- }
213
- else if (PasscodeInternal.observedAttributes.includes(attrName)) {
186
+ if (PasscodeInternal.observedAttributes.includes(attrName) && !BaseInputClass.observedAttributes.includes(attrName)) {
214
187
  this.inputs.forEach((input) => input.setAttribute(attrName, newValue))
215
188
  }
216
189
  }
@@ -218,4 +191,3 @@ class PasscodeInternal extends HTMLElement {
218
191
  }
219
192
 
220
193
  export default PasscodeInternal;
221
-
@@ -3,7 +3,7 @@ import {
3
3
  createStyleMixin,
4
4
  draggableMixin,
5
5
  createProxy,
6
- inputMixin,
6
+ proxyInputMixin,
7
7
  compose,
8
8
  componentNameValidationMixin
9
9
  } from '../../componentsHelpers';
@@ -26,7 +26,7 @@ const PasswordField = compose(
26
26
  }
27
27
  }),
28
28
  draggableMixin,
29
- inputMixin,
29
+ proxyInputMixin,
30
30
  componentNameValidationMixin
31
31
  )(
32
32
  createProxy({
@@ -3,7 +3,7 @@ import {
3
3
  createStyleMixin,
4
4
  draggableMixin,
5
5
  createProxy,
6
- inputMixin,
6
+ proxyInputMixin,
7
7
  compose,
8
8
  componentNameValidationMixin,
9
9
  } from '../../componentsHelpers';
@@ -21,7 +21,7 @@ const SwitchToggle = compose(
21
21
  }
22
22
  }),
23
23
  draggableMixin,
24
- inputMixin,
24
+ proxyInputMixin,
25
25
  componentNameValidationMixin
26
26
  )(
27
27
  createProxy({
@@ -6,7 +6,7 @@ import {
6
6
  componentNameValidationMixin
7
7
  } from '../../componentsHelpers';
8
8
  import { matchHostStyle } from '../../componentsHelpers/createStyleMixin/helpers';
9
- import { DescopeBaseClass } from '../DescopeBaseClass';
9
+ import { DescopeBaseClass } from '../../baseClasses/DescopeBaseClass';
10
10
 
11
11
  export const componentName = getComponentName('text');
12
12
 
@@ -3,7 +3,7 @@ import {
3
3
  createStyleMixin,
4
4
  draggableMixin,
5
5
  createProxy,
6
- inputMixin,
6
+ proxyInputMixin,
7
7
  compose,
8
8
  componentNameValidationMixin
9
9
  } from '../../componentsHelpers';
@@ -36,7 +36,7 @@ const TextArea = compose(
36
36
  }
37
37
  }),
38
38
  draggableMixin,
39
- inputMixin,
39
+ proxyInputMixin,
40
40
  componentNameValidationMixin
41
41
  )(
42
42
  createProxy({
@@ -3,7 +3,7 @@ import {
3
3
  createStyleMixin,
4
4
  draggableMixin,
5
5
  createProxy,
6
- inputMixin,
6
+ proxyInputMixin,
7
7
  compose,
8
8
  componentNameValidationMixin
9
9
  } from '../../componentsHelpers';
@@ -18,7 +18,7 @@ const TextField = compose(
18
18
  mappings: textFieldMappings
19
19
  }),
20
20
  draggableMixin,
21
- inputMixin,
21
+ proxyInputMixin,
22
22
  componentNameValidationMixin
23
23
  )(
24
24
  createProxy({
@@ -0,0 +1,3 @@
1
+ export default (...fns) =>
2
+ (val) =>
3
+ fns.reduceRight((res, fn) => fn(res), val);
@@ -1,5 +1,5 @@
1
- import { compose } from '..';
2
- import { DescopeBaseClass } from '../../components/DescopeBaseClass';
1
+ import compose from '../compose';
2
+ import { DescopeBaseClass } from '../../baseClasses/DescopeBaseClass';
3
3
  import { hoverableMixin } from '../hoverableMixin';
4
4
  import { syncAttrs, forwardProps } from './helpers';
5
5
 
@@ -19,65 +19,65 @@ const insertNestingLevel = (srcEle, nestingEle) => {
19
19
  // to be under the nesting element
20
20
  export const enforceNestingElementsStylesMixin =
21
21
  ({ nestingElementTagName, nestingElementDestSlotName, forwardAttrOptions }) =>
22
- (superclass) => {
23
- const getChildNodeEle = () =>
24
- Object.assign(document.createElement(nestingElementTagName), {
25
- slot: nestingElementDestSlotName
26
- });
27
-
28
- let childObserver;
29
-
30
- const getObserver = () => childObserver;
31
-
32
- return class EnforceNestingElementsStylesMixinClass extends superclass {
33
- constructor() {
34
- super();
35
-
36
- const childObserverCallback = () => {
37
- // we are going to change the DOM, so we need to disconnect the observer before
38
- // and reconnect it after the child component is added
39
- getObserver().disconnect(this.shadowRoot.host);
40
-
41
- const isNestingElementExist = this.shadowRoot.host.querySelector(nestingElementTagName);
42
- const hasNewChildren = this.shadowRoot.host.childNodes.length > 0;
43
-
44
- if (!isNestingElementExist && hasNewChildren) {
45
- // if before there were no children and now there are children - insert
46
- insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
47
- } else if (isNestingElementExist && hasNewChildren) {
48
- // if children existed, and they changed -
49
- // we need to update (move) the new children into
50
- // descope-text and remove previous children
51
- this.shadowRoot.host.querySelector(child).remove();
52
- insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
53
- }
54
- else if (isNestingElementExist && !hasNewChildren) {
55
- // if children existed and now there are none -
56
- // we need to remove descope-text completely
57
- this.shadowRoot.host.querySelector(child).remove();
58
- }
22
+ (superclass) => {
23
+ const getChildNodeEle = () =>
24
+ document.createElement(nestingElementTagName, {
25
+ slot: nestingElementDestSlotName
26
+ });
59
27
 
60
- // we need a new observer, because we remove the nesting element
61
- this.shadowRoot.host.querySelector(nestingElementTagName) &&
62
- forwardAttrs(
63
- this.shadowRoot.host,
64
- this.shadowRoot.host.querySelector(nestingElementTagName),
65
- forwardAttrOptions
66
- );
28
+ let childObserver;
67
29
 
68
- getObserver().observe(this.shadowRoot.host, {
69
- childList: true
70
- });
71
- };
30
+ const getObserver = () => childObserver;
72
31
 
73
- childObserver = getChildObserver(childObserverCallback);
74
- }
32
+ let isMutating = false;
33
+
34
+ const filterNestingElement = (node) => node.localName !== nestingElementTagName
35
+ return class EnforceNestingElementsStylesMixinClass extends superclass {
36
+ constructor() {
37
+ super();
38
+
39
+ const childObserverCallback = (mutation, observer) => {
40
+
41
+ // we are going to change the DOM, so we need to skip the upcoming mutations
42
+ if (isMutating) return;
43
+
44
+ isMutating = true
45
+
46
+ const { addedNodes, removedNodes } = mutation
47
+
48
+ const nestingElement = this.shadowRoot.host.querySelector(nestingElementTagName);
49
+ const hasNewChildren = Array.from(addedNodes)
50
+ .filter(filterNestingElement)
51
+ .length > 0;
52
+ const hasRemovedChildren = Array.from(removedNodes)
53
+ .filter(filterNestingElement)
54
+ .length > 0;
75
55
 
76
- connectedCallback() {
77
- super.connectedCallback?.();
56
+ if (!nestingElement && hasNewChildren) {
57
+ // if before there were no children and now there are children - insert
58
+ this.handleNestingLevelInsertion()
78
59
 
79
- if (this.shadowRoot.host.childNodes.length > 0) {
80
- // on the first render - we want to move all component's children to be under descope-text
60
+ } else if (nestingElement && hasNewChildren) {
61
+ // if children existed, and they changed -
62
+ // we need to update (move) the new children into
63
+ // descope-text and remove previous children
64
+ nestingElement.replaceChildren(...addedNodes)
65
+ }
66
+ else if (nestingElement && !hasNewChildren && hasRemovedChildren) {
67
+ // // if children existed and now there are none -
68
+ // // we need to remove descope-text completely
69
+ nestingElement.remove();
70
+ }
71
+
72
+ setTimeout(() => {
73
+ isMutating = false
74
+ })
75
+ };
76
+
77
+ childObserver = getChildObserver(childObserverCallback);
78
+ }
79
+
80
+ handleNestingLevelInsertion() {
81
81
  insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
82
82
 
83
83
  forwardAttrs(
@@ -87,9 +87,17 @@ export const enforceNestingElementsStylesMixin =
87
87
  );
88
88
  }
89
89
 
90
- getObserver().observe(this.shadowRoot.host, {
91
- childList: true
92
- });
93
- }
90
+ connectedCallback() {
91
+ super.connectedCallback?.();
92
+
93
+ if (this.shadowRoot.host.childNodes.length > 0) {
94
+ // on the first render - we want to move all component's children to be under descope-text
95
+ this.handleNestingLevelInsertion()
96
+ }
97
+
98
+ getObserver().observe(this.shadowRoot.host, {
99
+ childList: true
100
+ });
101
+ }
102
+ };
94
103
  };
95
- };
@@ -3,13 +3,9 @@ import { kebabCaseJoin } from '../helpers';
3
3
 
4
4
  export const getComponentName = (name) => kebabCaseJoin(DESCOPE_PREFIX, name);
5
5
 
6
- export const compose =
7
- (...fns) =>
8
- (val) =>
9
- fns.reduceRight((res, fn) => fn(res), val);
10
-
11
6
  export { createStyleMixin } from './createStyleMixin';
12
7
  export { draggableMixin } from './draggableMixin';
13
8
  export { createProxy } from './createProxy';
14
- export { inputMixin } from './inputMixin';
9
+ export { proxyInputMixin } from './proxyInputMixin';
15
10
  export { componentNameValidationMixin } from './componentNameValidationMixin';
11
+ export { default as compose } from './compose'