@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
package/dist/index.esm.js CHANGED
@@ -256,6 +256,10 @@ const draggableMixin = (superclass) =>
256
256
  }
257
257
  };
258
258
 
259
+ var compose = (...fns) =>
260
+ (val) =>
261
+ fns.reduceRight((res, fn) => fn(res), val);
262
+
259
263
  class DescopeBaseClass extends HTMLElement {}
260
264
 
261
265
  const hoverableMixin =
@@ -438,9 +442,177 @@ const createProxy = ({
438
442
  return compose(hoverableMixin())(ProxyElement);
439
443
  };
440
444
 
441
- const attrs = {
442
- valueMissing: 'data-errormessage-value-missing',
443
- patternMismatch: 'data-errormessage-pattern-mismatch'
445
+ const upperFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
446
+
447
+ const events = [
448
+ 'change',
449
+ 'input',
450
+ 'blur',
451
+ 'focus',
452
+ 'invalid',
453
+ 'valid',
454
+ ];
455
+
456
+ const observedAttributes = [
457
+ 'required',
458
+ 'pattern',
459
+ ];
460
+
461
+ const errorAttributes = {
462
+ valueMissing: 'data-errormessage-value-missing',
463
+ patternMismatch: 'data-errormessage-pattern-mismatch'
464
+ };
465
+ const inputMixin = (superclass) => class InputMixinClass extends superclass {
466
+ static get observedAttributes() {
467
+ return [
468
+ ...superclass.observedAttributes || [],
469
+ ...observedAttributes
470
+ ];
471
+ }
472
+
473
+ static get formAssociated() {
474
+ return true;
475
+ }
476
+
477
+ #internals
478
+
479
+ constructor() {
480
+ super();
481
+
482
+ this.#internals = this.attachInternals();
483
+
484
+ for (const event of events) {
485
+ this[`dispatch${upperFirst(event)}`] = function () {
486
+ this.dispatchInputEvent(event);
487
+ };
488
+ }
489
+ }
490
+
491
+ get defaultErrorMsgValueMissing() {
492
+ return 'Please fill out this field.'
493
+ }
494
+
495
+ get defaultErrorMsgPatternMismatch() {
496
+ return 'Please match the requested format.'
497
+ }
498
+
499
+ getErrorMessage(flags) {
500
+ switch (true) {
501
+ case flags.valueMissing:
502
+ return this.getAttribute(errorAttributes.valueMissing) ||
503
+ this.defaultErrorMsgValueMissing
504
+ case flags.patternMismatch || flags.typeMismatch:
505
+ return this.getAttribute(errorAttributes.patternMismatch) ||
506
+ this.defaultErrorMsgPatternMismatch
507
+ case flags.customError:
508
+ return this.validationMessage
509
+ default:
510
+ return ''
511
+ }
512
+ }
513
+
514
+ setValidity() {
515
+ const validity = this.getValidity();
516
+ this.#internals.setValidity(validity, this.getErrorMessage(validity));
517
+ }
518
+
519
+ get validationMessage() {
520
+ return this.#internals.validationMessage;
521
+ }
522
+
523
+ getValidity() {
524
+ throw Error('getValidity', 'is not implemented')
525
+ }
526
+
527
+ checkValidity() {
528
+ return this.#internals.validity.valid
529
+ }
530
+
531
+ reportValidity() {
532
+ return this.#internals.reportValidity()
533
+ }
534
+
535
+ get validity() {
536
+ return this.#internals.validity
537
+ }
538
+
539
+ setCustomValidity(errorMessage) {
540
+ if(errorMessage){
541
+ this.#internals.setValidity({customError: true}, errorMessage);
542
+ } else {
543
+ this.#internals.setValidity({});
544
+ this.setValidity();
545
+ }
546
+ }
547
+
548
+ get isRequired() {
549
+ return this.hasAttribute('required') && this.getAttribute('required') !== 'false'
550
+ }
551
+
552
+ get pattern() {
553
+ return this.getAttribute('pattern')
554
+ }
555
+
556
+ get value() {
557
+ throw Error('get value', 'is not implemented')
558
+ }
559
+
560
+ set value(value) {
561
+ throw Error('set value', 'is not implemented')
562
+ }
563
+
564
+ handleFocus() {
565
+ throw Error('handleFocus', 'is not implemented')
566
+ }
567
+
568
+ handleInput() {
569
+ this.setValidity();
570
+ this.handleDispatchValidationEvents();
571
+ }
572
+
573
+ handleBlur() {
574
+ throw Error('handleBlur', 'is not implemented')
575
+ }
576
+
577
+ handleChange() {
578
+ throw Error('handleChange', 'is not implemented')
579
+ }
580
+
581
+ dispatchInputEvent(eventName) {
582
+ this[`on${eventName}`]?.(); // in case we got an event callback as property
583
+ this.dispatchEvent(new InputEvent(eventName));
584
+ }
585
+
586
+ attributeChangedCallback(attrName, oldValue, newValue) {
587
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
588
+
589
+ if (observedAttributes.includes(attrName)) {
590
+ this.setValidity();
591
+ }
592
+ }
593
+
594
+ handleDispatchValidationEvents(){
595
+ if(this.checkValidity()) {
596
+ this.dispatchValid();
597
+ } else {
598
+ this.dispatchInvalid();
599
+ }
600
+ }
601
+
602
+ connectedCallback() {
603
+ super.connectedCallback?.();
604
+
605
+ this.setValidity();
606
+ this.handleDispatchValidationEvents();
607
+
608
+ // create proxy replace the addEventListener fn
609
+ // and we want to be able to access the focus events
610
+ // of this element and not the nested element's events
611
+ this.onfocus = this.handleFocus.bind(this);
612
+ this.addEventListener('input', this.handleInput.bind(this));
613
+ this.addEventListener('blur', this.handleBlur.bind(this));
614
+ this.addEventListener('change', this.handleBlur.bind(this));
615
+ }
444
616
  };
445
617
 
446
618
  const errorAttrs = ['invalid', 'has-error-message'];
@@ -457,79 +629,140 @@ const propertyObserver = (src, target, property) => {
457
629
  });
458
630
  };
