Skip to content

Commit

Permalink
fix(multiple): remove unnecessary base classes (#27632)
Browse files Browse the repository at this point in the history
* fix(material/autocomplete): remove base classes

* fix(material/checkbox): remove base classes

* fix(material/dialog): remove base classes

* fix(material/form-field): remove base classes

* fix(material/menu): remove base classes

* fix(material/paginator): remove base classes

* fix(material/radio): remove base classes

* fix(material/select): remove base classes

* fix(material/slide-toggle): remove base classes

* fix(material/snack-bar): remove base classes

* fix(material/table): remove base classes

* fix(material/tabs): remove base classes

* fix(material/tooltip): remove base classes

* fix(material/core): remove base classes

* fix(material/menu): fix harness test

* fix(multiple): update API goldens

* fix(multiple): update API to match previous accesible members
  • Loading branch information
andrewseguin authored Aug 14, 2023
1 parent 251581a commit 55f9618
Show file tree
Hide file tree
Showing 72 changed files with 1,871 additions and 3,442 deletions.
16 changes: 6 additions & 10 deletions src/material/autocomplete/autocomplete-origin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@

import {Directive, ElementRef} from '@angular/core';

/** Base class containing all of the functionality for `MatAutocompleteOrigin`. */
@Directive()
export abstract class _MatAutocompleteOriginBase {
constructor(
/** Reference to the element on which the directive is applied. */
public elementRef: ElementRef<HTMLElement>,
) {}
}

/**
* Directive applied to an element to make it usable
* as a connection point for an autocomplete panel.
Expand All @@ -25,4 +16,9 @@ export abstract class _MatAutocompleteOriginBase {
selector: '[matAutocompleteOrigin]',
exportAs: 'matAutocompleteOrigin',
})
export class MatAutocompleteOrigin extends _MatAutocompleteOriginBase {}
export class MatAutocompleteOrigin {
constructor(
/** Reference to the element on which the directive is applied. */
public elementRef: ElementRef<HTMLElement>,
) {}
}
69 changes: 32 additions & 37 deletions src/material/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@ import {
MatOptionSelectionChange,
_countGroupLabelsBeforeOption,
_getOptionScrollPosition,
_MatOptionBase,
MatOption,
} from '@angular/material/core';
import {MAT_FORM_FIELD, MatFormField} from '@angular/material/form-field';
import {defer, fromEvent, merge, Observable, of as observableOf, Subject, Subscription} from 'rxjs';
import {delay, filter, map, switchMap, take, tap, startWith} from 'rxjs/operators';
import {_MatAutocompleteOriginBase} from './autocomplete-origin';
import {MatAutocompleteOrigin} from './autocomplete-origin';
import {
MatAutocompleteDefaultOptions,
MAT_AUTOCOMPLETE_DEFAULT_OPTIONS,
_MatAutocompleteBase,
MatAutocomplete,
} from './autocomplete';

