@descope/web-components-ui 1.0.70 → 1.0.72

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. package/dist/index.esm.js +420 -464
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/umd/809.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-box-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 -1
  10. package/dist/umd/descope-email-field-index-js.js +1 -1
  11. package/dist/umd/descope-image-index-js.js +1 -0
  12. package/dist/umd/descope-link-index-js.js +1 -1
  13. package/dist/umd/descope-loader-linear-index-js.js +1 -1
  14. package/dist/umd/descope-loader-radial-index-js.js +1 -1
  15. package/dist/umd/descope-logo-index-js.js +1 -1
  16. package/dist/umd/descope-number-field-index-js.js +1 -1
  17. package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -1
  18. package/dist/umd/descope-passcode-index-js.js +1 -1
  19. package/dist/umd/descope-password-field-index-js.js +1 -1
  20. package/dist/umd/descope-switch-toggle-index-js.js +1 -1
  21. package/dist/umd/descope-text-area-index-js.js +1 -1
  22. package/dist/umd/descope-text-field-index-js.js +1 -1
  23. package/dist/umd/descope-text-index-js.js +1 -1
  24. package/dist/umd/index.js +1 -1
  25. package/package.json +1 -1
  26. package/src/baseClasses/createBaseClass.js +29 -3
  27. package/src/baseClasses/createBaseInputClass.js +9 -0
  28. package/src/components/descope-image/Image.js +53 -0
  29. package/src/components/descope-image/index.js +5 -0
  30. package/src/components/descope-passcode/Passcode.js +1 -1
  31. package/src/components/descope-passcode/descope-passcode-internal/PasscodeInternal.js +67 -51
  32. package/src/helpers/mixinsHelpers.js +26 -9
  33. package/src/index.js +1 -0
  34. package/src/mixins/changeMixin.js +13 -39
  35. package/src/mixins/componentNameValidationMixin.js +2 -4
  36. package/src/mixins/createProxy.js +45 -53
  37. package/src/mixins/createStyleMixin/index.js +2 -0
  38. package/src/mixins/focusMixin.js +20 -125
  39. package/src/mixins/hoverableMixin.js +10 -16
  40. package/src/mixins/index.js +1 -0
  41. package/src/mixins/inputValidationMixin.js +10 -30
  42. package/src/mixins/normalizeBooleanAttributesMixin.js +11 -0
  43. package/src/mixins/proxyInputMixin.js +51 -58
  44. package/src/theme/components/container.js +1 -1
  45. package/src/theme/components/image.js +7 -0
  46. package/src/theme/components/index.js +3 -1
  47. package/dist/umd/775.js +0 -1
  48. package/src/baseClasses/BaseInputClass.js +0 -4
package/dist/index.esm.js CHANGED
@@ -22,8 +22,6 @@ const compose = (...fns) =>
22
22
  (val) =>
23
23
  fns.reduceRight((res, fn) => fn(res), val);
24
24
 
25
- const upperFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
26
-
27
25
  const isFunction = (maybeFunc) => typeof maybeFunc === 'function';
28
26
 
29
27
  const DESCOPE_PREFIX = 'descope';
@@ -384,6 +382,8 @@ const createStyleMixin =
384
382
  }
385
383
 
386
384
  disconnectedCallback() {
385
+ super.disconnectedCallback?.();
386
+
387
387
  this.#disconnectThemeManager?.();
388
388
  }
389
389
  };
@@ -420,56 +420,40 @@ const draggableMixin = (superclass) =>
420
420
  }
421
421
  };
422
422
 
423
- const componentNameValidationMixin = (superclass) =>
424
- class ComponentNameValidationMixinClass extends superclass {
425
- #checkComponentName() {
426
- const currentComponentName = this.shadowRoot.host.tagName.toLowerCase();
423
+ // create a dispatch event function that also calls to the onevent function in case it's set
424
+ // usage example:
425
+ // #dispatchSomething = createDispatchEvent.bind(this, 'something' { ...options })
426
+ // this will dispatch a new event when called, but also call to "onsomething"
427
+ function createDispatchEvent(eventName, options = {}) {
428
+ const event = new Event(eventName, options);
427
429
 
428
- if (!superclass.componentName) {
429
- throw Error(
430
- `component name is not defined on super class, make sure you have a static get for "componentName"`
431
- );
432
- }
430
+ this[`on${eventName}`]?.(event); // in case we got an event callback as property
431
+ this.dispatchEvent(event);
432
+ }
433
433
 
434
- if (currentComponentName !== superclass.componentName) {
435
- throw Error(
436
- `component name mismatch, expected "${superclass.componentName}", current "${currentComponentName}"`
437
- );
438
- }
439
- }
434
+ // add an event listener that is automatically removed on disconnect
435
+ // usage example:
436
+ // createEventListener.call(this,'change', this.onChange, { element? , ...options })
437
+ function createEventListener(event, callback, { element, ...options } = {}) {
438
+ const timerId = setTimeout(() => console.warn(this.localName, 'is not using "createBaseClass", events will not be removed automatically on disconnect'), 2000);
440
439
 
441
- connectedCallback() {
442
- super.connectedCallback?.();
443
- if (this.shadowRoot.isConnected) {
444
- this.#checkComponentName();
445
- }
446
- }
447
- };
440
+ this.addEventListener('connected', () => {
441
+ clearTimeout(timerId);
442
+ }, { once: true });
448
443
 
449
- const hoverableMixin =
450
- (superclass) =>
451
- class HoverableMixinClass extends superclass {
452
- #boundOnMouseOver = this.#onMouseOver.bind(this)
453
-
454
- #onMouseOver(e) {
455
- this.setAttribute('hover', 'true');
456
- e.target.addEventListener(
457
- 'mouseleave',
458
- () => this.shadowRoot.host.removeAttribute('hover'),
459
- { once: true }
460
- );
461
- }
444
+ const targetEle = element || this;
445
+ const boundCallback = callback.bind(this);
462
446
 
463
- connectedCallback() {
464
- super.connectedCallback?.();
447
+ const onDisconnect = () => {
448
+ targetEle.removeEventListener(event, boundCallback);
449
+ };
465
450
 
466
- const baseElement = this.shadowRoot.querySelector(
467
- this.baseSelector
468
- );
451
+ this.addEventListener('disconnected', onDisconnect, { once: true });
469
452
 
470
- baseElement.addEventListener('mouseover', this.#boundOnMouseOver);
471
- }
472
- };
453
+ targetEle.addEventListener(event, boundCallback, options);
454
+
455
+ return onDisconnect
456
+ }
473
457
 
