@angular/material
Version:
Angular Material
1 lines • 147 kB
Source Map (JSON)
{"version":3,"file":"chips.mjs","sources":["../../../../../../src/material/chips/tokens.ts","../../../../../../src/material/chips/chip-action.ts","../../../../../../src/material/chips/chip-icons.ts","../../../../../../src/material/chips/chip.ts","../../../../../../src/material/chips/chip.html","../../../../../../src/material/chips/chip-option.ts","../../../../../../src/material/chips/chip-option.html","../../../../../../src/material/chips/chip-edit-input.ts","../../../../../../src/material/chips/chip-row.ts","../../../../../../src/material/chips/chip-row.html","../../../../../../src/material/chips/chip-set.ts","../../../../../../src/material/chips/chip-listbox.ts","../../../../../../src/material/chips/chip-grid.ts","../../../../../../src/material/chips/chip-input.ts","../../../../../../src/material/chips/module.ts","../../../../../../src/material/chips/chip-text-control.ts","../../../../../../src/material/chips/public-api.ts","../../../../../../src/material/chips/index.ts","../../../../../../src/material/chips/chips_public_index.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {InjectionToken} from '@angular/core';\n\n/** Default options, for the chips module, that can be overridden. */\nexport interface MatChipsDefaultOptions {\n /** The list of key codes that will trigger a chipEnd event. */\n separatorKeyCodes: readonly number[] | ReadonlySet<number>;\n}\n\n/** Injection token to be used to override the default options for the chips module. */\nexport const MAT_CHIPS_DEFAULT_OPTIONS = new InjectionToken<MatChipsDefaultOptions>(\n 'mat-chips-default-options',\n);\n\n/**\n * Injection token that can be used to reference instances of `MatChipAvatar`. It serves as\n * alternative token to the actual `MatChipAvatar` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */\nexport const MAT_CHIP_AVATAR = new InjectionToken('MatChipAvatar');\n\n/**\n * Injection token that can be used to reference instances of `MatChipTrailingIcon`. It serves as\n * alternative token to the actual `MatChipTrailingIcon` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */\nexport const MAT_CHIP_TRAILING_ICON = new InjectionToken('MatChipTrailingIcon');\n\n/**\n * Injection token that can be used to reference instances of `MatChipRemove`. It serves as\n * alternative token to the actual `MatChipRemove` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */\nexport const MAT_CHIP_REMOVE = new InjectionToken('MatChipRemove');\n\n/**\n * Injection token used to avoid a circular dependency between the `MatChip` and `MatChipAction`.\n */\nexport const MAT_CHIP = new InjectionToken('MatChip');\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {ENTER, SPACE} from '@angular/cdk/keycodes';\nimport {Directive, ElementRef, Inject, Input} from '@angular/core';\nimport {HasTabIndex, mixinTabIndex} from '@angular/material/core';\nimport {MAT_CHIP} from './tokens';\n\nabstract class _MatChipActionBase {\n abstract disabled: boolean;\n}\n\nconst _MatChipActionMixinBase = mixinTabIndex(_MatChipActionBase, -1);\n\n/**\n * Section within a chip.\n * @docs-private\n */\n@Directive({\n selector: '[matChipAction]',\n inputs: ['disabled', 'tabIndex'],\n host: {\n 'class': 'mdc-evolution-chip__action mat-mdc-chip-action',\n '[class.mdc-evolution-chip__action--primary]': '_isPrimary',\n // Note that while our actions are interactive, we have to add the `--presentational` class,\n // in order to avoid some super-specific `:hover` styles from MDC.\n '[class.mdc-evolution-chip__action--presentational]': '_isPrimary',\n '[class.mdc-evolution-chip__action--trailing]': '!_isPrimary',\n '[attr.tabindex]': '_getTabindex()',\n '[attr.disabled]': '_getDisabledAttribute()',\n '[attr.aria-disabled]': 'disabled',\n '(click)': '_handleClick($event)',\n '(keydown)': '_handleKeydown($event)',\n },\n})\nexport class MatChipAction extends _MatChipActionMixinBase implements HasTabIndex {\n /** Whether the action is interactive. */\n @Input() isInteractive = true;\n\n /** Whether this is the primary action in the chip. */\n _isPrimary = true;\n\n /** Whether the action is disabled. */\n @Input()\n get disabled(): boolean {\n return this._disabled || this._parentChip.disabled;\n }\n set disabled(value: BooleanInput) {\n this._disabled = coerceBooleanProperty(value);\n }\n private _disabled = false;\n\n /**\n * Private API to allow focusing this chip when it is disabled.\n */\n @Input()\n private _allowFocusWhenDisabled = false;\n\n /**\n * Determine the value of the disabled attribute for this chip action.\n */\n protected _getDisabledAttribute(): string | null {\n // When this chip action is disabled and focusing disabled chips is not permitted, return empty\n // string to indicate that disabled attribute should be included.\n return this.disabled && !this._allowFocusWhenDisabled ? '' : null;\n }\n\n /**\n * Determine the value of the tabindex attribute for this chip action.\n */\n protected _getTabindex(): string | null {\n return (this.disabled && !this._allowFocusWhenDisabled) || !this.isInteractive\n ? null\n : this.tabIndex.toString();\n }\n\n constructor(\n public _elementRef: ElementRef<HTMLElement>,\n @Inject(MAT_CHIP)\n protected _parentChip: {\n _handlePrimaryActionInteraction(): void;\n remove(): void;\n disabled: boolean;\n },\n ) {\n super();\n\n if (_elementRef.nativeElement.nodeName === 'BUTTON') {\n _elementRef.nativeElement.setAttribute('type', 'button');\n }\n }\n\n focus() {\n this._elementRef.nativeElement.focus();\n }\n\n _handleClick(event: MouseEvent) {\n if (!this.disabled && this.isInteractive && this._isPrimary) {\n event.preventDefault();\n this._parentChip._handlePrimaryActionInteraction();\n }\n }\n\n _handleKeydown(event: KeyboardEvent) {\n if (\n (event.keyCode === ENTER || event.keyCode === SPACE) &&\n !this.disabled &&\n this.isInteractive &&\n this._isPrimary\n ) {\n event.preventDefault();\n this._parentChip._handlePrimaryActionInteraction();\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {ENTER, SPACE} from '@angular/cdk/keycodes';\nimport {Directive} from '@angular/core';\nimport {MatChipAction} from './chip-action';\nimport {MAT_CHIP_AVATAR, MAT_CHIP_REMOVE, MAT_CHIP_TRAILING_ICON} from './tokens';\n\n/** Avatar image within a chip. */\n@Directive({\n selector: 'mat-chip-avatar, [matChipAvatar]',\n host: {\n 'class': 'mat-mdc-chip-avatar mdc-evolution-chip__icon mdc-evolution-chip__icon--primary',\n 'role': 'img',\n },\n providers: [{provide: MAT_CHIP_AVATAR, useExisting: MatChipAvatar}],\n})\nexport class MatChipAvatar {}\n\n/** Non-interactive trailing icon in a chip. */\n@Directive({\n selector: 'mat-chip-trailing-icon, [matChipTrailingIcon]',\n host: {\n 'class':\n 'mat-mdc-chip-trailing-icon mdc-evolution-chip__icon mdc-evolution-chip__icon--trailing',\n 'aria-hidden': 'true',\n },\n providers: [{provide: MAT_CHIP_TRAILING_ICON, useExisting: MatChipTrailingIcon}],\n})\nexport class MatChipTrailingIcon extends MatChipAction {\n /**\n * MDC considers all trailing actions as a remove icon,\n * but we support non-interactive trailing icons.\n */\n override isInteractive = false;\n\n override _isPrimary = false;\n}\n\n/**\n * Directive to remove the parent chip when the trailing icon is clicked or\n * when the ENTER key is pressed on it.\n *\n * Recommended for use with the Material Design \"cancel\" icon\n * available at https://material.io/icons/#ic_cancel.\n *\n * Example:\n *\n * ```\n * <mat-chip>\n * <mat-icon matChipRemove>cancel</mat-icon>\n * </mat-chip>\n * ```\n */\n\n@Directive({\n selector: '[matChipRemove]',\n host: {\n 'class':\n 'mat-mdc-chip-remove mat-mdc-chip-trailing-icon mat-mdc-focus-indicator ' +\n 'mdc-evolution-chip__icon mdc-evolution-chip__icon--trailing',\n 'role': 'button',\n '[attr.aria-hidden]': 'null',\n },\n providers: [{provide: MAT_CHIP_REMOVE, useExisting: MatChipRemove}],\n})\nexport class MatChipRemove extends MatChipAction {\n override _isPrimary = false;\n\n override _handleClick(event: MouseEvent): void {\n if (!this.disabled) {\n event.stopPropagation();\n event.preventDefault();\n this._parentChip.remove();\n }\n }\n\n override _handleKeydown(event: KeyboardEvent) {\n if ((event.keyCode === ENTER || event.keyCode === SPACE) && !this.disabled) {\n event.stopPropagation();\n event.preventDefault();\n this._parentChip.remove();\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';\nimport {\n AfterViewInit,\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n ContentChild,\n ElementRef,\n EventEmitter,\n Inject,\n Input,\n NgZone,\n OnDestroy,\n Optional,\n Output,\n ViewEncapsulation,\n ViewChild,\n Attribute,\n} from '@angular/core';\nimport {DOCUMENT} from '@angular/common';\nimport {\n CanColor,\n CanDisable,\n CanDisableRipple,\n HasTabIndex,\n MatRipple,\n MAT_RIPPLE_GLOBAL_OPTIONS,\n mixinColor,\n mixinDisableRipple,\n mixinTabIndex,\n mixinDisabled,\n RippleGlobalOptions,\n} from '@angular/material/core';\nimport {FocusMonitor} from '@angular/cdk/a11y';\nimport {Subject} from 'rxjs';\nimport {take} from 'rxjs/operators';\nimport {MatChipAvatar, MatChipTrailingIcon, MatChipRemove} from './chip-icons';\nimport {MatChipAction} from './chip-action';\nimport {BACKSPACE, DELETE} from '@angular/cdk/keycodes';\nimport {MAT_CHIP, MAT_CHIP_AVATAR, MAT_CHIP_REMOVE, MAT_CHIP_TRAILING_ICON} from './tokens';\n\nlet uid = 0;\n\n/** Represents an event fired on an individual `mat-chip`. */\nexport interface MatChipEvent {\n /** The chip the event was fired on. */\n chip: MatChip;\n}\n\n/**\n * Boilerplate for applying mixins to MatChip.\n * @docs-private\n */\nconst _MatChipMixinBase = mixinTabIndex(\n mixinColor(\n mixinDisableRipple(\n mixinDisabled(\n class {\n constructor(public _elementRef: ElementRef<HTMLElement>) {}\n },\n ),\n ),\n 'primary',\n ),\n -1,\n);\n\n/**\n * Material design styled Chip base component. Used inside the MatChipSet component.\n *\n * Extended by MatChipOption and MatChipRow for different interaction patterns.\n */\n@Component({\n selector: 'mat-basic-chip, mat-chip',\n inputs: ['color', 'disabled', 'disableRipple', 'tabIndex'],\n exportAs: 'matChip',\n templateUrl: 'chip.html',\n styleUrls: ['chip.css'],\n host: {\n 'class': 'mat-mdc-chip',\n '[class.mdc-evolution-chip]': '!_isBasicChip',\n '[class.mdc-evolution-chip--disabled]': 'disabled',\n '[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',\n '[class.mdc-evolution-chip--with-primary-graphic]': 'leadingIcon',\n '[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',\n '[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',\n '[class.mat-mdc-chip-with-avatar]': 'leadingIcon',\n '[class.mat-mdc-chip-highlighted]': 'highlighted',\n '[class.mat-mdc-chip-disabled]': 'disabled',\n '[class.mat-mdc-basic-chip]': '_isBasicChip',\n '[class.mat-mdc-standard-chip]': '!_isBasicChip',\n '[class.mat-mdc-chip-with-trailing-icon]': '_hasTrailingIcon()',\n '[class._mat-animation-noopable]': '_animationsDisabled',\n '[id]': 'id',\n '[attr.role]': 'role',\n '[attr.tabindex]': 'role ? tabIndex : null',\n '[attr.aria-label]': 'ariaLabel',\n '(keydown)': '_handleKeydown($event)',\n },\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [{provide: MAT_CHIP, useExisting: MatChip}],\n})\nexport class MatChip\n extends _MatChipMixinBase\n implements AfterViewInit, CanColor, CanDisableRipple, CanDisable, HasTabIndex, OnDestroy\n{\n protected _document: Document;\n\n /** Whether the ripple is centered on the chip. */\n readonly _isRippleCentered = false;\n\n /** Emits when the chip is focused. */\n readonly _onFocus = new Subject<MatChipEvent>();\n\n /** Emits when the chip is blurred. */\n readonly _onBlur = new Subject<MatChipEvent>();\n\n /** Whether this chip is a basic (unstyled) chip. */\n readonly _isBasicChip: boolean;\n\n /** Role for the root of the chip. */\n @Input() role: string | null = null;\n\n /** Whether the chip has focus. */\n private _hasFocusInternal = false;\n\n /** Whether moving focus into the chip is pending. */\n private _pendingFocus: boolean;\n\n /** Whether animations for the chip are enabled. */\n _animationsDisabled: boolean;\n\n _hasFocus() {\n return this._hasFocusInternal;\n }\n\n /** A unique id for the chip. If none is supplied, it will be auto-generated. */\n @Input() id: string = `mat-mdc-chip-${uid++}`;\n\n /** ARIA label for the content of the chip. */\n @Input('aria-label') ariaLabel: string | null = null;\n\n private _textElement!: HTMLElement;\n\n /**\n * The value of the chip. Defaults to the content inside\n * the `mat-mdc-chip-action-label` element.\n */\n @Input()\n get value(): any {\n return this._value !== undefined ? this._value : this._textElement.textContent!.trim();\n }\n set value(value: any) {\n this._value = value;\n }\n protected _value: any;\n\n /**\n * Determines whether or not the chip displays the remove styling and emits (removed) events.\n */\n @Input()\n get removable(): boolean {\n return this._removable;\n }\n set removable(value: BooleanInput) {\n this._removable = coerceBooleanProperty(value);\n }\n protected _removable: boolean = true;\n\n /**\n * Colors the chip for emphasis as if it were selected.\n */\n @Input()\n get highlighted(): boolean {\n return this._highlighted;\n }\n set highlighted(value: BooleanInput) {\n this._highlighted = coerceBooleanProperty(value);\n }\n protected _highlighted: boolean = false;\n\n /** Emitted when a chip is to be removed. */\n @Output() readonly removed: EventEmitter<MatChipEvent> = new EventEmitter<MatChipEvent>();\n\n /** Emitted when the chip is destroyed. */\n @Output() readonly destroyed: EventEmitter<MatChipEvent> = new EventEmitter<MatChipEvent>();\n\n /** The unstyled chip selector for this component. */\n protected basicChipAttrName = 'mat-basic-chip';\n\n /** The chip's leading icon. */\n @ContentChild(MAT_CHIP_AVATAR) leadingIcon: MatChipAvatar;\n\n /** The chip's trailing icon. */\n @ContentChild(MAT_CHIP_TRAILING_ICON) trailingIcon: MatChipTrailingIcon;\n\n /** The chip's trailing remove icon. */\n @ContentChild(MAT_CHIP_REMOVE) removeIcon: MatChipRemove;\n\n /** Reference to the MatRipple instance of the chip. */\n @ViewChild(MatRipple) ripple: MatRipple;\n\n /** Action receiving the primary set of user interactions. */\n @ViewChild(MatChipAction) primaryAction: MatChipAction;\n\n constructor(\n public _changeDetectorRef: ChangeDetectorRef,\n elementRef: ElementRef<HTMLElement>,\n protected _ngZone: NgZone,\n private _focusMonitor: FocusMonitor,\n @Inject(DOCUMENT) _document: any,\n @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string,\n @Optional()\n @Inject(MAT_RIPPLE_GLOBAL_OPTIONS)\n private _globalRippleOptions?: RippleGlobalOptions,\n @Attribute('tabindex') tabIndex?: string,\n ) {\n super(elementRef);\n const element = elementRef.nativeElement;\n this._document = _document;\n this._animationsDisabled = animationMode === 'NoopAnimations';\n this._isBasicChip =\n element.hasAttribute(this.basicChipAttrName) ||\n element.tagName.toLowerCase() === this.basicChipAttrName;\n if (tabIndex != null) {\n this.tabIndex = parseInt(tabIndex) ?? this.defaultTabIndex;\n }\n this._monitorFocus();\n }\n\n ngAfterViewInit() {\n this._textElement = this._elementRef.nativeElement.querySelector('.mat-mdc-chip-action-label')!;\n\n if (this._pendingFocus) {\n this._pendingFocus = false;\n this.focus();\n }\n }\n\n ngOnDestroy() {\n this._focusMonitor.stopMonitoring(this._elementRef);\n this.destroyed.emit({chip: this});\n this.destroyed.complete();\n }\n\n /**\n * Allows for programmatic removal of the chip.\n *\n * Informs any listeners of the removal request. Does not remove the chip from the DOM.\n */\n remove(): void {\n if (this.removable) {\n this.removed.emit({chip: this});\n }\n }\n\n /** Whether or not the ripple should be disabled. */\n _isRippleDisabled(): boolean {\n return (\n this.disabled ||\n this.disableRipple ||\n this._animationsDisabled ||\n this._isBasicChip ||\n !!this._globalRippleOptions?.disabled\n );\n }\n\n /** Returns whether the chip has a trailing icon. */\n _hasTrailingIcon() {\n return !!(this.trailingIcon || this.removeIcon);\n }\n\n /** Handles keyboard events on the chip. */\n _handleKeydown(event: KeyboardEvent) {\n if (event.keyCode === BACKSPACE || event.keyCode === DELETE) {\n event.preventDefault();\n this.remove();\n }\n }\n\n /** Allows for programmatic focusing of the chip. */\n focus(): void {\n if (!this.disabled) {\n // If `focus` is called before `ngAfterViewInit`, we won't have access to the primary action.\n // This can happen if the consumer tries to focus a chip immediately after it is added.\n // Queue the method to be called again on init.\n if (this.primaryAction) {\n this.primaryAction.focus();\n } else {\n this._pendingFocus = true;\n }\n }\n }\n\n /** Gets the action that contains a specific target node. */\n _getSourceAction(target: Node): MatChipAction | undefined {\n return this._getActions().find(action => {\n const element = action._elementRef.nativeElement;\n return element === target || element.contains(target);\n });\n }\n\n /** Gets all of the actions within the chip. */\n _getActions(): MatChipAction[] {\n const result: MatChipAction[] = [];\n\n if (this.primaryAction) {\n result.push(this.primaryAction);\n }\n\n if (this.removeIcon) {\n result.push(this.removeIcon);\n }\n\n if (this.trailingIcon) {\n result.push(this.trailingIcon);\n }\n\n return result;\n }\n\n /** Handles interactions with the primary action of the chip. */\n _handlePrimaryActionInteraction() {\n // Empty here, but is overwritten in child classes.\n }\n\n /** Starts the focus monitoring process on the chip. */\n private _monitorFocus() {\n this._focusMonitor.monitor(this._elementRef, true).subscribe(origin => {\n const hasFocus = origin !== null;\n\n if (hasFocus !== this._hasFocusInternal) {\n this._hasFocusInternal = hasFocus;\n\n if (hasFocus) {\n this._onFocus.next({chip: this});\n } else {\n // When animations are enabled, Angular may end up removing the chip from the DOM a little\n // earlier than usual, causing it to be blurred and throwing off the logic in the chip list\n // that moves focus not the next item. To work around the issue, we defer marking the chip\n // as not focused until the next time the zone stabilizes.\n this._ngZone.onStable\n .pipe(take(1))\n .subscribe(() => this._ngZone.run(() => this._onBlur.next({chip: this})));\n }\n }\n });\n }\n}\n","<span matRipple class=\"mat-mdc-chip-ripple\"\n [matRippleDisabled]=\"_isRippleDisabled()\"\n [matRippleCentered]=\"_isRippleCentered\"\n [matRippleTrigger]=\"_elementRef.nativeElement\"></span>\n<span class=\"mat-mdc-chip-focus-overlay\"></span>\n\n<span class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--primary\">\n <div matChipAction [isInteractive]=\"false\">\n <span class=\"mdc-evolution-chip__graphic mat-mdc-chip-graphic\" *ngIf=\"leadingIcon\">\n <ng-content select=\"mat-chip-avatar, [matChipAvatar]\"></ng-content>\n </span>\n <span class=\"mdc-evolution-chip__text-label mat-mdc-chip-action-label\">\n <ng-content></ng-content>\n <span class=\"mat-mdc-chip-primary-focus-indicator mat-mdc-focus-indicator\"></span>\n </span>\n </div>\n</span>\n\n<span\n class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--trailing\"\n *ngIf=\"_hasTrailingIcon()\">\n <ng-content select=\"mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]\"></ng-content>\n</span>\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n ViewEncapsulation,\n OnInit,\n} from '@angular/core';\nimport {MatChip} from './chip';\nimport {MAT_CHIP} from './tokens';\n\n/** Event object emitted by MatChipOption when selected or deselected. */\nexport class MatChipSelectionChange {\n constructor(\n /** Reference to the chip that emitted the event. */\n public source: MatChipOption,\n /** Whether the chip that emitted the event is selected. */\n public selected: boolean,\n /** Whether the selection change was a result of a user interaction. */\n public isUserInput = false,\n ) {}\n}\n\n/**\n * An extension of the MatChip component that supports chip selection. Used with MatChipListbox.\n *\n * Unlike other chips, the user can focus on disabled chip options inside a MatChipListbox. The\n * user cannot click disabled chips.\n */\n@Component({\n selector: 'mat-basic-chip-option, mat-chip-option',\n templateUrl: 'chip-option.html',\n styleUrls: ['chip.css'],\n inputs: ['color', 'disabled', 'disableRipple', 'tabIndex'],\n host: {\n 'class':\n 'mat-mdc-chip mat-mdc-chip-option mdc-evolution-chip mdc-evolution-chip--filter mdc-evolution-chip--selectable mdc-evolution-chip--with-primary-graphic',\n '[class.mat-mdc-chip-selected]': 'selected',\n '[class.mat-mdc-chip-multiple]': '_chipListMultiple',\n '[class.mat-mdc-chip-disabled]': 'disabled',\n '[class.mat-mdc-chip-with-avatar]': 'leadingIcon',\n '[class.mdc-evolution-chip--disabled]': 'disabled',\n '[class.mdc-evolution-chip--selected]': 'selected',\n // This class enables the transition on the checkmark. Usually MDC adds it when selection\n // starts and removes it once the animation is finished. We don't need to go through all\n // the trouble, because we only care about the selection animation. MDC needs to do it,\n // because they also have an exit animation that we don't care about.\n '[class.mdc-evolution-chip--selecting]': '!_animationsDisabled',\n '[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',\n '[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',\n '[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',\n '[class.mat-mdc-chip-highlighted]': 'highlighted',\n '[class.mat-mdc-chip-with-trailing-icon]': '_hasTrailingIcon()',\n '[attr.tabindex]': 'null',\n '[attr.aria-label]': 'null',\n '[attr.role]': 'role',\n '[id]': 'id',\n },\n providers: [\n {provide: MatChip, useExisting: MatChipOption},\n {provide: MAT_CHIP, useExisting: MatChipOption},\n ],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatChipOption extends MatChip implements OnInit {\n /** Whether the chip list is selectable. */\n chipListSelectable: boolean = true;\n\n /** Whether the chip list is in multi-selection mode. */\n _chipListMultiple: boolean = false;\n\n /**\n * Whether or not the chip is selectable.\n *\n * When a chip is not selectable, changes to its selected state are always\n * ignored. By default an option chip is selectable, and it becomes\n * non-selectable if its parent chip list is not selectable.\n */\n @Input()\n get selectable(): boolean {\n return this._selectable && this.chipListSelectable;\n }\n set selectable(value: BooleanInput) {\n this._selectable = coerceBooleanProperty(value);\n this._changeDetectorRef.markForCheck();\n }\n protected _selectable: boolean = true;\n\n /** Whether the chip is selected. */\n @Input()\n get selected(): boolean {\n return this._selected;\n }\n set selected(value: BooleanInput) {\n this._setSelectedState(coerceBooleanProperty(value), false, true);\n }\n private _selected = false;\n\n /**\n * The ARIA selected applied to the chip. Conforms to WAI ARIA best practices for listbox\n * interaction patterns.\n *\n * From [WAI ARIA Listbox authoring practices guide](\n * https://www.w3.org/WAI/ARIA/apg/patterns/listbox/):\n * \"If any options are selected, each selected option has either aria-selected or aria-checked\n * set to true. All options that are selectable but not selected have either aria-selected or\n * aria-checked set to false.\"\n *\n * Set `aria-selected=\"false\"` on not-selected listbox options that are selectable to fix\n * VoiceOver reading every option as \"selected\" (#25736).\n */\n get ariaSelected(): string | null {\n return this.selectable ? this.selected.toString() : null;\n }\n\n /** The unstyled chip selector for this component. */\n protected override basicChipAttrName = 'mat-basic-chip-option';\n\n /** Emitted when the chip is selected or deselected. */\n @Output() readonly selectionChange: EventEmitter<MatChipSelectionChange> =\n new EventEmitter<MatChipSelectionChange>();\n\n ngOnInit() {\n this.role = 'presentation';\n }\n\n /** Selects the chip. */\n select(): void {\n this._setSelectedState(true, false, true);\n }\n\n /** Deselects the chip. */\n deselect(): void {\n this._setSelectedState(false, false, true);\n }\n\n /** Selects this chip and emits userInputSelection event */\n selectViaInteraction(): void {\n this._setSelectedState(true, true, true);\n }\n\n /** Toggles the current selected state of this chip. */\n toggleSelected(isUserInput: boolean = false): boolean {\n this._setSelectedState(!this.selected, isUserInput, true);\n return this.selected;\n }\n\n override _handlePrimaryActionInteraction() {\n if (this.selectable && !this.disabled) {\n this.toggleSelected(true);\n }\n }\n\n _setSelectedState(isSelected: boolean, isUserInput: boolean, emitEvent: boolean) {\n if (isSelected !== this.selected) {\n this._selected = isSelected;\n\n if (emitEvent) {\n this.selectionChange.emit({\n source: this,\n isUserInput,\n selected: this.selected,\n });\n }\n\n this._changeDetectorRef.markForCheck();\n }\n }\n}\n","<span matRipple class=\"mat-mdc-chip-ripple\"\n [matRippleDisabled]=\"_isRippleDisabled()\"\n [matRippleCentered]=\"_isRippleCentered\"\n [matRippleTrigger]=\"_elementRef.nativeElement\"></span>\n<span class=\"mat-mdc-chip-focus-overlay\"></span>\n\n<span class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--primary\">\n <button\n matChipAction\n [tabIndex]=\"tabIndex\"\n [_allowFocusWhenDisabled]=\"true\"\n [attr.aria-selected]=\"ariaSelected\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"option\">\n <span class=\"mdc-evolution-chip__graphic mat-mdc-chip-graphic\">\n <ng-content select=\"mat-chip-avatar, [matChipAvatar]\"></ng-content>\n <span class=\"mdc-evolution-chip__checkmark\">\n <svg class=\"mdc-evolution-chip__checkmark-svg\" viewBox=\"-2 -3 30 30\" focusable=\"false\">\n <path class=\"mdc-evolution-chip__checkmark-path\"\n fill=\"none\" stroke=\"currentColor\" d=\"M1.73,12.91 8.1,19.28 22.79,4.59\" />\n </svg>\n </span>\n </span>\n <span class=\"mdc-evolution-chip__text-label mat-mdc-chip-action-label\">\n <ng-content></ng-content>\n <span class=\"mat-mdc-chip-primary-focus-indicator mat-mdc-focus-indicator\"></span>\n </span>\n </button>\n</span>\n\n<span\n class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--trailing\"\n *ngIf=\"_hasTrailingIcon()\">\n <ng-content select=\"mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]\"></ng-content>\n</span>\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {Directive, ElementRef, Inject} from '@angular/core';\nimport {DOCUMENT} from '@angular/common';\n\n/**\n * A directive that makes a span editable and exposes functions to modify and retrieve the\n * element's contents.\n */\n@Directive({\n selector: 'span[matChipEditInput]',\n host: {\n 'class': 'mat-chip-edit-input',\n 'role': 'textbox',\n 'tabindex': '-1',\n 'contenteditable': 'true',\n },\n})\nexport class MatChipEditInput {\n constructor(\n private readonly _elementRef: ElementRef,\n @Inject(DOCUMENT) private readonly _document: any,\n ) {}\n\n initialize(initialValue: string) {\n this.getNativeElement().focus();\n this.setValue(initialValue);\n }\n\n getNativeElement(): HTMLElement {\n return this._elementRef.nativeElement;\n }\n\n setValue(value: string) {\n this.getNativeElement().textContent = value;\n this._moveCursorToEndOfInput();\n }\n\n getValue(): string {\n return this.getNativeElement().textContent || '';\n }\n\n private _moveCursorToEndOfInput() {\n const range = this._document.createRange();\n range.selectNodeContents(this.getNativeElement());\n range.collapse(false);\n const sel = window.getSelection()!;\n sel.removeAllRanges();\n sel.addRange(range);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {ENTER} from '@angular/cdk/keycodes';\nimport {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';\nimport {\n AfterViewInit,\n Attribute,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChild,\n ElementRef,\n EventEmitter,\n Inject,\n Input,\n NgZone,\n Optional,\n Output,\n ViewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport {DOCUMENT} from '@angular/common';\nimport {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';\nimport {FocusMonitor} from '@angular/cdk/a11y';\nimport {MatChip, MatChipEvent} from './chip';\nimport {MatChipEditInput} from './chip-edit-input';\nimport {takeUntil} from 'rxjs/operators';\nimport {MAT_CHIP} from './tokens';\n\n/** Represents an event fired on an individual `mat-chip` when it is edited. */\nexport interface MatChipEditedEvent extends MatChipEvent {\n /** The final edit value. */\n value: string;\n}\n\n/**\n * An extension of the MatChip component used with MatChipGrid and\n * the matChipInputFor directive.\n */\n@Component({\n selector: 'mat-chip-row, mat-basic-chip-row',\n templateUrl: 'chip-row.html',\n styleUrls: ['chip.css'],\n inputs: ['color', 'disabled', 'disableRipple', 'tabIndex'],\n host: {\n 'class': 'mat-mdc-chip mat-mdc-chip-row mdc-evolution-chip',\n '[class.mat-mdc-chip-with-avatar]': 'leadingIcon',\n '[class.mat-mdc-chip-disabled]': 'disabled',\n '[class.mat-mdc-chip-editing]': '_isEditing',\n '[class.mat-mdc-chip-editable]': 'editable',\n '[class.mdc-evolution-chip--disabled]': 'disabled',\n '[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',\n '[class.mdc-evolution-chip--with-primary-graphic]': 'leadingIcon',\n '[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',\n '[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',\n '[class.mat-mdc-chip-highlighted]': 'highlighted',\n '[class.mat-mdc-chip-with-trailing-icon]': '_hasTrailingIcon()',\n '[id]': 'id',\n '[attr.tabindex]': 'null',\n '[attr.aria-label]': 'null',\n '[attr.role]': 'role',\n '(mousedown)': '_mousedown($event)',\n '(dblclick)': '_doubleclick($event)',\n },\n providers: [\n {provide: MatChip, useExisting: MatChipRow},\n {provide: MAT_CHIP, useExisting: MatChipRow},\n ],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatChipRow extends MatChip implements AfterViewInit {\n protected override basicChipAttrName = 'mat-basic-chip-row';\n\n /**\n * The editing action has to be triggered in a timeout. While we're waiting on it, a blur\n * event might occur which will interrupt the editing. This flag is used to avoid interruptions\n * while the editing action is being initialized.\n */\n private _editStartPending = false;\n\n @Input() editable: boolean = false;\n\n /** Emitted when the chip is edited. */\n @Output() readonly edited: EventEmitter<MatChipEditedEvent> =\n new EventEmitter<MatChipEditedEvent>();\n\n /** The default chip edit input that is used if none is projected into this chip row. */\n @ViewChild(MatChipEditInput) defaultEditInput?: MatChipEditInput;\n\n /** The projected chip edit input. */\n @ContentChild(MatChipEditInput) contentEditInput?: MatChipEditInput;\n\n _isEditing = false;\n\n constructor(\n changeDetectorRef: ChangeDetectorRef,\n elementRef: ElementRef,\n ngZone: NgZone,\n focusMonitor: FocusMonitor,\n @Inject(DOCUMENT) _document: any,\n @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string,\n @Optional()\n @Inject(MAT_RIPPLE_GLOBAL_OPTIONS)\n globalRippleOptions?: RippleGlobalOptions,\n @Attribute('tabindex') tabIndex?: string,\n ) {\n super(\n changeDetectorRef,\n elementRef,\n ngZone,\n focusMonitor,\n _document,\n animationMode,\n globalRippleOptions,\n tabIndex,\n );\n\n this.role = 'row';\n this._onBlur.pipe(takeUntil(this.destroyed)).subscribe(() => {\n if (this._isEditing && !this._editStartPending) {\n this._onEditFinish();\n }\n });\n }\n\n override _hasTrailingIcon() {\n // The trailing icon is hidden while editing.\n return !this._isEditing && super._hasTrailingIcon();\n }\n\n /** Sends focus to the first gridcell when the user clicks anywhere inside the chip. */\n _mousedown(event: MouseEvent) {\n if (!this._isEditing) {\n if (!this.disabled) {\n this.focus();\n }\n\n event.preventDefault();\n }\n }\n\n override _handleKeydown(event: KeyboardEvent): void {\n if (event.keyCode === ENTER && !this.disabled) {\n if (this._isEditing) {\n event.preventDefault();\n this._onEditFinish();\n } else if (this.editable) {\n this._startEditing(event);\n }\n } else if (this._isEditing) {\n // Stop the event from reaching the chip set in order to avoid navigating.\n event.stopPropagation();\n } else {\n super._handleKeydown(event);\n }\n }\n\n _doubleclick(event: MouseEvent) {\n if (!this.disabled && this.editable) {\n this._startEditing(event);\n }\n }\n\n private _startEditing(event: Event) {\n if (\n !this.primaryAction ||\n (this.removeIcon && this._getSourceAction(event.target as Node) === this.removeIcon)\n ) {\n return;\n }\n\n // The value depends on the DOM so we need to extract it before we flip the flag.\n const value = this.value;\n\n this._isEditing = true;\n this._editStartPending = true;\n\n // Defer initializing the input so it has time to be added to the DOM.\n setTimeout(() => {\n this._getEditInput().initialize(value);\n this._editStartPending = false;\n });\n }\n\n private _onEditFinish() {\n this._isEditing = false;\n this._editStartPending = false;\n this.edited.emit({chip: this, value: this._getEditInput().getValue()});\n\n // If the edit input is still focused or focus was returned to the body after it was destroyed,\n // return focus to the chip contents.\n if (\n this._document.activeElement === this._getEditInput().getNativeElement() ||\n this._document.activeElement === this._document.body\n ) {\n this.primaryAction.focus();\n }\n }\n\n /**\n * Gets the projected chip edit input, or the default input if none is projected in. One of these\n * two values is guaranteed to be defined.\n */\n private _getEditInput(): MatChipEditInput {\n return this.contentEditInput || this.defaultEditInput!;\n }\n}\n","<ng-container *ngIf=\"!_isEditing\">\n <span matRipple class=\"mat-mdc-chip-ripple\"\n [matRippleDisabled]=\"_isRippleDisabled()\"\n [matRippleCentered]=\"_isRippleCentered\"\n [matRippleTrigger]=\"_elementRef.nativeElement\"></span>\n <span class=\"mat-mdc-chip-focus-overlay\"></span>\n</ng-container>\n\n\n<span class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--primary\" role=\"gridcell\">\n <span\n matChipAction\n [attr.role]=\"editable ? 'button' : null\"\n [tabIndex]=\"tabIndex\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\">\n <span class=\"mdc-evolution-chip__graphic mat-mdc-chip-graphic\" *ngIf=\"leadingIcon\">\n <ng-content select=\"mat-chip-avatar, [matChipAvatar]\"></ng-content>\n </span>\n <span class=\"mdc-evolution-chip__text-label mat-mdc-chip-action-label\" [ngSwitch]=\"_isEditing\">\n <ng-container *ngSwitchCase=\"false\"><ng-content></ng-content></ng-container>\n\n <ng-container *ngSwitchCase=\"true\">\n <ng-content *ngIf=\"contentEditInput; else defaultMatChipEditInput\"\n select=\"[matChipEditInput]\"></ng-content>\n <ng-template #defaultMatChipEditInput><span matChipEditInput></span></ng-template>\n </ng-container>\n\n <span class=\"mat-mdc-chip-primary-focus-indicator mat-mdc-focus-indicator\"></span>\n </span>\n </span>\n</span>\n\n<span\n class=\"mdc-evolution-chip__cell mdc-evolution-chip__cell--trailing\"\n role=\"gridcell\"\n *ngIf=\"_hasTrailingIcon()\">\n <ng-content select=\"mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]\"></ng-content>\n</span>\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport {FocusKeyManager} from '@angular/cdk/a11y';\nimport {Directionality} from '@angular/cdk/bidi';\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChildren,\n ElementRef,\n Input,\n OnDestroy,\n Optional,\n QueryList,\n ViewEncapsulation,\n} from '@angular/core';\nimport {HasTabIndex, mixinTabIndex} from '@angular/material/core';\nimport {merge, Observable, Subject} from 'rxjs';\nimport {startWith, switchMap, takeUntil} from 'rxjs/operators';\nimport {MatChip, MatChipEvent} from './chip';\nimport {MatChipAction} from './chip-action';\n\n/**\n * Boilerplate for applying mixins to MatChipSet.\n * @docs-private\n */\nabstract class MatChipSetBase {\n abstract disabled: boolean;\n constructor(_elementRef: ElementRef) {}\n}\nconst _MatChipSetMixinBase = mixinTabIndex(MatChipSetBase);\n\n/**\n * Basic container component for the MatChip component.\n *\n * Extended by MatChipListbox and MatChipGrid for different interaction patterns.\n */\n@Component({\n selector: 'mat-chip-set',\n template: `\n <span class=\"mdc-evolution-chip-set__chips\" role=\"presentation\">\n <ng-content></ng-content>\n </span>\n `,\n styleUrls: ['chip-set.css'],\n host: {\n 'class': 'mat-mdc-chip-set mdc-evolution-chip-set',\n '(keydown)': '_handleKeydown($event)',\n '[attr.role]': 'role',\n },\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatChipSet\n extends _MatChipSetMixinBase\n implements AfterViewInit, HasTabIndex, OnDestroy\n{\n /** Index of the last destroyed chip that had focus. */\n private _lastDestroyedFocusedChipIndex: number | null = null;\n\n /** Used to manage focus within the chip list. */\n protected _keyManager: FocusKeyManager<MatChipAction>;\n\n /** Subject that emits when the component has been destroyed. */\n protected _destroyed = new Subject<void>();\n\n /** Role to use if it hasn't been overwritten by the user. */\n protected _defaultRole = 'presentation';\n\n /** Combined stream of all of the child chips' focus events. */\n get chipFocusChanges(): Observable<MatChipEvent> {\n return this._getChipStream(chip => chip._onFocus);\n }\n\n /** Combined stream of all of the child chips' remove events. */\n get chipDestroyedChanges(): Observable<MatChipEvent> {\n return this._getChipStream(chip => chip.destroyed);\n }\n\n /** Whether the chip set is disabled. */\n @Input()\n get disabled(): boolean {\n return this._disabled;\n }\n set disabled(value: BooleanInput) {\n this._disabled = coerceBooleanProperty(value);\n this._syncChipsState();\n }\n protected _disabled: boolean = false;\n\n /** Whether the chip list contains chips or not. */\n get empty(): boolean {\n return this._chips.length === 0;\n }\n\n /** The ARIA role applied to the chip set. */\n @Input()\n get role(): string | null {\n if (this._explicitRole) {\n return this._explicitRole;\n }\n\n return this.empty ? null : this._defaultRole;\n }\n\n set role(value: string | null) {\n this._explicitRole = value;\n }\n private _explicitRole: string | null = null;\n\n /** Whether any of the chips inside of this chip-set has focus. */\n get focused(): boolean {\n return this._hasFocusedChip();\n }\n\n /** The chips that are part of this chip set. */\n @ContentChildren(MatChip, {\n // We need to use `descendants: true`, because Ivy will no longer match\n // indirect descendants if it's left as false.\n descendants: true,\n })\n _chips: QueryList<MatChip>;\n\n /** Flat list of all the actions contained within the chips. */\n _chipActions = new QueryList<MatChipAction>();\n\n constructor(\n protected _elementRef: ElementRef<HTMLElement>,\n protected _changeDetectorRef: ChangeDetectorRef,\n @Optional() private _dir: Directionality,\n ) {\n super(_elementRef);\n }\n\n ngAfterViewInit() {\n this._setUpFocusManagement();\n this._trackChipSetChanges();\n this._trackDestroyedFocusedChip();\n }\n\n ngOnDestroy() {\n this._keyManager?.destroy();\n this._chipActions.destroy();\n this._destroyed.next();\n this._destroyed.complete();\n }\n\n /** Checks whether any of the chips is focused. */\n protected _hasFocusedChip() {\n return this._chips && this._chips.some(chip => chip._hasFocus());\n }\n\n /** Syncs the chip-set's state with the individual chips. */\n protected _syncChipsState() {\n if (this._chips) {\n this._chips.forEach(chip => {\n chip.disabled = this._disabled;\n chip._changeDetectorRef.markForCheck();\n });\n }\n }\n\n /** Dummy method for subclasses to override. Base chip set cannot be focused. */\n focus() {}\n\n /** Handles keyboard events on the chip set. */\n _handleKeydown(event: KeyboardEvent) {\n if (this._originatesFromChip(event)) {\n this._keyManager.onKeydown(event);\n }\n }\n\n /**\n * Utility to ensure all indexes are valid.\n *\n * @param index The index to be checked.\n * @returns True if the index is valid for our list of chips.\n */\n protected _isValidIndex(index: number): boolean {\n return index >= 0 && index < this._chips.length;\n }\n\n /**\n * Removes the `tabindex` from the chip grid and resets it back afterwards, allowing the\n * user to tab out of it. This prevents the grid from capturing focus and redirecting\n * it back to the first chip, creating a focus trap, if it user tries to tab away.\n */\n protected _allowFocusEscape() {\n const previousTabIndex = this.tabIndex;\n\n if (this.tabIndex !== -1) {\n this.tabIndex = -1;\n\n setTimeout(() => {\n this.tabIndex = previousTabIndex;\n this._changeDetectorRef.markForCheck();\n });\n }\n }\n\n /**\n * Gets a stream of events from all the chips within the set.\n * The stream will automatically incorporate any newly-added chips.\n */\n protected _getChipStream<T, C extends MatChip = MatChip>(\n mappingFunction: (chip: C) => Observable<T>,\n ): Observable<T> {\n return this._chips.changes.pipe(\n startWith(null),\n switchMap(() => merge(...(this._chips as QueryList<C>).map(mappingFunction))),\n );\n }\n\n /** Checks whether an event comes from inside a chip element. */\n protected _originatesFromChip(event: Event): boolean {\n let currentElement = event.target as HTMLElement | null;\n\n while (currentElement && currentElement !== this._elementRef.nativeElement) {\n // Null check the classList, because IE and Edge don't support it on all elements.\n if (currentElement.classList && currentElement.classList.contains('mdc-evolution-chip')) {\n return true;\n }\n currentElement = currentElement.parentElement;\n }\n return false;\n }\n\n /** Sets up the chip set's focus management logic. */\n private _setUpFocusManagement() {\n // Create a flat `QueryList` containing the actions of all of the chips.\n // This allows us to navigate both within the chip and move to the next/previous\n // one using the existing `ListKeyManager`.\n this._chips.changes.pipe(startWith(this._chips)).subscribe((chips: QueryList<MatChip>) => {\n const actions: MatChipAction[] = [];\n chips.forEach(chip => chip._getActions().forEach(action => actions.push(action)));\n this._chipActions.reset(actions);\n this._chipActions.notifyOnChanges();\n });\n\n this._keyManager = new FocusKeyManager(this._chipActions)\n .withVerticalOrientation()\n .withHorizontalOrientation(this._dir ? this._dir.value : 'ltr')\n .withHomeAndEnd()\n .skipPredicate(action => this._skipPredicate(action));\n\n // Keep the manager active index in sync so that navigation picks\n // up from the current chip if the user clicks into the list directly.\n this.chipFocusChanges.pipe(takeUntil(this._destroyed)).subscribe(({chip}) => {\n const action = chip._getSourceAction(document.activeElement as Element);\n\n if (action) {\n this._keyManager.updateActiveItem(action);\n }\n });\n\n this._dir?.change\n .pipe(takeUntil(this._destroyed))\n .subscribe(direction => this._keyManager.withHorizontalOrientation(direction));\n }\n\n /**\n * Determines if key manager should avoid putting a given chip action in the tab index. Skip\n * non-interactive and disabled actions since the user can't do anything with them.\n */\n protected _skipPredicate(action: MatChipAction): boolean {\n // Skip chips that the user cannot interact with. `mat-chip-set` does not permit focusing disabled\n // chips.\n return !action.isInteractive || action.disabled;\n }\n\n /** Listens to changes in the chip set and syncs up the state of the individual chips. */\n private _trackChipSetChanges() {\n this._chips.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {\n if (this.disabled) {\n // Since this happens after the content has been\n // checked, we need to defer it to the next tick.\n Promise.resolve().then(() => this._syncChipsState());\n }\n\n this._redirectDestroyedChipFocus();\n });\n }\n\n /** Starts tracking the destroyed chips in order to capture the focused one. */\n private _trackDestroyedFocusedChip() {\n this.chipDestroyedChanges.pipe(takeUntil(this._destroyed)).subscribe((event: MatChipEvent) => {\n const chipArray = this._chips.toArray();\n const chipIndex = chipArray.indexOf(event.chip);\n\n // If the focused chip is destroyed, save its index so that we can move focus to the next\n // chip. We only save the index here, rather than move the focus immediately, because we want\n // to wait until the chip is removed from the chip list before focusing the next one. This\n // allows us to keep focus on the same index if the chip gets swapped out.\n if (this._isValidIndex(chipIndex) && event.chip._hasFocus()) {\n this._lastDestroyedFocusedChipIndex = chipIndex;\n }\n });\n }\n\n /**\n * Finds the next appropriate chip to move focus to,\n * if the currently-focused chip is destroyed.\n */\n private _redirectDestroyedChipFocus() {\n if (this._lastDestroyedFocusedChipIndex == null) {\n return;\n }\n\n if (this._chips.l