Skip to content

Commit

Permalink
fix(material/core): remove base classes
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewseguin committed Aug 11, 2023
1 parent efb8591 commit 99d034e
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 80 deletions.
8 changes: 4 additions & 4 deletions src/material/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ 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';
Expand Down Expand Up @@ -162,7 +162,7 @@ export class MatAutocompleteTrigger
* 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 Down Expand Up @@ -374,7 +374,7 @@ export class MatAutocompleteTrigger
}) 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 @@ -689,7 +689,7 @@ export class MatAutocompleteTrigger
/**
* 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
2 changes: 1 addition & 1 deletion src/material/autocomplete/testing/autocomplete-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@angular/material/core/testing';
import {AutocompleteHarnessFilters} from './autocomplete-harness-filters';

export abstract class MatAutocompleteHarness extends ComponentHarness {
export class MatAutocompleteHarness extends ComponentHarness {
private _documentRootLocator = this.documentRootLocatorFactory();

/** The selector for the host element of a `MatAutocomplete` instance. */
Expand Down
34 changes: 15 additions & 19 deletions src/material/core/option/optgroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
Inject,
Optional,
InjectionToken,
Directive,
} from '@angular/core';
import {CanDisable, mixinDisabled} from '../common-behaviors/disabled';
import {MatOptionParentComponent, MAT_OPTION_PARENT_COMPONENT} from './option-parent';
Expand Down Expand Up @@ -46,23 +45,6 @@ const _MatOptgroupMixinBase = mixinDisabled(class {});
// Counter for unique group ids.
let _uniqueOptgroupIdCounter = 0;

@Directive()
export class _MatOptgroupBase extends _MatOptgroupMixinBase implements CanDisable {
/** Label for the option group. */
@Input() label: string;

/** Unique id for the underlying label. */
_labelId: string = `mat-optgroup-label-${_uniqueOptgroupIdCounter++}`;

/** Whether the group is in inert a11y mode. */
_inert: boolean;

constructor(@Inject(MAT_OPTION_PARENT_COMPONENT) @Optional() parent?: MatOptionParentComponent) {
super();
this._inert = parent?.inertGroups ?? false;
}
}

/**
* Injection token that can be used to reference instances of `MatOptgroup`. It serves as
* alternative token to the actual `MatOptgroup` class which could cause unnecessary
Expand All @@ -89,4 +71,18 @@ export const MAT_OPTGROUP = new InjectionToken<MatOptgroup>('MatOptgroup');
},
providers: [{provide: MAT_OPTGROUP, useExisting: MatOptgroup}],
})
export class MatOptgroup extends _MatOptgroupBase {}
export class MatOptgroup extends _MatOptgroupMixinBase implements CanDisable {
/** Label for the option group. */
@Input() label: string;

/** Unique id for the underlying label. */
_labelId: string = `mat-optgroup-label-${_uniqueOptgroupIdCounter++}`;

/** Whether the group is in inert a11y mode. */
_inert: boolean;

constructor(@Inject(MAT_OPTION_PARENT_COMPONENT) @Optional() parent?: MatOptionParentComponent) {
super();
this._inert = parent?.inertGroups ?? false;
}
}
89 changes: 38 additions & 51 deletions src/material/core/option/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
ChangeDetectorRef,
Optional,
Inject,
Directive,
AfterViewChecked,
OnDestroy,
Input,
Expand All @@ -27,7 +26,7 @@ import {
ViewChild,
} from '@angular/core';
import {Subject} from 'rxjs';
import {MatOptgroup, MAT_OPTGROUP, _MatOptgroupBase} from './optgroup';
import {MAT_OPTGROUP, MatOptgroup} from './optgroup';
import {MatOptionParentComponent, MAT_OPTION_PARENT_COMPONENT} from './option-parent';

/**
Expand All @@ -40,14 +39,46 @@ let _uniqueIdCounter = 0;
export class MatOptionSelectionChange<T = any> {
constructor(
/** Reference to the option that emitted the event. */
public source: _MatOptionBase<T>,
public source: MatOption<T>,
/** Whether the change in the option's value was a result of a user action. */
public isUserInput = false,
) {}
}