/**
Expand Down Expand Up @@ -97,8 +97,29 @@ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER = {
};

/** Base class with all of the `MatAutocompleteTrigger` functionality. */
@Directive()
export abstract class _MatAutocompleteTriggerBase
@Directive({
selector: `input[matAutocomplete], textarea[matAutocomplete]`,
host: {
'class': 'mat-mdc-autocomplete-trigger',
'[attr.autocomplete]': 'autocompleteAttribute',
'[attr.role]': 'autocompleteDisabled ? null : "combobox"',
'[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"',
'[attr.aria-activedescendant]': '(panelOpen && activeOption) ? activeOption.id : null',
'[attr.aria-expanded]': 'autocompleteDisabled ? null : panelOpen.toString()',
'[attr.aria-controls]': '(autocompleteDisabled || !panelOpen) ? null : autocomplete?.id',
'[attr.aria-haspopup]': 'autocompleteDisabled ? null : "listbox"',
// Note: we use `focusin`, as opposed to `focus`, in order to open the panel
// a little earlier. This avoids issues where IE delays the focusing of the input.
'(focusin)': '_handleFocus()',
'(blur)': '_onTouched()',
'(input)': '_handleInput($event)',
'(keydown)': '_handleKeydown($event)',
'(click)': '_handleClick()',
},
exportAs: 'matAutocompleteTrigger',
providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR],
})
export class MatAutocompleteTrigger
implements ControlValueAccessor, AfterViewInit, OnChanges, OnDestroy
{
private _overlayRef: OverlayRef | null;
Expand Down Expand Up @@ -141,7 +162,7 @@ export abstract class _MatAutocompleteTriggerBase
* Current option that we have auto-selected as the user is navigating,
* but which hasn't been propagated to the model value yet.
*/
private _pendingAutoselectedOption: _MatOptionBase | null;
private _pendingAutoselectedOption: MatOption | null;

/** Stream of keyboard events that can close the panel. */
private readonly _closeKeyEventStream = new Subject<void>();
Expand All @@ -165,7 +186,7 @@ export abstract class _MatAutocompleteTriggerBase
_onTouched = () => {};

/** The autocomplete panel to be attached to this trigger. */
@Input('matAutocomplete') autocomplete: _MatAutocompleteBase;
@Input('matAutocomplete') autocomplete: MatAutocomplete;

/**
* Position of the autocomplete panel relative to the trigger element. A position of `auto`
Expand All @@ -180,7 +201,7 @@ export abstract class _MatAutocompleteTriggerBase
* Reference relative to which to position the autocomplete panel.
* Defaults to the autocomplete trigger element.
*/
@Input('matAutocompleteConnectedTo') connectedTo: _MatAutocompleteOriginBase;
@Input('matAutocompleteConnectedTo') connectedTo: MatAutocompleteOrigin;

/**
* `autocomplete` attribute to be set on the input element.
Expand Down Expand Up @@ -219,7 +240,7 @@ export abstract class _MatAutocompleteTriggerBase
}

/** Class to apply to the panel when it's above the input. */
protected abstract _aboveClass: string;
private _aboveClass = 'mat-mdc-autocomplete-panel-above';

ngAfterViewInit() {
const window = this._getWindow();
Expand Down Expand Up @@ -353,7 +374,7 @@ export abstract class _MatAutocompleteTriggerBase
}) as Observable<MatOptionSelectionChange>;

/** The currently active option, coerced to MatOption type. */
get activeOption(): _MatOptionBase | null {
get activeOption(): MatOption | null {
if (this.autocomplete && this.autocomplete._keyManager) {
return this.autocomplete._keyManager.activeItem;
}
Expand Down Expand Up @@ -668,7 +689,7 @@ export abstract class _MatAutocompleteTriggerBase
/**
* Clear any previous selected option and emit a selection change event for this option
*/
private _clearPreviousSelectedOption(skip: _MatOptionBase | null, emitEvent?: boolean) {
private _clearPreviousSelectedOption(skip: MatOption | null, emitEvent?: boolean) {
// Null checks are necessary here, because the autocomplete
// or its options may not have been assigned yet.
this.autocomplete?.options?.forEach(option => {
Expand Down Expand Up @@ -984,29 +1005,3 @@ export abstract class _MatAutocompleteTriggerBase
}
}
}

@Directive({
selector: `input[matAutocomplete], textarea[matAutocomplete]`,
host: {
'class': 'mat-mdc-autocomplete-trigger',
'[attr.autocomplete]': 'autocompleteAttribute',
'[attr.role]': 'autocompleteDisabled ? null : "combobox"',
'[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"',
'[attr.aria-activedescendant]': '(panelOpen && activeOption) ? activeOption.id : null',
'[attr.aria-expanded]': 'autocompleteDisabled ? null : panelOpen.toString()',
'[attr.aria-controls]': '(autocompleteDisabled || !panelOpen) ? null : autocomplete?.id',
'[attr.aria-haspopup]': 'autocompleteDisabled ? null : "listbox"',
// Note: we use `focusin`, as opposed to `focus`, in order to open the panel
// a little earlier. This avoids issues where IE delays the focusing of the input.
'(focusin)': '_handleFocus()',
'(blur)': '_onTouched()',
'(input)': '_handleInput($event)',
'(keydown)': '_handleKeydown($event)',
'(click)': '_handleClick()',
},
exportAs: 'matAutocompleteTrigger',
providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR],
})
export class MatAutocompleteTrigger extends _MatAutocompleteTriggerBase {
protected _aboveClass = 'mat-mdc-autocomplete-panel-above';
}
126 changes: 52 additions & 74 deletions src/material/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
ChangeDetectorRef,
Component,
ContentChildren,
Directive,
ElementRef,
EventEmitter,
Inject,
Expand All @@ -33,8 +32,6 @@ import {
MatOption,
mixinDisableRipple,
CanDisableRipple,
_MatOptionBase,
_MatOptgroupBase,
ThemePalette,
} from '@angular/material/core';
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
Expand All @@ -53,19 +50,19 @@ let _uniqueAutocompleteIdCounter = 0;
export class MatAutocompleteSelectedEvent {
constructor(
/** Reference to the autocomplete panel that emitted the event. */
public source: _MatAutocompleteBase,
public source: MatAutocomplete,
/** Option that was selected. */
public option: _MatOptionBase,
public option: MatOption,
) {}
}

/** Event object that is emitted when an autocomplete option is activated. */
export interface MatAutocompleteActivatedEvent {
/** Reference to the autocomplete panel that emitted the event. */
source: _MatAutocompleteBase;
source: MatAutocomplete;

/** Option that was selected. */
option: _MatOptionBase | null;
option: MatOption | null;
}

// Boilerplate for applying mixins to MatAutocomplete.
Expand Down Expand Up @@ -112,25 +109,39 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau
};
}

