@descope/web-components-ui 1.0.60 → 1.0.62

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 (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'