@descope/web-components-ui 1.88.0 → 1.89.0

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.
@@ -1765,8 +1765,9 @@ const inputEventsDispatchingMixin$1 = (superclass) =>
1765
1765
  #blockNativeEvents() {
1766
1766
  ['blur', 'focus', 'focusin', 'focusout'].forEach((event) => {
1767
1767
  this.addEventListener(event, (e) => {
1768
- e.isTrusted && e.target === this && e.stopImmediatePropagation();
1769
- });
1768
+ if (e.isTrusted && e.target === this) {
1769
+ e.stopImmediatePropagation();
1770
+ } });
1770
1771
  });
1771
1772
  }
1772
1773
 
@@ -15595,6 +15596,7 @@ const COUNTER_SUPPORTED_KEYS = [
15595
15596
  'PageUp',
15596
15597
  'PageDown',
15597
15598
  'Meta',
15599
+ 'Enter',
15598
15600
  ];
15599
15601
 
15600
15602
  const months = [
@@ -15625,7 +15627,7 @@ const weekdays = [
15625
15627
  const counterConfig = {
15626
15628
  MONTH: { id: 'month', min: 1, max: 12, placeholder: 'MM', count: 5, shiftCount: 10 },
15627
15629
  DAY: { id: 'day', min: 1, max: 31, placeholder: 'DD', count: 5, shiftCount: 10 },
15628
- YEAR: { id: 'year', min: 0, max: 9999, placeholder: 'YYYY', count: 10, shiftCount: 100 },
15630
+ YEAR: { id: 'year', min: 1900, max: 2099, placeholder: 'YYYY', count: 10, shiftCount: 100 },
15629
15631
  };
15630
15632
 
15631
15633
  const BUTTON_LABEL_DONE = 'Done';
@@ -15637,7 +15639,7 @@ const isValidTimestamp = (val) => !Number.isNaN(Number(val));
15637
15639
  const isNumber = (val) => !Number.isNaN(Number(val));
15638
15640
 
15639
15641
  const getTimestampParts = (timestamp) => {
15640
- const date = new Date(timestamp);
15642
+ const date = newDate(timestamp);
15641
15643
  const year = date.getFullYear();
15642
15644
  const month = date.getMonth() + 1;
15643
15645
  const day = date.getDate();
@@ -15685,6 +15687,7 @@ const getKeyMap = (key, shiftKey, metaKey) => {
15685
15687
  shiftArrowDown: shiftKey && key === 'ArrowDown',
15686
15688
  shiftPageUp: shiftKey && key === 'PageUp',
15687
15689
  shiftPageDown: shiftKey && key === 'PageDown',
15690
+ enter: key === 'Enter',
15688
15691
  };
15689
15692
  };
15690
15693
 
@@ -16669,12 +16672,23 @@ const formats = Object.fromEntries(SUPPORTED_FORMATS.map((f) => [f, createFormat
16669
16672
  // For examele, we have a DayCounter, MonthCounter and YearCounter, which can each separately navigate
16670
16673
  // between different ranges.
16671
16674
  class DateCounter {
16672
- constructor({ id, min, max, placeholder }) {
16675
+ #data = Object.freeze([]);
16676
+
16677
+ constructor({ id, min, max, placeholder }, onChange) {
16673
16678
  this.id = id;
16674
- this.data = [];
16675
16679
  this.min = min;
16676
16680
  this.max = max;
16677
16681
  this.placeholder = placeholder;
16682
+ this.onChange = onChange;
16683
+ }
16684
+
16685
+ get data() {
16686
+ return this.#data;
16687
+ }
16688
+
16689
+ set data(val) {
16690
+ this.#data = Object.freeze(val);
16691
+ this.onChange?.();
16678
16692
  }
16679
16693
 
16680
16694
  get #initialNumValue() {
@@ -16706,23 +16720,27 @@ class DateCounter {
16706
16720
  }
16707
16721
 
16708
16722
  add(num) {
16709
- this.data.push(num);
16723
+ // use local var to avoid triggering onChange
16724
+ let data = this.data;
16725
+
16726
+ data = [...data, num];
16710
16727
 
16711
16728
  if (this.numberValue > this.max) {
16712
- this.data.length = 0;
16713
- this.data.push(num);
16714
- } else if (this.length < this.data.length) {
16715
- this.data.shift();
16729
+ data = [num];
16730
+ } else if (this.length < data.length) {
16731
+ data = data.slice(1, data.length);
16716
16732
  }
16717
16733
 
16734
+ this.data = data;
16735
+
16718
16736
  return num;
16719
16737
  }
16720
16738
 
16721
16739
  del() {
16722
16740
  if (!this.data.filter((d) => d !== '0').filter(Boolean).length) {
16723
- this.data.length = 0;
16741
+ this.data = [];
16724
16742
  } else {
16725
- this.data.pop();
16743
+ this.data = this.data.slice(0, this.data.length - 1);
16726
16744
  }
16727
16745
  }
16728
16746
 
@@ -16731,11 +16749,19 @@ class DateCounter {
16731
16749
  }
16732
16750
 
16733
16751
  inc(gap) {
16734
- this.replaceValue(this.#initialNumValue + (gap || 1));
16752
+ this.replaceValue(
16753
+ this.#initialNumValue < this.max
16754
+ ? Math.max(this.#initialNumValue + (gap || 1), this.min)
16755
+ : this.min
16756
+ );
16735
16757
  }
16736
16758
 
16737
16759
  dec(gap) {
16738
- this.replaceValue(this.#initialNumValue - (gap || 1));
16760
+ this.replaceValue(
16761
+ this.#initialNumValue > this.min
16762
+ ? Math.min(this.#initialNumValue - (gap || 1), this.max)
16763
+ : this.max
16764
+ );
16739
16765
  }
16740
16766
 
16741
16767
  isInRange(val) {
@@ -16747,6 +16773,14 @@ class DateCounter {
16747
16773
  this.data = val.toString().padStart(this.length, 0).split('');
16748
16774
  }
16749
16775
  }
16776
+
16777
+ setMin(val) {
16778
+ this.min = Number(val);
16779
+ }
16780
+
16781
+ setMax(val) {
16782
+ this.max = Number(val);
16783
+ }
16750
16784
  }
16751
16785
 
16752
16786
  const componentName$j = getComponentName$1('date-field');
@@ -16767,10 +16801,40 @@ class RawDateFieldClass extends BaseInputClass$1 {
16767
16801
 
16768
16802
  selectedCounterIdx = 0;
16769
16803
 
16804
+ updateCountersDisplay() {
16805
+ this.inputElement.value = this.countersValue;
16806
+ }
16807
+
16808
+ updateValue() {
16809
+ if (this.isCountersOutOfRange) {
16810
+ this.updateTimestamp('');
16811
+ } else {
16812
+ const date = formats[this.format].getDate(this.inputElement.value);
16813
+ this.updateTimestamp(date.getTime());
16814
+ }
16815
+ }
16816
+
16817
+ onDateCounterChange = () => {
16818
+ this.updateCountersDisplay();
16819
+ this.updateValue();
16820
+ // update validity
16821
+ this.#dispatchInput();
16822
+ };
16823
+
16824
+ updateTimestamp(epochOrDate) {
16825
+ if (!epochOrDate) {
16826
+ this.timestamp = '';
16827
+ } else {
16828
+ this.timestamp = newDate(epochOrDate).getTime();
16829
+ }
16830
+ }
16831
+
16832
+ #yearDateCounter = new DateCounter(counterConfig.YEAR, this.onDateCounterChange.bind(this));
16833
+
16770
16834
  dateCounters = [
16771
- new DateCounter(counterConfig.MONTH),
16772
- new DateCounter(counterConfig.DAY),
16773
- new DateCounter(counterConfig.YEAR),
16835
+ new DateCounter(counterConfig.MONTH, this.onDateCounterChange.bind(this)),
16836
+ new DateCounter(counterConfig.DAY, this.onDateCounterChange.bind(this)),
16837
+ this.#yearDateCounter,
16774
16838
  ];
16775
16839
 
16776
16840
  static get observedAttributes() {
@@ -16822,11 +16886,10 @@ class RawDateFieldClass extends BaseInputClass$1 {
16822
16886
 
16823
16887
  this.inputElement = this.shadowRoot.querySelector('descope-text-field');
16824
16888
  this.popoverToggleButton = this.inputElement.querySelector('.toggle-calendar');
16889
+ }
16825
16890
 
16826
- this.oninvalid = () => {
16827
- this.inputElement.setAttribute('invalid', 'true');
16828
- this.inputElement.focus();
16829
- };
16891
+ get validationTarget() {
16892
+ return this.inputElement;
16830
16893
  }
16831
16894
 
16832
16895
  get opened() {
@@ -16834,7 +16897,7 @@ class RawDateFieldClass extends BaseInputClass$1 {
16834
16897
  }
16835
16898
 
16836
16899
  // returns the input's value as a timestamp
16837
- get inputValueTimestamp() {
16900
+ get displayValueEpoch() {
16838
16901
  const date = formats[this.format].getDate(this.inputElement.value);
16839
16902
 
16840
16903
  if (!isValidTimestamp(date?.getTime())) {
@@ -16886,37 +16949,32 @@ class RawDateFieldClass extends BaseInputClass$1 {
16886
16949
  }
16887
16950
 
16888
16951
  set value(val) {
16889
- if (!val) return;
16890
-
16891
- const numVal = Number(val);
16892
- const isValTimestamp = !Number.isNaN(numVal);
16893
-
16894
- let date;
16895
- let timestamp;
16896
-
16897
- if (isValTimestamp) {
16898
- date = newDate(numVal);
16899
- timestamp = numVal;
16952
+ if (val) {
16953
+ this.updateTimestamp(val);
16954
+ this.updateDateCounters(newDate(val));
16900
16955
  } else {
16901
- date = newDate(val);
16902
- timestamp = date.getTime();
16956
+ this.updateTimestamp('');
16903
16957
  }
16958
+ }
16904
16959
 
16905
- if (!isValidTimestamp(timestamp) || timestamp === this.timestamp) {
16906
- return;
16907
- }
16960
+ get isCountersEmpty() {
16961
+ return this.dateCounters.every((dc) => dc.isEmpty);
16962
+ }
16908
16963
 
16909
- this.timestamp = timestamp;
16964
+ get isCountersOutOfRange() {
16965
+ return this.dateCounters.some((dc) => !dc.isInRange(dc.numberValue));
16966
+ }
16910
16967
 
16911
- this.updateInputDisplay();
16912
- this.updateDateCounters(date);
16968
+ reportValidity() {
16969
+ this.inputElement.reportValidity();
16970
+ }
16913
16971
 
16914
- // since baseElement is set to vaadin-popover, we need to manually dispatch an input event to trigger getValidity
16915
- this.dispatchEvent(new Event('input'));
16972
+ #dispatchInput() {
16973
+ this.inputElement.baseElement.dispatchEvent(new Event('input', { bubbles: true }));
16916
16974
  }
16917
16975
 
16918
16976
  updateInputDisplay() {
16919
- this.inputElement.value = formatTimestamp(newDate(this.value).getTime(), this.format);
16977
+ this.inputElement.value = formatTimestamp(newDate(this.countersValue).getTime(), this.format);
16920
16978
  }
16921
16979
 
16922
16980
  init() {
@@ -16924,6 +16982,7 @@ class RawDateFieldClass extends BaseInputClass$1 {
16924
16982
 
16925
16983
  this.updateFormatPattern();
16926
16984
  this.initPopover();
16985
+ this.onDateCounterChange();
16927
16986
  this.initInputElement();
16928
16987
 
16929
16988
  setTimeout(() => {
@@ -16932,15 +16991,16 @@ class RawDateFieldClass extends BaseInputClass$1 {
16932
16991
  }
16933
16992
 
16934
16993
  initInputElement() {
16994
+ this.inputElement.getValidity = this.getValidity.bind(this);
16995
+ this.inputElement.baseElement.checkValidity = this.checkValidity.bind(this);
16996
+
16935
16997
  this.popoverToggleButton.addEventListener('click', this.onPopoverToggle.bind(this));
16936
16998
 
16937
16999
  this.inputElement.addEventListener('focus', this.onFocus.bind(this));
16938
17000
  this.inputElement.addEventListener('blur', this.onBlur.bind(this));
16939
- this.inputElement.addEventListener('input', this.onInput.bind(this));
16940
17001
  this.inputElement.addEventListener('click', this.handleMouseCaretPositionChange.bind(this));
16941
- this.inputElement.addEventListener('keydown', this.handleKeyDownValueChange.bind(this));
16942
- this.inputElement.addEventListener('keydown', this.handleKeydownCaretPositionChange.bind(this));
16943
- this.inputElement.addEventListener('keydown', this.handleValueChange.bind(this));
17002
+ this.inputElement.addEventListener('keydown', this.handleNavKeys.bind(this));
17003
+ this.inputElement.addEventListener('keydown', this.handleDigitKeys.bind(this));
16944
17004
 
16945
17005
  forwardAttrs$1(this, this.inputElement, {
16946
17006
  includeAttrs: [
@@ -16954,8 +17014,14 @@ class RawDateFieldClass extends BaseInputClass$1 {
16954
17014
  'full-width',
16955
17015
  'st-host-direction',
16956
17016
  'pattern',
16957
- 'invalid',
16958
17017
  'bordered',
17018
+ 'data-errormessage-value-missing',
17019
+ 'data-errormessage-pattern-mismatch',
17020
+ 'data-errormessage-range-underflow',
17021
+ 'data-errormessage-range-overflow',
17022
+ 'st-error-message-icon',
17023
+ 'st-error-message-icon-size',
17024
+ 'st-error-message-icon-padding',
16959
17025
  ],
16960
17026
  });
16961
17027
  }
@@ -17083,7 +17149,7 @@ class RawDateFieldClass extends BaseInputClass$1 {
17083
17149
  this.getCounterById('month').replaceValue(calendarDate.getMonth() + 1);
17084
17150
  this.getCounterById('day').replaceValue(calendarDate.getDate());
17085
17151
 
17086
- this.dispatchEvent(new Event('input'));
17152
+ this.#dispatchInput();
17087
17153
  }
17088
17154
 
17089
17155
  this.closePopover();
@@ -17094,10 +17160,10 @@ class RawDateFieldClass extends BaseInputClass$1 {
17094
17160
  isValidTimestamp(newDate(this.inputElement.value || '').getTime()) &&
17095
17161
  formats[this.format].validate(this.inputElement.value);
17096
17162
 
17097
- if (this.inputValueTimestamp || validInputVal) {
17163
+ if (this.displayValueEpoch || validInputVal) {
17098
17164
  this.calendar.setAttribute(
17099
17165
  'initial-value',
17100
- formatTimestamp(this.inputValueTimestamp || this.timestamp, NATIVE_FORMAT)
17166
+ formatTimestamp(this.displayValueEpoch || this.timestamp, NATIVE_FORMAT)
17101
17167
  );
17102
17168
  } else {
17103
17169
  this.calendar.clearValue();
@@ -17120,13 +17186,6 @@ class RawDateFieldClass extends BaseInputClass$1 {
17120
17186
  });
17121
17187
  }
17122
17188
 
17123
- onInput(e) {
17124
- if (!e.target.value) {
17125
- this.calendar?.clear();
17126
- this.calendar?.renderCalendar();
17127
- }
17128
- }
17129
-
17130
17189
  onFocus() {
17131
17190
  if (this.isReadOnly) {
17132
17191
  return;
@@ -17138,16 +17197,13 @@ class RawDateFieldClass extends BaseInputClass$1 {
17138
17197
  }
17139
17198
  }
17140
17199
 
17141
- clearInputValue() {
17142
- this.inputElement.value = '';
17143
- this.resetDateCounters();
17144
- }
17145
-
17146
17200
  onBlur() {
17147
- if (this.inputValueTimestamp) {
17148
- this.value = this.inputValueTimestamp;
17149
- } else if (!this.opened && this.countersValue === this.format) {
17150
- this.clearInputValue();
17201
+ if (this.opened) {
17202
+ return;
17203
+ }
17204
+
17205
+ if (this.inputElement.value === this.format) {
17206
+ this.inputElement.value = '';
17151
17207
  }
17152
17208
  }
17153
17209
 
@@ -17164,11 +17220,11 @@ class RawDateFieldClass extends BaseInputClass$1 {
17164
17220
  this.setAttribute('pattern', formats[format].pattern);
17165
17221
  }
17166
17222
 
17167
- handleValueChange(e) {
17223
+ handleDigitKeys(e) {
17168
17224
  if (isNumber(e.key)) {
17169
17225
  e.preventDefault();
17170
17226
 
17171
- this.handleCountersValue(e.key);
17227
+ this.activeCounter.add(e.key);
17172
17228
 
17173
17229
  if (this.activeCounter.isFull) {
17174
17230
  this.selectNextCounter();
@@ -17188,11 +17244,6 @@ class RawDateFieldClass extends BaseInputClass$1 {
17188
17244
  return [c1, c2, c3].indexOf(true);
17189
17245
  }
17190
17246
 
17191
- handleCountersValue(val) {
17192
- this.activeCounter.add(val);
17193
- this.inputElement.value = this.countersValue;
17194
- }
17195
-
17196
17247
  setSelectedCounterByCaretPosition(e) {
17197
17248
  this.selectedCounterIdx = this.getCounterIdx(e.target.selectionStart);
17198
17249
  }
@@ -17250,21 +17301,21 @@ class RawDateFieldClass extends BaseInputClass$1 {
17250
17301
  });
17251
17302
  }
17252
17303
 
17253
- handleKeyDownValueChange(e) {
17304
+ handleNavKeys(e) {
17254
17305
  if (this.isReadOnly) {
17255
17306
  return;
17256
17307
  }
17257
17308
 
17258
17309
  const { key, shiftKey, metaKey } = e;
17259
17310
  const keys = getKeyMap(key, shiftKey, metaKey);
17260
- const allowedOperations = keys.refresh || keys.tab || keys.shiftTab;
17261
17311
 
17262
17312
  if (this.opened) {
17263
17313
  this.closePopover();
17264
17314
  }
17265
17315
 
17316
+ e.preventDefault();
17317
+
17266
17318
  if (isSupportedKey(key)) {
17267
- e.preventDefault();
17268
17319
  const counter = this.activeCounter;
17269
17320
 
17270
17321
  if (!counter) return;
@@ -17281,12 +17332,10 @@ class RawDateFieldClass extends BaseInputClass$1 {
17281
17332
  else if (keys.pageDown) counter.dec(count);
17282
17333
  else if (keys.shiftPageUp) counter.inc(shiftCount);
17283
17334
  else if (keys.shiftPageDown) counter.dec(shiftCount);
17284
-
17285
- this.inputElement.value = this.countersValue;
17335
+ else if (keys.arrowRight) this.selectNextCounter();
17336
+ else if (keys.arrowLeft) this.selectPrevCounter();
17286
17337
 
17287
17338
  this.setInputSelectionRange();
17288
- } else if (!allowedOperations) {
17289
- e.preventDefault();
17290
17339
  }
17291
17340
  }
17292
17341
 
@@ -17301,25 +17350,6 @@ class RawDateFieldClass extends BaseInputClass$1 {
17301
17350
  }
17302
17351
  }
17303
17352
 
17304
- handleKeydownCaretPositionChange(e) {
17305
- if (this.opened) {
17306
- return;
17307
- }
17308
-
17309
- const { key } = e;
17310
-
17311
- if (isSupportedKey(key)) {
17312
- e.preventDefault();
17313
-
17314
- const keys = getKeyMap(key, false);
17315
-
17316
- if (keys.arrowRight) this.selectNextCounter();
17317
- else if (keys.arrowLeft) this.selectPrevCounter();
17318
-
17319
- this.setInputSelectionRange();
17320
- }
17321
- }
17322
-
17323
17353
  handleMouseCaretPositionChange(e) {
17324
17354
  if (this.opened) {
17325
17355
  return;
@@ -17339,10 +17369,22 @@ class RawDateFieldClass extends BaseInputClass$1 {
17339
17369
  });
17340
17370
  }
17341
17371
 
17372
+ setYearRange(val) {
17373
+ if (!val) return;
17374
+ const [min, max] = val.split?.('-');
17375
+ if (min && max) {
17376
+ this.#yearDateCounter.setMin(min);
17377
+ this.#yearDateCounter.setMax(max);
17378
+ }
17379
+ }
17380
+
17342
17381
  attributeChangedCallback(attrName, oldValue, newValue) {
17343
17382
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
17344
17383
 
17345
17384
  if (oldValue !== newValue) {
17385
+ if (attrName === 'years-range') {
17386
+ this.setYearRange(newValue);
17387
+ }
17346
17388
  if (dateFieldAttrs.includes(attrName)) {
17347
17389
  if (newValue && attrName === 'format') {
17348
17390
  this.onFormatUpdate(newValue);
@@ -17361,16 +17403,20 @@ class RawDateFieldClass extends BaseInputClass$1 {
17361
17403
  }
17362
17404
 
17363
17405
  getValidity() {
17364
- if (this.isRequired && !this.inputElement.value) {
17406
+ if (this.isRequired && this.isCountersEmpty) {
17365
17407
  return { valueMissing: true };
17366
17408
  }
17367
17409
 
17410
+ if (this.isCountersOutOfRange) {
17411
+ return { patternMismatch: true };
17412
+ }
17413
+
17368
17414
  return {};
17369
17415
  }
17370
17416
  }
17371
17417
 
17372
17418
  const textVars = TextFieldClass.cssVarList;
17373
- const { host: host$5, input, inputEleRTL, toggleButton, overlay, backdrop } = {
17419
+ const { host: host$5, input, inputEleRTL, toggleButton, overlay, backdrop} = {
17374
17420
  host: { selector: () => ':host' },
17375
17421
  input: { selector: () => 'descope-text-field' },
17376
17422
  inputEleRTL: { selector: () => ':host([st-host-direction="rtl"]) descope-text-field' },
@@ -17408,6 +17454,30 @@ const DateFieldClass = compose$1(
17408
17454
  overlayOutlineStyle: {
17409
17455
  property: () => DateFieldClass.cssVarList.overlayOutlineStyle,
17410
17456
  },
17457
+ errorMessageIcon: {
17458
+ selector: TextFieldClass.componentName,
17459
+ property: TextFieldClass.cssVarList.errorMessageIcon,
17460
+ },
17461
+ errorMessageIconSize: {
17462
+ selector: TextFieldClass.componentName,
17463
+ property: TextFieldClass.cssVarList.errorMessageIconSize,
17464
+ },
17465
+ errorMessageIconPadding: {
17466
+ selector: TextFieldClass.componentName,
17467
+ property: TextFieldClass.cssVarList.errorMessageIconPadding,
17468
+ },
17469
+ errorMessageIconRepeat: {
17470
+ selector: TextFieldClass.componentName,
17471
+ property: TextFieldClass.cssVarList.errorMessageIconRepeat,
17472
+ },
17473
+ errorMessageIconPosition: {
17474
+ selector: TextFieldClass.componentName,
17475
+ property: TextFieldClass.cssVarList.errorMessageIconPosition,
17476
+ },
17477
+ errorMessageFontSize: {
17478
+ selector: TextFieldClass.componentName,
17479
+ property: TextFieldClass.cssVarList.errorMessageFontSize,
17480
+ },
17411
17481
  },
17412
17482
  }),
17413
17483
  portalMixin({
@@ -17452,6 +17522,13 @@ const dateField = {
17452
17522
 
17453
17523
  [vars$g.rtlInputDirection]: 'ltr',
17454
17524
  [vars$g.rtlInputAlignment]: 'right',
17525
+
17526
+ [vars$g.errorMessageIcon]: refs$1.errorMessageIcon,
17527
+ [vars$g.errorMessageIconSize]: refs$1.errorMessageIconSize,
17528
+ [vars$g.errorMessageIconPadding]: refs$1.errorMessageIconPadding,
17529
+ [vars$g.errorMessageIconRepeat]: refs$1.errorMessageIconRepeat,
17530
+ [vars$g.errorMessageIconPosition]: refs$1.errorMessageIconPosition,
17531
+ [vars$g.errorMessageFontSize]: refs$1.errorMessageFontSize,
17455
17532
  };
17456
17533
 
17457
17534
  var dateField$1 = /*#__PURE__*/Object.freeze({