diff --git a/src/dev-app/mdc-chips/mdc-chips-demo.html b/src/dev-app/mdc-chips/mdc-chips-demo.html index 228e8ea2f88f..5352c6b16c84 100644 --- a/src/dev-app/mdc-chips/mdc-chips-demo.html +++ b/src/dev-app/mdc-chips/mdc-chips-demo.html @@ -25,7 +25,7 @@

With avatar, icons, and color

home Home - @@ -33,7 +33,7 @@

With avatar, icons, and color

P Portel - @@ -45,7 +45,7 @@

With avatar, icons, and color

Koby - @@ -85,7 +85,7 @@

With Events

With Events - @@ -152,7 +152,7 @@

Input is last child of chip grid

(removed)="remove(person)" (edited)="edit(person, $event)"> {{person.name}} - @@ -171,7 +171,7 @@

Input is next sibling child of chip grid

{{person.name}} - diff --git a/src/material-experimental/mdc-chips/chip-row.html b/src/material-experimental/mdc-chips/chip-row.html index 4d8b74b3f6c0..bf7473656c66 100644 --- a/src/material-experimental/mdc-chips/chip-row.html +++ b/src/material-experimental/mdc-chips/chip-row.html @@ -8,8 +8,9 @@ - + { return chipNativeElement.querySelector('.mat-chip-edit-input')!; } + it('should set the role of the primary action based on whether it is editable', () => { + testComponent.editable = false; + fixture.detectChanges(); + expect(primaryAction.hasAttribute('role')).toBe(false); + + testComponent.editable = true; + fixture.detectChanges(); + expect(primaryAction.getAttribute('role')).toBe('button'); + }); + it('should not delete the chip on DELETE or BACKSPACE', () => { spyOn(testComponent, 'chipDestroy'); keyDownOnPrimaryAction(DELETE, 'Delete'); diff --git a/src/material-experimental/mdc-chips/chip-row.ts b/src/material-experimental/mdc-chips/chip-row.ts index c5f3bb96af3a..39cc05b72123 100644 --- a/src/material-experimental/mdc-chips/chip-row.ts +++ b/src/material-experimental/mdc-chips/chip-row.ts @@ -81,6 +81,13 @@ export interface MatChipEditedEvent extends MatChipEvent { export class MatChipRow extends MatChip implements AfterViewInit { protected override basicChipAttrName = 'mat-basic-chip-row'; + /** + * The editing action has to be triggered in a timeout. While we're waiting on it, a blur + * event might occur which will interrupt the editing. This flag is used to avoid interruptions + * while the editing action is being initialized. + */ + private _editStartPending = false; + @Input() editable: boolean = false; /** Emitted when the chip is edited. */ @@ -120,7 +127,7 @@ export class MatChipRow extends MatChip implements AfterViewInit { this.role = 'row'; this._onBlur.pipe(takeUntil(this.destroyed)).subscribe(() => { - if (this._isEditing) { + if (this._isEditing && !this._editStartPending) { this._onEditFinish(); } }); @@ -175,18 +182,19 @@ export class MatChipRow extends MatChip implements AfterViewInit { // The value depends on the DOM so we need to extract it before we flip the flag. const value = this.value; - // Make the primary action non-interactive so that it doesn't - // navigate when the user presses the arrow keys while editing. - this.primaryAction.isInteractive = false; this._isEditing = true; + this._editStartPending = true; // Defer initializing the input so it has time to be added to the DOM. - setTimeout(() => this._getEditInput().initialize(value)); + setTimeout(() => { + this._getEditInput().initialize(value); + this._editStartPending = false; + }); } private _onEditFinish() { this._isEditing = false; - this.primaryAction.isInteractive = true; + this._editStartPending = false; this.edited.emit({chip: this, value: this._getEditInput().getValue()}); // If the edit input is still focused or focus was returned to the body after it was destroyed,