@descope/web-components-ui 1.0.51 → 1.0.53

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. package/dist/index.esm.js +774 -377
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/umd/832.js +1 -0
  4. package/dist/umd/descope-button-index-js.js +1 -1
  5. package/dist/umd/descope-checkbox-index-js.js +1 -1
  6. package/dist/umd/descope-combo-index-js.js +1 -1
  7. package/dist/umd/descope-container-index-js.js +1 -1
  8. package/dist/umd/descope-date-picker-index-js.js +1 -1
  9. package/dist/umd/descope-divider-index-js.js +1 -0
  10. package/dist/umd/descope-email-field-index-js.js +1 -1
  11. package/dist/umd/descope-logo-index-js.js +1 -1
  12. package/dist/umd/descope-number-field-index-js.js +1 -1
  13. package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -0
  14. package/dist/umd/descope-passcode-index-js.js +1 -0
  15. package/dist/umd/descope-password-field-index-js.js +1 -1
  16. package/dist/umd/descope-switch-toggle-index-js.js +1 -1
  17. package/dist/umd/descope-text-area-index-js.js +1 -1
  18. package/dist/umd/descope-text-field-index-js.js +1 -1
  19. package/dist/umd/descope-text-index-js.js +1 -1
  20. package/dist/umd/index.js +1 -1
  21. package/package.json +1 -1
  22. package/src/components/DescopeBaseClass.js +1 -0
  23. package/src/components/descope-button/Button.js +0 -1
  24. package/src/components/descope-combo/index.js +2 -1
  25. package/src/components/descope-container/Container.js +14 -6
  26. package/src/components/descope-divider/Divider.js +85 -0
  27. package/src/components/descope-divider/index.js +6 -0
  28. package/src/components/descope-logo/Logo.js +5 -4
  29. package/src/components/descope-passcode/Passcode.js +141 -0
  30. package/src/components/descope-passcode/descope-passcode-internal/PasscodeInternal.js +213 -0
  31. package/src/components/descope-passcode/descope-passcode-internal/helpers.js +14 -0
  32. package/src/components/descope-passcode/descope-passcode-internal/index.js +3 -0
  33. package/src/components/descope-passcode/index.js +5 -0
  34. package/src/components/descope-password-field/PasswordField.js +0 -1
  35. package/src/components/descope-text/Text.js +8 -1
  36. package/src/components/descope-text/index.js +0 -1
  37. package/src/componentsHelpers/createProxy/helpers.js +24 -7
  38. package/src/componentsHelpers/createProxy/index.js +8 -6
  39. package/src/componentsHelpers/createStyleMixin/index.js +103 -72
  40. package/src/componentsHelpers/enforceNestingElementsStylesMixin.js +95 -0
  41. package/src/componentsHelpers/inputMixin.js +13 -13
  42. package/src/index.js +3 -0
  43. package/src/theme/components/divider.js +24 -0
  44. package/src/theme/components/index.js +5 -1
  45. package/src/theme/components/passcode.js +8 -0
  46. package/src/theme/components/text.js +6 -0
  47. package/dist/umd/433.js +0 -1