/** Base class with all of the `MatAutocomplete` functionality. */
@Directive()
export abstract class _MatAutocompleteBase
/** Autocomplete component. */
@Component({
selector: 'mat-autocomplete',
templateUrl: 'autocomplete.html',
styleUrls: ['autocomplete.css'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'matAutocomplete',
inputs: ['disableRipple'],
host: {
'class': 'mat-mdc-autocomplete',
'ngSkipHydration': '',
},
providers: [{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatAutocomplete}],
animations: [panelAnimation],
})
export class MatAutocomplete
extends _MatAutocompleteMixinBase
implements AfterContentInit, CanDisableRipple, OnDestroy
{
private _activeOptionChanges = Subscription.EMPTY;

/** Class to apply to the panel when it's visible. */
protected abstract _visibleClass: string;
private _visibleClass = 'mat-mdc-autocomplete-visible';

/** Class to apply to the panel when it's hidden. */
protected abstract _hiddenClass: string;
private _hiddenClass = 'mat-mdc-autocomplete-hidden';

/** Emits when the panel animation is done. Null if the panel doesn't animate. */
abstract _animationDone: EventEmitter<AnimationEvent> | null;
_animationDone = new EventEmitter<AnimationEvent>();

/** Manages active item in option list based on key events. */
_keyManager: ActiveDescendantKeyManager<_MatOptionBase>;
_keyManager: ActiveDescendantKeyManager<MatOption>;

/** Whether the autocomplete panel should be visible, depending on option length. */
showPanel: boolean = false;
Expand Down Expand Up @@ -160,10 +171,10 @@ export abstract class _MatAutocompleteBase
@ViewChild('panel') panel: ElementRef;

/** Reference to all options within the autocomplete. */
abstract options: QueryList<_MatOptionBase>;
@ContentChildren(MatOption, {descendants: true}) options: QueryList<MatOption>;

/** Reference to all option groups within the autocomplete. */
abstract optionGroups: QueryList<_MatOptgroupBase>;
@ContentChildren(MAT_OPTGROUP, {descendants: true}) optionGroups: QueryList<MatOptgroup>;

/** Aria label of the autocomplete. */
@Input('aria-label') ariaLabel: string;
Expand Down Expand Up @@ -253,6 +264,27 @@ export abstract class _MatAutocompleteBase
}
_classList: {[key: string]: boolean} = {};

/** Whether checkmark indicator for single-selection options is hidden. */
@Input()
get hideSingleSelectionIndicator(): boolean {
return this._hideSingleSelectionIndicator;
}
set hideSingleSelectionIndicator(value: BooleanInput) {
this._hideSingleSelectionIndicator = coerceBooleanProperty(value);
this._syncParentProperties();
}
private _hideSingleSelectionIndicator: boolean =
this._defaults.hideSingleSelectionIndicator ?? false;

/** Syncs the parent state with the individual options. */
_syncParentProperties(): void {
if (this.options) {
for (const option of this.options) {
option._changeDetectorRef.markForCheck();
}
}
}

/** Unique ID to be used by autocomplete trigger's "aria-owns" property. */
id: string = `mat-autocomplete-${_uniqueAutocompleteIdCounter++}`;

Expand Down Expand Up @@ -281,7 +313,7 @@ export abstract class _MatAutocompleteBase
}

