@fundamental-ngx/cdk 0.63.0-rc.32 → 0.63.0-rc.34

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.
@@ -652,6 +652,13 @@ class AutoCompleteDirective {
652
652
  this._stopKeys = [BACKSPACE, DELETE, ESCAPE];
653
653
  /** @hidden */
654
654
  this._isComposing = false;
655
+ /**
656
+ * Tracks the intended user-typed value, derived from native `input` events.
657
+ * When Angular's NgModel re-pushes a stale value (e.g. after Ctrl+A → Delete),
658
+ * the DOM may contain the old model value when the user types the next character.
659
+ * We reconstruct the intended value using the cursor position and typed character.
660
+ */
661
+ this._lastInputEventValue = null;
655
662
  /** @hidden */
656
663
  this._elementRef = inject(ElementRef);
657
664
  /** @hidden */
@@ -667,6 +674,25 @@ class AutoCompleteDirective {
667
674
  const keyupEvent = fromEvent(this._elementRef.nativeElement, 'keyup');
668
675
  const compositionStartEvent = fromEvent(this._elementRef.nativeElement, 'compositionstart');
669
676
  const compositionEndEvent = fromEvent(this._elementRef.nativeElement, 'compositionend');
677
+ // Track the intended user-typed value. Uses the cursor position and typed character
678
+ // to reconstruct the value the user intended, independent of any NgModel re-push.
679
+ fromEvent(this._elementRef.nativeElement, 'input')
680
+ .pipe(takeUntilDestroyed(this._destroyRef))
681
+ .subscribe((evt) => {
682
+ const el = this._elementRef.nativeElement;
683
+ const cursorPos = el.selectionStart ?? el.value.length;
684
+ if (evt.inputType === 'insertText' && evt.data) {
685
+ // Cursor is after the inserted char. Intended value = previously tracked
686
+ // prefix + new char. Handles the case where NgModel re-pushed a stale
687
+ // value before this keystroke (e.g. "Apple" after Ctrl+A→Delete→"B").
688
+ const prev = this._lastInputEventValue ?? '';
689
+ this._lastInputEventValue = prev + evt.data;
690
+ }
691
+ else {
692
+ // Deletion, paste, or other input — use current DOM value at cursor.
693
+ this._lastInputEventValue = el.value.substring(0, cursorPos);
694
+ }
695
+ });
670
696
  keyupEvent.pipe(takeUntilDestroyed()).subscribe((evt) => this._handleKeyboardEvent(evt));
671
697
  compositionStartEvent.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
672
698
  this._isComposing = true;
@@ -680,7 +706,10 @@ class AutoCompleteDirective {
680
706
  _handleKeyboardEvent(event) {
681
707
  if (this.enable && !this._isComposing) {
682
708
  if (KeyUtil.isKeyCode(event, this._stopKeys)) {
683
- this._elementRef.nativeElement.value = this.inputText;
709
+ const el = this._elementRef.nativeElement;
710
+ if (el.selectionStart !== el.selectionEnd) {
711
+ el.value = this.inputText;
712
+ }
684
713
  }
685
714
  else if (KeyUtil.isKeyCode(event, this._completeKeys)) {
686
715
  this._sendCompleteEvent(true);
@@ -689,26 +718,38 @@ class AutoCompleteDirective {
689
718
  else if (KeyUtil.isKeyCode(event, this._fillKeys)) {
690
719
  this._sendCompleteEvent(false);
691
720
  }
692
- else if (!this._isControlKey(event) && this.inputText) {
693
- const hasSelection = this._elementRef.nativeElement.selectionStart !== this._elementRef.nativeElement.selectionEnd;
721
+ else if (!this._isControlKey(event)) {
722
+ const el = this._elementRef.nativeElement;
723
+ const hasSelection = el.selectionStart !== el.selectionEnd;
724
+ // Use the value from the last native `input` event as the authoritative
725
+ // user-typed value. Angular's NgModel may have re-written el.value with a
726
+ // stale model value (e.g. after Ctrl+A → Delete), but the native `input`
727
+ // event only fires on actual user input — not on programmatic writes.
728
+ const currentNativeValue = this._lastInputEventValue !== null ? this._lastInputEventValue : el.value;
729
+ // After consuming, keep the current value so the next `input` event's
730
+ // `insertText` accumulation has the right prefix.
731
+ this._lastInputEventValue = currentNativeValue;
694
732
  if (hasSelection) {
695
733
  return;
696
734
  }
697
- const currentNativeValue = this._elementRef.nativeElement.value;
698
- if (this.inputText.length > currentNativeValue.length + 1) {
699
- this.inputText = currentNativeValue;
735
+ if (!currentNativeValue) {
700
736
  return;
701
737
  }
738
+ const effectiveInputText = this.inputText.length > currentNativeValue.length + 1 ||
739
+ !this.inputText.toLocaleLowerCase().startsWith(currentNativeValue.toLocaleLowerCase())
740
+ ? currentNativeValue
741
+ : this.inputText;
702
742
  if (!this._triggerTypeAhead()) {
703
743
  return;
704
744
  }
705
745
  this.oldValue = this.inputText;
706
- const item = this.options.find((option) => this.matcher(this.displayFn(option).toLocaleLowerCase(), this.inputText.toLocaleLowerCase()));
746
+ const searchTerm = effectiveInputText || currentNativeValue;
747
+ const item = this.options.find((option) => this.matcher(this.displayFn(option).toLocaleLowerCase(), searchTerm.toLocaleLowerCase()));
707
748
  if (item) {
708
749
  const displayedValue = this.displayFn(item);
709
750
  // Only autocomplete if the current native value matches the start of the found item
710
751
  if (displayedValue.toLocaleLowerCase().startsWith(currentNativeValue.toLocaleLowerCase())) {
711
- this._typeahead(displayedValue);
752
+ this._typeahead(displayedValue, currentNativeValue.length);
712
753
  }
713
754
  }
714
755
  }
@@ -716,9 +757,9 @@ class AutoCompleteDirective {
716
757
  this.lastKeyUpEvent = event;
717
758
  }
718
759
  /** @hidden */
719
- _typeahead(displayedValue) {
760
+ _typeahead(displayedValue, currentInputLength) {
720
761
  this._elementRef.nativeElement.value = displayedValue;
721
- const selectionStartIndex = this.inputText.length;
762
+ const selectionStartIndex = currentInputLength;
722
763
  this._elementRef.nativeElement.setSelectionRange(selectionStartIndex, displayedValue.length);
723
764
  }
724
765
  /** @hidden */