diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c39e11661f98..64630df574c5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,6 @@ # Angular Material components /src/material/* @andrewseguin -/src/material/autocomplete/** @crisbeto +/src/material/legacy-autocomplete/** @crisbeto /src/material/badge/** @jelbourn /src/material/bottom-sheet/** @jelbourn @crisbeto /src/material/button-toggle/** @andrewseguin @@ -110,7 +110,7 @@ # Material experimental package /src/material-experimental/* @andrewseguin /src/material-experimental/column-resize/** @andrewseguin -/src/material-experimental/mdc-autocomplete/** @crisbeto +/src/material/autocomplete/** @crisbeto /src/material-experimental/mdc-button/** @andrewseguin /src/material/card/** @mmalerba /src/material-experimental/mdc-checkbox/** @mmalerba diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index bf2a8bfd5f3f..1477686e5b5b 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -40,7 +40,6 @@ export const commitMessage: CommitMessageConfig = { 'cdk/tree', 'google-maps', 'material-experimental/column-resize', - 'material-experimental/mdc-autocomplete', 'material-experimental/mdc-button', 'material/card', 'material-experimental/mdc-checkbox', @@ -68,6 +67,7 @@ export const commitMessage: CommitMessageConfig = { 'material-date-fns-adapter', 'material-luxon-adapter', 'material/autocomplete', + 'material/legacy-autocomplete', 'material/badge', 'material/bottom-sheet', 'material/button', diff --git a/integration/size-test/material/autocomplete/BUILD.bazel b/integration/size-test/material/autocomplete/BUILD.bazel index 1deede624097..c52ba4f38263 100644 --- a/integration/size-test/material/autocomplete/BUILD.bazel +++ b/integration/size-test/material/autocomplete/BUILD.bazel @@ -3,5 +3,5 @@ load("//integration/size-test:index.bzl", "size_test") size_test( name = "without-optgroup", file = "without-optgroup.ts", - deps = ["//src/material/autocomplete"], + deps = ["//src/material/legacy-autocomplete"], ) diff --git a/integration/size-test/material/autocomplete/without-optgroup.ts b/integration/size-test/material/autocomplete/without-optgroup.ts index f439047dc847..1fd66fda5730 100644 --- a/integration/size-test/material/autocomplete/without-optgroup.ts +++ b/integration/size-test/material/autocomplete/without-optgroup.ts @@ -1,5 +1,5 @@ import {Component, NgModule} from '@angular/core'; -import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatLegacyAutocompleteModule} from '@angular/material/legacy-autocomplete'; /** * Basic component using `MatAutocomplete` and `MatOption`. Other supported parts of the @@ -16,7 +16,7 @@ import {MatAutocompleteModule} from '@angular/material/autocomplete'; export class TestComponent {} @NgModule({ - imports: [MatAutocompleteModule], + imports: [MatLegacyAutocompleteModule], declarations: [TestComponent], bootstrap: [TestComponent], }) diff --git a/src/components-examples/material/autocomplete/BUILD.bazel b/src/components-examples/material/autocomplete/BUILD.bazel index c10db0919759..e29af751ecff 100644 --- a/src/components-examples/material/autocomplete/BUILD.bazel +++ b/src/components-examples/material/autocomplete/BUILD.bazel @@ -16,8 +16,8 @@ ng_module( "//src/cdk/overlay", "//src/cdk/testing", "//src/cdk/testing/testbed", - "//src/material/autocomplete", - "//src/material/autocomplete/testing", + "//src/material/legacy-autocomplete", + "//src/material/legacy-autocomplete/testing", "//src/material/legacy-form-field", "//src/material/legacy-input", "//src/material/slide-toggle", @@ -44,8 +44,8 @@ ng_test_library( ":autocomplete", "//src/cdk/testing", "//src/cdk/testing/testbed", - "//src/material/autocomplete", - "//src/material/autocomplete/testing", + "//src/material/legacy-autocomplete", + "//src/material/legacy-autocomplete/testing", "@npm//@angular/platform-browser-dynamic", ], ) diff --git a/src/components-examples/material/autocomplete/autocomplete-harness/autocomplete-harness-example.spec.ts b/src/components-examples/material/autocomplete/autocomplete-harness/autocomplete-harness-example.spec.ts index 69cdfb434b53..74fb80cd7520 100644 --- a/src/components-examples/material/autocomplete/autocomplete-harness/autocomplete-harness-example.spec.ts +++ b/src/components-examples/material/autocomplete/autocomplete-harness/autocomplete-harness-example.spec.ts @@ -1,8 +1,8 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; -import {MatAutocompleteHarness} from '@angular/material/autocomplete/testing'; +import {MatLegacyAutocompleteHarness} from '@angular/material/legacy-autocomplete/testing'; import {HarnessLoader} from '@angular/cdk/testing'; -import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatLegacyAutocompleteModule} from '@angular/material/legacy-autocomplete'; import {AutocompleteHarnessExample} from './autocomplete-harness-example'; describe('AutocompleteHarnessExample', () => { @@ -11,7 +11,7 @@ describe('AutocompleteHarnessExample', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatAutocompleteModule], + imports: [MatLegacyAutocompleteModule], declarations: [AutocompleteHarnessExample], }).compileComponents(); fixture = TestBed.createComponent(AutocompleteHarnessExample); @@ -20,20 +20,24 @@ describe('AutocompleteHarnessExample', () => { }); it('should load all autocomplete harnesses', async () => { - const autocompletes = await loader.getAllHarnesses(MatAutocompleteHarness); + const autocompletes = await loader.getAllHarnesses(MatLegacyAutocompleteHarness); expect(autocompletes.length).toBe(2); }); it('should get disabled state', async () => { - const enabled = await loader.getHarness(MatAutocompleteHarness.with({selector: '#plain'})); - const disabled = await loader.getHarness(MatAutocompleteHarness.with({selector: '#disabled'})); + const enabled = await loader.getHarness( + MatLegacyAutocompleteHarness.with({selector: '#plain'}), + ); + const disabled = await loader.getHarness( + MatLegacyAutocompleteHarness.with({selector: '#disabled'}), + ); expect(await enabled.isDisabled()).toBe(false); expect(await disabled.isDisabled()).toBe(true); }); it('should focus and blur an input', async () => { - const input = await loader.getHarness(MatAutocompleteHarness.with({selector: '#plain'})); + const input = await loader.getHarness(MatLegacyAutocompleteHarness.with({selector: '#plain'})); expect(await input.isFocused()).toBe(false); await input.focus(); expect(await input.isFocused()).toBe(true); @@ -42,13 +46,13 @@ describe('AutocompleteHarnessExample', () => { }); it('should be able to type in an input', async () => { - const input = await loader.getHarness(MatAutocompleteHarness.with({selector: '#plain'})); + const input = await loader.getHarness(MatLegacyAutocompleteHarness.with({selector: '#plain'})); await input.enterText('Hello there'); expect(await input.getValue()).toBe('Hello there'); }); it('should be able to get filtered options', async () => { - const input = await loader.getHarness(MatAutocompleteHarness.with({selector: '#plain'})); + const input = await loader.getHarness(MatLegacyAutocompleteHarness.with({selector: '#plain'})); await input.focus(); const options = await input.getOptions({text: /New/}); diff --git a/src/components-examples/material/autocomplete/index.ts b/src/components-examples/material/autocomplete/index.ts index e23d0b99d436..0b235db1cb99 100644 --- a/src/components-examples/material/autocomplete/index.ts +++ b/src/components-examples/material/autocomplete/index.ts @@ -1,7 +1,7 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; -import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatLegacyAutocompleteModule} from '@angular/material/legacy-autocomplete'; import {MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; import {MatLegacyInputModule} from '@angular/material/legacy-input'; import {MatSlideToggleModule} from '@angular/material/slide-toggle'; @@ -39,7 +39,7 @@ const EXAMPLES = [ @NgModule({ imports: [ CommonModule, - MatAutocompleteModule, + MatLegacyAutocompleteModule, MatLegacyFormFieldModule, MatLegacyInputModule, MatSlideToggleModule, diff --git a/src/components-examples/material/chips/BUILD.bazel b/src/components-examples/material/chips/BUILD.bazel index e5b9ed325f29..36f26f2a69c5 100644 --- a/src/components-examples/material/chips/BUILD.bazel +++ b/src/components-examples/material/chips/BUILD.bazel @@ -16,11 +16,11 @@ ng_module( "//src/cdk/drag-drop", "//src/cdk/testing", "//src/cdk/testing/testbed", - "//src/material/autocomplete", "//src/material/button", "//src/material/chips", "//src/material/chips/testing", "//src/material/icon", + "//src/material/legacy-autocomplete", "//src/material/legacy-form-field", "@npm//@angular/forms", "@npm//@angular/platform-browser", diff --git a/src/components-examples/material/chips/chips-autocomplete/chips-autocomplete-example.ts b/src/components-examples/material/chips/chips-autocomplete/chips-autocomplete-example.ts index c9a62b023165..1e6523d6a536 100644 --- a/src/components-examples/material/chips/chips-autocomplete/chips-autocomplete-example.ts +++ b/src/components-examples/material/chips/chips-autocomplete/chips-autocomplete-example.ts @@ -1,7 +1,7 @@ import {COMMA, ENTER} from '@angular/cdk/keycodes'; import {Component, ElementRef, ViewChild} from '@angular/core'; import {FormControl} from '@angular/forms'; -import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {MatAutocompleteSelectedEvent} from '@angular/material/legacy-autocomplete'; import {MatChipInputEvent} from '@angular/material/chips'; import {Observable} from 'rxjs'; import {map, startWith} from 'rxjs/operators'; diff --git a/src/components-examples/material/chips/index.ts b/src/components-examples/material/chips/index.ts index 6aed9792f48a..535101bf92d7 100644 --- a/src/components-examples/material/chips/index.ts +++ b/src/components-examples/material/chips/index.ts @@ -2,7 +2,7 @@ import {DragDropModule} from '@angular/cdk/drag-drop'; import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {ReactiveFormsModule} from '@angular/forms'; -import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatLegacyAutocompleteModule} from '@angular/material/legacy-autocomplete'; import {MatChipsModule} from '@angular/material/chips'; import {MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; import {MatIconModule} from '@angular/material/icon'; @@ -42,7 +42,7 @@ const EXAMPLES = [ imports: [ CommonModule, DragDropModule, - MatAutocompleteModule, + MatLegacyAutocompleteModule, MatButtonModule, MatChipsModule, MatIconModule, diff --git a/src/dev-app/autocomplete/BUILD.bazel b/src/dev-app/autocomplete/BUILD.bazel index b0615f9f28ca..47e732fd6ddd 100644 --- a/src/dev-app/autocomplete/BUILD.bazel +++ b/src/dev-app/autocomplete/BUILD.bazel @@ -10,8 +10,8 @@ ng_module( ":autocomplete_demo_scss", ], deps = [ - "//src/material/autocomplete", "//src/material/button", + "//src/material/legacy-autocomplete", "//src/material/legacy-card", "//src/material/legacy-form-field", "//src/material/legacy-input", diff --git a/src/dev-app/autocomplete/autocomplete-demo.ts b/src/dev-app/autocomplete/autocomplete-demo.ts index 9ed44e70de8a..67c8c13f92eb 100644 --- a/src/dev-app/autocomplete/autocomplete-demo.ts +++ b/src/dev-app/autocomplete/autocomplete-demo.ts @@ -9,7 +9,7 @@ import {Component, ViewChild} from '@angular/core'; import {CommonModule} from '@angular/common'; import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms'; -import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatLegacyAutocompleteModule} from '@angular/material/legacy-autocomplete'; import {MatButtonModule} from '@angular/material/button'; import {MatLegacyCardModule} from '@angular/material/legacy-card'; import {MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; @@ -35,7 +35,7 @@ export interface StateGroup { imports: [ CommonModule, FormsModule, - MatAutocompleteModule, + MatLegacyAutocompleteModule, MatButtonModule, MatLegacyCardModule, MatLegacyFormFieldModule, diff --git a/src/dev-app/mdc-autocomplete/BUILD.bazel b/src/dev-app/mdc-autocomplete/BUILD.bazel index 1b7de485b782..ed00daed99ee 100644 --- a/src/dev-app/mdc-autocomplete/BUILD.bazel +++ b/src/dev-app/mdc-autocomplete/BUILD.bazel @@ -10,8 +10,8 @@ ng_module( ":mdc_autocomplete_demo_scss", ], deps = [ - "//src/material-experimental/mdc-autocomplete", "//src/material-experimental/mdc-button", + "//src/material/autocomplete", "//src/material/card", "//src/material/form-field", "//src/material/input", diff --git a/src/dev-app/mdc-autocomplete/mdc-autocomplete-demo.ts b/src/dev-app/mdc-autocomplete/mdc-autocomplete-demo.ts index 968bc041404e..1092f7fa1687 100644 --- a/src/dev-app/mdc-autocomplete/mdc-autocomplete-demo.ts +++ b/src/dev-app/mdc-autocomplete/mdc-autocomplete-demo.ts @@ -9,7 +9,7 @@ import {Component, ViewChild} from '@angular/core'; import {FormControl, NgModel, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {CommonModule} from '@angular/common'; -import {MatAutocompleteModule} from '@angular/material-experimental/mdc-autocomplete'; +import {MatAutocompleteModule} from '@angular/material/autocomplete'; import {MatButtonModule} from '@angular/material-experimental/mdc-button'; import {MatCardModule} from '@angular/material/card'; import {MatInputModule} from '@angular/material/input'; diff --git a/src/dev-app/mdc-input/BUILD.bazel b/src/dev-app/mdc-input/BUILD.bazel index 488db769e29e..4693a72efc97 100644 --- a/src/dev-app/mdc-input/BUILD.bazel +++ b/src/dev-app/mdc-input/BUILD.bazel @@ -11,10 +11,10 @@ ng_module( ], deps = [ "//src/components-examples/material-experimental/mdc-form-field", - "//src/material-experimental/mdc-autocomplete", "//src/material-experimental/mdc-button", "//src/material-experimental/mdc-checkbox", "//src/material-experimental/mdc-tabs", + "//src/material/autocomplete", "//src/material/button-toggle", "//src/material/card", "//src/material/form-field", diff --git a/src/dev-app/mdc-input/mdc-input-demo.ts b/src/dev-app/mdc-input/mdc-input-demo.ts index 97264e909679..96103ea7f166 100644 --- a/src/dev-app/mdc-input/mdc-input-demo.ts +++ b/src/dev-app/mdc-input/mdc-input-demo.ts @@ -17,7 +17,7 @@ import {ErrorStateMatcher, ThemePalette} from '@angular/material/core'; import {CommonModule} from '@angular/common'; import {MdcFormFieldExamplesModule} from '@angular/components-examples/material-experimental/mdc-form-field'; import {MatInputModule} from '@angular/material/input'; -import {MatAutocompleteModule} from '@angular/material-experimental/mdc-autocomplete'; +import {MatAutocompleteModule} from '@angular/material/autocomplete'; import {MatButtonModule} from '@angular/material-experimental/mdc-button'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; import {MatCardModule} from '@angular/material/card'; diff --git a/src/material-experimental/_index.scss b/src/material-experimental/_index.scss index 8faab20ba91d..b7efd255225b 100644 --- a/src/material-experimental/_index.scss +++ b/src/material-experimental/_index.scss @@ -17,8 +17,6 @@ // MDC-related themes @forward './mdc-core/core-theme' as mdc-core-* show mdc-core-theme, mdc-core-color, mdc-core-density, mdc-core-typography; -@forward './mdc-autocomplete/autocomplete-theme' as mdc-autocomplete-* show mdc-autocomplete-color, - mdc-autocomplete-typography, mdc-autocomplete-density, mdc-autocomplete-theme; @forward './mdc-button/button-theme' as mdc-button-* show mdc-button-color, mdc-button-typography, mdc-button-density, mdc-button-theme; @forward './mdc-button/fab-theme' as mdc-fab-* show mdc-fab-color, mdc-fab-typography, diff --git a/src/material-experimental/config.bzl b/src/material-experimental/config.bzl index 7fb75ca0e7aa..bcb1b860177d 100644 --- a/src/material-experimental/config.bzl +++ b/src/material-experimental/config.bzl @@ -1,7 +1,5 @@ entryPoints = [ "column-resize", - "mdc-autocomplete", - "mdc-autocomplete/testing", "mdc-button", "mdc-button/testing", "mdc-checkbox", diff --git a/src/material-experimental/mdc-autocomplete/BUILD.bazel b/src/material-experimental/mdc-autocomplete/BUILD.bazel deleted file mode 100644 index 8e9ad76fe6dc..000000000000 --- a/src/material-experimental/mdc-autocomplete/BUILD.bazel +++ /dev/null @@ -1,75 +0,0 @@ -load("//tools:defaults.bzl", "ng_module", "ng_test_library", "ng_web_test_suite", "sass_binary", "sass_library") - -package(default_visibility = ["//visibility:public"]) - -ng_module( - name = "mdc-autocomplete", - srcs = glob( - ["**/*.ts"], - exclude = [ - "**/*.spec.ts", - ], - ), - assets = [ - ":autocomplete_scss", - ] + glob(["**/*.html"]), - deps = [ - "//src/cdk/overlay", - "//src/cdk/scrolling", - "//src/material/autocomplete", - "//src/material/core", - "@npm//@angular/common", - ], -) - -sass_library( - name = "mdc_autocomplete_scss_lib", - srcs = glob(["**/_*.scss"]), - deps = [ - "//:mdc_sass_lib", - "//src/material:sass_lib", - "//src/material/core:core_scss_lib", - ], -) - -sass_binary( - name = "autocomplete_scss", - src = "autocomplete.scss", - deps = [ - "//:mdc_sass_lib", - "//src/cdk:sass_lib", - "//src/material/core:core_scss_lib", - ], -) - -ng_test_library( - name = "mdc_autocomplete_tests_lib", - srcs = glob( - ["**/*.spec.ts"], - exclude = [ - "**/*.e2e.spec.ts", - ], - ), - deps = [ - ":mdc-autocomplete", - "//src/cdk/bidi", - "//src/cdk/keycodes", - "//src/cdk/overlay", - "//src/cdk/platform", - "//src/cdk/scrolling", - "//src/cdk/testing/private", - "//src/material/core", - "//src/material/form-field", - "//src/material/input", - "@npm//@angular/forms", - "@npm//@angular/platform-browser", - "@npm//rxjs", - ], -) - -ng_web_test_suite( - name = "unit_tests", - deps = [ - ":mdc_autocomplete_tests_lib", - ], -) diff --git a/src/material-experimental/mdc-autocomplete/README.md b/src/material-experimental/mdc-autocomplete/README.md deleted file mode 100644 index 632899785968..000000000000 --- a/src/material-experimental/mdc-autocomplete/README.md +++ /dev/null @@ -1,98 +0,0 @@ -This is prototype of an alternate version of `` built on top of -[MDC Web](https://github.com/material-components/material-components-web). It demonstrates how -Angular Material could use MDC Web under the hood while still exposing the same API Angular users as -the existing ``. This component is experimental and should not be used in production. - -## How to use -Assuming your application is already up and running using Angular Material, you can add this -component by following these steps: - -1. Install Angular Material Experimental & MDC WEB: - - ```bash - npm i material-components-web @angular/material-experimental - ``` - -2. In your `angular.json`, make sure `node_modules/` is listed as a Sass include path. This is - needed for the Sass compiler to be able to find the MDC Web Sass files. - - ```json - ... - "styles": [ - "src/styles.scss" - ], - "stylePreprocessorOptions": { - "includePaths": [ - "node_modules/" - ] - }, - ... - ``` - -3. Import the experimental `MatAutocompleteModule` and add it to the module that declares your - component: - - ```ts - import {MatAutocompleteModule} from '@angular/material-experimental/mdc-autocomplete'; - - @NgModule({ - declarations: [MyComponent], - imports: [MatAutocompleteModule], - }) - export class MyModule {} - ``` - -4. Add use `` in your component's template, just like you would the normal - ``: - - ```html - - - Option 1 - Option 2 - - ``` - -5. Add the theme and typography mixins to your Sass. (There is currently no pre-built CSS option for - the experimental ``): - - ```scss - @use '@angular/material' as mat; - @use '@angular/material-experimental' as mat-experimental; - - $my-primary: mat.define-palette(mat.$indigo-palette); - $my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); - $my-theme: mat.define-light-theme(( - color: ( - primary: $my-primary, - accent: $my-accent - ) - )); - - @include mat-experimental.mdc-autocomplete-theme($my-theme); - @include mat-experimental.mdc-autocomplete-typography($my-theme); - ``` - -## API differences -The experimental autocomplete API closely matches the -[API of the standard autocomplete](https://material.angular.io/components/autocomplete/api). -`@angular/material-experimental/mdc-autocomplete` exports symbols with the same name and public -interface as all of the symbols found under `@angular/material/autocomplete` - -## Replacing the standard autocomplete in an existing app -Because the experimental API mirrors the API for the standard autocomplete, it can easily be swapped -in by just changing the import paths. There is currently no schematic for this, but you can run the -following string replace across your TypeScript files: - -```bash -grep -lr --include="*.ts" --exclude-dir="node_modules" \ - --exclude="*.d.ts" "['\"]@angular/material/autocomplete['\"]" | xargs sed -i \ - "s/['\"]@angular\/material\/autocomplete['\"]/'@angular\/material-experimental\/mdc-autocomplete'/g" -``` - -CSS styles and tests that depend on implementation details of `mat-autocomplete` (such as getting -elements from the template by class name) will need to be manually updated. - -There are some small visual differences between this autocomplete and the standard one. This -autocomplete has a different font size and elevation `box-shadow`, as well as padding at the top -and bottom of the list. diff --git a/src/material-experimental/mdc-autocomplete/_autocomplete-theme.import.scss b/src/material-experimental/mdc-autocomplete/_autocomplete-theme.import.scss deleted file mode 100644 index a56d6566e3f3..000000000000 --- a/src/material-experimental/mdc-autocomplete/_autocomplete-theme.import.scss +++ /dev/null @@ -1 +0,0 @@ -@forward 'autocomplete-theme' as mat-mdc-autocomplete-*; diff --git a/src/material-experimental/mdc-autocomplete/_autocomplete-theme.scss b/src/material-experimental/mdc-autocomplete/_autocomplete-theme.scss deleted file mode 100644 index 2c1769f2efda..000000000000 --- a/src/material-experimental/mdc-autocomplete/_autocomplete-theme.scss +++ /dev/null @@ -1,46 +0,0 @@ -@use '@angular/material' as mat; -@use '@material/menu-surface/mixins' as mdc-menu-surface; -@use '@material/list/evolution-mixins' as mdc-list; - -@mixin color($config-or-theme) { - $config: mat.get-color-config($config-or-theme); - @include mat.private-using-mdc-theme($config) { - @include mdc-menu-surface.core-styles(mat.$private-mdc-theme-styles-query); - @include mdc-list.without-ripple(mat.$private-mdc-theme-styles-query); - } -} - -@mixin typography($config-or-theme) { - $config: mat.private-typography-to-2018-config( - mat.get-typography-config($config-or-theme)); - @include mat.private-using-mdc-typography($config) { - @include mdc-menu-surface.core-styles(mat.$private-mdc-typography-styles-query); - - .mat-mdc-autocomplete-panel { - // Note that we include this private mixin, because the public one adds - // a bunch of styles that we aren't using for the autocomplete panel. - @include mdc-list.list-base(mat.$private-mdc-typography-styles-query); - } - } -} - -@mixin density($config-or-theme) {} - -@mixin theme($theme-or-color-config) { - $theme: mat.private-legacy-get-theme($theme-or-color-config); - @include mat.private-check-duplicate-theme-styles($theme, 'mat-mdc-autocomplete') { - $color: mat.get-color-config($theme); - $density: mat.get-density-config($theme); - $typography: mat.get-typography-config($theme); - - @if $color != null { - @include color($color); - } - @if $density != null { - @include density($density); - } - @if $typography != null { - @include typography($typography); - } - } -} diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.html b/src/material-experimental/mdc-autocomplete/autocomplete.html deleted file mode 100644 index da358691b7b2..000000000000 --- a/src/material-experimental/mdc-autocomplete/autocomplete.html +++ /dev/null @@ -1,13 +0,0 @@ - -
- -
-
diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.scss b/src/material-experimental/mdc-autocomplete/autocomplete.scss deleted file mode 100644 index 70978e4944dc..000000000000 --- a/src/material-experimental/mdc-autocomplete/autocomplete.scss +++ /dev/null @@ -1,49 +0,0 @@ -@use '@angular/cdk'; -@use '@material/menu-surface/mixins' as mdc-menu-surface; -@use '@material/list/evolution-mixins' as mdc-list; - -@include mdc-menu-surface.core-styles($query: structure); - -// Note that the `.mdc-menu-surface` is here in order to bump up the specificity -// and avoid interference with `mat-menu` which uses the same mixins from MDC. -.mdc-menu-surface.mat-mdc-autocomplete-panel { - width: 100%; // Ensures that the panel matches the overlay width. - max-height: 256px; // Prevents lists with a lot of option from growing too high. - position: static; // MDC uses `absolute` by default which will throw off our positioning. - visibility: hidden; - // MDC sets the transform-origin programmatically based on whether the dropdown is above or - // below the input. We use our own positioning logic, so we need to set this ourselves. - transform-origin: center top; - - @include mdc-list.list-base($query: structure); - @include cdk.high-contrast(active, off) { - outline: solid 1px; - } - - .cdk-overlay-pane:not(.mat-mdc-autocomplete-panel-above) & { - border-top-left-radius: 0; - border-top-right-radius: 0; - } - - .mat-mdc-autocomplete-panel-above & { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - // MDC sets the transform-origin programmatically based on whether the dropdown is above or - // below the input. We use our own positioning logic, so we need to set this ourselves. - transform-origin: center bottom; - } - - // These classes are used to toggle the panel visibility depending on whether it has any options. - &.mat-mdc-autocomplete-visible { - visibility: visible; - } - - &.mat-mdc-autocomplete-hidden { - visibility: hidden; - } -} - -// Prevent the overlay host node from affecting its surrounding layout. -mat-autocomplete { - display: none; -} diff --git a/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.spec.ts b/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.spec.ts deleted file mode 100644 index 97b29d77666a..000000000000 --- a/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {MatAutocompleteModule} from '@angular/material-experimental/mdc-autocomplete'; -import {runHarnessTests} from '@angular/material/autocomplete/testing/shared.spec'; -import {MatAutocompleteHarness} from './autocomplete-harness'; - -describe('MDC-based MatAutocompleteHarness', () => { - runHarnessTests(MatAutocompleteModule, MatAutocompleteHarness as any); -}); diff --git a/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.ts b/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.ts deleted file mode 100644 index fde360595f00..000000000000 --- a/src/material-experimental/mdc-autocomplete/testing/autocomplete-harness.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {ComponentHarnessConstructor, HarnessPredicate} from '@angular/cdk/testing'; -import { - MatOptgroupHarness, - MatOptionHarness, - OptgroupHarnessFilters, - OptionHarnessFilters, -} from '@angular/material/core/testing'; -import {_MatAutocompleteHarnessBase} from '@angular/material/autocomplete/testing'; -import {AutocompleteHarnessFilters} from './autocomplete-harness-filters'; - -/** Harness for interacting with an MDC-based mat-autocomplete in tests. */ -export class MatAutocompleteHarness extends _MatAutocompleteHarnessBase< - typeof MatOptionHarness, - MatOptionHarness, - OptionHarnessFilters, - typeof MatOptgroupHarness, - MatOptgroupHarness, - OptgroupHarnessFilters -> { - protected _prefix = 'mat-mdc'; - protected _optionClass = MatOptionHarness; - protected _optionGroupClass = MatOptgroupHarness; - - /** The selector for the host element of a `MatAutocomplete` instance. */ - static hostSelector = '.mat-mdc-autocomplete-trigger'; - - /** - * Gets a `HarnessPredicate` that can be used to search for an autocomplete with specific - * attributes. - * @param options Options for filtering which autocomplete instances are considered a match. - * @return a `HarnessPredicate` configured with the given options. - */ - static with( - this: ComponentHarnessConstructor, - options: AutocompleteHarnessFilters = {}, - ): HarnessPredicate { - return new HarnessPredicate(this, options).addOption('value', options.value, (harness, value) => - HarnessPredicate.stringMatches(harness.getValue(), value), - ); - } -} diff --git a/src/material-experimental/mdc-core/color/_all-color.import.scss b/src/material-experimental/mdc-core/color/_all-color.import.scss index 6227424ff2d6..87235f0f817a 100644 --- a/src/material-experimental/mdc-core/color/_all-color.import.scss +++ b/src/material-experimental/mdc-core/color/_all-color.import.scss @@ -51,7 +51,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-autocomplete/autocomplete-theme' as mat-mdc-autocomplete-*; @forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; diff --git a/src/material-experimental/mdc-core/density/_all-density.import.scss b/src/material-experimental/mdc-core/density/_all-density.import.scss index f33da4d614f3..c804f5a3c815 100644 --- a/src/material-experimental/mdc-core/density/_all-density.import.scss +++ b/src/material-experimental/mdc-core/density/_all-density.import.scss @@ -46,7 +46,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-autocomplete/autocomplete-theme' as mat-mdc-autocomplete-*; @forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; diff --git a/src/material-experimental/mdc-core/theming/BUILD.bazel b/src/material-experimental/mdc-core/theming/BUILD.bazel index 5706b59eaa14..793d8fa06a78 100644 --- a/src/material-experimental/mdc-core/theming/BUILD.bazel +++ b/src/material-experimental/mdc-core/theming/BUILD.bazel @@ -20,7 +20,6 @@ sass_library( ], deps = [ "//src/material:sass_lib", - "//src/material-experimental/mdc-autocomplete:mdc_autocomplete_scss_lib", "//src/material-experimental/mdc-button:mdc_button_scss_lib", "//src/material-experimental/mdc-checkbox:mdc_checkbox_scss_lib", "//src/material-experimental/mdc-chips:mdc_chips_scss_lib", @@ -36,6 +35,7 @@ sass_library( "//src/material-experimental/mdc-snack-bar:mdc_snack_bar_scss_lib", "//src/material-experimental/mdc-table:mdc_table_scss_lib", "//src/material-experimental/mdc-tabs:mdc_tabs_scss_lib", + "//src/material/autocomplete:autocomplete_scss_lib", "//src/material/card:card_scss_lib", "//src/material/form-field:form_field_scss_lib", "//src/material/input:input_scss_lib", diff --git a/src/material-experimental/mdc-core/theming/_all-theme.import.scss b/src/material-experimental/mdc-core/theming/_all-theme.import.scss index e2a37ac84b87..d92dcbe0697d 100644 --- a/src/material-experimental/mdc-core/theming/_all-theme.import.scss +++ b/src/material-experimental/mdc-core/theming/_all-theme.import.scss @@ -46,7 +46,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-autocomplete/autocomplete-theme' as mat-mdc-autocomplete-*; @forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; @@ -57,7 +56,6 @@ $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table- @forward 'all-theme' hide all-mdc-component-themes;; @import '../core-theme'; -@import '../../mdc-autocomplete/autocomplete-theme'; @import '../../mdc-button/button-theme'; @import '../../mdc-checkbox/checkbox-theme'; @import '../../mdc-chips/chips-theme'; diff --git a/src/material-experimental/mdc-core/theming/_all-theme.scss b/src/material-experimental/mdc-core/theming/_all-theme.scss index 7add7f13ce86..a9da3af9c36a 100644 --- a/src/material-experimental/mdc-core/theming/_all-theme.scss +++ b/src/material-experimental/mdc-core/theming/_all-theme.scss @@ -1,7 +1,6 @@ @use '@angular/material' as mat; @use '../core-theme'; -@use '../../mdc-autocomplete/autocomplete-theme'; @use '../../mdc-button/button-theme'; @use '../../mdc-button/fab-theme'; @use '../../mdc-button/icon-button-theme'; @@ -23,7 +22,7 @@ $dedupe-key: 'angular-material-mdc-theme'; @include mat.private-check-duplicate-theme-styles($theme-or-color-config, $dedupe-key) { @include core-theme.theme($theme-or-color-config); - @include autocomplete-theme.theme($theme-or-color-config); + @include mat.autocomplete-theme($theme-or-color-config); @include button-theme.theme($theme-or-color-config); @include dialog-theme.theme($theme-or-color-config); @include fab-theme.theme($theme-or-color-config); diff --git a/src/material-experimental/mdc-core/typography/_all-typography.import.scss b/src/material-experimental/mdc-core/typography/_all-typography.import.scss index 517976c883e2..4379f851e484 100644 --- a/src/material-experimental/mdc-core/typography/_all-typography.import.scss +++ b/src/material-experimental/mdc-core/typography/_all-typography.import.scss @@ -46,7 +46,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-autocomplete/autocomplete-theme' as mat-mdc-autocomplete-*; @forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; diff --git a/src/material/_index.scss b/src/material/_index.scss index f5f5544d387e..dc44a64f430a 100644 --- a/src/material/_index.scss +++ b/src/material/_index.scss @@ -74,6 +74,8 @@ strong-focus-indicators-color, strong-focus-indicators-theme; @forward './autocomplete/autocomplete-theme' as autocomplete-* show autocomplete-theme, autocomplete-color, autocomplete-typography; +@forward './legacy-autocomplete/autocomplete-theme' as legacy-autocomplete-* show + legacy-autocomplete-theme, legacy-autocomplete-color, legacy-autocomplete-typography; @forward './badge/badge-theme' as badge-* show badge-theme, badge-color, badge-typography; @forward './bottom-sheet/bottom-sheet-theme' as bottom-sheet-* show bottom-sheet-theme, bottom-sheet-color, bottom-sheet-typography; diff --git a/src/material/autocomplete/BUILD.bazel b/src/material/autocomplete/BUILD.bazel index 108d83ba4234..ebd6c1090507 100644 --- a/src/material/autocomplete/BUILD.bazel +++ b/src/material/autocomplete/BUILD.bazel @@ -1,12 +1,4 @@ -load( - "//tools:defaults.bzl", - "markdown_to_html", - "ng_module", - "ng_test_library", - "ng_web_test_suite", - "sass_binary", - "sass_library", -) +load("//tools:defaults.bzl", "markdown_to_html", "ng_module", "ng_test_library", "ng_web_test_suite", "sass_binary", "sass_library") package(default_visibility = ["//visibility:public"]) @@ -14,49 +6,47 @@ ng_module( name = "autocomplete", srcs = glob( ["**/*.ts"], - exclude = ["**/*.spec.ts"], + exclude = [ + "**/*.spec.ts", + ], ), - assets = [":autocomplete.css"] + glob(["**/*.html"]), + assets = [ + ":autocomplete_scss", + ] + glob(["**/*.html"]), deps = [ - "//src:dev_mode_types", - "//src/cdk/a11y", - "//src/cdk/bidi", "//src/cdk/coercion", - "//src/cdk/keycodes", "//src/cdk/overlay", - "//src/cdk/platform", - "//src/cdk/portal", "//src/cdk/scrolling", "//src/material/core", - "//src/material/legacy-core", - "//src/material/legacy-form-field", + "//src/material/form-field", "@npm//@angular/common", - "@npm//@angular/core", - "@npm//@angular/forms", - "@npm//rxjs", ], ) sass_library( name = "autocomplete_scss_lib", srcs = glob(["**/_*.scss"]), - deps = ["//src/material/core:core_scss_lib"], + deps = [ + "//:mdc_sass_lib", + ], ) sass_binary( name = "autocomplete_scss", src = "autocomplete.scss", deps = [ + "//:mdc_sass_lib", "//src/cdk:sass_lib", - "//src/material/core:core_scss_lib", ], ) ng_test_library( - name = "unit_test_sources", + name = "autocomplete_tests_lib", srcs = glob( ["**/*.spec.ts"], - exclude = ["**/*.e2e.spec.ts"], + exclude = [ + "**/*.e2e.spec.ts", + ], ), deps = [ ":autocomplete", @@ -67,9 +57,8 @@ ng_test_library( "//src/cdk/scrolling", "//src/cdk/testing/private", "//src/material/core", - "//src/material/legacy-core", - "//src/material/legacy-form-field", - "//src/material/legacy-input", + "//src/material/form-field", + "//src/material/input", "@npm//@angular/forms", "@npm//@angular/platform-browser", "@npm//rxjs", @@ -78,7 +67,9 @@ ng_test_library( ng_web_test_suite( name = "unit_tests", - deps = [":unit_test_sources"], + deps = [ + ":autocomplete_tests_lib", + ], ) markdown_to_html( diff --git a/src/material/autocomplete/_autocomplete-legacy-index.scss b/src/material/autocomplete/_autocomplete-legacy-index.scss deleted file mode 100644 index 677f21160802..000000000000 --- a/src/material/autocomplete/_autocomplete-legacy-index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@forward 'autocomplete-theme' hide color, theme, typography; -@forward 'autocomplete-theme' as mat-autocomplete-* hide mat-autocomplete-density; diff --git a/src/material/autocomplete/_autocomplete-theme.import.scss b/src/material/autocomplete/_autocomplete-theme.import.scss index a0833d90ec77..a56d6566e3f3 100644 --- a/src/material/autocomplete/_autocomplete-theme.import.scss +++ b/src/material/autocomplete/_autocomplete-theme.import.scss @@ -1,7 +1 @@ -@forward '../core/style/private.import'; -@forward '../core/theming/theming.import'; -@forward 'autocomplete-theme' hide color, theme, typography; -@forward 'autocomplete-theme' as mat-autocomplete-* hide mat-autocomplete-density; - -@import '../core/style/private'; -@import '../core/theming/theming'; +@forward 'autocomplete-theme' as mat-mdc-autocomplete-*; diff --git a/src/material/autocomplete/_autocomplete-theme.scss b/src/material/autocomplete/_autocomplete-theme.scss index 09e4782f9880..a66cdaa2af4e 100644 --- a/src/material/autocomplete/_autocomplete-theme.scss +++ b/src/material/autocomplete/_autocomplete-theme.scss @@ -1,35 +1,32 @@ -@use 'sass:map'; -@use '../core/style/private'; +@use '@material/menu-surface/mixins' as mdc-menu-surface; +@use '@material/list/evolution-mixins' as mdc-list; @use '../core/theming/theming'; +@use '../core/typography/typography'; +@use '../core/mdc-helpers/mdc-helpers'; @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); - $foreground: map.get($config, foreground); - $background: map.get($config, background); - - .mat-autocomplete-panel { - @include private.private-theme-overridable-elevation(4, $config); - background: theming.get-color-from-palette($background, card); - color: theming.get-color-from-palette($foreground, text); + @include mdc-helpers.using-mdc-theme($config) { + @include mdc-menu-surface.core-styles(mdc-helpers.$mdc-theme-styles-query); + @include mdc-list.without-ripple(mdc-helpers.$mdc-theme-styles-query); + } +} - // Selected options in autocompletes should not be gray, but we - // only want to override the background for selected options if - // they are *not* in hover or focus state. This change has to be - // made here because base option styles are shared between the - // autocomplete and the select. - .mat-option.mat-selected:not(.mat-active):not(:hover) { - background: theming.get-color-from-palette($background, card); +@mixin typography($config-or-theme) { + $config: typography.private-typography-to-2018-config( + theming.get-typography-config($config-or-theme)); + @include mdc-helpers.using-mdc-typography($config) { + @include mdc-menu-surface.core-styles(mdc-helpers.$mdc-typography-styles-query); - &:not(.mat-option-disabled) { - color: theming.get-color-from-palette($foreground, text); - } + .mat-mdc-autocomplete-panel { + // Note that we include this private mixin, because the public one adds + // a bunch of styles that we aren't using for the autocomplete panel. + @include mdc-list.list-base(mdc-helpers.$mdc-typography-styles-query); } } } -@mixin typography($config-or-theme) {} - -@mixin _density($config-or-theme) {} +@mixin density($config-or-theme) {} @mixin theme($theme-or-color-config) { $theme: theming.private-legacy-get-theme($theme-or-color-config); @@ -42,7 +39,7 @@ @include color($color); } @if $density != null { - @include _density($density); + @include density($density); } @if $typography != null { @include typography($typography); diff --git a/src/material-experimental/mdc-autocomplete/animations.ts b/src/material/autocomplete/animations.ts similarity index 100% rename from src/material-experimental/mdc-autocomplete/animations.ts rename to src/material/autocomplete/animations.ts diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 58a1fc1cda35..e87871d23ab4 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -5,22 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {Directionality} from '@angular/cdk/bidi'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; -import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW, hasModifierKey} from '@angular/cdk/keycodes'; -import { - FlexibleConnectedPositionStrategy, - Overlay, - OverlayConfig, - OverlayRef, - PositionStrategy, - ScrollStrategy, - ConnectedPosition, -} from '@angular/cdk/overlay'; -import {_getEventTarget} from '@angular/cdk/platform'; -import {TemplatePortal} from '@angular/cdk/portal'; -import {ViewportRuler} from '@angular/cdk/scrolling'; -import {DOCUMENT} from '@angular/common'; + import { AfterViewInit, ChangeDetectorRef, @@ -32,46 +17,44 @@ import { InjectionToken, Input, NgZone, + OnChanges, OnDestroy, Optional, - ViewContainerRef, - OnChanges, SimpleChanges, + ViewContainerRef, } from '@angular/core'; +import {DOCUMENT} from '@angular/common'; +import {Directionality} from '@angular/cdk/bidi'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW, hasModifierKey} from '@angular/cdk/keycodes'; +import {_getEventTarget} from '@angular/cdk/platform'; +import {TemplatePortal} from '@angular/cdk/portal'; +import {ViewportRuler} from '@angular/cdk/scrolling'; +import { + FlexibleConnectedPositionStrategy, + Overlay, + OverlayConfig, + OverlayRef, + PositionStrategy, + ScrollStrategy, + ConnectedPosition, +} from '@angular/cdk/overlay'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import { + MatOptionSelectionChange, _countGroupLabelsBeforeOption, _getOptionScrollPosition, _MatOptionBase, - MatOptionSelectionChange, } from '@angular/material/core'; -import {MAT_FORM_FIELD, MatLegacyFormField} from '@angular/material/legacy-form-field'; +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 { - _MatAutocompleteBase, - MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, MatAutocompleteDefaultOptions, + MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + _MatAutocompleteBase, } from './autocomplete'; -import {_MatAutocompleteOriginBase} from './autocomplete-origin'; - -/** Injection token that determines the scroll handling while the autocomplete panel is open. */ -export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( - 'mat-autocomplete-scroll-strategy', -); - -/** @docs-private */ -export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition(); -} - -/** @docs-private */ -export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER = { - provide: MAT_AUTOCOMPLETE_SCROLL_STRATEGY, - deps: [Overlay], - useFactory: MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY, -}; /** * Provider that allows the autocomplete to register as a ControlValueAccessor. @@ -95,6 +78,23 @@ export function getMatAutocompleteMissingPanelError(): Error { ); } +/** Injection token that determines the scroll handling while the autocomplete panel is open. */ +export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( + 'mat-autocomplete-scroll-strategy', +); + +/** @docs-private */ +export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { + return () => overlay.scrollStrategies.reposition(); +} + +/** @docs-private */ +export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER = { + provide: MAT_AUTOCOMPLETE_SCROLL_STRATEGY, + deps: [Overlay], + useFactory: MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY, +}; + /** Base class with all of the `MatAutocompleteTrigger` functionality. */ @Directive() export abstract class _MatAutocompleteTriggerBase @@ -202,7 +202,7 @@ export abstract class _MatAutocompleteTriggerBase private _changeDetectorRef: ChangeDetectorRef, @Inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY) scrollStrategy: any, @Optional() private _dir: Directionality, - @Optional() @Inject(MAT_FORM_FIELD) @Host() private _formField: MatLegacyFormField, + @Optional() @Inject(MAT_FORM_FIELD) @Host() private _formField: MatFormField, @Optional() @Inject(DOCUMENT) private _document: any, private _viewportRuler: ViewportRuler, @Optional() @@ -847,7 +847,7 @@ export abstract class _MatAutocompleteTriggerBase @Directive({ selector: `input[matAutocomplete], textarea[matAutocomplete]`, host: { - 'class': 'mat-autocomplete-trigger', + 'class': 'mat-mdc-autocomplete-trigger', '[attr.autocomplete]': 'autocompleteAttribute', '[attr.role]': 'autocompleteDisabled ? null : "combobox"', '[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"', @@ -867,5 +867,5 @@ export abstract class _MatAutocompleteTriggerBase providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR], }) export class MatAutocompleteTrigger extends _MatAutocompleteTriggerBase { - protected _aboveClass = 'mat-autocomplete-panel-above'; + protected _aboveClass = 'mat-mdc-autocomplete-panel-above'; } diff --git a/src/material/autocomplete/autocomplete.html b/src/material/autocomplete/autocomplete.html index 78118ff9f205..da358691b7b2 100644 --- a/src/material/autocomplete/autocomplete.html +++ b/src/material/autocomplete/autocomplete.html @@ -1,11 +1,13 @@ -
+
diff --git a/src/material/autocomplete/autocomplete.scss b/src/material/autocomplete/autocomplete.scss index 8ae0f435fe24..70978e4944dc 100644 --- a/src/material/autocomplete/autocomplete.scss +++ b/src/material/autocomplete/autocomplete.scss @@ -1,44 +1,45 @@ @use '@angular/cdk'; +@use '@material/menu-surface/mixins' as mdc-menu-surface; +@use '@material/list/evolution-mixins' as mdc-list; -@use '../core/style/menu-common'; - -// The max-height of the panel, currently matching mat-select value. -$panel-max-height: 256px !default; -$panel-border-radius: 4px !default; - -.mat-autocomplete-panel { - @include menu-common.base(); +@include mdc-menu-surface.core-styles($query: structure); +// Note that the `.mdc-menu-surface` is here in order to bump up the specificity +// and avoid interference with `mat-menu` which uses the same mixins from MDC. +.mdc-menu-surface.mat-mdc-autocomplete-panel { + width: 100%; // Ensures that the panel matches the overlay width. + max-height: 256px; // Prevents lists with a lot of option from growing too high. + position: static; // MDC uses `absolute` by default which will throw off our positioning. visibility: hidden; - max-width: none; - max-height: $panel-max-height; - position: relative; - width: 100%; - border-bottom-left-radius: $panel-border-radius; - border-bottom-right-radius: $panel-border-radius; - - &.mat-autocomplete-visible { - visibility: visible; + // MDC sets the transform-origin programmatically based on whether the dropdown is above or + // below the input. We use our own positioning logic, so we need to set this ourselves. + transform-origin: center top; + + @include mdc-list.list-base($query: structure); + @include cdk.high-contrast(active, off) { + outline: solid 1px; } - &.mat-autocomplete-hidden { - visibility: hidden; + .cdk-overlay-pane:not(.mat-mdc-autocomplete-panel-above) & { + border-top-left-radius: 0; + border-top-right-radius: 0; } - .mat-autocomplete-panel-above & { - border-radius: 0; - border-top-left-radius: $panel-border-radius; - border-top-right-radius: $panel-border-radius; + .mat-mdc-autocomplete-panel-above & { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + // MDC sets the transform-origin programmatically based on whether the dropdown is above or + // below the input. We use our own positioning logic, so we need to set this ourselves. + transform-origin: center bottom; } - // We need to offset horizontal dividers by their height, because - // they throw off the keyboard navigation inside the panel. - .mat-divider-horizontal { - margin-top: -1px; + // These classes are used to toggle the panel visibility depending on whether it has any options. + &.mat-mdc-autocomplete-visible { + visibility: visible; } - @include cdk.high-contrast(active, off) { - outline: solid 1px; + &.mat-mdc-autocomplete-hidden { + visibility: hidden; } } diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index 7ae2f82d4ac8..2e855bef18f5 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -4,15 +4,15 @@ import {Overlay, OverlayContainer} from '@angular/cdk/overlay'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { - MockNgZone, clearElement, createKeyboardEvent, dispatchEvent, dispatchFakeEvent, dispatchKeyboardEvent, - typeInElement, dispatchMouseEvent, -} from '@angular/cdk/testing/private'; + MockNgZone, + typeInElement, +} from '../../cdk/testing/private'; import { ChangeDetectionStrategy, Component, @@ -36,28 +36,25 @@ import { tick, } from '@angular/core/testing'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; -import {MatLegacyOption, MatOptionSelectionChange} from '@angular/material/legacy-core'; -import {MatLegacyFormField, MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; +import {MatOption, MatOptionSelectionChange} from '@angular/material/core'; +import {MatFormField, MatFormFieldModule} from '@angular/material/form-field'; +import {MatInputModule} from '@angular/material/input'; import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {EMPTY, Observable, Subject, Subscription} from 'rxjs'; import {map, startWith} from 'rxjs/operators'; - -import {MatLegacyInputModule} from '../legacy-input/index'; - import { getMatAutocompleteMissingPanelError, - MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, - MAT_AUTOCOMPLETE_SCROLL_STRATEGY, MatAutocomplete, MatAutocompleteModule, MatAutocompleteOrigin, MatAutocompleteSelectedEvent, MatAutocompleteTrigger, + MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + MAT_AUTOCOMPLETE_SCROLL_STRATEGY, } from './index'; -describe('MatAutocomplete', () => { - let overlayContainer: OverlayContainer; +describe('MDC-based MatAutocomplete', () => { let overlayContainerElement: HTMLElement; let zone: MockNgZone; @@ -66,8 +63,8 @@ describe('MatAutocomplete', () => { TestBed.configureTestingModule({ imports: [ MatAutocompleteModule, - MatLegacyFormFieldModule, - MatLegacyInputModule, + MatFormFieldModule, + MatInputModule, FormsModule, ReactiveFormsModule, NoopAnimationsModule, @@ -79,7 +76,6 @@ describe('MatAutocomplete', () => { TestBed.compileComponents(); inject([OverlayContainer], (oc: OverlayContainer) => { - overlayContainer = oc; overlayContainerElement = oc.getContainerElement(); })(); @@ -184,6 +180,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); zone.simulateZoneExit(); dispatchFakeEvent(document, 'click'); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking outside the panel to set its state to closed.`) @@ -198,6 +195,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); zone.simulateZoneExit(); dispatchFakeEvent(document, 'auxclick'); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking outside the panel to set its state to closed.`) @@ -229,6 +227,7 @@ describe('MatAutocomplete', () => { const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking an option to set the panel state to closed.`) @@ -264,6 +263,7 @@ describe('MatAutocomplete', () => { options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; options[1].click(); fixture.detectChanges(); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking a new option to set the panel state to closed.`) @@ -273,12 +273,13 @@ describe('MatAutocomplete', () => { .toEqual(''); })); - it('should close the panel programmatically', () => { + it('should close the panel programmatically', fakeAsync(() => { fixture.componentInstance.trigger.openPanel(); fixture.detectChanges(); fixture.componentInstance.trigger.closePanel(); fixture.detectChanges(); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected closing programmatically to set the panel state to closed.`) @@ -286,7 +287,7 @@ describe('MatAutocomplete', () => { expect(overlayContainerElement.textContent) .withContext(`Expected closing programmatically to close the panel.`) .toEqual(''); - }); + })); it('should not throw when attempting to close the panel of a destroyed autocomplete', () => { const trigger = fixture.componentInstance.trigger; @@ -302,11 +303,13 @@ describe('MatAutocomplete', () => { dispatchFakeEvent(input, 'focusin'); fixture.detectChanges(); - const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel') as HTMLElement; + const panel = overlayContainerElement.querySelector( + '.mat-mdc-autocomplete-panel', + ) as HTMLElement; expect(panel.classList) .withContext(`Expected panel to start out visible.`) - .toContain('mat-autocomplete-visible'); + .toContain('mat-mdc-autocomplete-visible'); // Filter down the option list such that no options match the value typeInElement(input, 'af'); @@ -316,7 +319,7 @@ describe('MatAutocomplete', () => { expect(panel.classList) .withContext(`Expected panel to hide itself when empty.`) - .toContain('mat-autocomplete-hidden'); + .toContain('mat-mdc-autocomplete-hidden'); })); it('should keep the label floating until the panel closes', fakeAsync(() => { @@ -402,18 +405,18 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-autocomplete-panel')!.classList) + expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be visible.') - .toContain('mat-autocomplete-visible'); + .toContain('mat-mdc-autocomplete-visible'); typeInElement(input, 'x'); fixture.detectChanges(); tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-autocomplete-panel')!.classList) + expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be hidden.') - .toContain('mat-autocomplete-hidden'); + .toContain('mat-mdc-autocomplete-hidden'); fixture.componentInstance.trigger.closePanel(); fixture.detectChanges(); @@ -427,9 +430,9 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-autocomplete-panel')!.classList) + expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be visible.') - .toContain('mat-autocomplete-visible'); + .toContain('mat-mdc-autocomplete-visible'); })); it('should animate the label when the input is focused', () => { @@ -842,7 +845,9 @@ describe('MatAutocomplete', () => { })); it('should disable input in view when disabled programmatically', () => { - const formFieldElement = fixture.debugElement.query(By.css('.mat-form-field'))!.nativeElement; + const formFieldElement = fixture.debugElement.query( + By.css('.mat-mdc-form-field'), + )!.nativeElement; expect(input.disabled) .withContext(`Expected input to start out enabled in view.`) @@ -924,7 +929,6 @@ describe('MatAutocomplete', () => { }); it('should disable the input when used with a value accessor and without `matInput`', () => { - overlayContainer.ngOnDestroy(); fixture.destroy(); TestBed.resetTestingModule(); @@ -999,8 +1003,8 @@ describe('MatAutocomplete', () => { expect(componentInstance.trigger.activeOption === componentInstance.options.first) .withContext('Expected first option to be active.') .toBe(true); - expect(optionEls[0].classList).toContain('mat-active'); - expect(optionEls[1].classList).not.toContain('mat-active'); + expect(optionEls[0].classList).toContain('mat-mdc-option-active'); + expect(optionEls[1].classList).not.toContain('mat-mdc-option-active'); componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1008,8 +1012,8 @@ describe('MatAutocomplete', () => { expect(componentInstance.trigger.activeOption === componentInstance.options.toArray()[1]) .withContext('Expected second option to be active.') .toBe(true); - expect(optionEls[0].classList).not.toContain('mat-active'); - expect(optionEls[1].classList).toContain('mat-active'); + expect(optionEls[0].classList).not.toContain('mat-mdc-option-active'); + expect(optionEls[1].classList).toContain('mat-mdc-option-active'); }); it('should set the active item to the last option when UP key is pressed', () => { @@ -1028,8 +1032,8 @@ describe('MatAutocomplete', () => { expect(componentInstance.trigger.activeOption === componentInstance.options.last) .withContext('Expected last option to be active.') .toBe(true); - expect(optionEls[10].classList).toContain('mat-active'); - expect(optionEls[0].classList).not.toContain('mat-active'); + expect(optionEls[10].classList).toContain('mat-mdc-option-active'); + expect(optionEls[0].classList).not.toContain('mat-mdc-option-active'); componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1037,7 +1041,7 @@ describe('MatAutocomplete', () => { expect(componentInstance.trigger.activeOption === componentInstance.options.first) .withContext('Expected first option to be active.') .toBe(true); - expect(optionEls[0].classList).toContain('mat-active'); + expect(optionEls[0].classList).toContain('mat-mdc-option-active'); }); it('should set the active item properly after filtering', fakeAsync(() => { @@ -1064,8 +1068,8 @@ describe('MatAutocomplete', () => { expect(componentInstance.trigger.activeOption === componentInstance.options.first) .withContext('Expected first option to be active.') .toBe(true); - expect(optionEls[0].classList).toContain('mat-active'); - expect(optionEls[1].classList).not.toContain('mat-active'); + expect(optionEls[0].classList).toContain('mat-mdc-option-active'); + expect(optionEls[1].classList).not.toContain('mat-mdc-option-active'); }); it('should fill the text field when an option is selected with ENTER', fakeAsync(() => { @@ -1136,7 +1140,9 @@ describe('MatAutocomplete', () => { fixture.componentInstance.trigger._handleKeydown(SPACE_EVENT); fixture.detectChanges(); - expect(input.value).not.toContain('New York', `Expected option not to be selected on SPACE.`); + expect(input.value) + .not.withContext(`Expected option not to be selected on SPACE.`) + .toContain('New York'); }); it('should mark the control dirty when selecting an option from the keyboard', fakeAsync(() => { @@ -1159,6 +1165,7 @@ describe('MatAutocomplete', () => { flush(); fixture.componentInstance.trigger._handleKeydown(ENTER_EVENT); fixture.detectChanges(); + tick(); expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read closed after ENTER key.`) @@ -1207,7 +1214,9 @@ describe('MatAutocomplete', () => { it('should scroll to active options below the fold', () => { const trigger = fixture.componentInstance.trigger; - const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!; + const scrollContainer = document.querySelector( + '.cdk-overlay-pane .mat-mdc-autocomplete-panel', + )!; trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1216,11 +1225,11 @@ describe('MatAutocomplete', () => { // These down arrows will set the 6th option active, below the fold. [1, 2, 3, 4, 5].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT)); - // Expect option bottom minus the panel height (288 - 256 = 32) - // Expect option bottom minus the panel height (288 - 256 = 32) + // Expect option bottom minus the panel height plus padding (288 - 256 + 8 = 40) + // Expect option bottom minus the panel height plus padding (288 - 256 + 8 = 40) expect(scrollContainer.scrollTop) .withContext(`Expected panel to reveal the sixth option.`) - .toEqual(32); + .toEqual(40); }); it('should scroll to active options below if the option height is variable', () => { @@ -1233,7 +1242,9 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const trigger = fixture.componentInstance.trigger; - const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!; + const scrollContainer = document.querySelector( + '.cdk-overlay-pane .mat-mdc-autocomplete-panel', + )!; trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1242,29 +1253,32 @@ describe('MatAutocomplete', () => { // These down arrows will set the 6th option active, below the fold. [1, 2, 3, 4, 5].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT)); - // Expect option bottom minus the panel height (336 - 256 = 80) - // Expect option bottom minus the panel height (336 - 256 = 80) + // Expect option bottom minus the panel height (336 - 256 + 8 = 88) + // Expect option bottom minus the panel height (336 - 256 + 8 = 88) expect(scrollContainer.scrollTop) .withContext(`Expected panel to reveal the sixth option.`) - .toEqual(80); + .toEqual(88); }); it('should scroll to active options on UP arrow', () => { - const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!; + const scrollContainer = document.querySelector( + '.cdk-overlay-pane .mat-mdc-autocomplete-panel', + )!; + const initialScrollTop = scrollContainer.scrollTop; fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT); fixture.detectChanges(); - // Expect option bottom minus the panel height (528 - 256 = 272) - // Expect option bottom minus the panel height (528 - 256 = 272) expect(scrollContainer.scrollTop) .withContext(`Expected panel to reveal last option.`) - .toEqual(272); + .toBeGreaterThan(initialScrollTop); }); it('should not scroll to active options that are fully in the panel', () => { const trigger = fixture.componentInstance.trigger; - const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!; + const scrollContainer = document.querySelector( + '.cdk-overlay-pane .mat-mdc-autocomplete-panel', + )!; trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1274,11 +1288,11 @@ describe('MatAutocomplete', () => { // These down arrows will set the 6th option active, below the fold. [1, 2, 3, 4, 5].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT)); - // Expect option bottom minus the panel height (288 - 256 = 32) - // Expect option bottom minus the panel height (288 - 256 = 32) + // Expect option bottom minus the panel height plus the padding (288 - 256 + 8 = 40) + // Expect option bottom minus the panel height plus the padding (288 - 256 + 8 = 40) expect(scrollContainer.scrollTop) .withContext(`Expected panel to reveal the sixth option.`) - .toEqual(32); + .toEqual(40); // These up arrows will set the 2nd option active [4, 3, 2, 1].forEach(() => trigger._handleKeydown(UP_ARROW_EVENT)); @@ -1287,12 +1301,14 @@ describe('MatAutocomplete', () => { // Expect no scrolling to have occurred. Still showing bottom of 6th option. expect(scrollContainer.scrollTop) .withContext(`Expected panel not to scroll up since sixth option still fully visible.`) - .toEqual(32); + .toEqual(40); }); it('should scroll to active options that are above the panel', () => { const trigger = fixture.componentInstance.trigger; - const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!; + const scrollContainer = document.querySelector( + '.cdk-overlay-pane .mat-mdc-autocomplete-panel', + )!; trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); @@ -1309,7 +1325,7 @@ describe('MatAutocomplete', () => { // Expect to show the top of the 2nd option at the top of the panel expect(scrollContainer.scrollTop) .withContext(`Expected panel to scroll up when option is above panel.`) - .toEqual(48); + .toEqual(56); }); it('should close the panel when pressing escape', fakeAsync(() => { @@ -1389,14 +1405,15 @@ describe('MatAutocomplete', () => { input.focus(); flush(); - expect(overlayContainerElement.querySelector('.mat-autocomplete-panel')) + expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')) .withContext('Expected panel to be rendered.') .toBeTruthy(); dispatchKeyboardEvent(input, 'keydown', TAB); fixture.detectChanges(); + tick(); - expect(overlayContainerElement.querySelector('.mat-autocomplete-panel')) + expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')) .withContext('Expected panel to be removed.') .toBeFalsy(); })); @@ -1508,7 +1525,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); zone.simulateZoneExit(); fixture.detectChanges(); - const container = document.querySelector('.mat-autocomplete-panel') as HTMLElement; + const container = document.querySelector('.mat-mdc-autocomplete-panel') as HTMLElement; fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); tick(); @@ -1521,13 +1538,13 @@ describe('MatAutocomplete', () => { tick(); }); - //