@descope/web-components-ui 1.0.371 → 1.0.372

Sign up to get free protection for your applications and to get access to all the features.
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;
@@ -2601,6 +2850,10 @@ const {
2601
2850
  disabledPlaceholder,
2602
2851
  inputDisabled,
2603
2852
  inputIcon,
2853
+ externalInput,
2854
+ externalInputDisabled,
2855
+ externalPlaceholder,
2856
+ externalDisabledPlaceholder,
2604
2857
  } = {
2605
2858
  host: { selector: () => ':host' },
2606
2859
  label: { selector: '::part(label)' },
@@ -2617,6 +2870,10 @@ const {
2617
2870
  helperText: { selector: '::part(helper-text)' },
2618
2871
  errorMessage: { selector: '::part(error-message)' },
2619
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)' },
2620
2877
  };
2621
2878
 
2622
2879
  var textFieldMappings = {
@@ -2649,8 +2906,12 @@ var textFieldMappings = {
2649
2906
  inputValueTextColor: [
2650
2907
  { ...inputField$6, property: 'color' },
2651
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' },
2652
2914
  ],
2653
- inputCaretTextColor: [{ ...input, property: 'color' }],
2654
2915
 
2655
2916
  labelRequiredIndicator: { ...requiredIndicator$9, property: 'content' },
2656
2917
 
@@ -2663,6 +2924,8 @@ var textFieldMappings = {
2663
2924
  inputHorizontalPadding: [
2664
2925
  { ...input, property: 'padding-left' },
2665
2926
  { ...input, property: 'padding-right' },
2927
+ { ...externalInput, property: 'padding-left' },
2928
+ { ...externalInput, property: 'padding-right' },
2666
2929
  ],
2667
2930
 
2668
2931
  inputOutlineColor: { ...inputField$6, property: 'outline-color' },
@@ -2670,12 +2933,17 @@ var textFieldMappings = {
2670
2933
  inputOutlineWidth: { ...inputField$6, property: 'outline-width' },
2671
2934
  inputOutlineOffset: { ...inputField$6, property: 'outline-offset' },
2672
2935
 
2673
- inputTextAlign: [{ ...input, property: 'text-align' }],
2936
+ inputTextAlign: [
2937
+ { ...input, property: 'text-align' },
2938
+ { ...externalInput, property: 'text-align' },
2939
+ ],
2674
2940
 
2675
2941
  inputPlaceholderColor: [
2676
2942
  { selector: () => ':host input:placeholder-shown', property: 'color' },
2943
+ { ...externalPlaceholder, property: 'color' },
2677
2944
  { ...placeholder$3, property: 'color' },
2678
2945
  { ...disabledPlaceholder, property: '-webkit-text-fill-color' },
2946
+ { ...externalDisabledPlaceholder, property: '-webkit-text-fill-color' },
2679
2947
  ],
2680
2948
 
2681
2949
  labelPosition: { ...label$9, property: 'position' },
@@ -2687,10 +2955,22 @@ var textFieldMappings = {
2687
2955
  inputTransformY: { ...label$9, property: 'transform' },
2688
2956
  inputTransition: { ...label$9, property: 'transition' },
2689
2957
  marginInlineStart: { ...label$9, property: 'margin-inline-start' },
2690
- placeholderOpacity: [{ selector: '> input:placeholder-shown', property: 'opacity' }],
2691
- inputVerticalAlignment: [{ ...inputField$6, property: 'align-items' }],
2692
- valueInputHeight: [{ ...input, property: 'height' }],
2693
- 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
+ ],
2694
2974
 
2695
2975
  inputIconOffset: [
2696
2976
  { ...inputIcon, property: 'margin-right' },
@@ -2716,6 +2996,8 @@ const customMixin$c = (superclass) =>
2716
2996
  if (!this.getAttribute('autocomplete')) {
2717
2997
  this.setAttribute('autocomplete', defaultAutocomplete);
2718
2998
  }
2999
+
3000
+ this.createExternalInput();
2719
3001
  }
2720
3002
  };
2721
3003
 
@@ -2724,6 +3006,11 @@ const EmailFieldClass = compose(
2724
3006
  mappings: textFieldMappings,
2725
3007
  }),
2726
3008
  draggableMixin,
3009
+ externalInputMixin({
3010
+ inputType: 'text',
3011
+ autocompleteType: 'username',
3012
+ includeAttrs: ['disabled', 'readonly', 'pattern'],
3013
+ }),
2727
3014
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'], useProxyTargets: true }),
2728
3015
  componentNameValidationMixin,
2729
3016
  customMixin$c
@@ -2755,6 +3042,10 @@ const EmailFieldClass = compose(
2755
3042
  :host ::slotted(*) {
2756
3043
  -webkit-mask-image: none;
2757
3044
  }
3045
+
3046
+ vaadin-email-field[external-input="true"] > input:not(:placeholder-shown) {
3047
+ opacity: 0;
3048
+ }
2758
3049
  `,
2759
3050
  excludeAttrsSync: ['tabindex'],
2760
3051
  componentName: componentName$Q,
@@ -3593,6 +3884,15 @@ const customMixin$9 = (superclass) =>
3593
3884
  this.origSetPasswordVisible = this.baseElement._setPasswordVisible;
3594
3885
  this.origSetFocused = this.baseElement._setFocused;
3595
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
+ }
3596
3896
  }
3597
3897
 
3598
3898
  get caretPosition() {
@@ -3607,6 +3907,7 @@ const customMixin$9 = (superclass) =>
3607
3907
  setTimeout(() => {
3608
3908
  origTogglePasswordVisibility();
3609
3909
  this.inputElement.setSelectionRange(this.caretPosition, this.caretPosition);
3910
+ return false;
3610
3911
  });
3611
3912
  };
3612
3913
  }
@@ -3633,6 +3934,44 @@ const customMixin$9 = (superclass) =>
3633
3934
  attributeChangedCallback(attrName, oldValue, newValue) {
3634
3935
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
3635
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
+ }
3636
3975
  };
3637
3976
 
3638
3977
  const {
@@ -3727,7 +4066,12 @@ const PasswordClass = compose(
3727
4066
  },
3728
4067
  }),
3729
4068
  draggableMixin,
3730
- 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 }),
3731
4075
  componentNameValidationMixin,
3732
4076
  passwordDraggableMixin,
3733
4077
  customMixin$9
@@ -3791,6 +4135,10 @@ const PasswordClass = compose(
3791
4135
  ::part(reveal-button) {
3792
4136
  align-self: center;
3793
4137
  }
4138
+
4139
+ vaadin-password-field[external-input="true"] > input:not(:placeholder-shown) {
4140
+ opacity: 0;
4141
+ }
3794
4142
  `,
3795
4143
  excludeAttrsSync: ['tabindex'],
3796
4144
  componentName: componentName$H,
@@ -6918,11 +7266,14 @@ const customMixin$6 = (superclass) =>
6918
7266
 
6919
7267
  const template = document.createElement('template');
6920
7268
 
7269
+ const externalInputAttr = this.getAttribute('external-input');
7270
+
6921
7271
  template.innerHTML = `
6922
7272
  <${componentName$y}
6923
7273
  name="new-password"
6924
7274
  tabindex="-1"
6925
7275
  slot="input"
7276
+ external-input="${externalInputAttr}"
6926
7277
  >
6927
7278
  </${componentName$y}>
6928
7279
  `;
@@ -6931,6 +7282,10 @@ const customMixin$6 = (superclass) =>
6931
7282
 
6932
7283
  this.inputElement = this.shadowRoot.querySelector(componentName$y);
6933
7284
 
7285
+ if (this.getAttribute('external-input') === 'true') {
7286
+ this.initExternalInput();
7287
+ }
7288
+
6934
7289
  forwardAttrs(this, this.inputElement, {
6935
7290
  includeAttrs: [
6936
7291
  'password-label',
@@ -6955,6 +7310,34 @@ const customMixin$6 = (superclass) =>
6955
7310
  ],
6956
7311
  });
6957
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
+ }
6958
7341
  };
6959
7342
 
6960
7343
  const {
@@ -7181,24 +7564,26 @@ class NewPasswordInternal extends BaseInputClass$4 {
7181
7564
  this.passwordInput.focus();
7182
7565
  }
7183
7566
  });
7184
-
7185
7567
  super.init?.();
7186
7568
  this.renderInputs(this.hasConfirm, this.hasValidation);
7187
7569
  }
7188
7570
 
7189
7571
  renderInputs() {
7572
+ const hasExternalInput = this.getAttribute('external-input') === 'true';
7190
7573
  const template = `
7191
7574
  <div>
7192
7575
  <descope-password
7193
7576
  autocomplete="new-password"
7194
7577
  manual-visibility-toggle="true"
7195
7578
  data-id="password"
7579
+ external-input="${hasExternalInput}"
7196
7580
  ></descope-password>
7197
7581
  <descope-policy-validation></descope-policy-validation>
7198
7582
  </div>
7199
7583
  <descope-password
7200
7584
  autocomplete="new-password"
7201
7585
  manual-visibility-toggle="true"
7586
+ external-input="${hasExternalInput}"
7202
7587
  data-id="confirm"
7203
7588
  ></descope-password>
7204
7589
  `;