@Directive()
export class _MatOptionBase<T = any> implements FocusableOption, AfterViewChecked, OnDestroy {
/**
* Single option inside of a `<mat-select>` element.
*/
@Component({
selector: 'mat-option',
exportAs: 'matOption',
host: {
'role': 'option',
'[class.mdc-list-item--selected]': 'selected',
'[class.mat-mdc-option-multiple]': 'multiple',
'[class.mat-mdc-option-active]': 'active',
'[class.mdc-list-item--disabled]': 'disabled',
'[id]': 'id',
// Set aria-selected to false for non-selected items and true for selected items. Conform to
// [WAI ARIA Listbox authoring practices guide](
// https://www.w3.org/WAI/ARIA/apg/patterns/listbox/), "If any options are selected, each
// selected option has either aria-selected or aria-checked set to true. All options that are
// selectable but not selected have either aria-selected or aria-checked set to false." Align
// aria-selected implementation of Chips and List components.
//
// Set `aria-selected="false"` on not-selected listbox options to fix VoiceOver announcing
// every option as "selected" (#21491).
'[attr.aria-selected]': 'selected',
'[attr.aria-disabled]': 'disabled.toString()',
'(click)': '_selectViaInteraction()',
'(keydown)': '_handleKeydown($event)',
'class': 'mat-mdc-option mdc-list-item',
},
styleUrls: ['option.css'],
templateUrl: 'option.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatOption<T = any> implements FocusableOption, AfterViewChecked, OnDestroy {
private _selected = false;
private _active = false;
private _disabled = false;
Expand Down Expand Up @@ -101,8 +132,8 @@ export class _MatOptionBase<T = any> implements FocusableOption, AfterViewChecke
constructor(
private _element: ElementRef<HTMLElement>,
public _changeDetectorRef: ChangeDetectorRef,
private _parent: MatOptionParentComponent,
readonly group: _MatOptgroupBase,
@Optional() @Inject(MAT_OPTION_PARENT_COMPONENT) private _parent: MatOptionParentComponent,
@Optional() @Inject(MAT_OPTGROUP) public group: MatOptgroup,
) {}

/**
Expand Down Expand Up @@ -252,50 +283,6 @@ export class _MatOptionBase<T = any> implements FocusableOption, AfterViewChecke
}
}

/**
* Single option inside of a `<mat-select>` element.
*/
@Component({
selector: 'mat-option',
exportAs: 'matOption',
host: {
'role': 'option',
'[class.mdc-list-item--selected]': 'selected',
'[class.mat-mdc-option-multiple]': 'multiple',
'[class.mat-mdc-option-active]': 'active',
'[class.mdc-list-item--disabled]': 'disabled',
'[id]': 'id',
// Set aria-selected to false for non-selected items and true for selected items. Conform to
// [WAI ARIA Listbox authoring practices guide](
// https://www.w3.org/WAI/ARIA/apg/patterns/listbox/), "If any options are selected, each
// selected option has either aria-selected or aria-checked set to true. All options that are
// selectable but not selected have either aria-selected or aria-checked set to false." Align
// aria-selected implementation of Chips and List components.
//
// Set `aria-selected="false"` on not-selected listbox options to fix VoiceOver announcing
// every option as "selected" (#21491).
'[attr.aria-selected]': 'selected',
'[attr.aria-disabled]': 'disabled.toString()',
'(click)': '_selectViaInteraction()',
'(keydown)': '_handleKeydown($event)',
'class': 'mat-mdc-option mdc-list-item',
},
styleUrls: ['option.css'],
templateUrl: 'option.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatOption<T = any> extends _MatOptionBase<T> {
constructor(
element: ElementRef<HTMLElement>,
changeDetectorRef: ChangeDetectorRef,
@Optional() @Inject(MAT_OPTION_PARENT_COMPONENT) parent: MatOptionParentComponent,
@Optional() @Inject(MAT_OPTGROUP) group: MatOptgroup,
) {
super(element, changeDetectorRef, parent, group);
}
}

/**
* Counts the amount of option group labels that precede the specified option.
* @param optionIndex Index of the option at which to start counting.
Expand Down
2 changes: 1 addition & 1 deletion src/material/form-field/testing/form-field-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type FormFieldControlHarness =
| MatDatepickerInputHarness
| MatDateRangeInputHarness;

export abstract class MatFormFieldHarness extends ComponentHarness {
export class MatFormFieldHarness extends ComponentHarness {
private _prefixContainer = this.locatorForOptional('.mat-mdc-form-field-text-prefix');
private _suffixContainer = this.locatorForOptional('.mat-mdc-form-field-text-suffix');
private _label = this.locatorForOptional('.mdc-floating-label');
Expand Down
5 changes: 2 additions & 3 deletions src/material/menu/testing/menu-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ export class MatMenuItemHarness extends ContentContainerComponentHarness<string>
async (harness, hasSubmenu) => (await harness.hasSubmenu()) === hasSubmenu,
);
}
protected _menuClass: typeof MatMenuHarness;

/** Whether the menu is disabled. */
async isDisabled(): Promise<boolean> {
Expand Down Expand Up @@ -213,13 +212,13 @@ export class MatMenuItemHarness extends ContentContainerComponentHarness<string>

/** Whether this item has a submenu. */
async hasSubmenu(): Promise<boolean> {
return (await this.host()).matchesSelector(this._menuClass.hostSelector);
return (await this.host()).matchesSelector(MatMenuHarness.hostSelector);
}

/** Gets the submenu associated with this menu item, or null if none. */
async getSubmenu(): Promise<MatMenuHarness | null> {
if (await this.hasSubmenu()) {
return new this._menuClass(this.locatorFactory);
return new MatMenuHarness(this.locatorFactory);
}
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/material/table/testing/table-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface MatTableHarnessColumnsText {
}

/** Harness for interacting with a mat-table in tests. */
export abstract class MatTableHarness extends ContentContainerComponentHarness<string> {
export class MatTableHarness extends ContentContainerComponentHarness<string> {
/** The selector for the host element of a `MatTableHarness` instance. */
static hostSelector = '.mat-mdc-table';
private _headerRowHarness = MatHeaderRowHarness;
Expand Down

0 comments on commit 99d034e

Please sign in to comment.