474
458
  const createBaseClass = ({ componentName, baseSelector = '' }) => {
475
459
  class DescopeBaseClass extends HTMLElement {
@@ -478,10 +462,17 @@ const createBaseClass = ({ componentName, baseSelector = '' }) => {
478
462
  }
479
463
 
480
464
  #baseElement;
465
+
466
+ #dispatchConnected = createDispatchEvent.bind(this, 'connected')
467
+ #dispatchDisconnected = createDispatchEvent.bind(this, 'disconnected')
468
+
469
+ // base selector is the selector for the component wrapper,
470
+ // it's the highest element that is relevant for the layout
481
471
  get baseSelector() {
482
472
  return baseSelector
483
473
  }
484
474
 
475
+ // this is the base element, which returned by querying the base selector
485
476
  get baseElement() {
486
477
  this.#baseElement ??= this.baseSelector ?
487
478
  this.rootElement.querySelector(this.baseSelector) :
@@ -490,12 +481,31 @@ const createBaseClass = ({ componentName, baseSelector = '' }) => {
490
481
  return this.#baseElement
491
482
  }
492
483
 
484
+ // this is the component root level element,
485
+ // it can be either a shadow root or the component's node from the light DOM
493
486
  get rootElement() {
494
487
  return this.shadowRoot || this
495
488
  }
489
+
490
+ connectedCallback() {
491
+ super.connectedCallback?.();
492
+
493
+ // we are waiting for all components to listen before dispatching
494
+ setTimeout(this.#dispatchConnected);
495
+ }
496
+
497
+ disconnectedCallback() {
498
+ super.disconnectedCallback?.();
499
+
500
+ this.#dispatchDisconnected();
501
+ }
496
502
  }
497
503
 
498
- return compose(componentNameValidationMixin, hoverableMixin)(DescopeBaseClass)
504
+ return compose(
505
+ componentNameValidationMixin,
506
+ hoverableMixin,
507
+ normalizeBooleanAttributesMixin
508
+ )(DescopeBaseClass)
499
509
  };
500
510
 
501
511
  const createProxy = ({
@@ -507,87 +517,69 @@ const createProxy = ({
507
517
  includeAttrsSync = [],
508
518
  includeForwardProps = []
509
519
  }) => {
510
- const template = `
511
- <style id="create-proxy"></style>
512
- <${wrappedEleName}>
513
- <slot></slot>
514
- ${slots.map((slot) => `<slot name="${slot}" slot="${slot}"></slot>`).join('')}
515
- </${wrappedEleName}>
516
- `;
517
-
518
520
  class ProxyClass extends createBaseClass({ componentName, baseSelector: wrappedEleName }) {
519
- constructor() {
520
- super().attachShadow({ mode: 'open' }).innerHTML = template;
521
- this.hostElement = this.shadowRoot.host;
522
- this.shadowRoot.getElementById('create-proxy').innerHTML =
523
- isFunction(style) ? style() : style;
524
- }
521
+ #dispatchBlur = createDispatchEvent.bind(this, 'blur')
522
+ #dispatchFocus = createDispatchEvent.bind(this, 'focus')
525
523
 
526
- #boundOnFocus = this.#onFocus.bind(this);
527
-
528
- // we want to focus on the proxy element when focusing our WCP
529
- #onFocus() {
530
- this.proxyElement.focus();
524
+ constructor() {
525
+ super().attachShadow({ mode: 'open' }).innerHTML = `
526
+ <style id="create-proxy">${isFunction(style) ? style() : style
527
+ }</style>
528
+ <${wrappedEleName}>
529
+ <slot></slot>
530
+ ${slots.map((slot) => `<slot name="${slot}" slot="${slot}"></slot>`).join('')}
531
+ </${wrappedEleName}>
532
+ `;
531
533
  }
532
534
 
533
- focus = this.#onFocus
535
+ focus = () => this.baseElement.focus()
534
536
 
535
537
  connectedCallback() {
536
- if (this.shadowRoot.isConnected) {
537
- this.proxyElement = this.shadowRoot.querySelector(wrappedEleName);
538
-
539
- this.addEventListener('focus', this.#boundOnFocus);
540
-
541
- // this is needed for components that uses props, such as combo box
542
- forwardProps(this.hostElement, this.proxyElement, includeForwardProps);
543
-
544
- // `onkeydown` is set on `proxyElement` support proper tab-index navigation
545
- // this support is needed since both proxy host and element catch `focus`/`blur` event
546
- // which causes faulty behavior.
547
- // we need this to happen only when the proxy component is in the light DOM,
548
- // otherwise it will focus the nested proxy element
549
- this.proxyElement.onkeydown = (e) => {
550
- if (e.shiftKey && e.keyCode === 9 && this.getRootNode() === document) {
551
- this.removeAttribute('tabindex');
552
- // We want to defer the action of setting the tab index back
553
- // so it will happen after focusing the previous element
554
- setTimeout(() => this.setAttribute('tabindex', '0'), 0);
555
- }
556
- };
538
+ super.connectedCallback?.();
557
539
 
558
- syncAttrs(this.proxyElement, this.hostElement, {
559
- excludeAttrs: excludeAttrsSync,
560
- includeAttrs: includeAttrsSync
561
- });
562
- }
563
- }
540
+ createEventListener.call(this, 'blur', (e) => {
541
+ this.#dispatchBlur();
542
+ }, { element: this.baseElement });
564
543
 
565
- attributeChangedCallback() {
566
- if (!this.proxyElement) {
567
- return;
568
- }
569
- }
544
+ createEventListener.call(this, 'focus', (e) => {
545
+ this.#dispatchFocus();
546
+ }, { element: this.baseElement });
570
547
 
571
- disconnectedCallback() {
572
- super.disconnectedCallback?.();
548
+ createEventListener.call(this, 'focus', (e) => {
549
+ // if we got a focus event we want to focus the proxy element
550
+ if (e.isTrusted) {
551
+ this.focus();
552
+ }
553
+ });
554
+
555
+ // this is needed for components that uses props, such as combo box
556
+ forwardProps(this, this.baseElement, includeForwardProps);
557
+
558
+ // `onkeydown` is set on `baseElement` support proper tab-index navigation
559
+ // this support is needed since both proxy host and element catch `focus`/`blur` event
560
+ // which causes faulty behavior.
561
+ // we need this to happen only when the proxy component is in the light DOM,
562
+ // otherwise it will focus the nested proxy element
563
+ this.baseElement.onkeydown = (e) => {
564
+ if (e.shiftKey && e.keyCode === 9 && this.getRootNode() === document) {
565
+ this.removeAttribute('tabindex');
566
+ // We want to defer the action of setting the tab index back
567
+ // so it will happen after focusing the previous element
568
+ setTimeout(() => this.setAttribute('tabindex', '0'), 0);
569
+ }
570
+ };
573
571
 
574
- this.removeEventListener('focus', this.#boundOnFocus);
572
+ syncAttrs(this.baseElement, this, {
573
+ excludeAttrs: excludeAttrsSync,
574
+ includeAttrs: includeAttrsSync
575
+ });
575
576
  }
576
577
  }
577
578
 
578
579
  return ProxyClass;
579
580
  };
580
581
 
581
- // move create event to here
582
-
583
- // usage example:
584
- // #dispatchSomething = createDispatchEvent.bind(this, 'something')
585
- function createDispatchEvent(eventName) {
586
- this[`on${eventName}`]?.(); // in case we got an event callback as property
587
- this.dispatchEvent(new Event(eventName));
588
- }
589
-
590
- const observedAttributes = [
582
+ const observedAttributes$2 = [
591
583
  'required',
592
584
  'pattern',
593
585
  ];
@@ -600,7 +592,7 @@ const inputValidationMixin = (superclass) => class InputValidationMixinClass ext
600
592
  static get observedAttributes() {
601
593
  return [
602
594
  ...superclass.observedAttributes || [],
603
- ...observedAttributes
595
+ ...observedAttributes$2
604
596
  ];
605
597
  }
606
598
 
@@ -608,19 +600,12 @@ const inputValidationMixin = (superclass) => class InputValidationMixinClass ext
608
600
  return true;
609
601
  }
610
602
 
611
- #dispatchValid = createDispatchEvent.bind(this, 'valid')
612
- #dispatchInvalid = createDispatchEvent.bind(this, 'invalid')
613
-
614
603
  #internals
615
604
 
616
- #boundedHandleInput
617
-
618
605
  constructor() {
619
606
  super();
620
607
 
621
608
  this.#internals = this.attachInternals();
622
-
623
- this.#boundedHandleInput = this.#handleInput.bind(this);
624
609
  }
625
610
 
626
611
  get defaultErrorMsgValueMissing() {
@@ -646,7 +631,7 @@ const inputValidationMixin = (superclass) => class InputValidationMixinClass ext
646
631
  }
647
632
  }
648
633
 
649
- setValidity() {
634
+ #setValidity() {
650
635
  const validity = this.getValidity();
651
636
  this.#internals.setValidity(validity, this.getErrorMessage(validity));
652
637
  }
@@ -676,7 +661,7 @@ const inputValidationMixin = (superclass) => class InputValidationMixinClass ext
676
661
  this.#internals.setValidity({ customError: true }, errorMessage);
677
662
  } else {
678
663
  this.#internals.setValidity({});
679
- this.setValidity();
664
+ this.#setValidity();
680
665
  }
681
666
  }
682
667
 
@@ -688,38 +673,25 @@ const inputValidationMixin = (superclass) => class InputValidationMixinClass ext
688
673
  return this.getAttribute('pattern')
689
674
  }
690
675
 
691
- #handleInput() {
692
- this.setValidity();
693
- this.handleDispatchValidationEvents();
676
+ get form() {
677
+ return this.#internals.form
694
678
  }
695
679
 
696
680
  attributeChangedCallback(attrName, oldValue, newValue) {
697
681
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
698
682
 
699
- if (observedAttributes.includes(attrName)) {
700
- this.setValidity();
701
- }
702
- }
703
-
704
- handleDispatchValidationEvents() {
705
- if (this.checkValidity()) {
706
- this.#dispatchValid();
707
- } else {
708
- this.#dispatchInvalid();
683
+ if (observedAttributes$2.includes(attrName)) {
684
+ this.#setValidity();
709
685
  }
710
686
  }
711
687
 
712
688
  connectedCallback() {
713
689
  super.connectedCallback?.();
690
+ createEventListener.call(this, 'change', this.#setValidity);
691
+ createEventListener.call(this, 'invalid', (e) => e.stopPropagation());
692
+ createEventListener.call(this, 'input', this.#setValidity);
714
693
 
715
- this.addEventListener('input', this.#boundedHandleInput);
716
-
717
- this.setValidity();
718
- this.handleDispatchValidationEvents();
719
- }
720
-
721
- disconnectedCallback() {
722
- this.removeEventListener('input', this.#boundedHandleInput);
694
+ this.#setValidity();
723
695
  }
724
696
  };
725
697
 
@@ -759,26 +731,17 @@ const proxyInputMixin = (superclass) =>
759
731
 
760
732
  #inputElement
761
733
 
762
- #boundHandleFocus
763
- #boundHandleInvalid
764
- #boundHandleValid
734
+ #dispatchChange = createDispatchEvent.bind(this, 'change')
765
735
 
766
736
  constructor() {
767
737
  super();
768
738
 
769
739
  this.#inputElement = super.inputElement;
770
-
771
- this.#boundHandleFocus = this.#handleFocus.bind(this);
772
- this.#boundHandleInvalid = this.#handleInvalid.bind(this);
773
- this.#boundHandleValid = this.#handleValid.bind(this);
774
-
775
- this.baseEle = this.shadowRoot.querySelector(this.baseSelector);
776
-
777
740
  }
778
741
 
779
742
  get inputElement() {
780
- const inputSlot = this.baseEle.shadowRoot.querySelector('slot[name="input"]');
781
- const textAreaSlot = this.baseEle.shadowRoot.querySelector('slot[name="textarea"]');
743
+ const inputSlot = this.baseElement.shadowRoot.querySelector('slot[name="input"]');
744
+ const textAreaSlot = this.baseElement.shadowRoot.querySelector('slot[name="textarea"]');
782
745
 
783
746
  this.#inputElement ??= getNestedInput(inputSlot) || getNestedInput(textAreaSlot);
784
747
 
@@ -797,7 +760,6 @@ const proxyInputMixin = (superclass) =>
797
760
 
798
761
  reportValidityOnInternalInput() {
799
762
  setTimeout(() => {
800
- this.baseEle.focus(); //TODO: check if this is needed
801
763
  this.inputElement.reportValidity();
802
764
  });
803
765
  }
@@ -810,202 +772,140 @@ const proxyInputMixin = (superclass) =>
810
772
  }
811
773
  }
812
774
 
813
- setInternalInputErrorMessage() {
814
- if (!this.checkValidity()) {
775
+ handleInternalInputErrorMessage() {
776
+ if (!this.inputElement.checkValidity()) {
815
777
  this.inputElement.setCustomValidity(this.validationMessage);
816
778
  }
817
779
  }
818
780
 
819
- // when clicking on the form submit button and the input is invalid
820
- // we want it to appear as invalid
821
- #handleFocus(e) {
822
- if (e.relatedTarget?.form) {
823
- if (!this.checkValidity()) {
824
- this.setAttribute('invalid', 'true');
825
- }
826
-
827
- if (this.hasAttribute('invalid')) {
828
- this.reportValidityOnInternalInput();
829
- }
830
- }
831
- }
832
-
833
- #handleInvalid() {
834
- this.setInternalInputErrorMessage();
781
+ #handleErrorMessage() {
782
+ this.handleInternalInputErrorMessage();
835
783
  this.setAttribute('error-message', this.validationMessage);
836
784
  }
837
785
 
838
- #handleValid() {
839
- this.removeAttribute('invalid');
840
- }
841
-
842
786
  connectedCallback() {
843
787
  super.connectedCallback?.();
844
788
 
845
- // this is our way to identify that the form was submitted
846
- // in this case, we want the input to be in error state if it's not valid
847
- this.addEventListener('focus', this.#boundHandleFocus);
789
+ createEventListener.call(this, 'input', (e) => {
790
+ if (!this.inputElement.checkValidity()) {
791
+ this.inputElement.setCustomValidity('');
792
+ // after updating the input validity we want to trigger set validity on the wrapping element
793
+ // so we will get the updated validity
794
+ this.setCustomValidity('');
795
+
796
+ // Vaadin is getting the input event before us,
797
+ // so in order to make sure they use the updated validity
798
+ // we calling their fn after updating the input validity
799
+ this.baseElement.__onInput(e);
800
+
801
+ this.#handleErrorMessage();
802
+ }
803
+ }, { element: this.inputElement });
804
+
805
+ createEventListener.call(this, 'change', () => {
806
+ this.#dispatchChange();
807
+ }, { element: this.baseElement });
848
808
 
849
- this.addEventListener('invalid', this.#boundHandleInvalid);
850
- this.addEventListener('valid', this.#boundHandleValid);
809
+ createEventListener.call(this, 'blur', () => {
810
+ if (!this.checkValidity()) {
811
+ this.setAttribute('invalid', 'true');
812
+ this.#handleErrorMessage();
813
+ }
814
+ });
851
815
 
852
- this.addEventListener('input', () => {
853
- this.inputElement.setCustomValidity('');
854
- if (!this.inputElement.checkValidity())
855
- this.setInternalInputErrorMessage();
816
+ createEventListener.call(this, 'focus', (e) => {
817
+ // when clicking on the form submit button and the input is invalid
818
+ // we want it to appear as invalid
819
+ if (e.relatedTarget?.form === this.form) {
820
+ if (!this.checkValidity()) {
821
+ this.setAttribute('invalid', 'true');
822
+ }
823
+
824
+ if (this.hasAttribute('invalid')) {
825
+ this.reportValidityOnInternalInput();
826
+ }
827
+ }
856
828
  });
857
829
 
830
+ createEventListener.call(this, 'invalid', this.#handleErrorMessage);
831
+
832
+ this.handleInternalInputErrorMessage();
833
+
858
834
  // this is needed in order to make sure the form input validation is working
835
+ // we do not want it to happen when the component is nested
859
836
  if (!this.hasAttribute('tabindex') && this.getRootNode() === document) {
860
837
  this.setAttribute('tabindex', 0);
861
838
  }
862
839
 
863
840
  // sync properties
864
841
  propertyObserver(this, this.inputElement, 'value');
842
+ propertyObserver(this, this.inputElement, 'selectionStart');
865
843
  this.setSelectionRange = this.inputElement.setSelectionRange?.bind(this.inputElement);
866
844
  }
845
+ };
867
846
 
868
- disconnectedCallback() {
869
- this.removeEventListener('focus', this.#boundHandleFocus);
870
- this.removeEventListener('invalid', this.#boundHandleInvalid);
871
- this.removeEventListener('valid', this.#boundHandleValid);
872
- }
847
+ const componentNameValidationMixin = (superclass) =>
848
+ class ComponentNameValidationMixinClass extends superclass {
849
+ #checkComponentName() {
850
+ const currentComponentName = this.localName;
873
851
 
874
- attributeChangedCallback(attrName, oldValue, newValue) {
875
- super.attributeChangedCallback?.(attrName, oldValue, newValue);
852
+ if (!superclass.componentName) {
853
+ throw Error(
854
+ `component name is not defined on super class, make sure you have a static get for "componentName"`
855
+ );
856
+ }
876
857
 
877
- if (attrName === 'invalid' && newValue === '') {
878
- this.setAttribute('invalid', 'true');
858
+ if (currentComponentName !== superclass.componentName) {
859
+ throw Error(
860
+ `component name mismatch, expected "${superclass.componentName}", current "${currentComponentName}"`
861
+ );
879
862
  }
880
863
  }
881
- };
882
-
883
- const events = [
884
- 'blur',
885
- 'focus',
886
- 'focusin',
887
- 'focusout',
888
- ];
889
-
890
- const focusMixin = (superclass) => class FocusMixinClass extends superclass {
891
- #isFocused = false
892
- #setFocusTimer
893
-
894
- #boundedHandleFocus
895
- #boundedHandleBlur
896
- #boundedHandleFocusIn
897
- #boundedHandleFocusOut
898
-
899
- constructor() {
900
- super();
901
-
902
- for (const event of events) {
903
- this[`dispatch${upperFirst(event)}`] = function () {
904
- this.dispatchInputEvent(event);
905
- };
906
- }
907
-
908
- this.#boundedHandleFocus = this.#handleFocus.bind(this);
909
- this.#boundedHandleBlur = this.#handleBlur.bind(this);
910
- this.#boundedHandleFocusIn = this.#handleFocusIn.bind(this);
911
- this.#boundedHandleFocusOut = this.#handleFocusOut.bind(this);
912
- }
913
-
914
- #handleFocus(e) {
915
- if (this.isReadOnly) {
916
- e.stopPropagation();
917
- return
918
- }
919
- // we want to listen only to browser events
920
- // and not to events we are dispatching
921
- if (e.isTrusted) { // TODO: check if this is needed, because Vaadin is also dispatching events
922
- // we want to control the focus events that dispatched by the component
923
- // so we are stopping propagation and handling it in setFocus
924
- e.stopPropagation();
925
- this.setFocus(true);
926
-
927
- // if the focus event is on the root component (and not on the inner components)
928
- // we want to notify the component and let it decide what to do with it
929
- if (e.target === this) {
930
- this.onFocus(e);
931
- }
932
- }
933
- }
934
-
935
- #handleFocusOut(e) {
936
- // we want to listen only to browser events
937
- // and not to events we are dispatching
938
- if (e.isTrusted) {
939
- // we want to control the focus events that dispatched by the component
940
- // so we are stopping propagation and handling it in setFocus
941
- e.stopPropagation();
942
- }
943
- }
944
-
945
- #handleFocusIn(e) {
946
- // we want to listen only to browser events
947
- // and not to events we are dispatching
948
- if (e.isTrusted) {
949
- // we want to control the focus events that dispatched by the component
950
- // so we are stopping propagation and handling it in setFocus
951
- e.stopPropagation();
952
- }
953
- }
954
-
955
- #handleBlur(e) {
956
- if (e.isTrusted) {
957
- e.stopPropagation();
958
- this.setFocus(false);
959
- }
960
- }
961
-
962
- get isReadOnly() {
963
- return this.hasAttribute('readonly') && this.getAttribute('readonly') !== 'false'
964
- }
965
864
 
966
- // we want to debounce the calls to this fn
967
- // so we can support input like components with multiple inputs inside
968
- setFocus(isFocused) {
969
- clearTimeout(this.#setFocusTimer);
970
-
971
- this.#setFocusTimer = setTimeout(() => {
972
- if (this.#isFocused !== isFocused) {
973
- this.#isFocused = isFocused;
974
- if (isFocused) {
975
- this.dispatchFocus();
976
- this.dispatchFocusin();
977
- }
978
- else {
979
- this.dispatchBlur();
980
- this.dispatchFocusout();
981
- }
982
- }
983
- });
984
- }
865
+ connectedCallback() {
866
+ super.connectedCallback?.();
867
+ this.#checkComponentName();
868
+ }
869
+ };
985
870
 
986
- onFocus() {
987
- console.warn('onFocus', 'is not implemented');
988
- }
871
+ const hoverableMixin =
872
+ (superclass) =>
873
+ class HoverableMixinClass extends superclass {
874
+ connectedCallback() {
875
+ super.connectedCallback?.();
989
876
 
990
- dispatchInputEvent(eventName) {
991
- this[`on${eventName}`]?.(); // in case we got an event callback as property
992
- this.dispatchEvent(new InputEvent(eventName));
993
- }
877
+ createEventListener.call(this, 'mouseover', (e) => {
878
+ this.setAttribute('hover', 'true');
879
+ e.target.addEventListener(
880
+ 'mouseleave',
881
+ () => this.removeAttribute('hover'),
882
+ { once: true }
883
+ );
884
+ }, { element: this.baseElement });
885
+ }
886
+ };
994
887
 
888
+ const focusMixin = (superclass) => class FocusMixinClass extends superclass {
889
+ // we want to block all native events,
890
+ // so the input can control when to dispatch it based on its internal behavior
995
891
  connectedCallback() {
996
- super.connectedCallback?.();
892
+ super.connectedCallback?.();
893
+
894
+ createEventListener.call(this, 'blur', (e) => {
895
+ e.isTrusted && e.stopImmediatePropagation();
896
+ });
997
897
 
998
- this.addEventListener('focus', this.#boundedHandleFocus, true);
999
- this.addEventListener('blur', this.#boundedHandleBlur, true);
1000
- this.addEventListener('focusin', this.#boundedHandleFocusIn);
1001
- this.addEventListener('focusout', this.#boundedHandleFocusOut);
1002
- }
898
+ createEventListener.call(this, 'focus', (e) => {
899
+ e.isTrusted && e.stopImmediatePropagation();
900
+ });
901
+
902
+ createEventListener.call(this, 'focusout', (e) => {
903
+ e.isTrusted && e.stopImmediatePropagation();
904
+ });
1003
905
 
1004
- disconnectedCallback() {
1005
- this.removeEventListener('focus', this.#boundedHandleFocus);
1006
- this.removeEventListener('blur', this.#boundedHandleBlur);
1007
- this.removeEventListener('focusin', this.#boundedHandleFocusIn);
1008
- this.removeEventListener('focusout', this.#boundedHandleFocusOut);
906
+ createEventListener.call(this, 'focusin', (e) => {
907
+ e.isTrusted && e.stopImmediatePropagation();
908
+ });
1009
909
  }
1010
910
  };
1011
911
 
@@ -1071,52 +971,38 @@ const portalMixin = ({ name, selector, mappings = {} }) => (superclass) => {
1071
971
  };
1072
972
 
1073
973
  const changeMixin = (superclass) => class ChangeMixinClass extends superclass {
1074
-
1075
- #boundedHandleChange
1076
- #boundedHandleBlur
1077
-
1078
- #removeChangeListener
1079
- #removeBlurListener
1080
-
1081
974
  #dispatchChange = createDispatchEvent.bind(this, 'change')
1082
975
 
1083
- constructor() {
1084
- super();
1085
-
1086
- this.#boundedHandleChange = this.#handleChange.bind(this);
1087
- this.#boundedHandleBlur = this.#handleBlur.bind(this);
1088
- }
976
+ connectedCallback() {
977
+ super.connectedCallback?.();
978
+ this.prevValue = this.value;
1089
979
 
1090
- #handleChange(e) {
1091
- // we want to listen only to browser events
1092
- // and not to events we are dispatching
1093
- if (e.isTrusted) {
1094
- // we want to control the change events that dispatched by the component
1095
- // so we are stopping propagation and handling it in handleBlur
980
+ createEventListener.call(this, 'change', (e) => {
1096
981
  e.stopPropagation();
1097
- }
1098
- }
982
+ });
1099
983
 
1100
- #handleBlur() {
1101
- // on blur, we want to dispatch a change event
1102
- this.#dispatchChange();
984
+ createEventListener.call(this, 'blur', () => {
985
+ if (this.value !== this.prevValue) {
986
+ this.#dispatchChange();
987
+ this.prevValue = this.value;
988
+ }
989
+ });
1103
990
  }
991
+ };
1104
992
 
1105
- connectedCallback() {
1106
- super.connectedCallback?.();
1107
-
1108
- this.#removeChangeListener = addEventListener.bind();
1109
- this.addEventListener('change', this.#boundedHandleChange, true);
1110
- this.addEventListener('blur', this.#boundedHandleBlur);
1111
- }
993
+ // we want all the valueless attributes to have "true" value
994
+ const normalizeBooleanAttributesMixin = (superclass) => class NormalizeBooleanAttributesMixinClass extends superclass {
995
+ attributeChangedCallback(attrName, oldValue, newValue) {
996
+ if (newValue === '') {
997
+ this.setAttribute(attrName, 'true');
998
+ newValue = 'true';
999
+ }
1112
1000
 
1113
- disconnectedCallback() {
1114
- this.removeEventListener('change', this.#boundedHandleChange);
1115
- this.removeEventListener('blur', this.#boundedHandleBlur);
1001
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
1116
1002
  }
1117
1003
  };
1118
1004
 
1119
- const componentName$i = getComponentName('button');
1005
+ const componentName$j = getComponentName('button');
1120
1006
 
1121
1007
  const editorOverrides = `vaadin-button::part(label) { pointer-events: none; }`;
1122
1008
  const resetStyles = `
@@ -1170,7 +1056,7 @@ const Button = compose(
1170
1056
  style: () =>
1171
1057
  `${resetStyles} ${editorOverrides} ${iconStyles} ${loadingIndicatorStyles}`,
1172
1058
  excludeAttrsSync: ['tabindex'],
1173
- componentName: componentName$i
1059
+ componentName: componentName$j
1174
1060
  })
1175
1061
  );
1176
1062
 
@@ -1207,9 +1093,9 @@ const loadingIndicatorStyles = `
1207
1093
  }
1208
1094
  `;
1209
1095
 
1210
- customElements.define(componentName$i, Button);
1096
+ customElements.define(componentName$j, Button);
1211
1097
 
1212
- const componentName$h = getComponentName('checkbox');
1098
+ const componentName$i = getComponentName('checkbox');
1213
1099
 
1214
1100
  const Checkbox = compose(
1215
1101
  createStyleMixin({
@@ -1235,17 +1121,17 @@ const Checkbox = compose(
1235
1121
  }
1236
1122
  `,
1237
1123
  excludeAttrsSync: ['tabindex'],
1238
- componentName: componentName$h
1124
+ componentName: componentName$i
1239
1125
  })
1240
1126
  );
1241
1127
 
1242
- customElements.define(componentName$h, Checkbox);
1128
+ customElements.define(componentName$i, Checkbox);
1243
1129
 
1244
- const componentName$g = getComponentName('loader-linear');
1130
+ const componentName$h = getComponentName('loader-linear');
1245
1131
 
1246
- class RawLoaderLinear extends createBaseClass({ componentName: componentName$g, baseSelector: ':host > div' }) {
1132
+ class RawLoaderLinear extends createBaseClass({ componentName: componentName$h, baseSelector: ':host > div' }) {
1247
1133
  static get componentName() {
1248
- return componentName$g;
1134
+ return componentName$h;
1249
1135
  }
1250
1136
  constructor() {
1251
1137
  super();
@@ -1303,11 +1189,11 @@ const LoaderLinear = compose(
1303
1189
  componentNameValidationMixin
1304
1190
  )(RawLoaderLinear);
1305
1191
 
1306
- customElements.define(componentName$g, LoaderLinear);
1192
+ customElements.define(componentName$h, LoaderLinear);
1307
1193
 
1308
- const componentName$f = getComponentName('loader-radial');
1194
+ const componentName$g = getComponentName('loader-radial');
1309
1195
 
1310
- class RawLoaderRadial extends createBaseClass({ componentName: componentName$f, baseSelector: ':host > div' }) {
1196
+ class RawLoaderRadial extends createBaseClass({ componentName: componentName$g, baseSelector: ':host > div' }) {
1311
1197
  constructor() {
1312
1198
  super();
1313
1199
 
@@ -1353,11 +1239,11 @@ const LoaderRadial = compose(
1353
1239
  componentNameValidationMixin
1354
1240
  )(RawLoaderRadial);
1355
1241
 
1356
- customElements.define(componentName$f, LoaderRadial);
1242
+ customElements.define(componentName$g, LoaderRadial);
1357
1243
 
1358
- const componentName$e = getComponentName('container');
1244
+ const componentName$f = getComponentName('container');
1359
1245
 
1360
- class RawContainer extends createBaseClass({componentName: componentName$e, baseSelector: ':host > slot'}) {
1246
+ class RawContainer extends createBaseClass({componentName: componentName$f, baseSelector: ':host > slot'}) {
1361
1247
  constructor() {
1362
1248
  super();
1363
1249
 
@@ -1413,26 +1299,26 @@ const Container = compose(
1413
1299
  componentNameValidationMixin
1414
1300
  )(RawContainer);
1415
1301
 
1416
- customElements.define(componentName$e, Container);
1302
+ customElements.define(componentName$f, Container);
1417
1303
 
1418
- const componentName$d = getComponentName('date-picker');
1304
+ const componentName$e = getComponentName('date-picker');
1419
1305
 
1420
1306
  const DatePicker = compose(
1421
1307
  draggableMixin,
1422
1308
  componentNameValidationMixin
1423
1309
  )(
1424
1310
  createProxy({
1425
- componentName: componentName$d,
1311
+ componentName: componentName$e,
1426
1312
  slots: ['prefix', 'suffix'],
1427
1313
  wrappedEleName: 'vaadin-date-picker',
1428
1314
  style: ``
1429
1315
  })
1430
1316
  );
1431
1317
 
1432
- customElements.define(componentName$d, DatePicker);
1318
+ customElements.define(componentName$e, DatePicker);
1433
1319
 
1434
- const componentName$c = getComponentName('divider');
1435
- class RawDivider extends createBaseClass({ componentName: componentName$c, baseSelector: ':host > div' }) {
1320
+ const componentName$d = getComponentName('divider');
1321
+ class RawDivider extends createBaseClass({ componentName: componentName$d, baseSelector: ':host > div' }) {
1436
1322
  constructor() {
1437
1323
  super();
1438
1324
 
@@ -1510,9 +1396,9 @@ const Divider = compose(
1510
1396
  componentNameValidationMixin
1511
1397
  )(RawDivider);
1512
1398
 
1513
- const componentName$b = getComponentName('text');
1399
+ const componentName$c = getComponentName('text');
1514
1400
 
1515
- class RawText extends createBaseClass({ componentName: componentName$b, baseSelector: ':host > slot' }) {
1401
+ class RawText extends createBaseClass({ componentName: componentName$c, baseSelector: ':host > slot' }) {
1516
1402
  constructor() {
1517
1403
  super();
1518
1404
 
@@ -1554,9 +1440,9 @@ const Text = compose(
1554
1440
  componentNameValidationMixin
1555
1441
  )(RawText);
1556
1442
 
1557
- customElements.define(componentName$b, Text);
1443
+ customElements.define(componentName$c, Text);
1558
1444
 
1559
- customElements.define(componentName$c, Divider);
1445
+ customElements.define(componentName$d, Divider);
1560
1446
 
1561
1447
  const selectors$3 = {
1562
1448
  label: '::part(label)',
@@ -1593,7 +1479,7 @@ var textFieldMappings = {
1593
1479
  placeholderColor: { selector: selectors$3.placeholder, property: 'color' }
1594
1480
  };
1595
1481
 
1596
- const componentName$a = getComponentName('email-field');
1482
+ const componentName$b = getComponentName('email-field');
1597
1483
 
1598
1484
  let overrides$5 = ``;
1599
1485
 
@@ -1612,7 +1498,7 @@ const EmailField = compose(
1612
1498
  wrappedEleName: 'vaadin-email-field',
1613
1499
  style: () => overrides$5,
1614
1500
  excludeAttrsSync: ['tabindex'],
1615
- componentName: componentName$a
1501
+ componentName: componentName$b
1616
1502
  })
1617
1503
  );
1618
1504
 
@@ -1656,10 +1542,10 @@ overrides$5 = `
1656
1542
  }
1657
1543
  `;
1658
1544
 
1659
- customElements.define(componentName$a, EmailField);
1545
+ customElements.define(componentName$b, EmailField);
1660
1546
 
1661
- const componentName$9 = getComponentName('link');
1662
- class RawLink extends createBaseClass({ componentName: componentName$9, baseSelector: ':host a' }) {
1547
+ const componentName$a = getComponentName('link');
1548
+ class RawLink extends createBaseClass({ componentName: componentName$a, baseSelector: ':host a' }) {
1663
1549
  constructor() {
1664
1550
  super();
1665
1551
  document.createElement('template');
@@ -1720,14 +1606,14 @@ const Link = compose(
1720
1606
  componentNameValidationMixin
1721
1607
  )(RawLink);
1722
1608
 
1723
- customElements.define(componentName$9, Link);
1609
+ customElements.define(componentName$a, Link);
1724
1610
 
1725
- const componentName$8 = getComponentName('logo');
1611
+ const componentName$9 = getComponentName('logo');
1726
1612
 
1727
1613
  let style;
1728
1614
  const getStyle = () => style;
1729
1615
 
1730
- class RawLogo extends createBaseClass({ componentName: componentName$8, baseSelector: ':host > div' }) {
1616
+ class RawLogo extends createBaseClass({ componentName: componentName$9, baseSelector: ':host > div' }) {
1731
1617
  constructor() {
1732
1618
  super();
1733
1619
 
@@ -1762,9 +1648,9 @@ style = `
1762
1648
  }
1763
1649
  `;
1764
1650
 
1765
- customElements.define(componentName$8, Logo);
1651
+ customElements.define(componentName$9, Logo);
1766
1652
 
1767
- const componentName$7 = getComponentName('number-field');
1653
+ const componentName$8 = getComponentName('number-field');
1768
1654
 
1769
1655
  let overrides$4 = ``;
1770
1656
 
@@ -1783,7 +1669,7 @@ const NumberField = compose(
1783
1669
  wrappedEleName: 'vaadin-number-field',
1784
1670
  style: () => overrides$4,
1785
1671
  excludeAttrsSync: ['tabindex'],
1786
- componentName: componentName$7
1672
+ componentName: componentName$8
1787
1673
  })
1788
1674
  );
1789
1675
 
@@ -1827,9 +1713,13 @@ overrides$4 = `
1827
1713
  }
1828
1714
  `;
1829
1715
 
1830
- customElements.define(componentName$7, NumberField);
1716
+ customElements.define(componentName$8, NumberField);
1831
1717
 
1832
- var BaseInputClass = compose(focusMixin, inputValidationMixin, changeMixin)(HTMLElement); //todo: maybe we should use base class?
1718
+ const createBaseInputClass = (...args) => compose(
1719
+ focusMixin,
1720
+ inputValidationMixin,
1721
+ changeMixin,
1722
+ )(createBaseClass(...args));
1833
1723
 
1834
1724
  const focusElement = (ele) => {
1835
1725
  ele?.focus();
@@ -1845,25 +1735,28 @@ const getSanitizedCharacters = (str) => {
1845
1735
  return [...pin]; // creating array of chars
1846
1736
  };
1847
1737
 
1848
- const componentName$6 = getComponentName('passcode-internal');
1738
+ const componentName$7 = getComponentName('passcode-internal');
1739
+
1740
+ const observedAttributes$1 = [
1741
+ 'disabled',
1742
+ 'bordered',
1743
+ 'size',
1744
+ 'invalid'
1745
+ ];
1746
+
1747
+ const BaseInputClass = createBaseInputClass({ componentName: componentName$7, baseSelector: ':host > div' });
1849
1748
 
1850
1749
  class PasscodeInternal extends BaseInputClass {
1851
1750
  static get observedAttributes() {
1852
- return [
1853
- ...(BaseInputClass.observedAttributes || []),
1854
- 'disabled',
1855
- 'bordered',
1856
- 'size',
1857
- ];
1751
+ return observedAttributes$1.concat(BaseInputClass.observedAttributes || []);
1858
1752
  }
1859
1753
 
1860
1754
  static get componentName() {
1861
- return componentName$6;
1755
+ return componentName$7;
1862
1756
  }
1863
1757
 
1864
- #boundHandleInvalid = this.#handleInvalid.bind(this)
1865
- #boundHandleValid = this.#handleValid.bind(this)
1866
- #boundHandleBlur = this.#handleBlur.bind(this)
1758
+ #dispatchBlur = createDispatchEvent.bind(this, 'blur')
1759
+ #dispatchFocus = createDispatchEvent.bind(this, 'focus')
1867
1760
 
1868
1761
  constructor() {
1869
1762
  super();
@@ -1872,7 +1765,7 @@ class PasscodeInternal extends BaseInputClass {
1872
1765
  st-width="35px"
1873
1766
  data-id=${idx}
1874
1767
  type="tel"
1875
- autocomplete="none"
1768
+ autocomplete="off"
1876
1769
  ></descope-text-field>
1877
1770
  `);
1878
1771
 
@@ -1882,8 +1775,6 @@ class PasscodeInternal extends BaseInputClass {
1882
1775
  </div>
1883
1776
  `;
1884
1777
 
1885
- this.baseSelector = ':host > div';
1886
-
1887
1778
  this.inputs = Array.from(this.querySelectorAll('descope-text-field'));
1888
1779
  }
1889
1780
 
@@ -1909,16 +1800,6 @@ class PasscodeInternal extends BaseInputClass {
1909
1800
  return `^$|^\\d{${this.digits},}$`
1910
1801
  }
1911
1802
 
1912
- #handleInvalid() {
1913
- if (this.hasAttribute('invalid')) {
1914
- this.inputs.forEach(input => input.setAttribute('invalid', 'true'));
1915
- }
1916
- }
1917
-
1918
- #handleValid() {
1919
- this.inputs.forEach(input => input.removeAttribute('invalid'));
1920
- }
1921
-
1922
1803
  getValidity() {
1923
1804
  if (this.isRequired && !this.value) {
1924
1805
  return { valueMissing: true };
@@ -1931,25 +1812,17 @@ class PasscodeInternal extends BaseInputClass {
1931
1812
  }
1932
1813
  };
1933
1814
 
1934
- onFocus(){
1935
- this.inputs[0].focus();
1936
- }
1937
-
1938
1815
  connectedCallback() {
1816
+ // we are adding listeners before calling to super because it's stopping the events
1817
+ createEventListener.call(this, 'focus', (e) => {
1818
+ // we want to ignore focus events we are dispatching
1819
+ if (e.isTrusted)
1820
+ this.inputs[0].focus();
1821
+ });
1822
+
1939
1823
  super.connectedCallback?.();
1940
1824
 
1941
1825
  this.initInputs();
1942
-
1943
- this.addEventListener('invalid', this.#boundHandleInvalid);
1944
- this.addEventListener('valid', this.#boundHandleValid);
1945
- this.addEventListener('blur', this.#boundHandleBlur);
1946
- }
1947
-
1948
- disconnectedCallback() {
1949
- super.connectedCallback?.();
1950
- this.removeEventListener('invalid', this.#boundHandleInvalid);
1951
- this.removeEventListener('valid', this.#boundHandleValid);
1952
- this.removeEventListener('blur', this.#boundHandleBlur);
1953
1826
  }
1954
1827
 
1955
1828
  getInputIdx(inputEle) {
@@ -1981,33 +1854,60 @@ class PasscodeInternal extends BaseInputClass {
1981
1854
  focusElement(currentInput);
1982
1855
  };
1983
1856
 
1984
- #handleBlur() {
1985
- this.#handleInvalid();
1986
- }
1987
-
1988
1857
  initInputs() {
1858
+ let prevVal = this.value;
1859
+ let blurTimerId;
1860
+
1989
1861
  this.inputs.forEach((input) => {
1990
- input.oninput = (e) => {
1862
+ // in order to simulate blur on the input
1863
+ // we are checking if focus on one of the digits happened immediately after blur on another digit
1864
+ // if not, the component is no longer focused and we should simulate blur
1865
+ createEventListener.call(this, 'blur', (e) => {
1866
+ e.stopImmediatePropagation();
1867
+
1868
+ blurTimerId = setTimeout(() => {
1869
+ blurTimerId = null;
1870
+ this.#dispatchBlur();
1871
+ });
1872
+ }, { element: input });
1873
+
1874
+ createEventListener.call(this, 'focus', (e) => {
1875
+ e.stopImmediatePropagation();
1876
+
1877
+ clearTimeout(blurTimerId);
1878
+ if (!blurTimerId) {
1879
+ this.#dispatchFocus();
1880
+ }
1881
+ }, { element: input });
1882
+
1883
+ createEventListener.call(this, 'input', (e) => {
1991
1884
  const charArr = getSanitizedCharacters(input.value);
1992
1885
 
1993
1886
  if (!charArr.length) {
1994
1887
  // if we got an invalid value we want to clear the input
1995
1888
  input.value = '';
1996
- if (e.data === null) {
1997
- // if the user deleted the char, we want to focus the prev digit
1998
- focusElement(this.getPrevInput(input));
1999
- }
2000
1889
  }
2001
1890
  else this.fillDigits(charArr, input);
2002
- };
1891
+
1892
+ // we want to stop input events if the value wasn't change
1893
+ if (prevVal === this.value) {
1894
+ e.stopImmediatePropagation();
1895
+ }
1896
+ }, { element: input });
2003
1897
 
2004
1898
  input.onkeydown = ({ key }) => {
1899
+ prevVal = this.value;
1900
+
2005
1901
  // when user deletes a digit, we want to focus the previous digit
2006
1902
  if (key === 'Backspace') {
1903
+ // if the cursor is at 0, we want to move it to 1, so the value will be deleted
1904
+ if (!input.selectionStart) {
1905
+ input.setSelectionRange(1, 1);
1906
+ }
2007
1907
  setTimeout(() => {
2008
1908
  focusElement(this.getPrevInput(input));
2009
1909
  });
2010
- } else if (key.match(/^(\d)$/g)) { // if input is a digit
1910
+ } else if (key.length === 1) { // we want only characters and not command keys
2011
1911
  input.value = ''; // we are clearing the previous value so we can override it with the new value
2012
1912
  }
2013
1913
  };
@@ -2017,15 +1917,20 @@ class PasscodeInternal extends BaseInputClass {
2017
1917
  attributeChangedCallback(attrName, oldValue, newValue) {
2018
1918
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
2019
1919
 
1920
+ // sync attributes to inputs
2020
1921
  if (oldValue !== newValue) {
2021
- if (PasscodeInternal.observedAttributes.includes(attrName) && !BaseInputClass.observedAttributes.includes(attrName)) {
2022
- this.inputs.forEach((input) => input.setAttribute(attrName, newValue));
1922
+ if (observedAttributes$1.includes(attrName)) {
1923
+ this.inputs.forEach(
1924
+ (input) => newValue === null ?
1925
+ input.removeAttribute(attrName) :
1926
+ input.setAttribute(attrName, newValue)
1927
+ );
2023
1928
  }
2024
1929
  }
2025
1930
  }
2026
1931
  }
2027
1932
 
2028
- const componentName$5 = getComponentName('text-field');
1933
+ const componentName$6 = getComponentName('text-field');
2029
1934
 
2030
1935
  let overrides$3 = ``;
2031
1936
 
@@ -2042,7 +1947,7 @@ const TextField = compose(
2042
1947
  wrappedEleName: 'vaadin-text-field',
2043
1948
  style: () => overrides$3,
2044
1949
  excludeAttrsSync: ['tabindex'],
2045
- componentName: componentName$5
1950
+ componentName: componentName$6
2046
1951
  })
2047
1952
  );
2048
1953
 
@@ -2087,7 +1992,7 @@ overrides$3 = `
2087
1992
  }
2088
1993
  `;
2089
1994
 
2090
- const componentName$4 = getComponentName('passcode');
1995
+ const componentName$5 = getComponentName('passcode');
2091
1996
 
2092
1997
  const customMixin = (superclass) =>
2093
1998
  class DraggableMixinClass extends superclass {
@@ -2104,17 +2009,17 @@ const customMixin = (superclass) =>
2104
2009
  const template = document.createElement('template');
2105
2010
 
2106
2011
  template.innerHTML = `
2107
- <${componentName$6}
2012
+ <${componentName$7}
2108
2013
  bordered="true"
2109
2014
  name="code"
2110
2015
  tabindex="-1"
2111
2016
  slot="input"
2112
- ></${componentName$6}>
2017
+ ></${componentName$7}>
2113
2018
  `;
2114
2019
 
2115
- this.proxyElement.appendChild(template.content.cloneNode(true));
2020
+ this.baseElement.appendChild(template.content.cloneNode(true));
2116
2021
 
2117
- this.inputElement = this.shadowRoot.querySelector(componentName$6);
2022
+ this.inputElement = this.shadowRoot.querySelector(componentName$7);
2118
2023
 
2119
2024
  forwardAttrs(this.shadowRoot.host, this.inputElement, { includeAttrs: ['required', 'pattern'] });
2120
2025
 
@@ -2193,17 +2098,17 @@ const Passcode = compose(
2193
2098
  }
2194
2099
  `,
2195
2100
  excludeAttrsSync: ['tabindex'],
2196
- componentName: componentName$4
2101
+ componentName: componentName$5
2197
2102
  })
2198
2103
  );
2199
2104
 
2200
- customElements.define(componentName$5, TextField);
2105
+ customElements.define(componentName$6, TextField);
2201
2106
 
2202
- customElements.define(componentName$6, PasscodeInternal);
2107
+ customElements.define(componentName$7, PasscodeInternal);
2203
2108
 
2204
- customElements.define(componentName$4, Passcode);
2109
+ customElements.define(componentName$5, Passcode);
2205
2110
 
2206
- const componentName$3 = getComponentName('password-field');
2111
+ const componentName$4 = getComponentName('password-field');
2207
2112
 
2208
2113
  let overrides$2 = ``;
2209
2114
 
@@ -2228,7 +2133,7 @@ const PasswordField = compose(
2228
2133
  wrappedEleName: 'vaadin-password-field',
2229
2134
  style: () => overrides$2,
2230
2135
  excludeAttrsSync: ['tabindex'],
2231
- componentName: componentName$3
2136
+ componentName: componentName$4
2232
2137
  })
2233
2138
  );
2234
2139
 
@@ -2272,9 +2177,9 @@ overrides$2 = `
2272
2177
  }
2273
2178
  `;
2274
2179
 
2275
- customElements.define(componentName$3, PasswordField);
2180
+ customElements.define(componentName$4, PasswordField);
2276
2181
 
2277
- const componentName$2 = getComponentName('switch-toggle');
2182
+ const componentName$3 = getComponentName('switch-toggle');
2278
2183
 
2279
2184
  let overrides$1 = ``;
2280
2185
 
@@ -2294,7 +2199,7 @@ const SwitchToggle = compose(
2294
2199
  wrappedEleName: 'vaadin-checkbox',
2295
2200
  style: () => overrides$1,
2296
2201
  excludeAttrsSync: ['tabindex'],
2297
- componentName: componentName$2
2202
+ componentName: componentName$3
2298
2203
  })
2299
2204
  );
2300
2205
 
@@ -2352,9 +2257,9 @@ overrides$1 = `
2352
2257
  }
2353
2258
  `;
2354
2259
 
2355
- customElements.define(componentName$2, SwitchToggle);
2260
+ customElements.define(componentName$3, SwitchToggle);
2356
2261
 
2357
- const componentName$1 = getComponentName('text-area');
2262
+ const componentName$2 = getComponentName('text-area');
2358
2263
 
2359
2264
  const selectors$1 = {
2360
2265
  label: '::part(label)',
@@ -2390,7 +2295,7 @@ const TextArea = compose(
2390
2295
  wrappedEleName: 'vaadin-text-area',
2391
2296
  style: () => overrides,
2392
2297
  excludeAttrsSync: ['tabindex'],
2393
- componentName: componentName$1
2298
+ componentName: componentName$2
2394
2299
  })
2395
2300
  );
2396
2301
 
@@ -2416,7 +2321,53 @@ overrides = `
2416
2321
  }
2417
2322
  `;
2418
2323
 
2419
- customElements.define(componentName$1, TextArea);
2324
+ customElements.define(componentName$2, TextArea);
2325
+
2326
+ const observedAttributes = ['src', 'alt'];
2327
+
2328
+ const componentName$1 = getComponentName('image');
2329
+
2330
+ const BaseClass = createBaseClass({ componentName: componentName$1, baseSelector: ':host > img' });
2331
+ class RawImage extends BaseClass {
2332
+ static get observedAttributes() {
2333
+ return observedAttributes.concat(BaseClass.observedAttributes || []);
2334
+ }
2335
+
2336
+ constructor() {
2337
+ super();
2338
+
2339
+ this.attachShadow({ mode: 'open' }).innerHTML = `
2340
+ <style>
2341
+ :host > img {
2342
+ width: 100%;
2343
+ height: 100%
2344
+ }
2345
+ :host {
2346
+ display: inline-flex;
2347
+ }
2348
+ </style>
2349
+ <img/>
2350
+ `;
2351
+ }
2352
+
2353
+ connectedCallback(){
2354
+ super.connectedCallback?.();
2355
+
2356
+ forwardAttrs(this, this.baseElement, {includeAttrs: observedAttributes});
2357
+ }
2358
+ }
2359
+
2360
+ const Image = compose(
2361
+ createStyleMixin({
2362
+ mappings: {
2363
+ height: { selector: () => ':host' },
2364
+ width: { selector: () => ':host' },
2365
+ }
2366
+ }),
2367
+ draggableMixin,
2368
+ )(RawImage);
2369
+
2370
+ customElements.define(componentName$1, Image);
2420
2371
 
2421
2372
  const getVarName = (path) => getCssVarName(DESCOPE_PREFIX, ...path);
2422
2373
 
@@ -2700,7 +2651,7 @@ const mode = {
2700
2651
  surface: globalRefs$7.colors.surface
2701
2652
  };
2702
2653
 
2703
- const [helperTheme$2, helperRefs$2] = createHelperVars({ mode }, componentName$i);
2654
+ const [helperTheme$2, helperRefs$2] = createHelperVars({ mode }, componentName$j);
2704
2655
 
2705
2656
  const button = {
2706
2657
  ...helperTheme$2,
@@ -2937,7 +2888,7 @@ const [helperTheme$1, helperRefs$1, helperVars] =
2937
2888
  verticalAlignment,
2938
2889
  horizontalAlignment,
2939
2890
  shadowColor: '#00000020' //if we want to support transparency vars, we should use different color format
2940
- }, 'container');
2891
+ }, Container.componentName);
2941
2892
 
2942
2893
  const container = {
2943
2894
  ...helperTheme$1,
@@ -3158,7 +3109,7 @@ const vars$3 = Divider.cssVarList;
3158
3109
 
3159
3110
  const thickness = '2px';
3160
3111
  const textPaddingSize = '10px';
3161
- const [helperTheme, helperRefs] = createHelperVars({ thickness, textPaddingSize }, componentName$c);
3112
+ const [helperTheme, helperRefs] = createHelperVars({ thickness, textPaddingSize }, componentName$d);
3162
3113
 
3163
3114
 
3164
3115
  const divider = {
@@ -3422,6 +3373,10 @@ const comboBox = {
3422
3373
  // [vars.overlayBorder]: '3px solid red',
3423
3374
  };
3424
3375
 
3376
+ Image.cssVarList;
3377
+
3378
+ const image = {};
3379
+
3425
3380
  var components = {
3426
3381
  button,
3427
3382
  textField: textField$1,
@@ -3439,7 +3394,8 @@ var components = {
3439
3394
  passcode,
3440
3395
  loaderRadial,
3441
3396
  loaderLinear,
3442
- comboBox
3397
+ comboBox,
3398
+ image
3443
3399
  };
3444
3400
 
3445
3401
  var index = { globals, components };