ngAfterContentInit() {
this._keyManager = new ActiveDescendantKeyManager<_MatOptionBase>(this.options)
this._keyManager = new ActiveDescendantKeyManager<MatOption>(this.options)
.withWrap()
.skipPredicate(this._skipPredicate);
this._activeOptionChanges = this._keyManager.change.subscribe(index => {
Expand All @@ -297,6 +329,7 @@ export abstract class _MatAutocompleteBase
ngOnDestroy() {
this._keyManager?.destroy();
this._activeOptionChanges.unsubscribe();
this._animationDone.complete();
}

/**
Expand All @@ -322,7 +355,7 @@ export abstract class _MatAutocompleteBase
}

/** Emits the `select` event. */
_emitSelectEvent(option: _MatOptionBase): void {
_emitSelectEvent(option: MatOption): void {
const event = new MatAutocompleteSelectedEvent(this, option);
this.optionSelected.emit(event);
}
Expand Down Expand Up @@ -350,61 +383,6 @@ export abstract class _MatAutocompleteBase
classList['mat-accent'] = this._color === 'accent';
}

protected _skipPredicate(option: _MatOptionBase) {
return option.disabled;
}
}

@Component({
selector: 'mat-autocomplete',
templateUrl: 'autocomplete.html',
styleUrls: ['autocomplete.css'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'matAutocomplete',
inputs: ['disableRipple'],
host: {
'class': 'mat-mdc-autocomplete',
'ngSkipHydration': '',
},
providers: [{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatAutocomplete}],
animations: [panelAnimation],
})
export class MatAutocomplete extends _MatAutocompleteBase implements OnDestroy {
/** Reference to all option groups within the autocomplete. */
@ContentChildren(MAT_OPTGROUP, {descendants: true}) optionGroups: QueryList<MatOptgroup>;
/** Reference to all options within the autocomplete. */
@ContentChildren(MatOption, {descendants: true}) options: QueryList<MatOption>;
protected _visibleClass = 'mat-mdc-autocomplete-visible';
protected _hiddenClass = 'mat-mdc-autocomplete-hidden';
override _animationDone = new EventEmitter<AnimationEvent>();

/** Whether checkmark indicator for single-selection options is hidden. */
@Input()
get hideSingleSelectionIndicator(): boolean {
return this._hideSingleSelectionIndicator;
}
set hideSingleSelectionIndicator(value: BooleanInput) {
this._hideSingleSelectionIndicator = coerceBooleanProperty(value);
this._syncParentProperties();
}
private _hideSingleSelectionIndicator: boolean =
this._defaults.hideSingleSelectionIndicator ?? false;

/** Syncs the parent state with the individual options. */
_syncParentProperties(): void {
if (this.options) {
for (const option of this.options) {
option._changeDetectorRef.markForCheck();
}
}
}

override ngOnDestroy(): void {
super.ngOnDestroy();
this._animationDone.complete();
}

// `skipPredicate` determines if key manager should avoid putting a given option in the tab
// order. Allow disabled list items to receive focus via keyboard to align with WAI ARIA
// recommendation.
Expand All @@ -419,7 +397,7 @@ export class MatAutocomplete extends _MatAutocompleteBase implements OnDestroy {
//
// The user can focus disabled options using the keyboard, but the user cannot click disabled
// options.
protected override _skipPredicate(_option: _MatOptionBase) {
protected _skipPredicate() {
return false;
}
}
Loading

0 comments on commit 55f9618

Please sign in to comment.