@descope/web-components-ui 1.0.370 → 1.0.372

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 (36) hide show
  1. package/dist/cjs/index.cjs.js +410 -41
  2. package/dist/cjs/index.cjs.js.map +1 -1
  3. package/dist/index.esm.js +413 -42
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/umd/4392.js +1 -1
  6. package/dist/umd/4978.js +1 -1
  7. package/dist/umd/DescopeDev.js +1 -1
  8. package/dist/umd/button-selection-group-fields-descope-button-multi-selection-group-index-js.js +1 -1
  9. package/dist/umd/button-selection-group-fields-descope-button-selection-group-index-js.js +1 -1
  10. package/dist/umd/button-selection-group-fields-descope-button-selection-group-item-index-js.js +1 -1
  11. package/dist/umd/descope-button-index-js.js +2 -2
  12. package/dist/umd/descope-email-field-index-js.js +2 -2
  13. package/dist/umd/descope-icon-index-js.js +1 -1
  14. package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -1
  15. package/dist/umd/descope-new-password-index-js.js +1 -1
  16. package/dist/umd/descope-number-field-index-js.js +1 -1
  17. package/dist/umd/descope-passcode-index-js.js +1 -1
  18. package/dist/umd/descope-password-index-js.js +1 -1
  19. package/dist/umd/descope-radio-group-index-js.js +1 -1
  20. package/dist/umd/descope-text-field-index-js.js +1 -1
  21. package/dist/umd/descope-upload-file-index-js.js +1 -1
  22. package/dist/umd/descope-user-attribute-index-js.js +1 -1
  23. package/dist/umd/descope-user-auth-method-index-js.js +1 -1
  24. package/dist/umd/mapping-fields-descope-mappings-field-index-js.js +1 -1
  25. package/package.json +1 -1
  26. package/src/components/descope-email-field/EmailFieldClass.js +12 -0
  27. package/src/components/descope-icon/IconClass.js +17 -30
  28. package/src/components/descope-new-password/NewPasswordClass.js +35 -0
  29. package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +3 -1
  30. package/src/components/descope-password/PasswordClass.js +59 -1
  31. package/src/components/descope-text-field/textFieldMappings.js +37 -6
  32. package/src/mixins/externalInputHelpers.js +86 -0
  33. package/src/mixins/externalInputMixin.js +165 -0
  34. package/src/mixins/index.js +1 -0
  35. package/src/mixins/proxyInputMixin.js +5 -2
  36. package/src/theme/components/button.js +0 -1
package/dist/index.esm.js CHANGED
@@ -1008,7 +1008,7 @@ const proxyInputMixin =
1008
1008
  ({
1009
1009
  proxyProps = [],
1010
1010
  // useProxyTargets flag allows to forwardProps to other targets, other than
1011
- // `this.inputElement`.
1011
+ // `this.inputElement`. It's to be used within `external-input` components,
1012
1012
  // if needed
1013
1013
  useProxyTargets = false,
1014
1014
  // allows us to set the event that should trigger validation
@@ -1147,7 +1147,10 @@ const proxyInputMixin =
1147
1147
 
1148
1148
  // sync properties
1149
1149
  proxyProps.forEach((prop) => {
1150
- const proxyTargets = useProxyTargets ? [this.baseElement].filter(Boolean) : [];
1150
+ const externalInput = this.querySelector('input[slot="external-input"]') || null;
1151
+ const proxyTargets = useProxyTargets
1152
+ ? [this.baseElement, externalInput].filter(Boolean)
1153
+ : [];
1151
1154
  forwardProps(this, [this.inputElement, ...proxyTargets], prop);
1152
1155
  });
1153
1156
 
@@ -1397,6 +1400,252 @@ const inputEventsDispatchingMixin = (superclass) =>
1397
1400
  }
1398
1401
  };
1399
1402
 
