@descope/web-components-ui 1.0.313 → 1.0.314

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.esm.js CHANGED
@@ -763,8 +763,13 @@ const errorAttributes = {
763
763
  tooShort: 'data-errormessage-pattern-mismatch-too-short',
764
764
  tooLong: 'data-errormessage-pattern-mismatch-too-long',
765
765
  };
766
+
767
+ const validationTargetSymbol = Symbol('validationTarget');
768
+
766
769
  const inputValidationMixin = (superclass) =>
767
770
  class InputValidationMixinClass extends superclass {
771
+ #validationTarget = validationTargetSymbol;
772
+
768
773
  static get observedAttributes() {
769
774
  return [...(superclass.observedAttributes || []), ...observedAttributes$6];
770
775
  }
@@ -881,7 +886,13 @@ const inputValidationMixin = (superclass) =>
881
886
  }
882
887
 
883
888
  get validationTarget() {
884
- return this.inputElement;
889
+ return this.#validationTarget === validationTargetSymbol
890
+ ? this.inputElement
891
+ : this.#validationTarget;
892
+ }
893
+
894
+ set validationTarget(val) {
895
+ this.#validationTarget = val;
885
896
  }
886
897
 
887
898
  setCustomValidity(errorMessage) {
@@ -2539,7 +2550,7 @@ var textFieldMappings = {
2539
2550
 
2540
2551
  const componentName$K = getComponentName('email-field');
2541
2552
 
2542
- const customMixin$8 = (superclass) =>
2553
+ const customMixin$9 = (superclass) =>
2543
2554
  class EmailFieldMixinClass extends superclass {
2544
2555
  init() {
2545
2556
  super.init?.();
@@ -2553,7 +2564,7 @@ const EmailFieldClass = compose(
2553
2564
  draggableMixin,
2554
2565
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
2555
2566
  componentNameValidationMixin,
2556
- customMixin$8
2567
+ customMixin$9
2557
2568
  )(
2558
2569
  createProxy({
2559
2570
  slots: ['', 'suffix'],
@@ -3012,7 +3023,7 @@ const componentName$D = getComponentName('text-field');
3012
3023
 
3013
3024
  const observedAttrs = ['type'];
3014
3025
 
3015
- const customMixin$7 = (superclass) =>
3026
+ const customMixin$8 = (superclass) =>
3016
3027
  class TextFieldClass extends superclass {
3017
3028
  static get observedAttributes() {
3018
3029
  return observedAttrs.concat(superclass.observedAttributes || []);
@@ -3064,7 +3075,7 @@ const TextFieldClass = compose(
3064
3075
  draggableMixin,
3065
3076
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
3066
3077
  componentNameValidationMixin,
3067
- customMixin$7
3078
+ customMixin$8
3068
3079
  )(
3069
3080
  createProxy({
3070
3081
  slots: ['prefix', 'suffix'],
@@ -3091,7 +3102,7 @@ const componentName$C = getComponentName('passcode');
3091
3102
 
3092
3103
  const observedAttributes$4 = ['digits'];
3093
3104
 
3094
- const customMixin$6 = (superclass) =>
3105
+ const customMixin$7 = (superclass) =>
3095
3106
  class PasscodeMixinClass extends superclass {
3096
3107
  static get observedAttributes() {
3097
3108
  return observedAttributes$4.concat(superclass.observedAttributes || []);
@@ -3187,7 +3198,7 @@ const PasscodeClass = compose(
3187
3198
  draggableMixin,
3188
3199
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
3189
3200
  componentNameValidationMixin,
3190
- customMixin$6
3201
+ customMixin$7
3191
3202
  )(
3192
3203
  createProxy({
3193
3204
  slots: [],
@@ -3283,32 +3294,165 @@ const passwordDraggableMixin = (superclass) =>
3283
3294
  // there is an issue in Chrome that input field with type password cannot be D&D
3284
3295
  // so in case the input is draggable & readonly, we are changing the input type to "text" before dragging
3285
3296
  // and return the original type when done
3286
- this.addEventListener('mousedown', (e) => {
3297
+ super.init?.();
3298
+
3299
+ const ele = this.querySelector('input');
3300
+
3301
+ ele?.addEventListener('mousedown', (e) => {
3287
3302
  if (this.isDraggable && this.isReadOnly) {
3288
- const inputEle = this.baseElement.querySelector('input');
3289
- const prevType = inputEle.getAttribute('type');
3303
+ ele.setAttribute('inert', 'true');
3290
3304
 
3305
+ const inputEle = e.target;
3306
+ const prevType = inputEle.getAttribute('type');
3291
3307
  inputEle.setAttribute('type', 'text');
3292
- setTimeout(() => inputEle.focus());
3308
+ setTimeout(() => {
3309
+ inputEle.focus();
3310
+ });
3293
3311
 
3294
3312
  const onComplete = (_) => {
3295
3313
  inputEle.setAttribute('type', prevType);
3296
-
3297
- e.target.removeEventListener('mouseup', onComplete);
3298
- e.target.removeEventListener('dragend', onComplete);
3314
+ ele.removeAttribute('inert');
3315
+ this.removeEventListener('mouseup', onComplete);
3316
+ this.removeEventListener('dragend', onComplete);
3299
3317
  };
3300
3318
 
3301
- e.target.addEventListener('mouseup', onComplete, { once: true });
3302
- e.target.addEventListener('dragend', onComplete, { once: true });
3319
+ this.addEventListener('dragend', onComplete, { once: true });
3320
+ this.addEventListener('mouseup', onComplete, { once: true });
3303
3321
  }
3304
3322
  });
3305
-
3306
- super.init?.();
3307
3323
  }
3308
3324
  };
3309
3325
 
3326
+ // since on load we can only sample the color of the placeholder,
3327
+ // we need to temporarily populate the input in order to sample the value color
3328
+ const getValueColor = (ele, computedStyle) => {
3329
+ // eslint-disable-next-line no-param-reassign
3330
+ ele.value = '_';
3331
+
3332
+ const valueColor = computedStyle.getPropertyValue('color');
3333
+
3334
+ // eslint-disable-next-line no-param-reassign
3335
+ ele.value = '';
3336
+
3337
+ return valueColor;
3338
+ };
3339
+
3340
+ const createExternalInputSlot = (slotName, targetSlotName) => {
3341
+ const slotEle = document.createElement('slot');
3342
+
3343
+ slotEle.setAttribute('name', slotName);
3344
+ slotEle.setAttribute('slot', targetSlotName);
3345
+
3346
+ return slotEle;
3347
+ };
3348
+
3349
+ const createExternalInputEle = (targetSlotName, autocompleteType) => {
3350
+ const inputEle = document.createElement('input');
3351
+
3352
+ inputEle.setAttribute('slot', targetSlotName);
3353
+ inputEle.setAttribute('type', 'password');
3354
+ inputEle.setAttribute('data-hidden-input', 'true');
3355
+ inputEle.setAttribute('autocomplete', autocompleteType);
3356
+
3357
+ return inputEle;
3358
+ };
3359
+
3360
+ const applyExternalInputStyles = (sourceInputEle, targetInputEle) => {
3361
+ const computedStyle = getComputedStyle(sourceInputEle);
3362
+ const height = computedStyle.getPropertyValue('height');
3363
+ const paddingLeft = computedStyle.getPropertyValue('padding-left');
3364
+ const paddingRight = computedStyle.getPropertyValue('padding-right');
3365
+ const fontSize = computedStyle.getPropertyValue('font-size');
3366
+ const fontFamily = computedStyle.getPropertyValue('font-family');
3367
+ const letterSpacing = computedStyle.getPropertyValue('letter-spacing');
3368
+ const caretColor = computedStyle.getPropertyValue('caret-color');
3369
+ const valueColor = getValueColor(sourceInputEle, computedStyle);
3370
+
3371
+ // set external input style (and lock it with `all: unset` and `!important` all around)
3372
+ // eslint-disable-next-line no-param-reassign
3373
+ targetInputEle.style = `
3374
+ all: unset !important;
3375
+ position: absolute !important;
3376
+ width: calc(100% - 3em) !important;
3377
+ background-color: transparent !important;
3378
+ color: ${valueColor} !important;
3379
+ height: ${height} !important;
3380
+ left: ${paddingLeft} !important;
3381
+ right: ${paddingRight} !important;
3382
+ font-size: ${fontSize} !important;
3383
+ font-family: ${fontFamily} !important;
3384
+ letter-spacing: ${letterSpacing} !important;
3385
+ caret-color: ${caretColor} !important;
3386
+ `;
3387
+ };
3388
+
3310
3389
  const componentName$B = getComponentName('password');
3311
3390
 
3391
+ const customMixin$6 = (superclass) =>
3392
+ class PasswordFieldMixinClass extends superclass {
3393
+ init() {
3394
+ super.init?.();
3395
+
3396
+ // reset vaadin's checkValidity
3397
+ this.baseElement.checkValidity = () => {};
3398
+ // set safety attribute `external-input`
3399
+ this.setAttribute('external-input', 'true');
3400
+
3401
+ // use original input element as reference
3402
+ const origInput = this.baseElement.querySelector('input');
3403
+
3404
+ // create external slot
3405
+ const externalInputSlot = createExternalInputSlot('external-input', 'suffix');
3406
+ // append external slot to base element
3407
+ this.baseElement.appendChild(externalInputSlot);
3408
+
3409
+ // create external input
3410
+ const externalInput = createExternalInputEle('external-input', this.getAutocompleteType());
3411
+
3412
+ // apply original input's styles to external input
3413
+ setTimeout(() => {
3414
+ applyExternalInputStyles(origInput, externalInput);
3415
+ });
3416
+
3417
+ // set external input events
3418
+ this.handleExternalInputEvents(externalInput);
3419
+
3420
+ // sync input stateful attributes: `type` (for visibility state change) and `readonly`
3421
+ syncAttrs(origInput, externalInput, { includeAttrs: ['type', 'readonly'] });
3422
+
3423
+ origInput.addEventListener('focus', (e) => {
3424
+ e.preventDefault();
3425
+ if (e.isTrusted) {
3426
+ externalInput.focus();
3427
+ }
3428
+ });
3429
+
3430
+ this.addEventListener('focus', (e) => {
3431
+ e.preventDefault();
3432
+ this.focus();
3433
+ });
3434
+
3435
+ // append external input to component's DOM
3436
+ this.appendChild(externalInput);
3437
+ }
3438
+
3439
+ getAutocompleteType() {
3440
+ return this.getAttribute('autocomplete') || 'current-password';
3441
+ }
3442
+
3443
+ handleExternalInputEvents(inputEle) {
3444
+ // sync value of insible input back to original input
3445
+ inputEle.addEventListener('input', (e) => {
3446
+ this.value = e.target.value;
3447
+ });
3448
+
3449
+ // sync `focused` attribute on host when focusing on external input
3450
+ inputEle.addEventListener('focus', () => {
3451
+ this.setAttribute('focused', 'true');
3452
+ });
3453
+ }
3454
+ };
3455
+
3312
3456
  const {
3313
3457
  host: host$f,
3314
3458
  inputField: inputField$5,
@@ -3324,9 +3468,9 @@ const {
3324
3468
  host: { selector: () => ':host' },
3325
3469
  inputField: { selector: '::part(input-field)' },
3326
3470
  inputElement: { selector: '> input' },
3327
- inputElementPlaceholder: { selector: '> input:placeholder-shown' },
3328
- revealButtonContainer: { selector: () => '::part(reveal-button)' },
3329
- revealButtonIcon: { selector: () => '::part(reveal-button)::before' },
3471
+ inputElementPlaceholder: { selector: () => ':host input:placeholder-shown' },
3472
+ revealButtonContainer: { selector: '::part(reveal-button)' },
3473
+ revealButtonIcon: { selector: '::part(reveal-button)::before' },
3330
3474
  label: { selector: '::part(label)' },
3331
3475
  requiredIndicator: { selector: '[required]::part(required-indicator)::after' },
3332
3476
  helperText: { selector: '::part(helper-text)' },
@@ -3365,8 +3509,14 @@ const PasswordClass = compose(
3365
3509
  labelRequiredIndicator: { ...requiredIndicator$7, property: 'content' },
3366
3510
  errorMessageTextColor: { ...errorMessage$8, property: 'color' },
3367
3511
 
3368
- inputValueTextColor: { ...inputElement$2, property: 'color' },
3369
- inputPlaceholderTextColor: { ...inputElementPlaceholder, property: 'color' },
3512
+ inputPlaceholderTextColor: [
3513
+ { ...inputElementPlaceholder, property: 'color' },
3514
+ { selector: () => ':host ::slotted(input:placeholder-shown)', property: 'color' },
3515
+ ],
3516
+ inputValueTextColor: [
3517
+ { ...inputElement$2, property: 'color' },
3518
+ { selector: () => ':host ::slotted(input)', property: 'color' },
3519
+ ],
3370
3520
 
3371
3521
  revealButtonOffset: [
3372
3522
  { ...revealButtonContainer, property: 'margin-right' },
@@ -3379,7 +3529,8 @@ const PasswordClass = compose(
3379
3529
  draggableMixin,
3380
3530
  composedProxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
3381
3531
  componentNameValidationMixin,
3382
- passwordDraggableMixin
3532
+ passwordDraggableMixin,
3533
+ customMixin$6
3383
3534
  )(
3384
3535
  createProxy({
3385
3536
  slots: ['', 'suffix'],
@@ -3390,6 +3541,7 @@ const PasswordClass = compose(
3390
3541
  max-width: 100%;
3391
3542
  min-width: 10em;
3392
3543
  box-sizing: border-box;
3544
+ position: relative;
3393
3545
  }
3394
3546
  ${useHostExternalPadding(PasswordClass.cssVarList)}
3395
3547
  ${resetInputCursor('vaadin-password-field')}
@@ -3401,7 +3553,9 @@ const PasswordClass = compose(
3401
3553
  padding: 0;
3402
3554
  }
3403
3555
  vaadin-password-field > input {
3556
+ -webkit-mask-image: none;
3404
3557
  box-sizing: border-box;
3558
+ opacity: 1;
3405
3559
  }
3406
3560
  vaadin-password-field::part(input-field) {
3407
3561
  box-sizing: border-box;
@@ -3410,12 +3564,11 @@ const PasswordClass = compose(
3410
3564
  vaadin-password-field[focus-ring]::part(input-field) {
3411
3565
  box-shadow: none;
3412
3566
  }
3413
- vaadin-password-field > input {
3567
+ :host ::slotted(input) {
3414
3568
  min-height: 0;
3415
- -webkit-mask-image: none;
3416
- }
3417
- vaadin-password-field[readonly] > input:placeholder-shown {
3418
- opacity: 1;
3569
+ }
3570
+ :host([readonly]) ::slotted(input:placeholder-shown) {
3571
+ opacity: 0;
3419
3572
  }
3420
3573
  vaadin-password-field::before {
3421
3574
  height: initial;
@@ -3426,11 +3579,9 @@ const PasswordClass = compose(
3426
3579
  vaadin-password-field-button {
3427
3580
  cursor: pointer;
3428
3581
  }
3429
-
3430
- [readonly] vaadin-password-field-button {
3582
+ :host([readonly]) vaadin-password-field-button {
3431
3583
  pointer-events: none;
3432
3584
  }
3433
-
3434
3585
  vaadin-password-field-button[focus-ring] {
3435
3586
  box-shadow: 0 0 0 2px var(${PasswordClass.cssVarList.inputOutlineColor});
3436
3587
  }
@@ -6354,13 +6505,24 @@ const customMixin$3 = (superclass) =>
6354
6505
  name="new-password"
6355
6506
  tabindex="-1"
6356
6507
  slot="input"
6357
- ></${componentName$s}>
6508
+ >
6509
+ </${componentName$s}>
6358
6510
  `;
6359
6511
 
6512
+ this.setAttribute('external-input', 'true');
6513
+
6360
6514
  this.baseElement.appendChild(template.content.cloneNode(true));
6361
6515
 
6362
6516
  this.inputElement = this.shadowRoot.querySelector(componentName$s);
6363
6517
 
6518
+ // get descope input components
6519
+ this.passwordInput = this.inputElement.querySelector('[data-id="password"]');
6520
+ this.confirmInput = this.inputElement.querySelector('[data-id="confirm"]');
6521
+
6522
+ // create slots for external password input
6523
+ this.createExternalInput(this.passwordInput, 'external-password-input');
6524
+ this.createExternalInput(this.confirmInput, 'external-confirm-input');
6525
+
6364
6526
  forwardAttrs(this, this.inputElement, {
6365
6527
  includeAttrs: [
6366
6528
  'password-label',
@@ -6383,6 +6545,20 @@ const customMixin$3 = (superclass) =>
6383
6545
  ],
6384
6546
  });
6385
6547
  }
6548
+
6549
+ createExternalInput(node, slotName) {
6550
+ const externalInput = node.querySelector('input');
6551
+ const slotEle = document.createElement('slot');
6552
+ const targetSlot = externalInput.getAttribute('slot');
6553
+ slotEle.setAttribute('name', slotName);
6554
+ slotEle.setAttribute('slot', targetSlot);
6555
+ node.appendChild(slotEle);
6556
+
6557
+ // move external input
6558
+ externalInput.setAttribute('slot', slotName);
6559
+ externalInput.setAttribute('data-hidden-input', 'true');
6560
+ this.appendChild(externalInput);
6561
+ }
6386
6562
  };
6387
6563
 
6388
6564
  const {
@@ -6470,6 +6646,7 @@ const NewPasswordClass = compose(
6470
6646
  padding: 0;
6471
6647
  }
6472
6648
  descope-new-password-internal > .wrapper {
6649
+ -webkit-mask-image: none;
6473
6650
  width: 100%;
6474
6651
  height: 100%;
6475
6652
  display: flex;
@@ -6506,6 +6683,7 @@ const passwordInputAttrs = ['password-label', 'password-placeholder'];
6506
6683
  const confirmInputAttrs = ['confirm-label', 'confirm-placeholder'];
6507
6684
  const policyPanelAttrs = ['has-validation'];
6508
6685
  const commonAttrs = [
6686
+ 'has-confirm',
6509
6687
  'disabled',
6510
6688
  'bordered',
6511
6689
  'size',
@@ -6528,7 +6706,7 @@ const BaseInputClass$4 = createBaseInputClass({ componentName: componentName$s,
6528
6706
 
6529
6707
  class NewPasswordInternal extends BaseInputClass$4 {
6530
6708
  static get observedAttributes() {
6531
- return ['has-confirm'].concat(BaseInputClass$4.observedAttributes || [], inputRelatedAttrs);
6709
+ return [].concat(BaseInputClass$4.observedAttributes || [], inputRelatedAttrs);
6532
6710
  }
6533
6711
 
6534
6712
  constructor() {
@@ -6554,6 +6732,14 @@ class NewPasswordInternal extends BaseInputClass$4 {
6554
6732
  return this.getAttribute('has-confirm') === 'true';
6555
6733
  }
6556
6734
 
6735
+ onHasConfirmChange(hasConfirm) {
6736
+ this.confirmInput.style.display = hasConfirm ? '' : 'none';
6737
+ }
6738
+
6739
+ onHasValidationChange(hasValidation) {
6740
+ this.policyPanel.style.display = hasValidation ? '' : 'none';
6741
+ }
6742
+
6557
6743
  get hasValidation() {
6558
6744
  return this.getAttribute('has-validation') === 'true';
6559
6745
  }
@@ -6592,20 +6778,15 @@ class NewPasswordInternal extends BaseInputClass$4 {
6592
6778
  this.renderInputs(this.hasConfirm, this.hasValidation);
6593
6779
  }
6594
6780
 
6595
- renderInputs(shouldRenderConfirm, shouldRenderValidation) {
6596
- let template = `
6781
+ renderInputs() {
6782
+ const template = `
6597
6783
  <div>
6598
- <descope-password data-id="password"></descope-password>
6599
- <descope-policy-validation class="${
6600
- shouldRenderValidation ? 'hidden' : ''
6601
- }"></descope-policy-validation>
6784
+ <descope-password autocomplete="new-password" data-id="password"></descope-password>
6785
+ <descope-policy-validation></descope-policy-validation>
6602
6786
  </div>
6787
+ <descope-password autocomplete="new-password" data-id="confirm"></descope-password>
6603
6788
  `;
6604
6789
 
6605
- if (shouldRenderConfirm) {
6606
- template += `<descope-password data-id="confirm"></descope-password>`;
6607
- }
6608
-
6609
6790
  this.wrapperEle.innerHTML = template;
6610
6791
 
6611
6792
  this.passwordInput = this.querySelector('[data-id="password"]');
@@ -6616,12 +6797,7 @@ class NewPasswordInternal extends BaseInputClass$4 {
6616
6797
 
6617
6798
  this.initInputs();
6618
6799
 
6619
- // we are calling attributeChangedCallback with all the input related attributes
6620
- // in order to set it on the newly generated input
6621
- [...passwordInputAttrs, ...confirmInputAttrs, ...commonAttrs].forEach((attr) => {
6622
- this.attributeChangedCallback(attr, null, this.getAttribute(attr));
6623
- });
6624
-
6800
+ // sync input value to policy validation panel
6625
6801
  this.passwordInput.addEventListener('input', (e) => {
6626
6802
  this.policyPanel.setAttribute('value', e.target.value);
6627
6803
  });
@@ -6697,22 +6873,14 @@ class NewPasswordInternal extends BaseInputClass$4 {
6697
6873
  value === null ? ele?.removeAttribute(name) : ele?.setAttribute(name, value);
6698
6874
  }
6699
6875
 
6700
- hidePolicy() {
6701
- this.policyPanel.classList.add('hidden');
6702
- }
6703
-
6704
- showPolicy() {
6705
- this.policyPanel.classList.remove('hidden');
6706
- }
6707
-
6708
6876
  attributeChangedCallback(attrName, oldValue, newValue) {
6709
6877
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
6710
6878
 
6711
6879
  if (oldValue !== newValue) {
6712
6880
  if (attrName === 'has-validation') {
6713
- this.renderInputs(this.hasConfirm, newValue === 'true');
6881
+ this.onHasValidationChange(newValue === 'true');
6714
6882
  } else if (attrName === 'has-confirm') {
6715
- this.renderInputs(newValue !== null && newValue !== 'false', this.hasValidation);
6883
+ this.onHasConfirmChange(newValue === 'true');
6716
6884
  } else if (commonAttrs.includes(attrName)) {
6717
6885
  this.inputs.forEach((input) => this.toggleBooleanAttribute(input, attrName, newValue));
6718
6886
  } else if (passwordInputAttrs.includes(attrName)) {
@@ -6728,9 +6896,6 @@ class NewPasswordInternal extends BaseInputClass$4 {
6728
6896
  newValue
6729
6897
  );
6730
6898
  }
6731
- if (attrName === 'has-validation') {
6732
- newValue === 'true' ? this.showPolicy() : this.hidePolicy();
6733
- }
6734
6899
  }
6735
6900
  }
6736
6901
  }