@@ -0,0 +1,213 @@
1
+ import { getComponentName } from '../../../componentsHelpers';
2
+ import { getSanitizedCharacters, focusElement } from './helpers';
3
+
4
+ export const componentName = getComponentName('passcode-internal');
5
+
6
+ class PasscodeInternal extends HTMLElement {
7
+ static get observedAttributes() {
8
+ return [
9
+ 'disabled',
10
+ 'bordered',
11
+ 'size'
12
+ ];
13
+ }
14
+
15
+ static get componentName() {
16
+ return componentName;
17
+ }
18
+
19
+ static get formAssociated() {
20
+ return true;
21
+ }
22
+
23
+ #internals
24
+
25
+ constructor() {
26
+ super();
27
+ const template = document.createElement('template');
28
+
29
+ const inputs = [...Array(this.digits).keys()].map((idx) => `
30
+ <descope-text-field
31
+ st-width="35px"
32
+ data-id=${idx}
33
+ type="tel"
34
+ autocomplete="none"
35
+ ></descope-text-field>
36
+ `)
37
+
38
+ template.innerHTML = `
39
+ <div>
40
+ ${inputs.join('')}
41
+ </div>
42
+ `;
43
+
44
+ this.appendChild(template.content.cloneNode(true));
45
+
46
+ this.baseSelector = ':host > div';
47
+
48
+ this.#internals = this.attachInternals();
49
+
50
+ this.inputs = Array.from(this.querySelectorAll('descope-text-field'))
51
+ }
52
+
53
+ checkValidity() {
54
+ // we need to toggle the has-error-message so the text inside the digits will become red when there is an error
55
+ if (this.#internals.validity.valid) {
56
+ this.inputs.forEach(input => input.removeAttribute('has-error-message'))
57
+ } else {
58
+ this.inputs.forEach(input => input.setAttribute('has-error-message', 'true'))
59
+ // we need to call it so the has-error-message with have the correct format (="true")
60
+ this.oninvalid?.()
61
+ }
62
+ return this.#internals.validity.valid
63
+ }
64
+
65
+ get digits() {
66
+ return Number.parseInt(this.getAttribute('digits')) || 6
67
+ }
68
+
69
+ get value() {
70
+ return this.inputs.map(({ value }) => value).join('')
71
+ }
72
+
73
+ set value(val) { }
74
+
75
+ get isRequired() {
76
+ return this.hasAttribute('required') && this.getAttribute('required') !== 'false'
77
+ }
78
+
79
+ get pattern() {
80
+ return `^$|^\\d{${this.digits},}$`
81
+ }
82
+
83
+ get valueMissingErrMsg() {
84
+ return 'Please fill out this field.'
85
+ }
86
+
87
+ get patternMismatchErrMsg() {
88
+ return `Must be a ${this.digits} digits number.`
89
+ }
90
+
91
+ get validity() {
92
+ return this.#internals.validity;
93
+ }
94
+
95
+ get validationMessage() {
96
+ return this.#internals.validationMessage;
97
+ }
98
+
99
+ reportValidity() {
100
+ this.#internals.reportValidity()
101
+ }
102
+
103
+ formAssociatedCallback() {
104
+ this.setValidity?.();
105
+ }
106
+
107
+ setValidity = () => {
108
+ if (this.isRequired && !this.value) {
109
+ this.#internals.setValidity({ valueMissing: true }, this.valueMissingErrMsg);
110
+ }
111
+ else if (this.pattern && !new RegExp(this.pattern).test(this.value)) {
112
+ this.#internals.setValidity({ patternMismatch: true }, this.patternMismatchErrMsg);
113
+ }
114
+ else {
115
+ this.#internals.setValidity({})
116
+ }
117
+ };
118
+
119
+ async connectedCallback() {
120
+ this.setValidity();
121
+ this.initInputs()
122
+
123
+ this.onfocus = () => {
124
+ this.inputs[0].focus();
125
+ }
126
+ }
127
+
128
+ getInputIdx(inputEle) {
129
+ return Number.parseInt(inputEle.getAttribute('data-id'), 10)
130
+ }
131
+
132
+ getNextInput(currInput) {
133
+ const currentIdx = this.getInputIdx(currInput)
134
+ const newIdx = Math.min(currentIdx + 1, this.inputs.length - 1)
135
+ return this.inputs[newIdx]
136
+ }
137
+
138
+ getPrevInput(currInput) {
139
+ const currentIdx = this.getInputIdx(currInput)
140
+ const newIdx = Math.max(currentIdx - 1, 0)
141
+ return this.inputs[newIdx]
142
+ }
143
+
144
+ fillDigits(charArr, currentInput) {
145
+ for (let i = 0; i < charArr.length; i += 1) {
146
+ currentInput.value = charArr[i] ?? '';
147
+
148
+ const nextInput = this.getNextInput(currentInput);
149
+ if (nextInput === currentInput) break;
150
+ currentInput = nextInput;
151
+ }
152
+
153
+ !currentInput.hasAttribute('focused') && focusElement(currentInput);
154
+ };
155
+
156
+ initInputs() {
157
+ this.inputs.forEach((input) => {
158
+
159
+ // in order to simulate blur on the input
160
+ // we are checking if focus on one of the digits happened immediately after blur on another digit
161
+ // if not, the component is no longer focused and we should simulate blur
162
+ input.addEventListener('blur', () => {
163
+ const timerId = setTimeout(() => {
164
+ this.dispatchEvent(new Event('blur'))
165
+ });
166
+
167
+ this.inputs.forEach((ele) =>
168
+ ele.addEventListener('focus', () => clearTimeout(timerId), { once: true })
169
+ );
170
+ })
171
+
172
+ input.oninput = (e) => {
173
+ const charArr = getSanitizedCharacters(input.value);
174
+
175
+ if (!charArr.length) input.value = ''; // if we got an invalid value we want to clear the input
176
+ else this.fillDigits(charArr, input);
177
+
178
+ this.setValidity();
179
+ };
180
+
181
+ input.onkeydown = ({ key }) => {
182
+ if (key === 'Backspace') {
183
+ input.value = '';
184
+
185
+ // if the user deleted the digit we want to focus the previous digit
186
+ const prevInput = this.getPrevInput(input)
187
+
188
+ !prevInput.hasAttribute('focused') && setTimeout(() => {
189
+ focusElement(prevInput);
190
+ });
191
+ } else if (key.match(/^(\d)$/g)) { // if input is a digit
192
+ input.value = ''; // we are clearing the previous value so we can override it with the new value
193
+ }
194
+
195
+ this.setValidity()
196
+ };
197
+ })
198
+ }
199
+
200
+ attributeChangedCallback(
201
+ attrName,
202
+ oldValue,
203
+ newValue
204
+ ) {
205
+ if (oldValue !== newValue &&
206
+ PasscodeInternal.observedAttributes.includes(attrName)) {
207
+ this.inputs.forEach((input) => input.setAttribute(attrName, newValue))
208
+ }
209
+ }
210
+ }
211
+
212
+ export default PasscodeInternal;
213
+
@@ -0,0 +1,14 @@
1
+
2
+ export const focusElement = (ele) => {
3
+ ele?.focus();
4
+ ele?.setSelectionRange(1, 1);
5
+ };
6
+
7
+ export const getSanitizedCharacters = (str) => {
8
+ const pin = str.replace(/\s/g, ''); // sanitize string
9
+
10
+ // accept only numbers
11
+ if (!pin.match(/^\d+$/)) return [];
12
+
13
+ return [...pin]; // creating array of chars
14
+ };
@@ -0,0 +1,3 @@
1
+ import PasscodeInternal, { componentName } from "./PasscodeInternal"
2
+
3
+ customElements.define(componentName, PasscodeInternal)
@@ -0,0 +1,5 @@
1
+ import Passcode, { componentName } from './Passcode';
2
+ import '../descope-text-field'
3
+ import './descope-passcode-internal'
4
+
5
+ customElements.define(componentName, Passcode);
@@ -17,7 +17,6 @@ const PasswordField = compose(
17
17
  createStyleMixin({
18
18
  mappings: {
19
19
  ...textFieldMappings,
20
- // todo: override cursor from lumo
21
20
  revealCursor: [
22
21
  {
23
22
  selector: '::part(reveal-button)::before',
@@ -6,10 +6,11 @@ import {
6
6
  componentNameValidationMixin
7
7
  } from '../../componentsHelpers';
8
8
  import { matchHostStyle } from '../../componentsHelpers/createStyleMixin/helpers';
9
+ import { DescopeBaseClass } from '../DescopeBaseClass';
9
10
 
10
11
  export const componentName = getComponentName('text');
11
12
 
12
- class RawText extends HTMLElement {
13
+ class RawText extends DescopeBaseClass {
13
14
  static get componentName() {
14
15
  return componentName;
15
16
  }
@@ -35,6 +36,12 @@ const Text = compose(
35
36
  fontWeight: {},
36
37
  width: {},
37
38
  color: {},
39
+ letterSpacing: {},
40
+ textShadow: {},
41
+ borderWidth: {},
42
+ borderStyle: {},
43
+ borderColor: {},
44
+ textTransform: {},
38
45
  textAlign: matchHostStyle(),
39
46
  display: matchHostStyle()
40
47
  }
@@ -1,5 +1,4 @@
1
1
  import Text, { componentName } from './Text';
2
2
 
3
3
  customElements.define(componentName, Text);
4
-
5
4
  export { Text };
@@ -1,14 +1,27 @@
1
- const observeAttributes = (ele, callback, excludeAttrs) => {
1
+ const observeAttributes = (
2
+ ele,
3
+ callback,
4
+ { excludeAttrs = [], includeAttrs = [] }
5
+ ) => {
2
6
  // sync all attrs on init
3
- callback(...Array.from(ele.attributes).map((attr) => attr.name));
7
+ callback(
8
+ ...Array.from(ele.attributes)
9
+ .filter(
10
+ (attr) =>
11
+ !excludeAttrs.includes(attr.name) &&
12
+ (!includeAttrs.length || includeAttrs.includes(attr.name))
13
+ )
14
+ .map((attr) => attr.name)
15
+ );
4
16
 
5
17
  const observer = new MutationObserver((mutationsList) => {
6
18
  for (const mutation of mutationsList) {
7
19
  if (
8
20
  mutation.type === 'attributes' &&
9
- !excludeAttrs.includes(mutation.attributeName)
21
+ !excludeAttrs.includes(mutation.attributeName) &&
22
+ (!includeAttrs.length || includeAttrs.includes(attr.name))
10
23
  ) {
11
- callback(mutation.attributeName);
24
+ callback([mutation.attributeName]);
12
25
  }
13
26
  }
14
27
  });
@@ -31,7 +44,11 @@ const createSyncAttrsCb =
31
44
  });
32
45
  };
33
46
 
34
- export const syncAttrs = (ele1, ele2, excludeAttrs) => {
35
- observeAttributes(ele1, createSyncAttrsCb(ele1, ele2), excludeAttrs);
36
- observeAttributes(ele2, createSyncAttrsCb(ele2, ele1), excludeAttrs);
47
+ export const syncAttrs = (ele1, ele2, options) => {
48
+ observeAttributes(ele1, createSyncAttrsCb(ele1, ele2), options);
49
+ observeAttributes(ele2, createSyncAttrsCb(ele2, ele1), options);
50
+ };
51
+
52
+ export const forwardAttrs = (source, dest, options) => {
53
+ observeAttributes(source, createSyncAttrsCb(source, dest), options);
37
54
  };
@@ -1,3 +1,4 @@
1
+ import { DescopeBaseClass } from '../../components/DescopeBaseClass';
1
2
  import { syncAttrs } from './helpers';
2
3
 
3
4
  export const createProxy = ({
@@ -15,7 +16,7 @@ export const createProxy = ({
15
16
  </${wrappedEleName}>
16
17
  `;
17
18
 
18
- class ProxyElement extends HTMLElement {
19
+ class ProxyElement extends DescopeBaseClass {
19
20
  static get componentName() {
20
21
  return componentName;
21
22
  }
@@ -23,7 +24,6 @@ export const createProxy = ({
23
24
  constructor() {
24
25
  super().attachShadow({ mode: 'open' }).innerHTML = template;
25
26
  this.hostElement = this.shadowRoot.host;
26
- this.componentName = this.hostElement.tagName.toLowerCase();
27
27
  this.baseSelector = wrappedEleName;
28
28
  this.shadowRoot.getElementById('create-proxy').innerHTML =
29
29
  typeof style === 'function' ? style() : style;
@@ -35,9 +35,9 @@ export const createProxy = ({
35
35
  this.setAttribute('tabindex', '0');
36
36
 
37
37
  // we want to focus on the proxy element when focusing our WC
38
- this.onfocus = (e) => {
38
+ this.addEventListener('focus', () => {
39
39
  this.proxyElement.focus();
40
- };
40
+ })
41
41
 
42
42
  // `onkeydown` is set on `proxyElement` support proper tab-index navigation
43
43
  // this support is needed since both proxy host and element catch `focus`/`blur` event
@@ -63,9 +63,11 @@ export const createProxy = ({
63
63
  this.proxyElement.addEventListener('mouseover', this.mouseoverCbRef);
64
64
 
65
65
  // sync events
66
- this.addEventListener = this.proxyElement.addEventListener;
66
+ this.addEventListener = (...args) => this.proxyElement.addEventListener(...args)
67
67
 
68
- syncAttrs(this.proxyElement, this.hostElement, excludeAttrsSync);
68
+ syncAttrs(this.proxyElement, this.hostElement, {
69
+ excludeAttrs: excludeAttrsSync
70
+ });
69
71
  }
70
72
  }
71
73
 
@@ -2,77 +2,108 @@ import { getCssVarName, kebabCaseJoin } from '../../helpers';
2
2
  import { createStyle, createCssVarsList } from './helpers';
3
3
 
4
4
  export const createStyleMixin =
5
- ({ mappings = {} }) =>
6
- (superclass) => {
7
- const styleAttributes = Object.keys(mappings).map((key) =>
8
- kebabCaseJoin('st', key)
9
- );
10
- return class CustomStyleMixinClass extends superclass {
11
- static get observedAttributes() {
12
- const superAttrs = superclass.observedAttributes || [];
13
- return [...superAttrs, ...styleAttributes];
14
- }
15
-
16
- static get cssVarList() {
17
- return createCssVarsList(superclass.componentName, mappings);
18
- }
19
-
20
- #styleEle = null;
21
-
22
- constructor() {
23
- super();
24
-
25
- this.#createComponentStyle();
26
- this.#createAttrOverrideStyle();
27
- }
28
-
29
- #createAttrOverrideStyle() {
30
- this.#styleEle = document.createElement('style');
31
- this.#styleEle.id = 'style-mixin-overrides';
32
-
33
- this.#styleEle.innerText = '* {}';
34
- this.shadowRoot.prepend(this.#styleEle);
35
- }
36
-
37
- #updateAttrOverrideStyle(attrName, value) {
38
- const style = this.#styleEle.sheet.cssRules[0].style;
39
- const varName = getCssVarName(
40
- superclass.componentName,
41
- attrName.replace(/^st-/, '')
42
- );
43
-
44
- if (value) style.setProperty(varName, value);
45
- else style.removeProperty(varName);
46
- }
47
-
48
- #createComponentStyle() {
49
- const themeStyle = document.createElement('style');
50
- themeStyle.id = 'style-mixin-component';
51
- themeStyle.innerHTML = createStyle(
52
- superclass.componentName,
53
- this.baseSelector,
54
- mappings
55
- );
56
- this.shadowRoot.prepend(themeStyle);
57
- }
58
-
59
- attributeChangedCallback(attrName, oldValue, newValue) {
60
- super.attributeChangedCallback?.(attrName, oldValue, newValue);
61
-
62
- if (styleAttributes.includes(attrName)) {
63
- this.#updateAttrOverrideStyle(attrName, newValue);
5
+ ({ mappings = {}, nestedMappings = {} }) =>
6
+ (superclass) => {
7
+ const styleAttributes = Object.keys(mappings).map((key) =>
8
+ kebabCaseJoin('st', key)
9
+ );
10
+ return class CustomStyleMixinClass extends superclass {
11
+ static get observedAttributes() {
12
+ const superAttrs = superclass.observedAttributes || [];
13
+ return [...superAttrs, ...styleAttributes];
64
14
  }
65
- }
66
-
67
- connectedCallback() {
68
- super.connectedCallback?.();
69
- if (this.shadowRoot.isConnected) {
70
- Array.from(this.attributes).forEach(attr => {
71
- if (styleAttributes.includes(attr.nodeName)) {
72
- this.#updateAttrOverrideStyle(attr.nodeName, attr.value)
73
- }
74
- });
75
- }
76
- }
15
+
16
+ static get cssVarList() {
17
+ return createCssVarsList(superclass.componentName, mappings);
18
+ }
19
+
20
+ #styleEle = null;
21
+
22
+ constructor() {
23
+ super();
24
+
25
+ this.#createComponentStyle();
26
+ this.#createAttrOverrideStyle();
27
+ }
28
+
29
+ #createAttrOverrideStyle() {
30
+ this.#styleEle = document.createElement('style');
31
+ this.#styleEle.id = 'style-mixin-overrides';
32
+
33
+ this.#styleEle.innerText = '* {}';
34
+ this.shadowRoot.prepend(this.#styleEle);
35
+ }
36
+
37
+ #updateAttrOverrideStyle(attrName, value) {
38
+ const style = this.#styleEle.sheet?.cssRules[0].style;
39
+ const varName = getCssVarName(
40
+ superclass.componentName,
41
+ attrName.replace(/^st-/, '')
42
+ );
43
+
44
+ if (value) style?.setProperty(varName, value);
45
+ else style?.removeProperty(varName);
46
+ }
47
+
48
+ #createComponentStyle() {
49
+ const themeStyle = document.createElement('style');
50
+ themeStyle.id = 'style-mixin-component';
51
+ themeStyle.innerHTML = createStyle(
52
+ superclass.componentName,
53
+ this.baseSelector,
54
+ mappings
55
+ );
56
+ this.shadowRoot.prepend(themeStyle);
57
+ }
58
+
59
+ #createComponentNestingStyle() {
60
+ // we need these selectors to be more specific from the theme selectors
61
+ // in order to do it, we are repeating the class name for specificity
62
+ const numOfClassNameSpecifier = 3
63
+
64
+ const rootNode = this.shadowRoot.host.getRootNode()
65
+ const styleId = `${superclass.componentName}-style-mixin-component`
66
+
67
+ const className = superclass.componentName
68
+ this.shadowRoot.host.classList.add(className)
69
+
70
+ if(rootNode.querySelector(`style#${styleId}`)) return;
71
+
72
+ const themeStyle = document.createElement('style');
73
+ themeStyle.id = styleId;
74
+ themeStyle.innerHTML = createStyle(
75
+ superclass.componentName,
76
+ `${superclass.componentName}${Array(numOfClassNameSpecifier).fill(`.${className}`).join('')}`,
77
+ nestedMappings
78
+ );
79
+
80
+ // rootNode can be either a shadow DOM or a light DOM
81
+ if (rootNode.nodeName === '#document') {
82
+ rootNode.head.append(themeStyle)
83
+ } else {
84
+ rootNode.append(themeStyle)
85
+ }
86
+ }
87
+
88
+ attributeChangedCallback(attrName, oldValue, newValue) {
89
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
90
+
91
+ if (styleAttributes.includes(attrName)) {
92
+ this.#updateAttrOverrideStyle(attrName, newValue);
93
+ }
94
+ }
95
+
96
+ connectedCallback() {
97
+ super.connectedCallback?.();
98
+ if (this.shadowRoot.isConnected) {
99
+ this.#createComponentNestingStyle();
100
+
101
+ Array.from(this.attributes).forEach(attr => {
102
+ if (styleAttributes.includes(attr.nodeName)) {
103
+ this.#updateAttrOverrideStyle(attr.nodeName, attr.value)
104
+ }
105
+ });
106
+ }
107
+ }
108
+ };
77
109
  };
78
- };
@@ -0,0 +1,95 @@
1
+ import { forwardAttrs } from '../componentsHelpers/createProxy/helpers';
2
+
3
+ const getChildObserver = (callback) => {
4
+ return new MutationObserver((mutationsList) => {
5
+ for (const mutation of mutationsList) {
6
+ if (mutation.type === 'childList') {
7
+ callback(mutation);
8
+ }
9
+ }
10
+ });
11
+ };
12
+
13
+ const insertNestingLevel = (srcEle, nestingEle) => {
14
+ nestingEle.append(...srcEle.childNodes);
15
+ srcEle.appendChild(nestingEle);
16
+ };
17
+
18
+ // adds a nesting element to the component, and move all existing children
19
+ // to be under the nesting element
20
+ export const enforceNestingElementsStylesMixin =
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
+ }
59
+
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
+ );
67
+
68
+ getObserver().observe(this.shadowRoot.host, {
69
+ childList: true
70
+ });
71
+ };
72
+
73
+ childObserver = getChildObserver(childObserverCallback);
74
+ }
75
+
76
+ connectedCallback() {
77
+ super.connectedCallback?.();
78
+
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
81
+ insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
82
+
83
+ forwardAttrs(
84
+ this.shadowRoot.host,
85
+ this.shadowRoot.host.querySelector(nestingElementTagName),
86
+ forwardAttrOptions
87
+ );
88
+ }
89
+
90
+ getObserver().observe(this.shadowRoot.host, {
91
+ childList: true
92
+ });
93
+ }
94
+ };
95
+ };