1403
+ // since on load we can only sample the color of the placeholder,
1404
+ // we need to temporarily populate the input in order to sample the value color
1405
+ const getValueColor = (ele, computedStyle) => {
1406
+ // eslint-disable-next-line no-param-reassign
1407
+ ele.value = '_';
1408
+
1409
+ const valueColor = computedStyle.getPropertyValue('color');
1410
+
1411
+ // eslint-disable-next-line no-param-reassign
1412
+ ele.value = '';
1413
+
1414
+ return valueColor;
1415
+ };
1416
+
1417
+ const createExternalInputSlot = (slotName, targetSlotName) => {
1418
+ const slotEle = document.createElement('slot');
1419
+
1420
+ slotEle.setAttribute('name', slotName);
1421
+ slotEle.setAttribute('slot', targetSlotName);
1422
+
1423
+ return slotEle;
1424
+ };
1425
+
1426
+ const createExternalInputEle = (targetSlotName, type, autocompleteType) => {
1427
+ const inputEle = document.createElement('input');
1428
+
1429
+ inputEle.setAttribute('slot', targetSlotName);
1430
+ inputEle.setAttribute('type', type);
1431
+ inputEle.setAttribute('data-hidden-input', 'true');
1432
+ inputEle.setAttribute('autocomplete', autocompleteType);
1433
+
1434
+ return inputEle;
1435
+ };
1436
+
1437
+ // We apply the original input's style to the external-input.
1438
+ // Eventually, the user should interact directly with the external input.
1439
+ // We keep the original input
1440
+ const applyExternalInputStyles = (sourceInputEle, targetInputEle, labelType) => {
1441
+ // We set a timeout here to avoid "Double Print" cases,
1442
+ // caused by sampling the computed style before it's ready.
1443
+ setTimeout(() => {
1444
+ const computedStyle = getComputedStyle(sourceInputEle);
1445
+ // Get minimal set of computed theme properties to set on external input
1446
+ const height = computedStyle.getPropertyValue('height');
1447
+ const paddingLeft = computedStyle.getPropertyValue('padding-left');
1448
+ const paddingRight = computedStyle.getPropertyValue('padding-right');
1449
+ const fontSize = computedStyle.getPropertyValue('font-size');
1450
+ const fontFamily = computedStyle.getPropertyValue('font-family');
1451
+ const letterSpacing = computedStyle.getPropertyValue('letter-spacing');
1452
+ const caretColor = computedStyle.getPropertyValue('caret-color');
1453
+
1454
+ const valueColor = getValueColor(sourceInputEle, computedStyle);
1455
+
1456
+ const commonThemeStyles = [
1457
+ ['all', 'unset'],
1458
+ ['position', 'absolute'],
1459
+ ['background-color', 'transparent'],
1460
+ ['height', height],
1461
+ ['left', paddingLeft],
1462
+ ['right', paddingRight],
1463
+ ['font-size', fontSize],
1464
+ ['font-family', fontFamily],
1465
+ ['letter-spacing', letterSpacing],
1466
+ ['caret-color', caretColor], // this is for seeing caret when focusing on external input
1467
+ ['color', valueColor],
1468
+ ];
1469
+
1470
+ commonThemeStyles.forEach(([key, val]) =>
1471
+ targetInputEle.style.setProperty(key, val, 'important')
1472
+ );
1473
+
1474
+ // Handle floating label theme properties
1475
+ if (labelType === 'floating') {
1476
+ const marginBottom = computedStyle.getPropertyValue('margin-bottom');
1477
+ targetInputEle.style.setProperty('margin-bottom', marginBottom, 'important');
1478
+ }
1479
+
1480
+ // sample and apply width only after original input is ready and fully rendered
1481
+ const width = computedStyle.getPropertyValue('width');
1482
+ targetInputEle.style.setProperty(
1483
+ 'width',
1484
+ `calc(${width} - ${paddingLeft} - ${paddingRight}`,
1485
+ 'important'
1486
+ );
1487
+ }, 0);
1488
+ };
1489
+
1490
+ const externalInputMixin =
1491
+ ({ inputType, autocompleteType, includeAttrs = [], noBlurDispatch = false }) =>
1492
+ (superclass) =>
1493
+ class ExternalInputMixinClass extends superclass {
1494
+ #timers = [];
1495
+
1496
+ get isExternalInput() {
1497
+ return this.getAttribute('external-input') === 'true';
1498
+ }
1499
+
1500
+ createExternalInput() {
1501
+ if (!this.isExternalInput) {
1502
+ return null;
1503
+ }
1504
+
1505
+ // use original input element as reference
1506
+ const origInput = this.baseElement.querySelector('input');
1507
+
1508
+ // to avoid focus loop between external-input and origInput
1509
+ // we set origInput's tabindex to -1
1510
+ // otherwise, shift-tab will never leave the component focus
1511
+ origInput.setAttribute('tabindex', '-1');
1512
+
1513
+ // create external slot
1514
+ const externalInputSlot = createExternalInputSlot('external-input', 'suffix');
1515
+
1516
+ // append external slot to base element
1517
+ this.baseElement.appendChild(externalInputSlot);
1518
+
1519
+ this.externalInput = createExternalInputEle(
1520
+ 'external-input',
1521
+ inputType,
1522
+ this.getAutocompleteType()
1523
+ );
1524
+
1525
+ // apply original input's styles to external input
1526
+ setTimeout(() => {
1527
+ applyExternalInputStyles(origInput, this.externalInput, this.getAttribute('label-type'));
1528
+ });
1529
+
1530
+ // 1Password catches the internal input, so we forward the value to the external input
1531
+ this.forwardInputValue(origInput, this.externalInput);
1532
+
1533
+ syncAttrs(origInput, this.externalInput, {
1534
+ includeAttrs,
1535
+ });
1536
+
1537
+ // We disable Vaadin's original `_setFocused` function, and use handleFocusEvents
1538
+ // and handleBlurEvents functions
1539
+ this.baseElement
1540
+ .querySelector('input')
1541
+ .addEventListener('focusout', (e) => e.stopImmediatePropagation(), true);
1542
+
1543
+ // In order to manage focus/blur events when moving between parts of the component
1544
+ // we're managing the event dispatching by ourselves, with the following strategy:
1545
+ // - If one of the component parts is focused - it means that the component is still focused - so we stop the blur events.
1546
+ // - When none of the component parts is focused, we dispatch blur event.
1547
+ this.handleFocusEvents();
1548
+ this.handleBlurEvents();
1549
+
1550
+ // sync input value
1551
+ this.handlelInputEvents(this.externalInput);
1552
+
1553
+ // append external input to component's DOM
1554
+ this.appendChild(this.externalInput);
1555
+
1556
+ return this.externalInput;
1557
+ }
1558
+
1559
+ clearBlurTimers() {
1560
+ this.#timers.forEach((timer) => clearTimeout(timer));
1561
+ this.#timers.length = 0;
1562
+ }
1563
+
1564
+ dispatchBlur() {
1565
+ return setTimeout(() => {
1566
+ this.dispatchEvent(new Event('blur', { bubbles: true, composed: true }));
1567
+ this.removeAttribute('focused');
1568
+ });
1569
+ }
1570
+
1571
+ handleFocusEvents() {
1572
+ // on baseElement `focus` we forward the focus to the external input.
1573
+ // also, in order to avoid any blur within the component, we clear the blur timers.
1574
+ this.baseElement.addEventListener('focus', () => {
1575
+ this.externalInput.focus();
1576
+ this.clearBlurTimers();
1577
+ });
1578
+
1579
+ // on `focus` of the external input, we manually set the `focused` attribute
1580
+ this.externalInput.addEventListener('focus', () => {
1581
+ this.clearBlurTimers();
1582
+ setTimeout(() => this.baseElement.setAttribute('focused', 'true'));
1583
+ });
1584
+ }
1585
+
1586
+ handleBlurEvents() {
1587
+ this.baseElement.addEventListener(
1588
+ 'blur',
1589
+ (e) => {
1590
+ e.stopImmediatePropagation();
1591
+ // some components do not require this synthetic blur dispatch (e.g. Password)
1592
+ // so we allow them to override this dispatch
1593
+ if (noBlurDispatch) return;
1594
+ this.#timers.push(this.dispatchBlur());
1595
+ },
1596
+ true
1597
+ );
1598
+
1599
+ this.externalInput.addEventListener(
1600
+ 'blur',
1601
+ (e) => {
1602
+ e.stopImmediatePropagation();
1603
+ this.#timers.push(this.dispatchBlur());
1604
+ },
1605
+ true
1606
+ );
1607
+ }
1608
+
1609
+ handlelInputEvents(externalInput) {
1610
+ // sync value of insible input back to original input
1611
+ externalInput.addEventListener('input', (e) => {
1612
+ this.value = e.target.value;
1613
+ });
1614
+
1615
+ // handle has-value attr
1616
+ externalInput.addEventListener('input', (e) => {
1617
+ if (!e.target.value) {
1618
+ this.removeAttribute('has-value');
1619
+ } else {
1620
+ this.setAttribute('has-value', 'true');
1621
+ }
1622
+ });
1623
+ }
1624
+
1625
+ getAutocompleteType() {
1626
+ return this.getAttribute('autocomplete') || autocompleteType;
1627
+ }
1628
+
1629
+ forwardInputValue(source, target) {
1630
+ // set internal sync events
1631
+ const valueDescriptor = Object.getOwnPropertyDescriptor(
1632
+ this.inputElement.constructor.prototype,
1633
+ 'value'
1634
+ );
1635
+
1636
+ Object.defineProperty(source, 'value', {
1637
+ ...valueDescriptor,
1638
+
1639
+ set(v) {
1640
+ valueDescriptor.set.call(this, v);
1641
+ // eslint-disable-next-line no-param-reassign
1642
+ target.value = v;
1643
+ },
1644
+ configurable: true,
1645
+ });
1646
+ }
1647
+ };
1648
+
1400
1649
  const getFileExtension = (path) => {
1401
1650
  const match = path.match(/\.([0-9a-z]+)(?:[\\?#]|$)/i);
1402
1651
  return match ? match[1] : null;
@@ -1453,7 +1702,7 @@ const componentName$_ = getComponentName('icon');
1453
1702
 
1454
1703
  class RawIcon extends createBaseClass({ componentName: componentName$_, baseSelector: 'slot' }) {
1455
1704
  static get observedAttributes() {
1456
- return ['src', 'fill-color'];
1705
+ return ['src'];
1457
1706
  }
1458
1707
 
1459
1708
  #icon;
@@ -1478,36 +1727,23 @@ class RawIcon extends createBaseClass({ componentName: componentName$_, baseSele
1478
1727
  `;
1479
1728
  }
1480
1729
 
1481
- get fillColor() {
1482
- return this.getAttribute('fill-color') === 'true';
1483
- }
1484
-
1485
1730
  get src() {
1486
1731
  return this.getAttribute('src');
1487
1732
  }
1488
1733
 
1489
1734
  // in order to fill an SVG with `currentColor` override all of its `fill` and `path` nodes
1490
1735
  // with the value from the `st-fill` attribute
1491
- updateFillColor() {
1492
- if (this.#icon && this.fillColor) {
1493
- const fillCssVar = (selector) => {
1494
- this.querySelectorAll(selector).forEach((ele) =>
1495
- ele.setAttribute(
1496
- 'fill',
1497
- `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
1498
- )
1499
- );
1500
- };
1501
-
1502
- fillCssVar('*[fill]');
1503
- fillCssVar('path');
1504
- }
1505
- }
1506
-
1507
- resetIcon() {
1508
- if (!this.#icon) return;
1509
- this.innerHTML = '';
1510
- this.appendChild(this.#icon.cloneNode(true));
1736
+ // eslint-disable-next-line class-methods-use-this
1737
+ updateFillColor(node) {
1738
+ // set fill to root node and all its relevant selectors
1739
+ const elementsToReplace = [node, ...node.querySelectorAll('*[fill]')];
1740
+
1741
+ elementsToReplace.forEach((ele) => {
1742
+ ele.setAttribute(
1743
+ 'fill',
1744
+ `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
1745
+ );
1746
+ });
1511
1747
  }
1512
1748
 
1513
1749
  attributeChangedCallback(attrName, oldValue, newValue) {
@@ -1517,13 +1753,13 @@ class RawIcon extends createBaseClass({ componentName: componentName$_, baseSele
1517
1753
 
1518
1754
  if (attrName === 'src') {
1519
1755
  createIcon(this.src).then((res) => {
1520
- this.#icon = res;
1521
- this.resetIcon();
1522
- this.updateFillColor();
1756
+ this.innerHTML = '';
1757
+ if (res) {
1758
+ const clonedNode = res.cloneNode(true);
1759
+ this.updateFillColor(clonedNode);
1760
+ this.appendChild(clonedNode);
1761
+ }
1523
1762
  });
1524
- } else if (attrName === 'fill-color') {
1525
- this.resetIcon();
1526
- this.updateFillColor();
1527
1763
  }
1528
1764
  }
1529
1765
  }
@@ -2614,6 +2850,10 @@ const {
2614
2850
  disabledPlaceholder,
2615
2851
  inputDisabled,
2616
2852
  inputIcon,
2853
+ externalInput,
2854
+ externalInputDisabled,
2855
+ externalPlaceholder,
2856
+ externalDisabledPlaceholder,
2617
2857
  } = {
2618
2858
  host: { selector: () => ':host' },
2619
2859
  label: { selector: '::part(label)' },
@@ -2630,6 +2870,10 @@ const {
2630
2870
  helperText: { selector: '::part(helper-text)' },
2631
2871
  errorMessage: { selector: '::part(error-message)' },
2632
2872
  inputIcon: { selector: 'vaadin-icon' },
2873
+ externalInput: { selector: () => '::slotted(input)' },
2874
+ externalInputDisabled: { selector: () => '::slotted(input:disabled)' },
2875
+ externalPlaceholder: { selector: () => '::slotted(input:placeholder-shown)' },
2876
+ externalDisabledPlaceholder: { selector: () => '::slotted(input:disabled::placeholder)' },
2633
2877
  };
2634
2878
 
2635
2879
  var textFieldMappings = {
@@ -2662,8 +2906,12 @@ var textFieldMappings = {
2662
2906
  inputValueTextColor: [
2663
2907
  { ...inputField$6, property: 'color' },
2664
2908
  { ...inputDisabled, property: '-webkit-text-fill-color' },
2909
+ { ...externalInputDisabled, property: '-webkit-text-fill-color' },
2910
+ ],
2911
+ inputCaretTextColor: [
2912
+ { ...input, property: 'caret-color' },
2913
+ { ...externalInput, property: 'caret-color' },
2665
2914
  ],
2666
- inputCaretTextColor: [{ ...input, property: 'color' }],
2667
2915
 
2668
2916
  labelRequiredIndicator: { ...requiredIndicator$9, property: 'content' },
2669
2917
 
@@ -2676,6 +2924,8 @@ var textFieldMappings = {
2676
2924
  inputHorizontalPadding: [
2677
2925
  { ...input, property: 'padding-left' },
2678
2926
  { ...input, property: 'padding-right' },
2927
+ { ...externalInput, property: 'padding-left' },
2928
+ { ...externalInput, property: 'padding-right' },
2679
2929
  ],
2680
2930
 
2681
2931
  inputOutlineColor: { ...inputField$6, property: 'outline-color' },
@@ -2683,12 +2933,17 @@ var textFieldMappings = {
2683
2933
  inputOutlineWidth: { ...inputField$6, property: 'outline-width' },
2684
2934
  inputOutlineOffset: { ...inputField$6, property: 'outline-offset' },
2685
2935
 
2686
- inputTextAlign: [{ ...input, property: 'text-align' }],
2936
+ inputTextAlign: [
2937
+ { ...input, property: 'text-align' },
2938
+ { ...externalInput, property: 'text-align' },
2939
+ ],
2687
2940
 
2688
2941
  inputPlaceholderColor: [
2689
2942
  { selector: () => ':host input:placeholder-shown', property: 'color' },
2943
+ { ...externalPlaceholder, property: 'color' },
2690
2944
  { ...placeholder$3, property: 'color' },
2691
2945
  { ...disabledPlaceholder, property: '-webkit-text-fill-color' },
2946
+ { ...externalDisabledPlaceholder, property: '-webkit-text-fill-color' },
2692
2947
  ],
2693
2948
 
2694
2949
  labelPosition: { ...label$9, property: 'position' },
@@ -2700,10 +2955,22 @@ var textFieldMappings = {
2700
2955
  inputTransformY: { ...label$9, property: 'transform' },
2701
2956
  inputTransition: { ...label$9, property: 'transition' },
2702
2957
  marginInlineStart: { ...label$9, property: 'margin-inline-start' },
2703
- placeholderOpacity: [{ selector: '> input:placeholder-shown', property: 'opacity' }],
2704
- inputVerticalAlignment: [{ ...inputField$6, property: 'align-items' }],
2705
- valueInputHeight: [{ ...input, property: 'height' }],
2706
- valueInputMarginBottom: [{ ...input, property: 'margin-bottom' }],
2958
+ placeholderOpacity: [
2959
+ { selector: '> input:placeholder-shown', property: 'opacity' },
2960
+ { ...externalPlaceholder, property: 'opacity' },
2961
+ ],
2962
+ inputVerticalAlignment: [
2963
+ { ...inputField$6, property: 'align-items' },
2964
+ { ...externalInput, property: 'align-items' },
2965
+ ],
2966
+ valueInputHeight: [
2967
+ { ...input, property: 'height' },
2968
+ { ...externalInput, property: 'height' },
2969
+ ],
2970
+ valueInputMarginBottom: [
2971
+ { ...input, property: 'margin-bottom' },
2972
+ { ...externalInput, property: 'margin-bottom' },
2973
+ ],
2707
2974
 
2708
2975
  inputIconOffset: [
2709
2976
  { ...inputIcon, property: 'margin-right' },
@@ -2729,6 +2996,8 @@ const customMixin$c = (superclass) =>
2729
2996
  if (!this.getAttribute('autocomplete')) {
2730
2997
  this.setAttribute('autocomplete', defaultAutocomplete);
2731
2998
  }
2999
+
3000
+ this.createExternalInput();
2732
3001
  }
2733
3002
  };
2734
3003
 
@@ -2737,6 +3006,11 @@ const EmailFieldClass = compose(
2737
3006
  mappings: textFieldMappings,
2738
3007
  }),
2739
3008
  draggableMixin,
3009
+ externalInputMixin({
3010
+ inputType: 'text',
3011
+ autocompleteType: 'username',
3012
+ includeAttrs: ['disabled', 'readonly', 'pattern'],
3013
+ }),
2740
3014
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'], useProxyTargets: true }),
2741
3015
  componentNameValidationMixin,
2742
3016
  customMixin$c
@@ -2768,6 +3042,10 @@ const EmailFieldClass = compose(
2768
3042
  :host ::slotted(*) {
2769
3043
  -webkit-mask-image: none;
2770
3044
  }
3045
+
3046
+ vaadin-email-field[external-input="true"] > input:not(:placeholder-shown) {
3047
+ opacity: 0;
3048
+ }
2771
3049
  `,
2772
3050
  excludeAttrsSync: ['tabindex'],
2773
3051
  componentName: componentName$Q,
@@ -3606,6 +3884,15 @@ const customMixin$9 = (superclass) =>
3606
3884
  this.origSetPasswordVisible = this.baseElement._setPasswordVisible;
3607
3885
  this.origSetFocused = this.baseElement._setFocused;
3608
3886
  this.baseElement._setFocused = this.setFocus.bind(this);
3887
+
3888
+ this.initExternalInput();
3889
+ }
3890
+
3891
+ initExternalInput() {
3892
+ const externalInput = this.createExternalInput();
3893
+ if (externalInput) {
3894
+ this.handlePasswordVisibility(externalInput);
3895
+ }
3609
3896
  }
3610
3897
 
3611
3898
  get caretPosition() {
@@ -3620,6 +3907,7 @@ const customMixin$9 = (superclass) =>
3620
3907
  setTimeout(() => {
3621
3908
  origTogglePasswordVisibility();
3622
3909
  this.inputElement.setSelectionRange(this.caretPosition, this.caretPosition);
3910
+ return false;
3623
3911
  });
3624
3912
  };
3625
3913
  }
@@ -3646,6 +3934,44 @@ const customMixin$9 = (superclass) =>
3646
3934
  attributeChangedCallback(attrName, oldValue, newValue) {
3647
3935
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
3648
3936
  }
3937
+
3938
+ // override vaadin's password visibility toggle.
3939
+ // we need this override in order to to resolve the external input `focus` race condition,
3940
+ // which is caused due to the focus sync between the two inputs.
3941
+ handlePasswordVisibility(externalInput) {
3942
+ // disable vaadin's `__boundRevealButtonMouseDown` mouse-down event lisetener
3943
+ const origBoundRevealButtonMouseDown = this.baseElement.__boundRevealButtonMouseDown;
3944
+ this.baseElement
3945
+ .querySelector('vaadin-password-field-button')
3946
+ .removeEventListener('mousedown', origBoundRevealButtonMouseDown);
3947
+
3948
+ // disable vaadin's `_passwordVisibleChanged` observer
3949
+ this.baseElement._passwordVisibleChanged = () => {};
3950
+
3951
+ // override vaadin's `_togglePasswordVisibility`
3952
+ this.baseElement._togglePasswordVisibility = () => {
3953
+ const currVisibility = externalInput.getAttribute('type');
3954
+ if (currVisibility === 'password') {
3955
+ this.showPasswordVisibility(externalInput);
3956
+ } else {
3957
+ this.hidePasswordVisibility(externalInput);
3958
+ }
3959
+ };
3960
+ }
3961
+
3962
+ showPasswordVisibility(input) {
3963
+ // handle input element's type
3964
+ input.setAttribute('type', 'text');
3965
+ // handle vaadin's `password-visible` attribute
3966
+ this.setAttribute('password-visible', 'true');
3967
+ }
3968
+
3969
+ hidePasswordVisibility(input) {
3970
+ // handle input element's type
3971
+ input.setAttribute('type', 'password');
3972
+ // handle vaadin's `password-visible` attribute
3973
+ this.setAttribute('password-visible', 'false');
3974
+ }
3649
3975
  };
3650
3976
 
3651
3977
  const {
@@ -3740,7 +4066,12 @@ const PasswordClass = compose(
3740
4066
  },
3741
4067
  }),
3742
4068
  draggableMixin,
3743
- composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
4069
+ externalInputMixin({
4070
+ inputType: 'password',
4071
+ includeAttrs: ['disabled', 'readonly', 'pattern', 'type', 'autocomplete'],
4072
+ noBlurDispatch: true,
4073
+ }),
4074
+ composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'], useProxyTargets: true }),
3744
4075
  componentNameValidationMixin,
3745
4076
  passwordDraggableMixin,
3746
4077
  customMixin$9
@@ -3804,6 +4135,10 @@ const PasswordClass = compose(
3804
4135
  ::part(reveal-button) {
3805
4136
  align-self: center;
3806
4137
  }
4138
+
4139
+ vaadin-password-field[external-input="true"] > input:not(:placeholder-shown) {
4140
+ opacity: 0;
4141
+ }
3807
4142
  `,
3808
4143
  excludeAttrsSync: ['tabindex'],
3809
4144
  componentName: componentName$H,
@@ -6931,11 +7266,14 @@ const customMixin$6 = (superclass) =>
6931
7266
 
6932
7267
  const template = document.createElement('template');
6933
7268
 
7269
+ const externalInputAttr = this.getAttribute('external-input');
7270
+
6934
7271
  template.innerHTML = `
6935
7272
  <${componentName$y}
6936
7273
  name="new-password"
6937
7274
  tabindex="-1"
6938
7275
  slot="input"
7276
+ external-input="${externalInputAttr}"
6939
7277
  >
6940
7278
  </${componentName$y}>
6941
7279
  `;
@@ -6944,6 +7282,10 @@ const customMixin$6 = (superclass) =>
6944
7282
 
6945
7283
  this.inputElement = this.shadowRoot.querySelector(componentName$y);
6946
7284
 
7285
+ if (this.getAttribute('external-input') === 'true') {
7286
+ this.initExternalInput();
7287
+ }
7288
+
6947
7289
  forwardAttrs(this, this.inputElement, {
6948
7290
  includeAttrs: [
6949
7291
  'password-label',
@@ -6968,6 +7310,34 @@ const customMixin$6 = (superclass) =>
6968
7310
  ],
6969
7311
  });
6970
7312
  }
7313
+
7314
+ createSlottedExternalInput(node, slotName) {
7315
+ const externalInput = node.querySelector('input');
7316
+ const slotEle = document.createElement('slot');
7317
+
7318
+ const targetSlot = externalInput.getAttribute('slot');
7319
+
7320
+ slotEle.setAttribute('name', slotName);
7321
+ slotEle.setAttribute('slot', targetSlot);
7322
+
7323
+ node.appendChild(slotEle);
7324
+
7325
+ // move external input
7326
+ externalInput.setAttribute('slot', slotName);
7327
+ externalInput.setAttribute('data-hidden-input', 'true');
7328
+
7329
+ this.appendChild(externalInput);
7330
+ }
7331
+
7332
+ initExternalInput() {
7333
+ // get descope input components
7334
+ this.passwordInput = this.inputElement.querySelector('[data-id="password"]');
7335
+ this.confirmInput = this.inputElement.querySelector('[data-id="confirm"]');
7336
+
7337
+ // create slots for external password input
7338
+ this.createSlottedExternalInput(this.passwordInput, 'external-password-input');
7339
+ this.createSlottedExternalInput(this.confirmInput, 'external-confirm-input');
7340
+ }
6971
7341
  };
6972
7342
 
6973
7343
  const {
@@ -7194,24 +7564,26 @@ class NewPasswordInternal extends BaseInputClass$4 {
7194
7564
  this.passwordInput.focus();
7195
7565
  }
7196
7566
  });
7197
-
7198
7567
  super.init?.();
7199
7568
  this.renderInputs(this.hasConfirm, this.hasValidation);
7200
7569
  }
7201
7570
 
7202
7571
  renderInputs() {
7572
+ const hasExternalInput = this.getAttribute('external-input') === 'true';
7203
7573
  const template = `
7204
7574
  <div>
7205
7575
  <descope-password
7206
7576
  autocomplete="new-password"
7207
7577
  manual-visibility-toggle="true"
7208
7578
  data-id="password"
7579
+ external-input="${hasExternalInput}"
7209
7580
  ></descope-password>
7210
7581
  <descope-policy-validation></descope-policy-validation>
7211
7582
  </div>
7212
7583
  <descope-password
7213
7584
  autocomplete="new-password"
7214
7585
  manual-visibility-toggle="true"
7586
+ external-input="${hasExternalInput}"
7215
7587
  data-id="confirm"
7216
7588
  ></descope-password>
7217
7589
  `;
@@ -12791,7 +13163,6 @@ const button = {
12791
13163
  [compVars$6.outlineColor]: 'transparent',
12792
13164
 
12793
13165
  [compVars$6.iconSize]: '1.5em',
12794
- [compVars$6.iconColor]: 'currentColor',
12795
13166
 
12796
13167
  size: {
12797
13168
  xs: { [compVars$6.fontSize]: '12px' },