459
631
 
460
- const inputMixin = (superclass) =>
461
- class InputMixinClass extends superclass {
462
- static get formAssociated() {
463
- return true;
632
+ // recursively take the first slot child until it finds an element which is not a slot
633
+ // stops after "nestingLevel" times
634
+ const getNestedInput = (ele) => {
635
+ if (!ele) return;
636
+
637
+ const nestingLevel = 10;
638
+
639
+ let nonSlotEle = ele;
640
+ for (let i = 0; i < nestingLevel; i++) {
641
+ nonSlotEle = nonSlotEle.assignedElements()[0];
642
+ if (nonSlotEle.localName !== 'slot') return nonSlotEle
643
+ }
644
+ };
645
+
646
+ const proxyInputMixin = (superclass) =>
647
+ class proxyInputMixinClass extends inputMixin(superclass) {
648
+ static get observedAttributes() {
649
+ return [...superclass.observedAttributes || [], ...errorAttrs];
464
650
  }
465
651
 
466
- #internals;
652
+ #inputElement
467
653
 
468
654
  constructor() {
469
655
  super();
470
656
 
471
- this.#internals = this.attachInternals();
657
+ this.#inputElement = super.inputElement;
658
+
659
+ // this is our way to identify that the form was submitted
660
+ // in this case, we want the input to be in error state if it's not valid
661
+ this.addEventListener('focus', (e) => {
662
+ if (e.relatedTarget?.form) {
663
+ if (!this.checkValidity()) {
664
+ this.setAttribute('invalid', 'true');
665
+ }
666
+
667
+ if (this.hasAttribute('invalid')) {
668
+ this.reportValidityOnInternalInput();
669
+ }
670
+ }
671
+ });
672
+
673
+ this.addEventListener('invalid', () => {
674
+ this.setInternalInputErrorMessage();
675
+ this.setAttribute('error-message', this.validationMessage);
676
+ });
677
+
678
+ this.addEventListener('valid', () => {
679
+ this.removeAttribute('invalid');
680
+ });
681
+ }
682
+
683
+ get inputElement() {
684
+ const inputSlot = this.baseEle.shadowRoot.querySelector('slot[name="input"]');
685
+ const textAreaSlot = this.baseEle.shadowRoot.querySelector('slot[name="textarea"]');
686
+
687
+ this.#inputElement ??= getNestedInput(inputSlot) || getNestedInput(textAreaSlot);
688
+
689
+ if (!this.#inputElement) throw Error('no input was found');
690
+
691
+ return this.#inputElement
692
+ }
693
+
694
+ set inputElement(ele) {
695
+ this.#inputElement = ele;
696
+ }
697
+
698
+ getValidity() {
699
+ return this.inputElement.validity
472
700
  }
473
701
 
474
- formAssociatedCallback() {
475
- this.setValidity?.();
702
+ reportValidityOnInternalInput() {
703
+ setTimeout(() => {
704
+ this.inputElement.reportValidity();
705
+ }, 0);
476
706
  }
477
707
 
478
- setValidationAttribute(attr) {
479
- const validationAttr = this.getAttribute(attr);
480
- if (validationAttr) {
481
- this.proxyElement.setAttribute('error-message', validationAttr);
708
+ handleBlur() { }
709
+
710
+ handleFocus() {
711
+ this.inputElement.focus();
712
+ if (this.hasAttribute('invalid')) {
713
+ this.reportValidityOnInternalInput();
482
714
  }
483
- // normalize vaadin error attributes to have a boolean value
484
- errorAttrs.forEach((att) => this.proxyElement.setAttribute(att, 'true'));
485
715
  }
486
716
 
487
- validate() {
488
- const { valueMissing, patternMismatch, typeMismatch } = this.validity;
489
- if (valueMissing) {
490
- this.setValidationAttribute(attrs.valueMissing);
491
- } else if (typeMismatch || patternMismatch) {
492
- this.setValidationAttribute(attrs.patternMismatch);
717
+ // we want reportValidity to behave like form submission
718
+ reportValidity() {
719
+ const isValid = super.reportValidity();
720
+ if (!isValid) {
721
+ this.setAttribute('invalid', 'true');
722
+ this.inputElement.focus();
723
+ }
724
+ this.reportValidityOnInternalInput();
725
+ }
726
+
727
+ setInternalInputErrorMessage() {
728
+ if (!this.checkValidity()) {
729
+ this.inputElement.setCustomValidity(this.validationMessage);
493
730
  }
494
731
  }
495
732
 
496
733
  connectedCallback() {
734
+ this.baseEle = this.shadowRoot.querySelector(this.baseSelector);
735
+
497
736
  super.connectedCallback?.();
498
737
 
499
- this.baseEle = this.shadowRoot.querySelector(this.baseSelector);
738
+ this.inputElement.addEventListener('input', () => {
739
+ this.inputElement.setCustomValidity('');
740
+ if (!this.inputElement.checkValidity())
741
+ this.setInternalInputErrorMessage();
742
+ });
743
+
744
+ this.inputElement.addEventListener('invalid', () => {
745
+ this.setValidity();
746
+ this.setInternalInputErrorMessage();
747
+ this.setAttribute('error-message', this.validationMessage);
748
+ });
500
749
 
501
750
  // this is needed in order to make sure the form input validation is working
502
751
  if (!this.hasAttribute('tabindex')) {
503
752
  this.setAttribute('tabindex', 0);
504
753
  }
505
754
 
506
- this.inputElement ??= this.baseEle.shadowRoot.querySelector('slot[name="input"]')?.assignedElements()[0] ||
507
- this.baseEle.shadowRoot.querySelector('slot[name="textarea"]')?.assignedElements()[0];
508
- if (!this.inputElement) throw Error('no input was found');
509
-
510
755
  // sync properties
511
756
  propertyObserver(this, this.inputElement, 'value');
512
757
  this.setSelectionRange = this.inputElement.setSelectionRange?.bind(this.inputElement);
758
+ }
513
759
 
514
- this.validity = this.inputElement.validity;
515
-
516
- this.setValidity = () => {
517
- this.#internals.setValidity(this.inputElement.validity, this.inputElement.validationMessage);
518
- };
519
-
520
- this.inputElement.oninput = () => {
521
- this.value = this.inputElement.value;
522
- this.setValidity();
523
- };
524
-
525
- this.onfocus = () => {
526
- setTimeout(() => this.inputElement.reportValidity(), 0);
527
- this.validate();
528
- };
760
+ attributeChangedCallback(attrName, oldValue, newValue) {
761
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
529
762
 
530
- this.inputElement.oninvalid = () => {
531
- this.validate();
532
- };
763
+ if (attrName === 'invalid' && newValue === '') {
764
+ this.setAttribute('invalid', 'true');
765
+ }
533
766
  }
534
767
  };
535
768
 
@@ -561,11 +794,6 @@ const componentNameValidationMixin = (superclass) =>
561
794
 
562
795
  const getComponentName = (name) => kebabCaseJoin(DESCOPE_PREFIX, name);
563
796
 
564
- const compose =
565
- (...fns) =>
566
- (val) =>
567
- fns.reduceRight((res, fn) => fn(res), val);
568
-
569
797
  const componentName$i = getComponentName('button');
570
798
 
571
799
  const editorOverrides = `vaadin-button::part(label) { pointer-events: none; }`;
@@ -664,7 +892,7 @@ const Checkbox = compose(
664
892
  }
665
893
  }),
666
894
  draggableMixin,
667
- inputMixin,
895
+ proxyInputMixin,
668
896
  componentNameValidationMixin
669
897
  )(
670
898
  createProxy({
@@ -846,7 +1074,7 @@ const TextField = compose(
846
1074
  mappings: textFieldMappings
847
1075
  }),
848
1076
  draggableMixin,
849
- inputMixin,
1077
+ proxyInputMixin,
850
1078
  componentNameValidationMixin
851
1079
  )(
852
1080
  createProxy({
@@ -1019,65 +1247,65 @@ const insertNestingLevel = (srcEle, nestingEle) => {
1019
1247
  // to be under the nesting element
1020
1248
  const enforceNestingElementsStylesMixin =
1021
1249
  ({ nestingElementTagName, nestingElementDestSlotName, forwardAttrOptions }) =>
1022
- (superclass) => {
1023
- const getChildNodeEle = () =>
1024
- Object.assign(document.createElement(nestingElementTagName), {
1025
- slot: nestingElementDestSlotName
1026
- });
1250
+ (superclass) => {
1251
+ const getChildNodeEle = () =>
1252
+ document.createElement(nestingElementTagName, {
1253
+ slot: nestingElementDestSlotName
1254
+ });
1027
1255
 
1028
- let childObserver;
1029
-
1030
- const getObserver = () => childObserver;
1256
+ let childObserver;
1031
1257
 
1032
- return class EnforceNestingElementsStylesMixinClass extends superclass {
1033
- constructor() {
1034
- super();
1258
+ const getObserver = () => childObserver;
1035
1259
 
1036
- const childObserverCallback = () => {
1037
- // we are going to change the DOM, so we need to disconnect the observer before
1038
- // and reconnect it after the child component is added
1039
- getObserver().disconnect(this.shadowRoot.host);
1040
-
1041
- const isNestingElementExist = this.shadowRoot.host.querySelector(nestingElementTagName);
1042
- const hasNewChildren = this.shadowRoot.host.childNodes.length > 0;
1043
-
1044
- if (!isNestingElementExist && hasNewChildren) {
1045
- // if before there were no children and now there are children - insert
1046
- insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
1047
- } else if (isNestingElementExist && hasNewChildren) {
1048
- // if children existed, and they changed -
1049
- // we need to update (move) the new children into
1050
- // descope-text and remove previous children
1051
- this.shadowRoot.host.querySelector(child).remove();
1052
- insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
1053
- }
1054
- else if (isNestingElementExist && !hasNewChildren) {
1055
- // if children existed and now there are none -
1056
- // we need to remove descope-text completely
1057
- this.shadowRoot.host.querySelector(child).remove();
1058
- }
1260
+ let isMutating = false;
1059
1261
 
1060
- // we need a new observer, because we remove the nesting element
1061
- this.shadowRoot.host.querySelector(nestingElementTagName) &&
1062
- forwardAttrs(
1063
- this.shadowRoot.host,
1064
- this.shadowRoot.host.querySelector(nestingElementTagName),
1065
- forwardAttrOptions
1066
- );
1262
+ const filterNestingElement = (node) => node.localName !== nestingElementTagName;
1263
+ return class EnforceNestingElementsStylesMixinClass extends superclass {
1264
+ constructor() {
1265
+ super();
1067
1266
 
1068
- getObserver().observe(this.shadowRoot.host, {
1069
- childList: true
1070
- });
1071
- };
1267
+ const childObserverCallback = (mutation, observer) => {
1072
1268
 
1073
- childObserver = getChildObserver(childObserverCallback);
1074
- }
1269
+ // we are going to change the DOM, so we need to skip the upcoming mutations
1270
+ if (isMutating) return;
1075
1271
 
1076
- connectedCallback() {
1077
- super.connectedCallback?.();
1272
+ isMutating = true;
1273
+
1274
+ const { addedNodes, removedNodes } = mutation;
1275
+
1276
+ const nestingElement = this.shadowRoot.host.querySelector(nestingElementTagName);
1277
+ const hasNewChildren = Array.from(addedNodes)
1278
+ .filter(filterNestingElement)
1279
+ .length > 0;
1280
+ const hasRemovedChildren = Array.from(removedNodes)
1281
+ .filter(filterNestingElement)
1282
+ .length > 0;
1283
+
1284
+ if (!nestingElement && hasNewChildren) {
1285
+ // if before there were no children and now there are children - insert
1286
+ this.handleNestingLevelInsertion();
1287
+
1288
+ } else if (nestingElement && hasNewChildren) {
1289
+ // if children existed, and they changed -
1290
+ // we need to update (move) the new children into
1291
+ // descope-text and remove previous children
1292
+ nestingElement.replaceChildren(...addedNodes);
1293
+ }
1294
+ else if (nestingElement && !hasNewChildren && hasRemovedChildren) {
1295
+ // // if children existed and now there are none -
1296
+ // // we need to remove descope-text completely
1297
+ nestingElement.remove();
1298
+ }
1078
1299
 
1079
- if (this.shadowRoot.host.childNodes.length > 0) {
1080
- // on the first render - we want to move all component's children to be under descope-text
1300
+ setTimeout(() => {
1301
+ isMutating = false;
1302
+ });
1303
+ };
1304
+
1305
+ childObserver = getChildObserver(childObserverCallback);
1306
+ }
1307
+
1308
+ handleNestingLevelInsertion() {
1081
1309
  insertNestingLevel(this.shadowRoot.host, getChildNodeEle());
1082
1310
 
1083
1311
  forwardAttrs(
@@ -1087,12 +1315,20 @@ const enforceNestingElementsStylesMixin =
1087
1315
  );
1088
1316
  }
1089
1317
 
1090
- getObserver().observe(this.shadowRoot.host, {
1091
- childList: true
1092
- });
1093
- }
1318
+ connectedCallback() {
1319
+ super.connectedCallback?.();
1320
+
1321
+ if (this.shadowRoot.host.childNodes.length > 0) {
1322
+ // on the first render - we want to move all component's children to be under descope-text
1323
+ this.handleNestingLevelInsertion();
1324
+ }
1325
+
1326
+ getObserver().observe(this.shadowRoot.host, {
1327
+ childList: true
1328
+ });
1329
+ }
1330
+ };
1094
1331
  };
1095
- };
1096
1332
 
1097
1333
  const componentName$a = getComponentName('text');
1098
1334
 
@@ -1230,7 +1466,7 @@ const EmailField = compose(
1230
1466
  }
1231
1467
  }),
1232
1468
  draggableMixin,
1233
- inputMixin,
1469
+ proxyInputMixin,
1234
1470
  componentNameValidationMixin
1235
1471
  )(
1236
1472
  createProxy({
@@ -1422,7 +1658,7 @@ const NumberField = compose(
1422
1658
  }
1423
1659
  }),
1424
1660
  draggableMixin,
1425
- inputMixin,
1661
+ proxyInputMixin,
1426
1662
  componentNameValidationMixin
1427
1663
  )(
1428
1664
  createProxy({
@@ -1476,6 +1712,8 @@ overrides$4 = `
1476
1712
 
1477
1713
  customElements.define(componentName$5, NumberField);
1478
1714
 
1715
+ var BaseInputClass = inputMixin(HTMLElement); //todo: maybe we should use base class?
1716
+
1479
1717
  const focusElement = (ele) => {
1480
1718
  ele?.focus();
1481
1719
  ele?.setSelectionRange(1, 1);
@@ -1492,14 +1730,13 @@ const getSanitizedCharacters = (str) => {
1492
1730
 
1493
1731
  const componentName$4 = getComponentName('passcode-internal');
1494
1732
 
1495
- class PasscodeInternal extends HTMLElement {
1733
+ class PasscodeInternal extends BaseInputClass {
1496
1734
  static get observedAttributes() {
1497
1735
  return [
1736
+ ...BaseInputClass.observedAttributes,
1498
1737
  'disabled',
1499
1738
  'bordered',
1500
- 'size',
1501
- 'required',
1502
- 'pattern'
1739
+ 'size'
1503
1740
  ];
1504
1741
  }
1505
1742
 
@@ -1507,12 +1744,6 @@ class PasscodeInternal extends HTMLElement {
1507
1744
  return componentName$4;
1508
1745
  }
1509
1746
 
1510
- static get formAssociated() {
1511
- return true;
1512
- }
1513
-
1514
- #internals
1515
-
1516
1747
  constructor() {
1517
1748
  super();
1518
1749
  const template = document.createElement('template');
@@ -1536,23 +1767,9 @@ class PasscodeInternal extends HTMLElement {
1536
1767
 
1537
1768
  this.baseSelector = ':host > div';
1538
1769
 
1539
- this.#internals = this.attachInternals();
1540
-
1541
1770
  this.inputs = Array.from(this.querySelectorAll('descope-text-field'));
1542
1771
  }
1543
1772
 
1544
- checkValidity() {
1545
- // we need to toggle the has-error-message so the text inside the digits will become red when there is an error
1546
- if (this.#internals.validity.valid) {
1547
- this.inputs.forEach(input => input.removeAttribute('has-error-message'));
1548
- } else {
1549
- this.inputs.forEach(input => input.setAttribute('has-error-message', 'true'));
1550
- // we need to call it so the has-error-message with have the correct format (="true")
1551
- this.oninvalid?.();
1552
- }
1553
- return this.#internals.validity.valid
1554
- }
1555
-
1556
1773
  get digits() {
1557
1774
  return Number.parseInt(this.getAttribute('digits')) || 6
1558
1775
  }
@@ -1561,59 +1778,54 @@ class PasscodeInternal extends HTMLElement {
1561
1778
  return this.inputs.map(({ value }) => value).join('')
1562
1779
  }
1563
1780
 
1564
- set value(val) { }
1781
+ set value(val) {
1782
+ if(val === this.value) return;
1783
+
1784
+ const charArr = getSanitizedCharacters(val);
1565
1785
 
1566
- get isRequired() {
1567
- return this.hasAttribute('required') && this.getAttribute('required') !== 'false'
1786
+ if (charArr.length) {
1787
+ this.fillDigits(charArr, this.inputs[0]);
1788
+ }
1568
1789
  }
1569
1790
 
1570
1791
  get pattern() {
1571
1792
  return `^$|^\\d{${this.digits},}$`
1572
1793
  }
1573
1794
 
1574
- get valueMissingErrMsg() {
1575
- return 'Please fill out this field.'
1576
- }
1577
-
1578
- get patternMismatchErrMsg() {
1579
- return `Must be a ${this.digits} digits number.`
1580
- }
1581
-
1582
- get validity() {
1583
- return this.#internals.validity;
1584
- }
1585
-
1586
- get validationMessage() {
1587
- return this.#internals.validationMessage;
1588
- }
1589
-
1590
- reportValidity() {
1591
- this.#internals.reportValidity();
1795
+ handleInputsInvalid() {
1796
+ setTimeout(() => {
1797
+ if (this.hasAttribute('invalid')) {
1798
+ this.inputs.forEach(input => input.setAttribute('invalid', 'true'));
1799
+ }
1800
+ });
1592
1801
  }
1593
1802
 
1594
- formAssociatedCallback() {
1595
- this.setValidity?.();
1803
+ handleInputsValid() {
1804
+ this.inputs.forEach(input => input.removeAttribute('invalid'));
1596
1805
  }
1597
1806
 
1598
- setValidity = () => {
1807
+ getValidity() {
1599
1808
  if (this.isRequired && !this.value) {
1600
- this.#internals.setValidity({ valueMissing: true }, this.valueMissingErrMsg);
1809
+ return { valueMissing: true };
1601
1810
  }
1602
1811
  else if (this.pattern && !new RegExp(this.pattern).test(this.value)) {
1603
- this.#internals.setValidity({ patternMismatch: true }, this.patternMismatchErrMsg);
1812
+ return { patternMismatch: true };
1604
1813
  }
1605
1814
  else {
1606
- this.#internals.setValidity({});
1815
+ return {}
1607
1816
  }
1608
1817
  };
1609
1818
 
1819
+ handleFocus() {
1820
+ this.inputs[0].focus();
1821
+ }
1822
+
1610
1823
  async connectedCallback() {
1611
- this.setValidity();
1824
+ super.connectedCallback();
1612
1825
  this.initInputs();
1613
1826
 
1614
- this.onfocus = () => {
1615
- this.inputs[0].focus();
1616
- };
1827
+ this.addEventListener('invalid', this.handleInputsInvalid);
1828
+ this.addEventListener('valid', this.handleInputsValid);
1617
1829
  }
1618
1830
 
1619
1831
  getInputIdx(inputEle) {
@@ -1644,6 +1856,10 @@ class PasscodeInternal extends HTMLElement {
1644
1856
  !currentInput.hasAttribute('focused') && focusElement(currentInput);
1645
1857
  };
1646
1858
 
1859
+ handleBlur() {
1860
+ this.handleInputsInvalid();
1861
+ }
1862
+
1647
1863
  initInputs() {
1648
1864
  this.inputs.forEach((input) => {
1649
1865
 
@@ -1652,7 +1868,7 @@ class PasscodeInternal extends HTMLElement {
1652
1868
  // if not, the component is no longer focused and we should simulate blur
1653
1869
  input.addEventListener('blur', () => {
1654
1870
  const timerId = setTimeout(() => {
1655
- this.dispatchEvent(new Event('blur'));
1871
+ this.dispatchBlur();
1656
1872
  });
1657
1873
 
1658
1874
  this.inputs.forEach((ele) =>
@@ -1660,13 +1876,13 @@ class PasscodeInternal extends HTMLElement {
1660
1876
  );
1661
1877
  });
1662
1878
 
1663
- input.oninput = (e) => {
1879
+ input.oninput = () => {
1664
1880
  const charArr = getSanitizedCharacters(input.value);
1665
1881
 
1666
1882
  if (!charArr.length) input.value = ''; // if we got an invalid value we want to clear the input
1667
1883
  else this.fillDigits(charArr, input);
1668
1884
 
1669
- this.setValidity();
1885
+ this.dispatchInput();
1670
1886
  };
1671
1887
 
1672
1888
  input.onkeydown = ({ key }) => {
@@ -1679,27 +1895,21 @@ class PasscodeInternal extends HTMLElement {
1679
1895
  !prevInput.hasAttribute('focused') && setTimeout(() => {
1680
1896
  focusElement(prevInput);
1681
1897
  });
1898
+
1899
+ this.dispatchInput();
1682
1900
  } else if (key.match(/^(\d)$/g)) { // if input is a digit
1683
1901
  input.value = ''; // we are clearing the previous value so we can override it with the new value
1684
1902
  }
1685
1903
 
1686
- this.setValidity();
1687
1904
  };
1688
1905
  });
1689
1906
  }
1690
1907
 
1691
- attributeChangedCallback(
1692
- attrName,
1693
- oldValue,
1694
- newValue
1695
- ) {
1696
- const validationRelatedAttributes = ['required', 'pattern'];
1908
+ attributeChangedCallback(attrName, oldValue, newValue) {
1909
+ super.attributeChangedCallback(attrName, oldValue, newValue);
1697
1910
 
1698
1911
  if (oldValue !== newValue) {
1699
- if (validationRelatedAttributes.includes(attrName)) {
1700
- this.setValidity();
1701
- }
1702
- else if (PasscodeInternal.observedAttributes.includes(attrName)) {
1912
+ if (PasscodeInternal.observedAttributes.includes(attrName) && !BaseInputClass.observedAttributes.includes(attrName)) {
1703
1913
  this.inputs.forEach((input) => input.setAttribute(attrName, newValue));
1704
1914
  }
1705
1915
  }
@@ -1771,7 +1981,7 @@ const Passcode = compose(
1771
1981
  }
1772
1982
  }),
1773
1983
  draggableMixin,
1774
- inputMixin,
1984
+ proxyInputMixin,
1775
1985
  componentNameValidationMixin,
1776
1986
  customMixin
1777
1987
  )(
@@ -1858,7 +2068,7 @@ const PasswordField = compose(
1858
2068
  }
1859
2069
  }),
1860
2070
  draggableMixin,
1861
- inputMixin,
2071
+ proxyInputMixin,
1862
2072
  componentNameValidationMixin
1863
2073
  )(
1864
2074
  createProxy({
@@ -1924,7 +2134,7 @@ const SwitchToggle = compose(
1924
2134
  }
1925
2135
  }),
1926
2136
  draggableMixin,
1927
- inputMixin,
2137
+ proxyInputMixin,
1928
2138
  componentNameValidationMixin
1929
2139
  )(
1930
2140
  createProxy({
@@ -2015,7 +2225,7 @@ const TextArea = compose(
2015
2225
  }
2016
2226
  }),
2017
2227
  draggableMixin,
2018
- inputMixin,
2228
+ proxyInputMixin,
2019
2229
  componentNameValidationMixin
2020
2230
  )(
2021
2231
  createProxy({
@@ -2442,7 +2652,7 @@ const textField = (vars) => ({
2442
2652
  [vars.borderColor]: globalRefs$6.colors.surface.main
2443
2653
  },
2444
2654
 
2445
- _hasErrorMessage: {
2655
+ _invalid: {
2446
2656
  [vars.borderColor]: globalRefs$6.colors.error.main,
2447
2657
  [vars.color]: globalRefs$6.colors.error.main,
2448
2658
  [vars.placeholderColor]: globalRefs$6.colors.error.light