@descope/web-components-ui 1.104.0 → 1.105.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.
@@ -15869,6 +15869,8 @@ const BUTTON_LABEL_DONE = 'Done';
15869
15869
  const BUTTON_LABEL_CANCEL = 'Cancel';
15870
15870
  const CALENDAR_LABEL_TODAY = 'Today';
15871
15871
 
15872
+ const MOBILE_DEVICE_INTERACTION_TIMEOUT_MS = 150;
15873
+
15872
15874
  const isValidAttrArr = (arr, count) =>
15873
15875
  Array.isArray(arr) && arr.length === count && arr.filter(Boolean).length === count;
15874
15876
 
@@ -16953,8 +16955,6 @@ class RawDateFieldClass extends BaseInputClass$1 {
16953
16955
 
16954
16956
  selectedCounterIdx = 0;
16955
16957
 
16956
- #focused = false;
16957
-
16958
16958
  updateCountersDisplay() {
16959
16959
  this.inputElement.value = this.countersValue;
16960
16960
  }
@@ -17164,22 +17164,7 @@ class RawDateFieldClass extends BaseInputClass$1 {
17164
17164
  this.inputElement.addEventListener('click', this.handleMouseCaretPositionChange.bind(this));
17165
17165
  this.inputElement.addEventListener('keydown', this.handleArrowKeys.bind(this));
17166
17166
  this.inputElement.addEventListener('beforeinput', this.handleInput.bind(this));
17167
-
17168
- // We want to handle touch events the same way we handle `click` events.
17169
- // Since we can't seem to block touch events (`touch-action: none` or preventing default on `touchstart`
17170
- // or `touchend`, we listen to `pointerdown` and in case it's of type `touch` we execute
17171
- // the component's logic for range selection.
17172
- this.inputElement.addEventListener('pointerdown', (e) => {
17173
- if (e.pointerType === 'touch') {
17174
- e.preventDefault();
17175
- if (!this.#focused) {
17176
- this.inputElement.focus();
17177
- }
17178
- setTimeout(() => {
17179
- this.handleMouseCaretPositionChange(e);
17180
- }, 250);
17181
- }
17182
- });
17167
+ this.inputElement.addEventListener('pointerdown', this.onPointerDown.bind(this));
17183
17168
 
17184
17169
  forwardAttrs$1(this, this.inputElement, {
17185
17170
  includeAttrs: [
@@ -17377,16 +17362,19 @@ class RawDateFieldClass extends BaseInputClass$1 {
17377
17362
  });
17378
17363
  }
17379
17364
 
17365
+ // In mobile devices, there are cases were `pointerdown` is triggered
17366
+ // instead of `click`.
17367
+ onPointerDown(e) {
17368
+ setTimeout(() => this.handleMouseCaretPositionChange(e), MOBILE_DEVICE_INTERACTION_TIMEOUT_MS);
17369
+ }
17370
+
17380
17371
  onFocus() {
17381
- if (this.isReadOnly || this.#focused) {
17372
+ if (this.isReadOnly) {
17382
17373
  return;
17383
17374
  }
17384
17375
 
17385
- // We use this flag to support mobile logic, which calls `focus` on touch event, we want to make sure
17386
- // focus executes it logic only when needed.
17387
- this.#focused = true;
17388
-
17389
- this.resetDisplay();
17376
+ // We need to wait for focus to end before we set selection
17377
+ setTimeout(() => this.resetDisplay());
17390
17378
  }
17391
17379
 
17392
17380
  resetDisplay() {
@@ -17394,18 +17382,12 @@ class RawDateFieldClass extends BaseInputClass$1 {
17394
17382
  this.inputElement.value = this.format;
17395
17383
  }
17396
17384
 
17397
- // On focus select the first part of the format placeholder
17385
+ // On focus select the first counter
17398
17386
  this.selectedCounterIdx = 0;
17399
-
17400
- setTimeout(() => {
17401
- // set selection on first counter
17402
- this.inputElement.setSelectionRange(0, this.sortedCounters[0].length);
17403
- });
17387
+ this.inputElement.setSelectionRange(0, this.sortedCounters[0].length);
17404
17388
  }
17405
17389
 
17406
17390
  onBlur() {
17407
- this.#focused = false;
17408
-
17409
17391
  if (this.opened) {
17410
17392
  return;
17411
17393
  }
@@ -17435,6 +17417,8 @@ class RawDateFieldClass extends BaseInputClass$1 {
17435
17417
  this.selectNextCounter();
17436
17418
  }
17437
17419
 
17420
+ // We wait for the digit to be parsed, and only then set the selection.
17421
+ // Failing to do so results in unexpected "jump" of the screen in mobile devices.
17438
17422
  this.setInputSelectionRange();
17439
17423
  }
17440
17424
 
@@ -17450,7 +17434,11 @@ class RawDateFieldClass extends BaseInputClass$1 {
17450
17434
 
17451
17435
  setSelectedCounterByCaretPosition(e) {
17452
17436
  this.selectedCounterIdx = this.getCounterIdx(
17453
- e.target.selectionStart || this.inputElement.selectionStart
17437
+ // if triggered by touch event, target might not include `selectionStart`
17438
+ // in that case we fall back to the inputElement's `selectionStart` value.
17439
+ // Therefore, it is recommended to run this function with setTimeout,
17440
+ // at least for mobile events.
17441
+ e.target?.selectionStart || this.inputElement.selectionStart
17454
17442
  );
17455
17443
  }
17456
17444
 
@@ -17476,14 +17464,18 @@ class RawDateFieldClass extends BaseInputClass$1 {
17476
17464
  return;
17477
17465
  }
17478
17466
 
17479
- const caretStart = this.sortedCounters
17480
- .slice(0, this.selectedCounterIdx)
17481
- .reduce((acc, counter) => acc + counter.length, this.selectedCounterIdx);
17467
+ // We wait for before setting the selection, otherwise there's an
17468
+ // unexpected "jump" of the screen in mobile devices.
17469
+ setTimeout(() => {
17470
+ const caretStart = this.sortedCounters
17471
+ .slice(0, this.selectedCounterIdx)
17472
+ .reduce((acc, counter) => acc + counter.length, this.selectedCounterIdx);
17482
17473
 
17483
- this.inputElement.setSelectionRange(
17484
- caretStart,
17485
- caretStart + this.sortedCounters[this.selectedCounterIdx].length
17486
- );
17474
+ this.inputElement.setSelectionRange(
17475
+ caretStart,
17476
+ caretStart + this.sortedCounters[this.selectedCounterIdx].length
17477
+ );
17478
+ });
17487
17479
  }
17488
17480
 
17489
17481
  resetDateCounters() {
@@ -17518,9 +17510,7 @@ class RawDateFieldClass extends BaseInputClass$1 {
17518
17510
  this.selectPrevCounter();
17519
17511
  }
17520
17512
 
17521
- setTimeout(() => {
17522
- this.setInputSelectionRange();
17523
- });
17513
+ this.setInputSelectionRange();
17524
17514
  }
17525
17515
 
17526
17516
  handleNavKeys(e) {
@@ -17542,27 +17532,32 @@ class RawDateFieldClass extends BaseInputClass$1 {
17542
17532
  }
17543
17533
 
17544
17534
  handleBackspace() {
17545
- if (this.activeCounter.isEmpty) {
17546
- this.activeCounter.clear();
17535
+ const counter = this.activeCounter;
17536
+
17537
+ if (counter.isEmpty) {
17547
17538
  this.selectPrevCounter();
17548
17539
  this.setInputSelectionRange();
17549
17540
  } else {
17550
- this.activeCounter.del();
17541
+ counter.set('');
17551
17542
  }
17543
+
17544
+ // To support keyboards like SwiftKey, we need to re-render the counters display and selection,
17545
+ // otherwise we get an unexpected behavior, where the format is deleted.
17546
+ setTimeout(() => {
17547
+ this.updateCountersDisplay();
17548
+ this.setInputSelectionRange();
17549
+ });
17552
17550
  }
17553
17551
 
17554
17552
  handleMouseCaretPositionChange(e) {
17555
17553
  if (this.opened) {
17556
17554
  return;
17557
17555
  }
17556
+
17558
17557
  e.preventDefault();
17559
- this.setSelectedCounterByCaretPosition(e);
17560
17558
 
17561
- // On keydown - in desktop mode - selection is sometimes not set, and instead there is a cursor.
17562
- // We need to wait until we can set selection range.
17563
- setTimeout(() => {
17564
- this.setInputSelectionRange();
17565
- });
17559
+ this.setSelectedCounterByCaretPosition(e);
17560
+ this.setInputSelectionRange();
17566
17561
  }
17567
17562
 
17568
17563
  onInitialValueChange(val) {