@angular/material 10.0.0-rc.3 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_theming.scss +17 -17
- package/autocomplete/index.metadata.json +1 -1
- package/autocomplete/testing/autocomplete-harness.d.ts +2 -0
- package/bundles/material-autocomplete-testing.umd.js +11 -0
- package/bundles/material-autocomplete-testing.umd.js.map +1 -1
- package/bundles/material-autocomplete-testing.umd.min.js +2 -2
- package/bundles/material-autocomplete-testing.umd.min.js.map +1 -1
- package/bundles/material-autocomplete.umd.js +3 -1
- package/bundles/material-autocomplete.umd.js.map +1 -1
- package/bundles/material-autocomplete.umd.min.js +5 -5
- package/bundles/material-autocomplete.umd.min.js.map +1 -1
- package/bundles/material-badge-testing.umd.min.js +1 -1
- package/bundles/material-badge-testing.umd.min.js.map +1 -1
- package/bundles/material-bottom-sheet-testing.umd.min.js +1 -1
- package/bundles/material-bottom-sheet-testing.umd.min.js.map +1 -1
- package/bundles/material-button-testing.umd.js +11 -0
- package/bundles/material-button-testing.umd.js.map +1 -1
- package/bundles/material-button-testing.umd.min.js +2 -2
- package/bundles/material-button-testing.umd.min.js.map +1 -1
- package/bundles/material-button-toggle-testing.umd.js +11 -0
- package/bundles/material-button-toggle-testing.umd.js.map +1 -1
- package/bundles/material-button-toggle-testing.umd.min.js +3 -3
- package/bundles/material-button-toggle-testing.umd.min.js.map +1 -1
- package/bundles/material-button-toggle.umd.js +12 -3
- package/bundles/material-button-toggle.umd.js.map +1 -1
- package/bundles/material-button-toggle.umd.min.js +2 -2
- package/bundles/material-button-toggle.umd.min.js.map +1 -1
- package/bundles/material-button.umd.js +7 -2
- package/bundles/material-button.umd.js.map +1 -1
- package/bundles/material-button.umd.min.js +4 -4
- package/bundles/material-button.umd.min.js.map +1 -1
- package/bundles/material-card-testing.umd.js +335 -0
- package/bundles/material-card-testing.umd.js.map +1 -0
- package/bundles/material-card-testing.umd.min.js +44 -0
- package/bundles/material-card-testing.umd.min.js.map +1 -0
- package/bundles/material-checkbox-testing.umd.js +11 -0
- package/bundles/material-checkbox-testing.umd.js.map +1 -1
- package/bundles/material-checkbox-testing.umd.min.js +3 -3
- package/bundles/material-checkbox-testing.umd.min.js.map +1 -1
- package/bundles/material-checkbox.umd.js.map +1 -1
- package/bundles/material-chips.umd.js +36 -12
- package/bundles/material-chips.umd.js.map +1 -1
- package/bundles/material-chips.umd.min.js +4 -4
- package/bundles/material-chips.umd.min.js.map +1 -1
- package/bundles/material-core-testing.umd.min.js +1 -1
- package/bundles/material-core-testing.umd.min.js.map +1 -1
- package/bundles/material-core.umd.js +11 -3
- package/bundles/material-core.umd.js.map +1 -1
- package/bundles/material-core.umd.min.js +11 -11
- package/bundles/material-core.umd.min.js.map +1 -1
- package/bundles/material-datepicker.umd.js +20 -11
- package/bundles/material-datepicker.umd.js.map +1 -1
- package/bundles/material-datepicker.umd.min.js +5 -5
- package/bundles/material-datepicker.umd.min.js.map +1 -1
- package/bundles/material-dialog-testing.umd.min.js +1 -1
- package/bundles/material-dialog-testing.umd.min.js.map +1 -1
- package/bundles/material-dialog.umd.js +45 -8
- package/bundles/material-dialog.umd.js.map +1 -1
- package/bundles/material-dialog.umd.min.js +14 -7
- package/bundles/material-dialog.umd.min.js.map +1 -1
- package/bundles/material-divider-testing.umd.min.js +1 -1
- package/bundles/material-divider-testing.umd.min.js.map +1 -1
- package/bundles/material-expansion-testing.umd.js +11 -0
- package/bundles/material-expansion-testing.umd.js.map +1 -1
- package/bundles/material-expansion-testing.umd.min.js +3 -3
- package/bundles/material-expansion-testing.umd.min.js.map +1 -1
- package/bundles/material-form-field-testing.umd.js +32 -0
- package/bundles/material-form-field-testing.umd.js.map +1 -1
- package/bundles/material-form-field-testing.umd.min.js +4 -4
- package/bundles/material-form-field-testing.umd.min.js.map +1 -1
- package/bundles/material-form-field.umd.js +47 -21
- package/bundles/material-form-field.umd.js.map +1 -1
- package/bundles/material-form-field.umd.min.js +5 -5
- package/bundles/material-form-field.umd.min.js.map +1 -1
- package/bundles/material-grid-list-testing.umd.min.js +1 -1
- package/bundles/material-grid-list-testing.umd.min.js.map +1 -1
- package/bundles/material-grid-list.umd.js +2 -2
- package/bundles/material-grid-list.umd.js.map +1 -1
- package/bundles/material-grid-list.umd.min.js +2 -2
- package/bundles/material-grid-list.umd.min.js.map +1 -1
- package/bundles/material-input-testing.umd.js +23 -6
- package/bundles/material-input-testing.umd.js.map +1 -1
- package/bundles/material-input-testing.umd.min.js +3 -3
- package/bundles/material-input-testing.umd.min.js.map +1 -1
- package/bundles/material-input.umd.js +28 -3
- package/bundles/material-input.umd.js.map +1 -1
- package/bundles/material-input.umd.min.js +3 -3
- package/bundles/material-input.umd.min.js.map +1 -1
- package/bundles/material-list-testing.umd.js +33 -0
- package/bundles/material-list-testing.umd.js.map +1 -1
- package/bundles/material-list-testing.umd.min.js +2 -2
- package/bundles/material-list-testing.umd.min.js.map +1 -1
- package/bundles/material-list.umd.js +3 -3
- package/bundles/material-list.umd.min.js +1 -1
- package/bundles/material-list.umd.min.js.map +1 -1
- package/bundles/material-menu-testing.umd.js +22 -0
- package/bundles/material-menu-testing.umd.js.map +1 -1
- package/bundles/material-menu-testing.umd.min.js +2 -2
- package/bundles/material-menu-testing.umd.min.js.map +1 -1
- package/bundles/material-menu.umd.js +13 -2
- package/bundles/material-menu.umd.js.map +1 -1
- package/bundles/material-menu.umd.min.js +4 -4
- package/bundles/material-menu.umd.min.js.map +1 -1
- package/bundles/material-paginator-testing.umd.min.js +1 -1
- package/bundles/material-paginator-testing.umd.min.js.map +1 -1
- package/bundles/material-progress-bar-testing.umd.min.js +1 -1
- package/bundles/material-progress-bar-testing.umd.min.js.map +1 -1
- package/bundles/material-progress-spinner-testing.umd.js +1 -1
- package/bundles/material-progress-spinner-testing.umd.js.map +1 -1
- package/bundles/material-progress-spinner-testing.umd.min.js +2 -2
- package/bundles/material-progress-spinner-testing.umd.min.js.map +1 -1
- package/bundles/material-progress-spinner.umd.js +2 -2
- package/bundles/material-progress-spinner.umd.min.js +3 -3
- package/bundles/material-progress-spinner.umd.min.js.map +1 -1
- package/bundles/material-radio-testing.umd.js +11 -0
- package/bundles/material-radio-testing.umd.js.map +1 -1
- package/bundles/material-radio-testing.umd.min.js +3 -3
- package/bundles/material-radio-testing.umd.min.js.map +1 -1
- package/bundles/material-radio.umd.js +15 -5
- package/bundles/material-radio.umd.js.map +1 -1
- package/bundles/material-radio.umd.min.js +2 -2
- package/bundles/material-radio.umd.min.js.map +1 -1
- package/bundles/material-select-testing.umd.js +11 -0
- package/bundles/material-select-testing.umd.js.map +1 -1
- package/bundles/material-select-testing.umd.min.js +2 -2
- package/bundles/material-select-testing.umd.min.js.map +1 -1
- package/bundles/material-select.umd.js +11 -3
- package/bundles/material-select.umd.js.map +1 -1
- package/bundles/material-select.umd.min.js +4 -4
- package/bundles/material-select.umd.min.js.map +1 -1
- package/bundles/material-sidenav-testing.umd.min.js +1 -1
- package/bundles/material-sidenav-testing.umd.min.js.map +1 -1
- package/bundles/material-sidenav.umd.js +41 -17
- package/bundles/material-sidenav.umd.js.map +1 -1
- package/bundles/material-sidenav.umd.min.js +2 -2
- package/bundles/material-sidenav.umd.min.js.map +1 -1
- package/bundles/material-slide-toggle-testing.umd.js +11 -0
- package/bundles/material-slide-toggle-testing.umd.js.map +1 -1
- package/bundles/material-slide-toggle-testing.umd.min.js +2 -2
- package/bundles/material-slide-toggle-testing.umd.min.js.map +1 -1
- package/bundles/material-slide-toggle.umd.js.map +1 -1
- package/bundles/material-slider-testing.umd.js +11 -0
- package/bundles/material-slider-testing.umd.js.map +1 -1
- package/bundles/material-slider-testing.umd.min.js +2 -2
- package/bundles/material-slider-testing.umd.min.js.map +1 -1
- package/bundles/material-snack-bar-testing.umd.min.js +1 -1
- package/bundles/material-snack-bar-testing.umd.min.js.map +1 -1
- package/bundles/material-snack-bar.umd.js +47 -39
- package/bundles/material-snack-bar.umd.js.map +1 -1
- package/bundles/material-snack-bar.umd.min.js +2 -2
- package/bundles/material-snack-bar.umd.min.js.map +1 -1
- package/bundles/material-sort-testing.umd.js +10 -10
- package/bundles/material-sort-testing.umd.js.map +1 -1
- package/bundles/material-sort-testing.umd.min.js +3 -3
- package/bundles/material-sort-testing.umd.min.js.map +1 -1
- package/bundles/material-sort.umd.js +25 -12
- package/bundles/material-sort.umd.js.map +1 -1
- package/bundles/material-sort.umd.min.js +5 -5
- package/bundles/material-sort.umd.min.js.map +1 -1
- package/bundles/material-table-testing.umd.min.js +1 -1
- package/bundles/material-table-testing.umd.min.js.map +1 -1
- package/bundles/material-table.umd.min.js +2 -2
- package/bundles/material-table.umd.min.js.map +1 -1
- package/bundles/material-tabs-testing.umd.min.js +1 -1
- package/bundles/material-tabs-testing.umd.min.js.map +1 -1
- package/bundles/material-tabs.umd.js +23 -4
- package/bundles/material-tabs.umd.js.map +1 -1
- package/bundles/material-tabs.umd.min.js +5 -12
- package/bundles/material-tabs.umd.min.js.map +1 -1
- package/bundles/material-toolbar-testing.umd.js +330 -0
- package/bundles/material-toolbar-testing.umd.js.map +1 -0
- package/bundles/material-toolbar-testing.umd.min.js +44 -0
- package/bundles/material-toolbar-testing.umd.min.js.map +1 -0
- package/bundles/material-tooltip-testing.umd.min.js +1 -1
- package/bundles/material-tooltip-testing.umd.min.js.map +1 -1
- package/bundles/material-tooltip.umd.js +14 -1
- package/bundles/material-tooltip.umd.js.map +1 -1
- package/bundles/material-tooltip.umd.min.js +3 -3
- package/bundles/material-tooltip.umd.min.js.map +1 -1
- package/bundles/material-tree.umd.js.map +1 -1
- package/button/_button-base.scss +1 -1
- package/button/_button-theme.scss +8 -8
- package/button/index.metadata.json +1 -1
- package/button/testing/button-harness.d.ts +2 -0
- package/button-toggle/button-toggle.d.ts +10 -3
- package/button-toggle/index.metadata.json +1 -1
- package/button-toggle/testing/button-toggle-harness.d.ts +2 -0
- package/card/testing/card-harness-filters.d.ts +17 -0
- package/card/testing/card-harness.d.ts +36 -0
- package/card/testing/index.d.ts +8 -0
- package/card/testing/package.json +9 -0
- package/card/testing/public-api.d.ts +9 -0
- package/checkbox/index.metadata.json +1 -1
- package/checkbox/testing/checkbox-harness.d.ts +2 -0
- package/chips/chip.d.ts +19 -1
- package/chips/index.metadata.json +1 -1
- package/core/focus-indicators/_focus-indicators.scss +6 -6
- package/core/index.metadata.json +1 -1
- package/core/option/optgroup.d.ts +7 -0
- package/core/ripple/ripple-ref.d.ts +21 -2
- package/core/ripple/ripple-renderer.d.ts +1 -19
- package/core/ripple/ripple.d.ts +2 -2
- package/core/style/_list-common.scss +1 -1
- package/datepicker/date-range-input-parts.d.ts +2 -4
- package/datepicker/date-range-input.d.ts +4 -4
- package/datepicker/date-range-picker.d.ts +10 -3
- package/datepicker/datepicker.d.ts +2 -3
- package/datepicker/index.metadata.json +1 -1
- package/datepicker/public-api.d.ts +1 -1
- package/dialog/dialog-container.d.ts +9 -2
- package/dialog/dialog-content-directives.d.ts +1 -0
- package/dialog/dialog-ref.d.ts +7 -0
- package/dialog/index.metadata.json +1 -1
- package/esm2015/autocomplete/autocomplete-module.js +18 -22
- package/esm2015/autocomplete/autocomplete-origin.js +16 -20
- package/esm2015/autocomplete/autocomplete-trigger.js +519 -521
- package/esm2015/autocomplete/autocomplete.js +126 -130
- package/esm2015/autocomplete/testing/autocomplete-harness.js +99 -97
- package/esm2015/badge/badge-module.js +13 -17
- package/esm2015/badge/badge.js +184 -188
- package/esm2015/badge/testing/badge-harness.js +74 -78
- package/esm2015/bottom-sheet/bottom-sheet-container.js +161 -165
- package/esm2015/bottom-sheet/bottom-sheet-module.js +15 -19
- package/esm2015/bottom-sheet/bottom-sheet.js +124 -128
- package/esm2015/bottom-sheet/testing/bottom-sheet-harness.js +29 -33
- package/esm2015/button/button-module.js +20 -24
- package/esm2015/button/button.js +111 -114
- package/esm2015/button/testing/button-harness.js +60 -58
- package/esm2015/button-toggle/button-toggle-module.js +10 -14
- package/esm2015/button-toggle/button-toggle.js +368 -368
- package/esm2015/button-toggle/testing/button-toggle-group-harness.js +42 -46
- package/esm2015/button-toggle/testing/button-toggle-harness.js +113 -111
- package/esm2015/card/card-module.js +30 -34
- package/esm2015/card/card.js +147 -203
- package/esm2015/card/testing/card-harness-filters.js +8 -0
- package/esm2015/card/testing/card-harness.js +52 -0
- package/esm2015/card/testing/index.js +9 -0
- package/esm2015/card/testing/public-api.js +10 -0
- package/esm2015/card/testing/testing.externs.js +0 -0
- package/esm2015/checkbox/checkbox-module.js +21 -29
- package/esm2015/checkbox/checkbox-required-validator.js +9 -13
- package/esm2015/checkbox/checkbox.js +315 -319
- package/esm2015/checkbox/testing/checkbox-harness.js +150 -148
- package/esm2015/chips/chip-input.js +119 -123
- package/esm2015/chips/chip-list.js +572 -576
- package/esm2015/chips/chip.js +333 -328
- package/esm2015/chips/chips-module.js +16 -20
- package/esm2015/core/animation/animation.js +12 -20
- package/esm2015/core/common-behaviors/common-module.js +91 -95
- package/esm2015/core/datetime/index.js +19 -27
- package/esm2015/core/datetime/native-date-adapter.js +202 -206
- package/esm2015/core/error/error-options.js +16 -24
- package/esm2015/core/line/line.js +18 -26
- package/esm2015/core/option/index.js +10 -14
- package/esm2015/core/option/optgroup.js +36 -33
- package/esm2015/core/option/option.js +181 -185
- package/esm2015/core/ripple/index.js +10 -14
- package/esm2015/core/ripple/ripple-ref.js +1 -1
- package/esm2015/core/ripple/ripple-renderer.js +1 -1
- package/esm2015/core/ripple/ripple.js +102 -106
- package/esm2015/core/selection/index.js +9 -13
- package/esm2015/core/selection/pseudo-checkbox/pseudo-checkbox.js +32 -36
- package/esm2015/core/testing/optgroup-harness.js +39 -43
- package/esm2015/core/testing/option-harness.js +51 -55
- package/esm2015/core/version.js +1 -1
- package/esm2015/datepicker/calendar-body.js +214 -218
- package/esm2015/datepicker/calendar.js +295 -303
- package/esm2015/datepicker/date-range-input-parts.js +214 -229
- package/esm2015/datepicker/date-range-input.js +244 -242
- package/esm2015/datepicker/date-range-picker.js +19 -23
- package/esm2015/datepicker/date-range-selection-strategy.js +31 -35
- package/esm2015/datepicker/date-selection-model.js +110 -122
- package/esm2015/datepicker/datepicker-base.js +418 -426
- package/esm2015/datepicker/datepicker-input-base.js +227 -224
- package/esm2015/datepicker/datepicker-input.js +111 -115
- package/esm2015/datepicker/datepicker-intl.js +37 -41
- package/esm2015/datepicker/datepicker-module.js +62 -66
- package/esm2015/datepicker/datepicker-toggle.js +81 -89
- package/esm2015/datepicker/datepicker.js +13 -17
- package/esm2015/datepicker/month-view.js +283 -287
- package/esm2015/datepicker/multi-year-view.js +198 -202
- package/esm2015/datepicker/public-api.js +2 -2
- package/esm2015/datepicker/year-view.js +220 -224
- package/esm2015/dialog/dialog-container.js +175 -164
- package/esm2015/dialog/dialog-content-directives.js +105 -114
- package/esm2015/dialog/dialog-module.js +32 -36
- package/esm2015/dialog/dialog-ref.js +17 -3
- package/esm2015/dialog/dialog.js +236 -240
- package/esm2015/dialog/testing/dialog-harness.js +58 -62
- package/esm2015/divider/divider-module.js +10 -14
- package/esm2015/divider/divider.js +33 -37
- package/esm2015/divider/testing/divider-harness.js +16 -20
- package/esm2015/expansion/accordion.js +73 -77
- package/esm2015/expansion/expansion-module.js +26 -30
- package/esm2015/expansion/expansion-panel-content.js +13 -17
- package/esm2015/expansion/expansion-panel-header.js +168 -180
- package/esm2015/expansion/expansion-panel.js +144 -152
- package/esm2015/expansion/testing/accordion-harness.js +24 -28
- package/esm2015/expansion/testing/expansion-harness.js +136 -134
- package/esm2015/form-field/error.js +26 -23
- package/esm2015/form-field/form-field-control.js +6 -10
- package/esm2015/form-field/form-field-module.js +31 -35
- package/esm2015/form-field/form-field.js +407 -409
- package/esm2015/form-field/hint.js +35 -29
- package/esm2015/form-field/label.js +8 -12
- package/esm2015/form-field/placeholder.js +8 -12
- package/esm2015/form-field/prefix.js +16 -13
- package/esm2015/form-field/suffix.js +16 -13
- package/esm2015/form-field/testing/form-field-harness.js +220 -206
- package/esm2015/grid-list/grid-list-module.js +26 -30
- package/esm2015/grid-list/grid-list.js +108 -112
- package/esm2015/grid-list/grid-tile.js +91 -111
- package/esm2015/grid-list/testing/grid-list-harness.js +62 -66
- package/esm2015/grid-list/testing/grid-tile-harness.js +69 -73
- package/esm2015/grid-list/tile-styler.js +1 -1
- package/esm2015/icon/icon-module.js +10 -14
- package/esm2015/icon/icon-registry.js +406 -410
- package/esm2015/icon/icon.js +228 -232
- package/esm2015/icon/testing/fake-icon-registry.js +66 -74
- package/esm2015/input/autosize.js +30 -34
- package/esm2015/input/input-module.js +21 -25
- package/esm2015/input/input.js +305 -284
- package/esm2015/input/testing/input-harness.js +129 -123
- package/esm2015/list/list-module.js +32 -36
- package/esm2015/list/list.js +165 -189
- package/esm2015/list/selection-list.js +503 -511
- package/esm2015/list/testing/action-list-harness.js +55 -57
- package/esm2015/list/testing/list-harness.js +31 -39
- package/esm2015/list/testing/list-item-harness-base.js +13 -17
- package/esm2015/list/testing/nav-list-harness.js +62 -64
- package/esm2015/list/testing/selection-list-harness.js +136 -138
- package/esm2015/menu/menu-content.js +74 -71
- package/esm2015/menu/menu-item.js +119 -123
- package/esm2015/menu/menu-module.js +29 -37
- package/esm2015/menu/menu-panel.js +1 -1
- package/esm2015/menu/menu-trigger.js +402 -405
- package/esm2015/menu/menu.js +329 -339
- package/esm2015/menu/testing/menu-harness.js +193 -189
- package/esm2015/paginator/paginator-intl.js +36 -40
- package/esm2015/paginator/paginator-module.js +16 -20
- package/esm2015/paginator/paginator.js +205 -209
- package/esm2015/paginator/testing/paginator-harness.js +91 -95
- package/esm2015/progress-bar/progress-bar-module.js +10 -14
- package/esm2015/progress-bar/progress-bar.js +114 -118
- package/esm2015/progress-bar/testing/progress-bar-harness.js +27 -31
- package/esm2015/progress-spinner/progress-spinner-module.js +17 -21
- package/esm2015/progress-spinner/progress-spinner.js +181 -189
- package/esm2015/progress-spinner/testing/progress-spinner-harness.js +28 -32
- package/esm2015/radio/radio-module.js +10 -14
- package/esm2015/radio/radio.js +437 -444
- package/esm2015/radio/testing/radio-harness.js +241 -243
- package/esm2015/select/select-module.js +23 -27
- package/esm2015/select/select.js +917 -918
- package/esm2015/select/testing/select-harness.js +138 -136
- package/esm2015/sidenav/drawer.js +632 -620
- package/esm2015/sidenav/sidenav-module.js +31 -35
- package/esm2015/sidenav/sidenav.js +104 -116
- package/esm2015/sidenav/testing/drawer-harness.js +40 -44
- package/esm2015/sidenav/testing/sidenav-harness.js +20 -24
- package/esm2015/slide-toggle/slide-toggle-module.js +27 -35
- package/esm2015/slide-toggle/slide-toggle-required-validator.js +9 -13
- package/esm2015/slide-toggle/slide-toggle.js +184 -188
- package/esm2015/slide-toggle/testing/slide-toggle-harness.js +123 -121
- package/esm2015/slider/slider-module.js +10 -14
- package/esm2015/slider/slider.js +640 -644
- package/esm2015/slider/testing/slider-harness.js +129 -127
- package/esm2015/snack-bar/simple-snack-bar.js +32 -36
- package/esm2015/snack-bar/snack-bar-container.js +144 -148
- package/esm2015/snack-bar/snack-bar-module.js +17 -21
- package/esm2015/snack-bar/snack-bar-ref.js +1 -1
- package/esm2015/snack-bar/snack-bar.js +208 -205
- package/esm2015/snack-bar/testing/snack-bar-harness.js +112 -116
- package/esm2015/sort/sort-header-intl.js +21 -21
- package/esm2015/sort/sort-header.js +200 -194
- package/esm2015/sort/sort-module.js +11 -15
- package/esm2015/sort/sort.js +92 -96
- package/esm2015/sort/testing/sort-harness.js +28 -32
- package/esm2015/sort/testing/sort-header-harness.js +66 -67
- package/esm2015/stepper/step-header.js +78 -82
- package/esm2015/stepper/step-label.js +8 -12
- package/esm2015/stepper/stepper-button.js +23 -31
- package/esm2015/stepper/stepper-icon.js +16 -20
- package/esm2015/stepper/stepper-intl.js +15 -19
- package/esm2015/stepper/stepper-module.js +40 -44
- package/esm2015/stepper/stepper.js +139 -155
- package/esm2015/table/cell.js +94 -122
- package/esm2015/table/row.js +90 -118
- package/esm2015/table/table-module.js +13 -17
- package/esm2015/table/table.js +26 -30
- package/esm2015/table/testing/cell-harness.js +56 -68
- package/esm2015/table/testing/row-harness.js +90 -102
- package/esm2015/table/testing/table-harness.js +65 -69
- package/esm2015/table/text-column.js +17 -21
- package/esm2015/tabs/index.js +4 -2
- package/esm2015/tabs/ink-bar.js +55 -59
- package/esm2015/tabs/paginated-tab-header.js +415 -419
- package/esm2015/tabs/tab-body.js +179 -191
- package/esm2015/tabs/tab-content.js +21 -16
- package/esm2015/tabs/tab-group.js +263 -271
- package/esm2015/tabs/tab-header.js +69 -77
- package/esm2015/tabs/tab-label-wrapper.js +29 -33
- package/esm2015/tabs/tab-label.js +16 -13
- package/esm2015/tabs/tab-nav-bar/tab-nav-bar.js +199 -215
- package/esm2015/tabs/tab.js +80 -83
- package/esm2015/tabs/tabs-module.js +38 -42
- package/esm2015/tabs/testing/tab-group-harness.js +52 -56
- package/esm2015/tabs/testing/tab-harness.js +78 -82
- package/esm2015/toolbar/testing/index.js +9 -0
- package/esm2015/toolbar/testing/public-api.js +10 -0
- package/esm2015/toolbar/testing/testing.externs.js +0 -0
- package/esm2015/toolbar/testing/toolbar-harness-filters.js +8 -0
- package/esm2015/toolbar/testing/toolbar-harness.js +47 -0
- package/esm2015/toolbar/toolbar-module.js +10 -14
- package/esm2015/toolbar/toolbar.js +61 -69
- package/esm2015/tooltip/testing/tooltip-harness.js +43 -47
- package/esm2015/tooltip/tooltip-module.js +17 -21
- package/esm2015/tooltip/tooltip.js +502 -497
- package/esm2015/tree/data-source/flat-data-source.js +1 -1
- package/esm2015/tree/node.js +99 -111
- package/esm2015/tree/outlet.js +19 -23
- package/esm2015/tree/padding.js +13 -17
- package/esm2015/tree/toggle.js +15 -19
- package/esm2015/tree/tree-module.js +10 -14
- package/esm2015/tree/tree.js +23 -27
- package/expansion/testing/expansion-harness.d.ts +2 -0
- package/fesm2015/autocomplete/testing.js +98 -95
- package/fesm2015/autocomplete/testing.js.map +1 -1
- package/fesm2015/autocomplete.js +677 -687
- package/fesm2015/autocomplete.js.map +1 -1
- package/fesm2015/badge/testing.js +73 -76
- package/fesm2015/badge/testing.js.map +1 -1
- package/fesm2015/badge.js +195 -201
- package/fesm2015/badge.js.map +1 -1
- package/fesm2015/bottom-sheet/testing.js +28 -31
- package/fesm2015/bottom-sheet/testing.js.map +1 -1
- package/fesm2015/bottom-sheet.js +297 -306
- package/fesm2015/bottom-sheet.js.map +1 -1
- package/fesm2015/button/testing.js +59 -56
- package/fesm2015/button/testing.js.map +1 -1
- package/fesm2015/button-toggle/testing.js +155 -155
- package/fesm2015/button-toggle/testing.js.map +1 -1
- package/fesm2015/button-toggle.js +377 -378
- package/fesm2015/button-toggle.js.map +1 -1
- package/fesm2015/button.js +129 -133
- package/fesm2015/button.js.map +1 -1
- package/fesm2015/card/testing.js +79 -0
- package/fesm2015/card/testing.js.map +1 -0
- package/fesm2015/card.js +175 -220
- package/fesm2015/card.js.map +1 -1
- package/fesm2015/checkbox/testing.js +149 -146
- package/fesm2015/checkbox/testing.js.map +1 -1
- package/fesm2015/checkbox.js +342 -354
- package/fesm2015/checkbox.js.map +1 -1
- package/fesm2015/chips.js +1039 -1039
- package/fesm2015/chips.js.map +1 -1
- package/fesm2015/core/testing.js +88 -94
- package/fesm2015/core/testing.js.map +1 -1
- package/fesm2015/core.js +729 -773
- package/fesm2015/core.js.map +1 -1
- package/fesm2015/datepicker.js +2821 -2884
- package/fesm2015/datepicker.js.map +1 -1
- package/fesm2015/dialog/testing.js +57 -60
- package/fesm2015/dialog/testing.js.map +1 -1
- package/fesm2015/dialog.js +564 -549
- package/fesm2015/dialog.js.map +1 -1
- package/fesm2015/divider/testing.js +15 -18
- package/fesm2015/divider/testing.js.map +1 -1
- package/fesm2015/divider.js +41 -47
- package/fesm2015/divider.js.map +1 -1
- package/fesm2015/expansion/testing.js +159 -159
- package/fesm2015/expansion/testing.js.map +1 -1
- package/fesm2015/expansion.js +422 -446
- package/fesm2015/expansion.js.map +1 -1
- package/fesm2015/form-field/testing.js +219 -204
- package/fesm2015/form-field/testing.js.map +1 -1
- package/fesm2015/form-field.js +538 -532
- package/fesm2015/form-field.js.map +1 -1
- package/fesm2015/grid-list/testing.js +129 -135
- package/fesm2015/grid-list/testing.js.map +1 -1
- package/fesm2015/grid-list.js +221 -242
- package/fesm2015/grid-list.js.map +1 -1
- package/fesm2015/icon/testing.js +65 -71
- package/fesm2015/icon/testing.js.map +1 -1
- package/fesm2015/icon.js +660 -669
- package/fesm2015/icon.js.map +1 -1
- package/fesm2015/input/testing.js +128 -121
- package/fesm2015/input/testing.js.map +1 -1
- package/fesm2015/input.js +353 -337
- package/fesm2015/input.js.map +1 -1
- package/fesm2015/list/testing.js +298 -307
- package/fesm2015/list/testing.js.map +1 -1
- package/fesm2015/list.js +698 -725
- package/fesm2015/list.js.map +1 -1
- package/fesm2015/menu/testing.js +192 -186
- package/fesm2015/menu/testing.js.map +1 -1
- package/fesm2015/menu.js +948 -962
- package/fesm2015/menu.js.map +1 -1
- package/fesm2015/paginator/testing.js +90 -93
- package/fesm2015/paginator/testing.js.map +1 -1
- package/fesm2015/paginator.js +247 -256
- package/fesm2015/paginator.js.map +1 -1
- package/fesm2015/progress-bar/testing.js +26 -29
- package/fesm2015/progress-bar/testing.js.map +1 -1
- package/fesm2015/progress-bar.js +122 -128
- package/fesm2015/progress-bar.js.map +1 -1
- package/fesm2015/progress-spinner/testing.js +27 -30
- package/fesm2015/progress-spinner/testing.js.map +1 -1
- package/fesm2015/progress-spinner.js +196 -205
- package/fesm2015/progress-spinner.js.map +1 -1
- package/fesm2015/radio/testing.js +240 -240
- package/fesm2015/radio/testing.js.map +1 -1
- package/fesm2015/radio.js +447 -453
- package/fesm2015/radio.js.map +1 -1
- package/fesm2015/select/testing.js +137 -134
- package/fesm2015/select/testing.js.map +1 -1
- package/fesm2015/select.js +939 -941
- package/fesm2015/select.js.map +1 -1
- package/fesm2015/sidenav/testing.js +58 -64
- package/fesm2015/sidenav/testing.js.map +1 -1
- package/fesm2015/sidenav.js +765 -762
- package/fesm2015/sidenav.js.map +1 -1
- package/fesm2015/slide-toggle/testing.js +122 -119
- package/fesm2015/slide-toggle/testing.js.map +1 -1
- package/fesm2015/slide-toggle.js +217 -229
- package/fesm2015/slide-toggle.js.map +1 -1
- package/fesm2015/slider/testing.js +128 -125
- package/fesm2015/slider/testing.js.map +1 -1
- package/fesm2015/slider.js +648 -654
- package/fesm2015/slider.js.map +1 -1
- package/fesm2015/snack-bar/testing.js +111 -114
- package/fesm2015/snack-bar/testing.js.map +1 -1
- package/fesm2015/snack-bar.js +426 -431
- package/fesm2015/snack-bar.js.map +1 -1
- package/fesm2015/sort/testing.js +92 -95
- package/fesm2015/sort/testing.js.map +1 -1
- package/fesm2015/sort.js +320 -318
- package/fesm2015/sort.js.map +1 -1
- package/fesm2015/stepper.js +312 -345
- package/fesm2015/stepper.js.map +1 -1
- package/fesm2015/table/testing.js +208 -229
- package/fesm2015/table/testing.js.map +1 -1
- package/fesm2015/table.js +235 -286
- package/fesm2015/table.js.map +1 -1
- package/fesm2015/tabs/testing.js +128 -134
- package/fesm2015/tabs/testing.js.map +1 -1
- package/fesm2015/tabs.js +1362 -1399
- package/fesm2015/tabs.js.map +1 -1
- package/fesm2015/toolbar/testing.js +74 -0
- package/fesm2015/toolbar/testing.js.map +1 -0
- package/fesm2015/toolbar.js +69 -78
- package/fesm2015/toolbar.js.map +1 -1
- package/fesm2015/tooltip/testing.js +42 -45
- package/fesm2015/tooltip/testing.js.map +1 -1
- package/fesm2015/tooltip.js +517 -513
- package/fesm2015/tooltip.js.map +1 -1
- package/fesm2015/tree.js +173 -197
- package/fesm2015/tree.js.map +1 -1
- package/form-field/error.d.ts +7 -0
- package/form-field/hint.d.ts +10 -0
- package/form-field/index.metadata.json +1 -1
- package/form-field/prefix.d.ts +7 -0
- package/form-field/suffix.d.ts +7 -0
- package/form-field/testing/form-field-harness.d.ts +8 -0
- package/grid-list/grid-list.d.ts +2 -1
- package/grid-list/index.metadata.json +1 -1
- package/grid-list/tile-styler.d.ts +10 -5
- package/input/_input-theme.scss +2 -2
- package/input/index.metadata.json +1 -1
- package/input/input.d.ts +6 -2
- package/input/testing/input-harness.d.ts +2 -0
- package/list/index.metadata.json +1 -1
- package/list/testing/action-list-harness.d.ts +2 -0
- package/list/testing/nav-list-harness.d.ts +2 -0
- package/list/testing/selection-list-harness.d.ts +2 -0
- package/menu/index.metadata.json +1 -1
- package/menu/menu-content.d.ts +7 -1
- package/menu/menu-panel.d.ts +1 -0
- package/menu/menu.d.ts +4 -0
- package/menu/testing/menu-harness.d.ts +4 -0
- package/package.json +6 -6
- package/prebuilt-themes/deeppurple-amber.css +1 -1
- package/prebuilt-themes/indigo-pink.css +1 -1
- package/prebuilt-themes/pink-bluegrey.css +1 -1
- package/prebuilt-themes/purple-green.css +1 -1
- package/progress-spinner/index.metadata.json +1 -1
- package/radio/index.metadata.json +1 -1
- package/radio/radio.d.ts +6 -0
- package/radio/testing/radio-harness.d.ts +2 -0
- package/schematics/migration.json +5 -0
- package/schematics/ng-add/index.js +2 -2
- package/schematics/ng-generate/navigation/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template +3 -3
- package/schematics/ng-generate/navigation/schema.json +5 -0
- package/schematics/ng-update/data/index.js +1 -1
- package/schematics/ng-update/index.d.ts +2 -0
- package/schematics/ng-update/index.js +7 -2
- package/schematics/ng-update/migrations/hammer-gestures-v9/hammer-gestures-migration.js +639 -639
- package/schematics/ng-update/migrations/misc-ripples-v7/ripple-speed-factor-migration.js +1 -1
- package/select/index.metadata.json +1 -1
- package/select/select.d.ts +6 -0
- package/select/testing/select-harness.d.ts +2 -0
- package/sidenav/drawer.d.ts +15 -3
- package/sidenav/index.metadata.json +1 -1
- package/slide-toggle/index.metadata.json +1 -1
- package/slide-toggle/testing/slide-toggle-harness.d.ts +2 -0
- package/slider/testing/slider-harness.d.ts +2 -0
- package/snack-bar/index.metadata.json +1 -1
- package/snack-bar/simple-snack-bar.d.ts +13 -1
- package/snack-bar/snack-bar-container.d.ts +16 -3
- package/snack-bar/snack-bar-ref.d.ts +3 -3
- package/snack-bar/snack-bar.d.ts +10 -3
- package/sort/index.metadata.json +1 -1
- package/sort/sort-header-intl.d.ts +5 -1
- package/sort/sort-header.d.ts +3 -1
- package/sort/testing/sort-header-harness.d.ts +6 -2
- package/tabs/index.d.ts +3 -1
- package/tabs/index.metadata.json +1 -1
- package/tabs/tab-content.d.ts +7 -1
- package/tabs/tab-label.d.ts +7 -0
- package/toolbar/testing/index.d.ts +8 -0
- package/toolbar/testing/package.json +9 -0
- package/toolbar/testing/public-api.d.ts +9 -0
- package/toolbar/testing/toolbar-harness-filters.d.ts +13 -0
- package/toolbar/testing/toolbar-harness.d.ts +31 -0
- package/tooltip/index.metadata.json +1 -1
- package/tooltip/tooltip.d.ts +1 -0
- package/tree/data-source/flat-data-source.d.ts +4 -4
- package/tree/index.metadata.json +1 -1
package/fesm2015/select.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Overlay, CdkConnectedOverlay, OverlayModule } from '@angular/cdk/overlay';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { InjectionToken, Directive, EventEmitter, isDevMode, Component, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, NgZone, ElementRef, Optional, Inject, Self, Attribute, ViewChild, ContentChildren, Input, ContentChild, Output, NgModule } from '@angular/core';
|
|
4
|
-
import { mixinDisableRipple, mixinTabIndex, mixinDisabled, mixinErrorState, _countGroupLabelsBeforeOption, _getOptionScrollPosition, MAT_OPTION_PARENT_COMPONENT, ErrorStateMatcher, MatOption,
|
|
4
|
+
import { mixinDisableRipple, mixinTabIndex, mixinDisabled, mixinErrorState, _countGroupLabelsBeforeOption, _getOptionScrollPosition, MAT_OPTION_PARENT_COMPONENT, ErrorStateMatcher, MatOption, MAT_OPTGROUP, MatOptionModule, MatCommonModule } from '@angular/material/core';
|
|
5
5
|
import { MatFormFieldControl, MatFormField, MAT_FORM_FIELD, MatFormFieldModule } from '@angular/material/form-field';
|
|
6
6
|
import { ViewportRuler, CdkScrollableModule } from '@angular/cdk/scrolling';
|
|
7
7
|
import { ActiveDescendantKeyManager, LiveAnnouncer } from '@angular/cdk/a11y';
|
|
@@ -174,1005 +174,1006 @@ class MatSelectBase {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
const _MatSelectMixinBase = mixinDisableRipple(mixinTabIndex(mixinDisabled(mixinErrorState(MatSelectBase))));
|
|
177
|
+
/**
|
|
178
|
+
* Injection token that can be used to reference instances of `MatSelectTrigger`. It serves as
|
|
179
|
+
* alternative token to the actual `MatSelectTrigger` class which could cause unnecessary
|
|
180
|
+
* retention of the class and its directive metadata.
|
|
181
|
+
*/
|
|
182
|
+
const MAT_SELECT_TRIGGER = new InjectionToken('MatSelectTrigger');
|
|
177
183
|
/**
|
|
178
184
|
* Allows the user to customize the trigger that is displayed when the select has a value.
|
|
179
185
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
this._transformOrigin = 'top';
|
|
225
|
-
/** Emits when the panel element is finished transforming in. */
|
|
226
|
-
this._panelDoneAnimatingStream = new Subject();
|
|
227
|
-
/**
|
|
228
|
-
* The y-offset of the overlay panel in relation to the trigger's top start corner.
|
|
229
|
-
* This must be adjusted to align the selected option text over the trigger text.
|
|
230
|
-
* when the panel opens. Will change based on the y-position of the selected option.
|
|
231
|
-
*/
|
|
232
|
-
this._offsetY = 0;
|
|
233
|
-
/**
|
|
234
|
-
* This position config ensures that the top "start" corner of the overlay
|
|
235
|
-
* is aligned with with the top "start" of the origin by default (overlapping
|
|
236
|
-
* the trigger completely). If the panel cannot fit below the trigger, it
|
|
237
|
-
* will fall back to a position above the trigger.
|
|
238
|
-
*/
|
|
239
|
-
this._positions = [
|
|
240
|
-
{
|
|
241
|
-
originX: 'start',
|
|
242
|
-
originY: 'top',
|
|
243
|
-
overlayX: 'start',
|
|
244
|
-
overlayY: 'top',
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
originX: 'start',
|
|
248
|
-
originY: 'bottom',
|
|
249
|
-
overlayX: 'start',
|
|
250
|
-
overlayY: 'bottom',
|
|
251
|
-
},
|
|
252
|
-
];
|
|
253
|
-
/** Whether the component is disabling centering of the active option over the trigger. */
|
|
254
|
-
this._disableOptionCentering = false;
|
|
255
|
-
this._focused = false;
|
|
256
|
-
/** A name for this control that can be used by `mat-form-field`. */
|
|
257
|
-
this.controlType = 'mat-select';
|
|
258
|
-
/** Aria label of the select. If not specified, the placeholder will be used as label. */
|
|
259
|
-
this.ariaLabel = '';
|
|
260
|
-
/** Combined stream of all of the child options' change events. */
|
|
261
|
-
this.optionSelectionChanges = defer(() => {
|
|
262
|
-
const options = this.options;
|
|
263
|
-
if (options) {
|
|
264
|
-
return options.changes.pipe(startWith(options), switchMap(() => merge(...options.map(option => option.onSelectionChange))));
|
|
265
|
-
}
|
|
266
|
-
return this._ngZone.onStable
|
|
267
|
-
.asObservable()
|
|
268
|
-
.pipe(take(1), switchMap(() => this.optionSelectionChanges));
|
|
269
|
-
});
|
|
270
|
-
/** Event emitted when the select panel has been toggled. */
|
|
271
|
-
this.openedChange = new EventEmitter();
|
|
272
|
-
/** Event emitted when the select has been opened. */
|
|
273
|
-
this._openedStream = this.openedChange.pipe(filter(o => o), map(() => { }));
|
|
274
|
-
/** Event emitted when the select has been closed. */
|
|
275
|
-
this._closedStream = this.openedChange.pipe(filter(o => !o), map(() => { }));
|
|
276
|
-
/** Event emitted when the selected value has been changed by the user. */
|
|
277
|
-
this.selectionChange = new EventEmitter();
|
|
278
|
-
/**
|
|
279
|
-
* Event that emits whenever the raw value of the select changes. This is here primarily
|
|
280
|
-
* to facilitate the two-way binding for the `value` input.
|
|
281
|
-
* @docs-private
|
|
282
|
-
*/
|
|
283
|
-
this.valueChange = new EventEmitter();
|
|
284
|
-
if (this.ngControl) {
|
|
285
|
-
// Note: we provide the value accessor through here, instead of
|
|
286
|
-
// the `providers` to avoid running into a circular import.
|
|
287
|
-
this.ngControl.valueAccessor = this;
|
|
288
|
-
}
|
|
289
|
-
this._scrollStrategyFactory = scrollStrategyFactory;
|
|
290
|
-
this._scrollStrategy = this._scrollStrategyFactory();
|
|
291
|
-
this.tabIndex = parseInt(tabIndex) || 0;
|
|
292
|
-
// Force setter to be called in case id was not specified.
|
|
293
|
-
this.id = this.id;
|
|
294
|
-
if (defaults) {
|
|
295
|
-
if (defaults.disableOptionCentering != null) {
|
|
296
|
-
this.disableOptionCentering = defaults.disableOptionCentering;
|
|
297
|
-
}
|
|
298
|
-
if (defaults.typeaheadDebounceInterval != null) {
|
|
299
|
-
this.typeaheadDebounceInterval = defaults.typeaheadDebounceInterval;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
/** Whether the select is focused. */
|
|
304
|
-
get focused() {
|
|
305
|
-
return this._focused || this._panelOpen;
|
|
306
|
-
}
|
|
307
|
-
/** Placeholder to be shown if no value has been selected. */
|
|
308
|
-
get placeholder() { return this._placeholder; }
|
|
309
|
-
set placeholder(value) {
|
|
310
|
-
this._placeholder = value;
|
|
311
|
-
this.stateChanges.next();
|
|
312
|
-
}
|
|
313
|
-
/** Whether the component is required. */
|
|
314
|
-
get required() { return this._required; }
|
|
315
|
-
set required(value) {
|
|
316
|
-
this._required = coerceBooleanProperty(value);
|
|
317
|
-
this.stateChanges.next();
|
|
318
|
-
}
|
|
319
|
-
/** Whether the user should be allowed to select multiple options. */
|
|
320
|
-
get multiple() { return this._multiple; }
|
|
321
|
-
set multiple(value) {
|
|
322
|
-
if (this._selectionModel) {
|
|
323
|
-
throw getMatSelectDynamicMultipleError();
|
|
324
|
-
}
|
|
325
|
-
this._multiple = coerceBooleanProperty(value);
|
|
326
|
-
}
|
|
327
|
-
/** Whether to center the active option over the trigger. */
|
|
328
|
-
get disableOptionCentering() { return this._disableOptionCentering; }
|
|
329
|
-
set disableOptionCentering(value) {
|
|
330
|
-
this._disableOptionCentering = coerceBooleanProperty(value);
|
|
331
|
-
}
|
|
186
|
+
class MatSelectTrigger {
|
|
187
|
+
}
|
|
188
|
+
MatSelectTrigger.decorators = [
|
|
189
|
+
{ type: Directive, args: [{
|
|
190
|
+
selector: 'mat-select-trigger',
|
|
191
|
+
providers: [{ provide: MAT_SELECT_TRIGGER, useExisting: MatSelectTrigger }],
|
|
192
|
+
},] }
|
|
193
|
+
];
|
|
194
|
+
class MatSelect extends _MatSelectMixinBase {
|
|
195
|
+
constructor(_viewportRuler, _changeDetectorRef, _ngZone, _defaultErrorStateMatcher, elementRef, _dir, _parentForm, _parentFormGroup, _parentFormField, ngControl, tabIndex, scrollStrategyFactory, _liveAnnouncer, defaults) {
|
|
196
|
+
super(elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
|
|
197
|
+
this._viewportRuler = _viewportRuler;
|
|
198
|
+
this._changeDetectorRef = _changeDetectorRef;
|
|
199
|
+
this._ngZone = _ngZone;
|
|
200
|
+
this._dir = _dir;
|
|
201
|
+
this._parentFormField = _parentFormField;
|
|
202
|
+
this.ngControl = ngControl;
|
|
203
|
+
this._liveAnnouncer = _liveAnnouncer;
|
|
204
|
+
/** Whether or not the overlay panel is open. */
|
|
205
|
+
this._panelOpen = false;
|
|
206
|
+
/** Whether filling out the select is required in the form. */
|
|
207
|
+
this._required = false;
|
|
208
|
+
/** The scroll position of the overlay panel, calculated to center the selected option. */
|
|
209
|
+
this._scrollTop = 0;
|
|
210
|
+
/** Whether the component is in multiple selection mode. */
|
|
211
|
+
this._multiple = false;
|
|
212
|
+
/** Comparison function to specify which option is displayed. Defaults to object equality. */
|
|
213
|
+
this._compareWith = (o1, o2) => o1 === o2;
|
|
214
|
+
/** Unique id for this input. */
|
|
215
|
+
this._uid = `mat-select-${nextUniqueId++}`;
|
|
216
|
+
/** Emits whenever the component is destroyed. */
|
|
217
|
+
this._destroy = new Subject();
|
|
218
|
+
/** The cached font-size of the trigger element. */
|
|
219
|
+
this._triggerFontSize = 0;
|
|
220
|
+
/** `View -> model callback called when value changes` */
|
|
221
|
+
this._onChange = () => { };
|
|
222
|
+
/** `View -> model callback called when select has been touched` */
|
|
223
|
+
this._onTouched = () => { };
|
|
224
|
+
/** The IDs of child options to be passed to the aria-owns attribute. */
|
|
225
|
+
this._optionIds = '';
|
|
226
|
+
/** The value of the select panel's transform-origin property. */
|
|
227
|
+
this._transformOrigin = 'top';
|
|
228
|
+
/** Emits when the panel element is finished transforming in. */
|
|
229
|
+
this._panelDoneAnimatingStream = new Subject();
|
|
332
230
|
/**
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
231
|
+
* The y-offset of the overlay panel in relation to the trigger's top start corner.
|
|
232
|
+
* This must be adjusted to align the selected option text over the trigger text.
|
|
233
|
+
* when the panel opens. Will change based on the y-position of the selected option.
|
|
336
234
|
*/
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
235
|
+
this._offsetY = 0;
|
|
236
|
+
/**
|
|
237
|
+
* This position config ensures that the top "start" corner of the overlay
|
|
238
|
+
* is aligned with with the top "start" of the origin by default (overlapping
|
|
239
|
+
* the trigger completely). If the panel cannot fit below the trigger, it
|
|
240
|
+
* will fall back to a position above the trigger.
|
|
241
|
+
*/
|
|
242
|
+
this._positions = [
|
|
243
|
+
{
|
|
244
|
+
originX: 'start',
|
|
245
|
+
originY: 'top',
|
|
246
|
+
overlayX: 'start',
|
|
247
|
+
overlayY: 'top',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
originX: 'start',
|
|
251
|
+
originY: 'bottom',
|
|
252
|
+
overlayX: 'start',
|
|
253
|
+
overlayY: 'bottom',
|
|
254
|
+
},
|
|
255
|
+
];
|
|
256
|
+
/** Whether the component is disabling centering of the active option over the trigger. */
|
|
257
|
+
this._disableOptionCentering = false;
|
|
258
|
+
this._focused = false;
|
|
259
|
+
/** A name for this control that can be used by `mat-form-field`. */
|
|
260
|
+
this.controlType = 'mat-select';
|
|
261
|
+
/** Aria label of the select. If not specified, the placeholder will be used as label. */
|
|
262
|
+
this.ariaLabel = '';
|
|
263
|
+
/** Combined stream of all of the child options' change events. */
|
|
264
|
+
this.optionSelectionChanges = defer(() => {
|
|
265
|
+
const options = this.options;
|
|
266
|
+
if (options) {
|
|
267
|
+
return options.changes.pipe(startWith(options), switchMap(() => merge(...options.map(option => option.onSelectionChange))));
|
|
346
268
|
}
|
|
269
|
+
return this._ngZone.onStable
|
|
270
|
+
.asObservable()
|
|
271
|
+
.pipe(take(1), switchMap(() => this.optionSelectionChanges));
|
|
272
|
+
});
|
|
273
|
+
/** Event emitted when the select panel has been toggled. */
|
|
274
|
+
this.openedChange = new EventEmitter();
|
|
275
|
+
/** Event emitted when the select has been opened. */
|
|
276
|
+
this._openedStream = this.openedChange.pipe(filter(o => o), map(() => { }));
|
|
277
|
+
/** Event emitted when the select has been closed. */
|
|
278
|
+
this._closedStream = this.openedChange.pipe(filter(o => !o), map(() => { }));
|
|
279
|
+
/** Event emitted when the selected value has been changed by the user. */
|
|
280
|
+
this.selectionChange = new EventEmitter();
|
|
281
|
+
/**
|
|
282
|
+
* Event that emits whenever the raw value of the select changes. This is here primarily
|
|
283
|
+
* to facilitate the two-way binding for the `value` input.
|
|
284
|
+
* @docs-private
|
|
285
|
+
*/
|
|
286
|
+
this.valueChange = new EventEmitter();
|
|
287
|
+
if (this.ngControl) {
|
|
288
|
+
// Note: we provide the value accessor through here, instead of
|
|
289
|
+
// the `providers` to avoid running into a circular import.
|
|
290
|
+
this.ngControl.valueAccessor = this;
|
|
347
291
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
292
|
+
this._scrollStrategyFactory = scrollStrategyFactory;
|
|
293
|
+
this._scrollStrategy = this._scrollStrategyFactory();
|
|
294
|
+
this.tabIndex = parseInt(tabIndex) || 0;
|
|
295
|
+
// Force setter to be called in case id was not specified.
|
|
296
|
+
this.id = this.id;
|
|
297
|
+
if (defaults) {
|
|
298
|
+
if (defaults.disableOptionCentering != null) {
|
|
299
|
+
this.disableOptionCentering = defaults.disableOptionCentering;
|
|
300
|
+
}
|
|
301
|
+
if (defaults.typeaheadDebounceInterval != null) {
|
|
302
|
+
this.typeaheadDebounceInterval = defaults.typeaheadDebounceInterval;
|
|
354
303
|
}
|
|
355
304
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
305
|
+
}
|
|
306
|
+
/** Whether the select is focused. */
|
|
307
|
+
get focused() {
|
|
308
|
+
return this._focused || this._panelOpen;
|
|
309
|
+
}
|
|
310
|
+
/** Placeholder to be shown if no value has been selected. */
|
|
311
|
+
get placeholder() { return this._placeholder; }
|
|
312
|
+
set placeholder(value) {
|
|
313
|
+
this._placeholder = value;
|
|
314
|
+
this.stateChanges.next();
|
|
315
|
+
}
|
|
316
|
+
/** Whether the component is required. */
|
|
317
|
+
get required() { return this._required; }
|
|
318
|
+
set required(value) {
|
|
319
|
+
this._required = coerceBooleanProperty(value);
|
|
320
|
+
this.stateChanges.next();
|
|
321
|
+
}
|
|
322
|
+
/** Whether the user should be allowed to select multiple options. */
|
|
323
|
+
get multiple() { return this._multiple; }
|
|
324
|
+
set multiple(value) {
|
|
325
|
+
if (this._selectionModel) {
|
|
326
|
+
throw getMatSelectDynamicMultipleError();
|
|
366
327
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
this._changeDetectorRef.markForCheck();
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
this._viewportRuler.change()
|
|
387
|
-
.pipe(takeUntil(this._destroy))
|
|
388
|
-
.subscribe(() => {
|
|
389
|
-
if (this._panelOpen) {
|
|
390
|
-
this._triggerRect = this.trigger.nativeElement.getBoundingClientRect();
|
|
391
|
-
this._changeDetectorRef.markForCheck();
|
|
392
|
-
}
|
|
393
|
-
});
|
|
328
|
+
this._multiple = coerceBooleanProperty(value);
|
|
329
|
+
}
|
|
330
|
+
/** Whether to center the active option over the trigger. */
|
|
331
|
+
get disableOptionCentering() { return this._disableOptionCentering; }
|
|
332
|
+
set disableOptionCentering(value) {
|
|
333
|
+
this._disableOptionCentering = coerceBooleanProperty(value);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Function to compare the option values with the selected values. The first argument
|
|
337
|
+
* is a value from an option. The second is a value from the selection. A boolean
|
|
338
|
+
* should be returned.
|
|
339
|
+
*/
|
|
340
|
+
get compareWith() { return this._compareWith; }
|
|
341
|
+
set compareWith(fn) {
|
|
342
|
+
if (typeof fn !== 'function') {
|
|
343
|
+
throw getMatSelectNonFunctionValueError();
|
|
394
344
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
event.removed.forEach(option => option.deselect());
|
|
400
|
-
});
|
|
401
|
-
this.options.changes.pipe(startWith(null), takeUntil(this._destroy)).subscribe(() => {
|
|
402
|
-
this._resetOptions();
|
|
403
|
-
this._initializeSelection();
|
|
404
|
-
});
|
|
345
|
+
this._compareWith = fn;
|
|
346
|
+
if (this._selectionModel) {
|
|
347
|
+
// A different comparator means the selection could change.
|
|
348
|
+
this._initializeSelection();
|
|
405
349
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
350
|
+
}
|
|
351
|
+
/** Value of the select control. */
|
|
352
|
+
get value() { return this._value; }
|
|
353
|
+
set value(newValue) {
|
|
354
|
+
if (newValue !== this._value) {
|
|
355
|
+
this.writeValue(newValue);
|
|
356
|
+
this._value = newValue;
|
|
410
357
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
358
|
+
}
|
|
359
|
+
/** Time to wait in milliseconds after the last keystroke before moving focus to an item. */
|
|
360
|
+
get typeaheadDebounceInterval() { return this._typeaheadDebounceInterval; }
|
|
361
|
+
set typeaheadDebounceInterval(value) {
|
|
362
|
+
this._typeaheadDebounceInterval = coerceNumberProperty(value);
|
|
363
|
+
}
|
|
364
|
+
/** Unique id of the element. */
|
|
365
|
+
get id() { return this._id; }
|
|
366
|
+
set id(value) {
|
|
367
|
+
this._id = value || this._uid;
|
|
368
|
+
this.stateChanges.next();
|
|
369
|
+
}
|
|
370
|
+
ngOnInit() {
|
|
371
|
+
this._selectionModel = new SelectionModel(this.multiple);
|
|
372
|
+
this.stateChanges.next();
|
|
373
|
+
// We need `distinctUntilChanged` here, because some browsers will
|
|
374
|
+
// fire the animation end event twice for the same animation. See:
|
|
375
|
+
// https://github.com/angular/angular/issues/24084
|
|
376
|
+
this._panelDoneAnimatingStream
|
|
377
|
+
.pipe(distinctUntilChanged(), takeUntil(this._destroy))
|
|
378
|
+
.subscribe(() => {
|
|
379
|
+
if (this.panelOpen) {
|
|
380
|
+
this._scrollTop = 0;
|
|
381
|
+
this.openedChange.emit(true);
|
|
419
382
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
this.stateChanges.complete();
|
|
425
|
-
}
|
|
426
|
-
/** Toggles the overlay panel open or closed. */
|
|
427
|
-
toggle() {
|
|
428
|
-
this.panelOpen ? this.close() : this.open();
|
|
429
|
-
}
|
|
430
|
-
/** Opens the overlay panel. */
|
|
431
|
-
open() {
|
|
432
|
-
if (this.disabled || !this.options || !this.options.length || this._panelOpen) {
|
|
433
|
-
return;
|
|
383
|
+
else {
|
|
384
|
+
this.openedChange.emit(false);
|
|
385
|
+
this.overlayDir.offsetX = 0;
|
|
386
|
+
this._changeDetectorRef.markForCheck();
|
|
434
387
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
this._panelOpen = true;
|
|
440
|
-
this._keyManager.withHorizontalOrientation(null);
|
|
441
|
-
this._calculateOverlayPosition();
|
|
442
|
-
this._highlightCorrectOption();
|
|
443
|
-
this._changeDetectorRef.markForCheck();
|
|
444
|
-
// Set the font size on the panel element once it exists.
|
|
445
|
-
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
|
|
446
|
-
if (this._triggerFontSize && this.overlayDir.overlayRef &&
|
|
447
|
-
this.overlayDir.overlayRef.overlayElement) {
|
|
448
|
-
this.overlayDir.overlayRef.overlayElement.style.fontSize = `${this._triggerFontSize}px`;
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
/** Closes the overlay panel and focuses the host element. */
|
|
453
|
-
close() {
|
|
388
|
+
});
|
|
389
|
+
this._viewportRuler.change()
|
|
390
|
+
.pipe(takeUntil(this._destroy))
|
|
391
|
+
.subscribe(() => {
|
|
454
392
|
if (this._panelOpen) {
|
|
455
|
-
this.
|
|
456
|
-
this._keyManager.withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr');
|
|
393
|
+
this._triggerRect = this.trigger.nativeElement.getBoundingClientRect();
|
|
457
394
|
this._changeDetectorRef.markForCheck();
|
|
458
|
-
this._onTouched();
|
|
459
395
|
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
ngAfterContentInit() {
|
|
399
|
+
this._initKeyManager();
|
|
400
|
+
this._selectionModel.changed.pipe(takeUntil(this._destroy)).subscribe(event => {
|
|
401
|
+
event.added.forEach(option => option.select());
|
|
402
|
+
event.removed.forEach(option => option.deselect());
|
|
403
|
+
});
|
|
404
|
+
this.options.changes.pipe(startWith(null), takeUntil(this._destroy)).subscribe(() => {
|
|
405
|
+
this._resetOptions();
|
|
406
|
+
this._initializeSelection();
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
ngDoCheck() {
|
|
410
|
+
if (this.ngControl) {
|
|
411
|
+
this.updateErrorState();
|
|
460
412
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
writeValue(value) {
|
|
468
|
-
if (this.options) {
|
|
469
|
-
this._setSelectionByValue(value);
|
|
470
|
-
}
|
|
413
|
+
}
|
|
414
|
+
ngOnChanges(changes) {
|
|
415
|
+
// Updating the disabled state is handled by `mixinDisabled`, but we need to additionally let
|
|
416
|
+
// the parent form field know to run change detection when the disabled state changes.
|
|
417
|
+
if (changes['disabled']) {
|
|
418
|
+
this.stateChanges.next();
|
|
471
419
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
* changes from user input. Part of the ControlValueAccessor interface
|
|
475
|
-
* required to integrate with Angular's core forms API.
|
|
476
|
-
*
|
|
477
|
-
* @param fn Callback to be triggered when the value changes.
|
|
478
|
-
*/
|
|
479
|
-
registerOnChange(fn) {
|
|
480
|
-
this._onChange = fn;
|
|
420
|
+
if (changes['typeaheadDebounceInterval'] && this._keyManager) {
|
|
421
|
+
this._keyManager.withTypeAhead(this._typeaheadDebounceInterval);
|
|
481
422
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
423
|
+
}
|
|
424
|
+
ngOnDestroy() {
|
|
425
|
+
this._destroy.next();
|
|
426
|
+
this._destroy.complete();
|
|
427
|
+
this.stateChanges.complete();
|
|
428
|
+
}
|
|
429
|
+
/** Toggles the overlay panel open or closed. */
|
|
430
|
+
toggle() {
|
|
431
|
+
this.panelOpen ? this.close() : this.open();
|
|
432
|
+
}
|
|
433
|
+
/** Opens the overlay panel. */
|
|
434
|
+
open() {
|
|
435
|
+
if (this.disabled || !this.options || !this.options.length || this._panelOpen) {
|
|
436
|
+
return;
|
|
491
437
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
438
|
+
this._triggerRect = this.trigger.nativeElement.getBoundingClientRect();
|
|
439
|
+
// Note: The computed font-size will be a string pixel value (e.g. "16px").
|
|
440
|
+
// `parseInt` ignores the trailing 'px' and converts this to a number.
|
|
441
|
+
this._triggerFontSize = parseInt(getComputedStyle(this.trigger.nativeElement).fontSize || '0');
|
|
442
|
+
this._panelOpen = true;
|
|
443
|
+
this._keyManager.withHorizontalOrientation(null);
|
|
444
|
+
this._calculateOverlayPosition();
|
|
445
|
+
this._highlightCorrectOption();
|
|
446
|
+
this._changeDetectorRef.markForCheck();
|
|
447
|
+
// Set the font size on the panel element once it exists.
|
|
448
|
+
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
|
|
449
|
+
if (this._triggerFontSize && this.overlayDir.overlayRef &&
|
|
450
|
+
this.overlayDir.overlayRef.overlayElement) {
|
|
451
|
+
this.overlayDir.overlayRef.overlayElement.style.fontSize = `${this._triggerFontSize}px`;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
/** Closes the overlay panel and focuses the host element. */
|
|
456
|
+
close() {
|
|
457
|
+
if (this._panelOpen) {
|
|
458
|
+
this._panelOpen = false;
|
|
459
|
+
this._keyManager.withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr');
|
|
500
460
|
this._changeDetectorRef.markForCheck();
|
|
501
|
-
this.
|
|
461
|
+
this._onTouched();
|
|
502
462
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Sets the select's value. Part of the ControlValueAccessor interface
|
|
466
|
+
* required to integrate with Angular's core forms API.
|
|
467
|
+
*
|
|
468
|
+
* @param value New value to be written to the model.
|
|
469
|
+
*/
|
|
470
|
+
writeValue(value) {
|
|
471
|
+
if (this.options) {
|
|
472
|
+
this._setSelectionByValue(value);
|
|
506
473
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Saves a callback function to be invoked when the select's value
|
|
477
|
+
* changes from user input. Part of the ControlValueAccessor interface
|
|
478
|
+
* required to integrate with Angular's core forms API.
|
|
479
|
+
*
|
|
480
|
+
* @param fn Callback to be triggered when the value changes.
|
|
481
|
+
*/
|
|
482
|
+
registerOnChange(fn) {
|
|
483
|
+
this._onChange = fn;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Saves a callback function to be invoked when the select is blurred
|
|
487
|
+
* by the user. Part of the ControlValueAccessor interface required
|
|
488
|
+
* to integrate with Angular's core forms API.
|
|
489
|
+
*
|
|
490
|
+
* @param fn Callback to be triggered when the component has been touched.
|
|
491
|
+
*/
|
|
492
|
+
registerOnTouched(fn) {
|
|
493
|
+
this._onTouched = fn;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Disables the select. Part of the ControlValueAccessor interface required
|
|
497
|
+
* to integrate with Angular's core forms API.
|
|
498
|
+
*
|
|
499
|
+
* @param isDisabled Sets whether the component is disabled.
|
|
500
|
+
*/
|
|
501
|
+
setDisabledState(isDisabled) {
|
|
502
|
+
this.disabled = isDisabled;
|
|
503
|
+
this._changeDetectorRef.markForCheck();
|
|
504
|
+
this.stateChanges.next();
|
|
505
|
+
}
|
|
506
|
+
/** Whether or not the overlay panel is open. */
|
|
507
|
+
get panelOpen() {
|
|
508
|
+
return this._panelOpen;
|
|
509
|
+
}
|
|
510
|
+
/** The currently selected option. */
|
|
511
|
+
get selected() {
|
|
512
|
+
return this.multiple ? this._selectionModel.selected : this._selectionModel.selected[0];
|
|
513
|
+
}
|
|
514
|
+
/** The value displayed in the trigger. */
|
|
515
|
+
get triggerValue() {
|
|
516
|
+
if (this.empty) {
|
|
517
|
+
return '';
|
|
510
518
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (this.
|
|
514
|
-
|
|
519
|
+
if (this._multiple) {
|
|
520
|
+
const selectedOptions = this._selectionModel.selected.map(option => option.viewValue);
|
|
521
|
+
if (this._isRtl()) {
|
|
522
|
+
selectedOptions.reverse();
|
|
515
523
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
if (this._isRtl()) {
|
|
519
|
-
selectedOptions.reverse();
|
|
520
|
-
}
|
|
521
|
-
// TODO(crisbeto): delimiter should be configurable for proper localization.
|
|
522
|
-
return selectedOptions.join(', ');
|
|
523
|
-
}
|
|
524
|
-
return this._selectionModel.selected[0].viewValue;
|
|
525
|
-
}
|
|
526
|
-
/** Whether the element is in RTL mode. */
|
|
527
|
-
_isRtl() {
|
|
528
|
-
return this._dir ? this._dir.value === 'rtl' : false;
|
|
524
|
+
// TODO(crisbeto): delimiter should be configurable for proper localization.
|
|
525
|
+
return selectedOptions.join(', ');
|
|
529
526
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
527
|
+
return this._selectionModel.selected[0].viewValue;
|
|
528
|
+
}
|
|
529
|
+
/** Whether the element is in RTL mode. */
|
|
530
|
+
_isRtl() {
|
|
531
|
+
return this._dir ? this._dir.value === 'rtl' : false;
|
|
532
|
+
}
|
|
533
|
+
/** Handles all keydown events on the select. */
|
|
534
|
+
_handleKeydown(event) {
|
|
535
|
+
if (!this.disabled) {
|
|
536
|
+
this.panelOpen ? this._handleOpenKeydown(event) : this._handleClosedKeydown(event);
|
|
535
537
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
else if (!this.multiple) {
|
|
550
|
-
const previouslySelectedOption = this.selected;
|
|
551
|
-
if (keyCode === HOME || keyCode === END) {
|
|
552
|
-
keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
|
|
553
|
-
event.preventDefault();
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
manager.onKeydown(event);
|
|
557
|
-
}
|
|
558
|
-
const selectedOption = this.selected;
|
|
559
|
-
// Since the value has changed, we need to announce it ourselves.
|
|
560
|
-
if (selectedOption && previouslySelectedOption !== selectedOption) {
|
|
561
|
-
// We set a duration on the live announcement, because we want the live element to be
|
|
562
|
-
// cleared after a while so that users can't navigate to it using the arrow keys.
|
|
563
|
-
this._liveAnnouncer.announce(selectedOption.viewValue, 10000);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
538
|
+
}
|
|
539
|
+
/** Handles keyboard events while the select is closed. */
|
|
540
|
+
_handleClosedKeydown(event) {
|
|
541
|
+
const keyCode = event.keyCode;
|
|
542
|
+
const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW ||
|
|
543
|
+
keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW;
|
|
544
|
+
const isOpenKey = keyCode === ENTER || keyCode === SPACE;
|
|
545
|
+
const manager = this._keyManager;
|
|
546
|
+
// Open the select on ALT + arrow key to match the native <select>
|
|
547
|
+
if (!manager.isTyping() && (isOpenKey && !hasModifierKey(event)) ||
|
|
548
|
+
((this.multiple || event.altKey) && isArrowKey)) {
|
|
549
|
+
event.preventDefault(); // prevents the page from scrolling down when pressing space
|
|
550
|
+
this.open();
|
|
566
551
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const manager = this._keyManager;
|
|
570
|
-
const keyCode = event.keyCode;
|
|
571
|
-
const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW;
|
|
572
|
-
const isTyping = manager.isTyping();
|
|
552
|
+
else if (!this.multiple) {
|
|
553
|
+
const previouslySelectedOption = this.selected;
|
|
573
554
|
if (keyCode === HOME || keyCode === END) {
|
|
574
|
-
event.preventDefault();
|
|
575
555
|
keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
|
|
576
|
-
}
|
|
577
|
-
else if (isArrowKey && event.altKey) {
|
|
578
|
-
// Close the select on ALT + arrow key to match the native <select>
|
|
579
|
-
event.preventDefault();
|
|
580
|
-
this.close();
|
|
581
|
-
// Don't do anything in this case if the user is typing,
|
|
582
|
-
// because the typing sequence can include the space key.
|
|
583
|
-
}
|
|
584
|
-
else if (!isTyping && (keyCode === ENTER || keyCode === SPACE) && manager.activeItem &&
|
|
585
|
-
!hasModifierKey(event)) {
|
|
586
556
|
event.preventDefault();
|
|
587
|
-
manager.activeItem._selectViaInteraction();
|
|
588
|
-
}
|
|
589
|
-
else if (!isTyping && this._multiple && keyCode === A && event.ctrlKey) {
|
|
590
|
-
event.preventDefault();
|
|
591
|
-
const hasDeselectedOptions = this.options.some(opt => !opt.disabled && !opt.selected);
|
|
592
|
-
this.options.forEach(option => {
|
|
593
|
-
if (!option.disabled) {
|
|
594
|
-
hasDeselectedOptions ? option.select() : option.deselect();
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
557
|
}
|
|
598
558
|
else {
|
|
599
|
-
const previouslyFocusedIndex = manager.activeItemIndex;
|
|
600
559
|
manager.onKeydown(event);
|
|
601
|
-
if (this._multiple && isArrowKey && event.shiftKey && manager.activeItem &&
|
|
602
|
-
manager.activeItemIndex !== previouslyFocusedIndex) {
|
|
603
|
-
manager.activeItem._selectViaInteraction();
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
_onFocus() {
|
|
608
|
-
if (!this.disabled) {
|
|
609
|
-
this._focused = true;
|
|
610
|
-
this.stateChanges.next();
|
|
611
560
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
this._focused = false;
|
|
619
|
-
if (!this.disabled && !this.panelOpen) {
|
|
620
|
-
this._onTouched();
|
|
621
|
-
this._changeDetectorRef.markForCheck();
|
|
622
|
-
this.stateChanges.next();
|
|
561
|
+
const selectedOption = this.selected;
|
|
562
|
+
// Since the value has changed, we need to announce it ourselves.
|
|
563
|
+
if (selectedOption && previouslySelectedOption !== selectedOption) {
|
|
564
|
+
// We set a duration on the live announcement, because we want the live element to be
|
|
565
|
+
// cleared after a while so that users can't navigate to it using the arrow keys.
|
|
566
|
+
this._liveAnnouncer.announce(selectedOption.viewValue, 10000);
|
|
623
567
|
}
|
|
624
568
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
569
|
+
}
|
|
570
|
+
/** Handles keyboard events when the selected is open. */
|
|
571
|
+
_handleOpenKeydown(event) {
|
|
572
|
+
const manager = this._keyManager;
|
|
573
|
+
const keyCode = event.keyCode;
|
|
574
|
+
const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW;
|
|
575
|
+
const isTyping = manager.isTyping();
|
|
576
|
+
if (keyCode === HOME || keyCode === END) {
|
|
577
|
+
event.preventDefault();
|
|
578
|
+
keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
|
|
634
579
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
580
|
+
else if (isArrowKey && event.altKey) {
|
|
581
|
+
// Close the select on ALT + arrow key to match the native <select>
|
|
582
|
+
event.preventDefault();
|
|
583
|
+
this.close();
|
|
584
|
+
// Don't do anything in this case if the user is typing,
|
|
585
|
+
// because the typing sequence can include the space key.
|
|
638
586
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
587
|
+
else if (!isTyping && (keyCode === ENTER || keyCode === SPACE) && manager.activeItem &&
|
|
588
|
+
!hasModifierKey(event)) {
|
|
589
|
+
event.preventDefault();
|
|
590
|
+
manager.activeItem._selectViaInteraction();
|
|
642
591
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
592
|
+
else if (!isTyping && this._multiple && keyCode === A && event.ctrlKey) {
|
|
593
|
+
event.preventDefault();
|
|
594
|
+
const hasDeselectedOptions = this.options.some(opt => !opt.disabled && !opt.selected);
|
|
595
|
+
this.options.forEach(option => {
|
|
596
|
+
if (!option.disabled) {
|
|
597
|
+
hasDeselectedOptions ? option.select() : option.deselect();
|
|
598
|
+
}
|
|
649
599
|
});
|
|
650
600
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
if (!Array.isArray(value)) {
|
|
658
|
-
throw getMatSelectNonArrayValueError();
|
|
659
|
-
}
|
|
660
|
-
this._selectionModel.clear();
|
|
661
|
-
value.forEach((currentValue) => this._selectValue(currentValue));
|
|
662
|
-
this._sortValues();
|
|
663
|
-
}
|
|
664
|
-
else {
|
|
665
|
-
this._selectionModel.clear();
|
|
666
|
-
const correspondingOption = this._selectValue(value);
|
|
667
|
-
// Shift focus to the active item. Note that we shouldn't do this in multiple
|
|
668
|
-
// mode, because we don't know what option the user interacted with last.
|
|
669
|
-
if (correspondingOption) {
|
|
670
|
-
this._keyManager.setActiveItem(correspondingOption);
|
|
671
|
-
}
|
|
672
|
-
else if (!this.panelOpen) {
|
|
673
|
-
// Otherwise reset the highlighted option. Note that we only want to do this while
|
|
674
|
-
// closed, because doing it while open can shift the user's focus unnecessarily.
|
|
675
|
-
this._keyManager.setActiveItem(-1);
|
|
676
|
-
}
|
|
601
|
+
else {
|
|
602
|
+
const previouslyFocusedIndex = manager.activeItemIndex;
|
|
603
|
+
manager.onKeydown(event);
|
|
604
|
+
if (this._multiple && isArrowKey && event.shiftKey && manager.activeItem &&
|
|
605
|
+
manager.activeItemIndex !== previouslyFocusedIndex) {
|
|
606
|
+
manager.activeItem._selectViaInteraction();
|
|
677
607
|
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
_onFocus() {
|
|
611
|
+
if (!this.disabled) {
|
|
612
|
+
this._focused = true;
|
|
613
|
+
this.stateChanges.next();
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Calls the touched callback only if the panel is closed. Otherwise, the trigger will
|
|
618
|
+
* "blur" to the panel when it opens, causing a false positive.
|
|
619
|
+
*/
|
|
620
|
+
_onBlur() {
|
|
621
|
+
this._focused = false;
|
|
622
|
+
if (!this.disabled && !this.panelOpen) {
|
|
623
|
+
this._onTouched();
|
|
678
624
|
this._changeDetectorRef.markForCheck();
|
|
625
|
+
this.stateChanges.next();
|
|
679
626
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Callback that is invoked when the overlay panel has been attached.
|
|
630
|
+
*/
|
|
631
|
+
_onAttached() {
|
|
632
|
+
this.overlayDir.positionChange.pipe(take(1)).subscribe(() => {
|
|
633
|
+
this._changeDetectorRef.detectChanges();
|
|
634
|
+
this._calculateOverlayOffsetX();
|
|
635
|
+
this.panel.nativeElement.scrollTop = this._scrollTop;
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
/** Returns the theme to be used on the panel. */
|
|
639
|
+
_getPanelTheme() {
|
|
640
|
+
return this._parentFormField ? `mat-${this._parentFormField.color}` : '';
|
|
641
|
+
}
|
|
642
|
+
/** Whether the select has a value. */
|
|
643
|
+
get empty() {
|
|
644
|
+
return !this._selectionModel || this._selectionModel.isEmpty();
|
|
645
|
+
}
|
|
646
|
+
_initializeSelection() {
|
|
647
|
+
// Defer setting the value in order to avoid the "Expression
|
|
648
|
+
// has changed after it was checked" errors from Angular.
|
|
649
|
+
Promise.resolve().then(() => {
|
|
650
|
+
this._setSelectionByValue(this.ngControl ? this.ngControl.value : this._value);
|
|
651
|
+
this.stateChanges.next();
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Sets the selected option based on a value. If no option can be
|
|
656
|
+
* found with the designated value, the select trigger is cleared.
|
|
657
|
+
*/
|
|
658
|
+
_setSelectionByValue(value) {
|
|
659
|
+
if (this.multiple && value) {
|
|
660
|
+
if (!Array.isArray(value)) {
|
|
661
|
+
throw getMatSelectNonArrayValueError();
|
|
662
|
+
}
|
|
663
|
+
this._selectionModel.clear();
|
|
664
|
+
value.forEach((currentValue) => this._selectValue(currentValue));
|
|
665
|
+
this._sortValues();
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
this._selectionModel.clear();
|
|
669
|
+
const correspondingOption = this._selectValue(value);
|
|
670
|
+
// Shift focus to the active item. Note that we shouldn't do this in multiple
|
|
671
|
+
// mode, because we don't know what option the user interacted with last.
|
|
698
672
|
if (correspondingOption) {
|
|
699
|
-
this.
|
|
673
|
+
this._keyManager.setActiveItem(correspondingOption);
|
|
674
|
+
}
|
|
675
|
+
else if (!this.panelOpen) {
|
|
676
|
+
// Otherwise reset the highlighted option. Note that we only want to do this while
|
|
677
|
+
// closed, because doing it while open can shift the user's focus unnecessarily.
|
|
678
|
+
this._keyManager.setActiveItem(-1);
|
|
700
679
|
}
|
|
701
|
-
return correspondingOption;
|
|
702
680
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
//
|
|
718
|
-
|
|
719
|
-
this.focus();
|
|
720
|
-
this.close();
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
this._keyManager.change.pipe(takeUntil(this._destroy)).subscribe(() => {
|
|
724
|
-
if (this._panelOpen && this.panel) {
|
|
725
|
-
this._scrollActiveOptionIntoView();
|
|
726
|
-
}
|
|
727
|
-
else if (!this._panelOpen && !this.multiple && this._keyManager.activeItem) {
|
|
728
|
-
this._keyManager.activeItem._selectViaInteraction();
|
|
681
|
+
this._changeDetectorRef.markForCheck();
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Finds and selects and option based on its value.
|
|
685
|
+
* @returns Option that has the corresponding value.
|
|
686
|
+
*/
|
|
687
|
+
_selectValue(value) {
|
|
688
|
+
const correspondingOption = this.options.find((option) => {
|
|
689
|
+
try {
|
|
690
|
+
// Treat null as a special reset value.
|
|
691
|
+
return option.value != null && this._compareWith(option.value, value);
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
if (isDevMode()) {
|
|
695
|
+
// Notify developers of errors in their comparator.
|
|
696
|
+
console.warn(error);
|
|
729
697
|
}
|
|
730
|
-
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
if (correspondingOption) {
|
|
702
|
+
this._selectionModel.select(correspondingOption);
|
|
731
703
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
704
|
+
return correspondingOption;
|
|
705
|
+
}
|
|
706
|
+
/** Sets up a key manager to listen to keyboard events on the overlay panel. */
|
|
707
|
+
_initKeyManager() {
|
|
708
|
+
this._keyManager = new ActiveDescendantKeyManager(this.options)
|
|
709
|
+
.withTypeAhead(this._typeaheadDebounceInterval)
|
|
710
|
+
.withVerticalOrientation()
|
|
711
|
+
.withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr')
|
|
712
|
+
.withAllowedModifierKeys(['shiftKey']);
|
|
713
|
+
this._keyManager.tabOut.pipe(takeUntil(this._destroy)).subscribe(() => {
|
|
714
|
+
if (this.panelOpen) {
|
|
715
|
+
// Select the active item when tabbing away. This is consistent with how the native
|
|
716
|
+
// select behaves. Note that we only want to do this in single selection mode.
|
|
717
|
+
if (!this.multiple && this._keyManager.activeItem) {
|
|
718
|
+
this._keyManager.activeItem._selectViaInteraction();
|
|
740
719
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
.pipe(takeUntil(changedOrDestroyed))
|
|
746
|
-
.subscribe(() => {
|
|
747
|
-
this._changeDetectorRef.markForCheck();
|
|
748
|
-
this.stateChanges.next();
|
|
749
|
-
});
|
|
750
|
-
this._setOptionIds();
|
|
751
|
-
}
|
|
752
|
-
/** Invoked when an option is clicked. */
|
|
753
|
-
_onSelect(option, isUserInput) {
|
|
754
|
-
const wasSelected = this._selectionModel.isSelected(option);
|
|
755
|
-
if (option.value == null && !this._multiple) {
|
|
756
|
-
option.deselect();
|
|
757
|
-
this._selectionModel.clear();
|
|
758
|
-
this._propagateChanges(option.value);
|
|
720
|
+
// Restore focus to the trigger before closing. Ensures that the focus
|
|
721
|
+
// position won't be lost if the user got focus into the overlay.
|
|
722
|
+
this.focus();
|
|
723
|
+
this.close();
|
|
759
724
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
if (isUserInput) {
|
|
766
|
-
this._keyManager.setActiveItem(option);
|
|
767
|
-
}
|
|
768
|
-
if (this.multiple) {
|
|
769
|
-
this._sortValues();
|
|
770
|
-
if (isUserInput) {
|
|
771
|
-
// In case the user selected the option with their mouse, we
|
|
772
|
-
// want to restore focus back to the trigger, in order to
|
|
773
|
-
// prevent the select keyboard controls from clashing with
|
|
774
|
-
// the ones from `mat-option`.
|
|
775
|
-
this.focus();
|
|
776
|
-
}
|
|
777
|
-
}
|
|
725
|
+
});
|
|
726
|
+
this._keyManager.change.pipe(takeUntil(this._destroy)).subscribe(() => {
|
|
727
|
+
if (this._panelOpen && this.panel) {
|
|
728
|
+
this._scrollActiveOptionIntoView();
|
|
778
729
|
}
|
|
779
|
-
if (
|
|
780
|
-
this.
|
|
730
|
+
else if (!this._panelOpen && !this.multiple && this._keyManager.activeItem) {
|
|
731
|
+
this._keyManager.activeItem._selectViaInteraction();
|
|
781
732
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
this.stateChanges.next();
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
/** Drops current option subscriptions and IDs and resets from scratch. */
|
|
736
|
+
_resetOptions() {
|
|
737
|
+
const changedOrDestroyed = merge(this.options.changes, this._destroy);
|
|
738
|
+
this.optionSelectionChanges.pipe(takeUntil(changedOrDestroyed)).subscribe(event => {
|
|
739
|
+
this._onSelect(event.source, event.isUserInput);
|
|
740
|
+
if (event.isUserInput && !this.multiple && this._panelOpen) {
|
|
741
|
+
this.close();
|
|
742
|
+
this.focus();
|
|
793
743
|
}
|
|
744
|
+
});
|
|
745
|
+
// Listen to changes in the internal state of the options and react accordingly.
|
|
746
|
+
// Handles cases like the labels of the selected options changing.
|
|
747
|
+
merge(...this.options.map(option => option._stateChanges))
|
|
748
|
+
.pipe(takeUntil(changedOrDestroyed))
|
|
749
|
+
.subscribe(() => {
|
|
750
|
+
this._changeDetectorRef.markForCheck();
|
|
751
|
+
this.stateChanges.next();
|
|
752
|
+
});
|
|
753
|
+
this._setOptionIds();
|
|
754
|
+
}
|
|
755
|
+
/** Invoked when an option is clicked. */
|
|
756
|
+
_onSelect(option, isUserInput) {
|
|
757
|
+
const wasSelected = this._selectionModel.isSelected(option);
|
|
758
|
+
if (option.value == null && !this._multiple) {
|
|
759
|
+
option.deselect();
|
|
760
|
+
this._selectionModel.clear();
|
|
761
|
+
this._propagateChanges(option.value);
|
|
794
762
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
valueToEmit = this.selected.map(option => option.value);
|
|
763
|
+
else {
|
|
764
|
+
if (wasSelected !== option.selected) {
|
|
765
|
+
option.selected ? this._selectionModel.select(option) :
|
|
766
|
+
this._selectionModel.deselect(option);
|
|
800
767
|
}
|
|
801
|
-
|
|
802
|
-
|
|
768
|
+
if (isUserInput) {
|
|
769
|
+
this._keyManager.setActiveItem(option);
|
|
803
770
|
}
|
|
804
|
-
this.
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
this._optionIds = this.options.map(option => option.id).join(' ');
|
|
813
|
-
}
|
|
814
|
-
/**
|
|
815
|
-
* Highlights the selected item. If no option is selected, it will highlight
|
|
816
|
-
* the first item instead.
|
|
817
|
-
*/
|
|
818
|
-
_highlightCorrectOption() {
|
|
819
|
-
if (this._keyManager) {
|
|
820
|
-
if (this.empty) {
|
|
821
|
-
this._keyManager.setFirstItemActive();
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
this._keyManager.setActiveItem(this._selectionModel.selected[0]);
|
|
771
|
+
if (this.multiple) {
|
|
772
|
+
this._sortValues();
|
|
773
|
+
if (isUserInput) {
|
|
774
|
+
// In case the user selected the option with their mouse, we
|
|
775
|
+
// want to restore focus back to the trigger, in order to
|
|
776
|
+
// prevent the select keyboard controls from clashing with
|
|
777
|
+
// the ones from `mat-option`.
|
|
778
|
+
this.focus();
|
|
825
779
|
}
|
|
826
780
|
}
|
|
827
781
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
const activeOptionIndex = this._keyManager.activeItemIndex || 0;
|
|
831
|
-
const labelCount = _countGroupLabelsBeforeOption(activeOptionIndex, this.options, this.optionGroups);
|
|
832
|
-
this.panel.nativeElement.scrollTop = _getOptionScrollPosition(activeOptionIndex + labelCount, this._getItemHeight(), this.panel.nativeElement.scrollTop, SELECT_PANEL_MAX_HEIGHT);
|
|
782
|
+
if (wasSelected !== this._selectionModel.isSelected(option)) {
|
|
783
|
+
this._propagateChanges();
|
|
833
784
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
}, undefined);
|
|
846
|
-
}
|
|
847
|
-
/** Calculates the scroll position and x- and y-offsets of the overlay panel. */
|
|
848
|
-
_calculateOverlayPosition() {
|
|
849
|
-
const itemHeight = this._getItemHeight();
|
|
850
|
-
const items = this._getItemCount();
|
|
851
|
-
const panelHeight = Math.min(items * itemHeight, SELECT_PANEL_MAX_HEIGHT);
|
|
852
|
-
const scrollContainerHeight = items * itemHeight;
|
|
853
|
-
// The farthest the panel can be scrolled before it hits the bottom
|
|
854
|
-
const maxScroll = scrollContainerHeight - panelHeight;
|
|
855
|
-
// If no value is selected we open the popup to the first item.
|
|
856
|
-
let selectedOptionOffset = this.empty ? 0 : this._getOptionIndex(this._selectionModel.selected[0]);
|
|
857
|
-
selectedOptionOffset += _countGroupLabelsBeforeOption(selectedOptionOffset, this.options, this.optionGroups);
|
|
858
|
-
// We must maintain a scroll buffer so the selected option will be scrolled to the
|
|
859
|
-
// center of the overlay panel rather than the top.
|
|
860
|
-
const scrollBuffer = panelHeight / 2;
|
|
861
|
-
this._scrollTop = this._calculateOverlayScroll(selectedOptionOffset, scrollBuffer, maxScroll);
|
|
862
|
-
this._offsetY = this._calculateOverlayOffsetY(selectedOptionOffset, scrollBuffer, maxScroll);
|
|
863
|
-
this._checkOverlayWithinViewport(maxScroll);
|
|
785
|
+
this.stateChanges.next();
|
|
786
|
+
}
|
|
787
|
+
/** Sorts the selected values in the selected based on their order in the panel. */
|
|
788
|
+
_sortValues() {
|
|
789
|
+
if (this.multiple) {
|
|
790
|
+
const options = this.options.toArray();
|
|
791
|
+
this._selectionModel.sort((a, b) => {
|
|
792
|
+
return this.sortComparator ? this.sortComparator(a, b, options) :
|
|
793
|
+
options.indexOf(a) - options.indexOf(b);
|
|
794
|
+
});
|
|
795
|
+
this.stateChanges.next();
|
|
864
796
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
*/
|
|
872
|
-
_calculateOverlayScroll(selectedIndex, scrollBuffer, maxScroll) {
|
|
873
|
-
const itemHeight = this._getItemHeight();
|
|
874
|
-
const optionOffsetFromScrollTop = itemHeight * selectedIndex;
|
|
875
|
-
const halfOptionHeight = itemHeight / 2;
|
|
876
|
-
// Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the
|
|
877
|
-
// scroll container, then subtracts the scroll buffer to scroll the option down to
|
|
878
|
-
// the center of the overlay panel. Half the option height must be re-added to the
|
|
879
|
-
// scrollTop so the option is centered based on its middle, not its top edge.
|
|
880
|
-
const optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
|
|
881
|
-
return Math.min(Math.max(0, optimalScrollPosition), maxScroll);
|
|
797
|
+
}
|
|
798
|
+
/** Emits change event to set the model value. */
|
|
799
|
+
_propagateChanges(fallbackValue) {
|
|
800
|
+
let valueToEmit = null;
|
|
801
|
+
if (this.multiple) {
|
|
802
|
+
valueToEmit = this.selected.map(option => option.value);
|
|
882
803
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
// If an ariaLabelledby value has been set by the consumer, the select should not overwrite the
|
|
886
|
-
// `aria-labelledby` value by setting the ariaLabel to the placeholder.
|
|
887
|
-
return this.ariaLabelledby ? null : this.ariaLabel || this.placeholder;
|
|
804
|
+
else {
|
|
805
|
+
valueToEmit = this.selected ? this.selected.value : fallbackValue;
|
|
888
806
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
807
|
+
this._value = valueToEmit;
|
|
808
|
+
this.valueChange.emit(valueToEmit);
|
|
809
|
+
this._onChange(valueToEmit);
|
|
810
|
+
this.selectionChange.emit(new MatSelectChange(this, valueToEmit));
|
|
811
|
+
this._changeDetectorRef.markForCheck();
|
|
812
|
+
}
|
|
813
|
+
/** Records option IDs to pass to the aria-owns property. */
|
|
814
|
+
_setOptionIds() {
|
|
815
|
+
this._optionIds = this.options.map(option => option.id).join(' ');
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Highlights the selected item. If no option is selected, it will highlight
|
|
819
|
+
* the first item instead.
|
|
820
|
+
*/
|
|
821
|
+
_highlightCorrectOption() {
|
|
822
|
+
if (this._keyManager) {
|
|
823
|
+
if (this.empty) {
|
|
824
|
+
this._keyManager.setFirstItemActive();
|
|
893
825
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
if (!this._parentFormField || !this._parentFormField._hasFloatingLabel() ||
|
|
897
|
-
this._getAriaLabel()) {
|
|
898
|
-
return null;
|
|
826
|
+
else {
|
|
827
|
+
this._keyManager.setActiveItem(this._selectionModel.selected[0]);
|
|
899
828
|
}
|
|
900
|
-
return this._parentFormField._labelId || null;
|
|
901
829
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
830
|
+
}
|
|
831
|
+
/** Scrolls the active option into view. */
|
|
832
|
+
_scrollActiveOptionIntoView() {
|
|
833
|
+
const activeOptionIndex = this._keyManager.activeItemIndex || 0;
|
|
834
|
+
const labelCount = _countGroupLabelsBeforeOption(activeOptionIndex, this.options, this.optionGroups);
|
|
835
|
+
this.panel.nativeElement.scrollTop = _getOptionScrollPosition(activeOptionIndex + labelCount, this._getItemHeight(), this.panel.nativeElement.scrollTop, SELECT_PANEL_MAX_HEIGHT);
|
|
836
|
+
}
|
|
837
|
+
/** Focuses the select element. */
|
|
838
|
+
focus(options) {
|
|
839
|
+
this._elementRef.nativeElement.focus(options);
|
|
840
|
+
}
|
|
841
|
+
/** Gets the index of the provided option in the option list. */
|
|
842
|
+
_getOptionIndex(option) {
|
|
843
|
+
return this.options.reduce((result, current, index) => {
|
|
844
|
+
if (result !== undefined) {
|
|
845
|
+
return result;
|
|
906
846
|
}
|
|
847
|
+
return option === current ? index : undefined;
|
|
848
|
+
}, undefined);
|
|
849
|
+
}
|
|
850
|
+
/** Calculates the scroll position and x- and y-offsets of the overlay panel. */
|
|
851
|
+
_calculateOverlayPosition() {
|
|
852
|
+
const itemHeight = this._getItemHeight();
|
|
853
|
+
const items = this._getItemCount();
|
|
854
|
+
const panelHeight = Math.min(items * itemHeight, SELECT_PANEL_MAX_HEIGHT);
|
|
855
|
+
const scrollContainerHeight = items * itemHeight;
|
|
856
|
+
// The farthest the panel can be scrolled before it hits the bottom
|
|
857
|
+
const maxScroll = scrollContainerHeight - panelHeight;
|
|
858
|
+
// If no value is selected we open the popup to the first item.
|
|
859
|
+
let selectedOptionOffset = this.empty ? 0 : this._getOptionIndex(this._selectionModel.selected[0]);
|
|
860
|
+
selectedOptionOffset += _countGroupLabelsBeforeOption(selectedOptionOffset, this.options, this.optionGroups);
|
|
861
|
+
// We must maintain a scroll buffer so the selected option will be scrolled to the
|
|
862
|
+
// center of the overlay panel rather than the top.
|
|
863
|
+
const scrollBuffer = panelHeight / 2;
|
|
864
|
+
this._scrollTop = this._calculateOverlayScroll(selectedOptionOffset, scrollBuffer, maxScroll);
|
|
865
|
+
this._offsetY = this._calculateOverlayOffsetY(selectedOptionOffset, scrollBuffer, maxScroll);
|
|
866
|
+
this._checkOverlayWithinViewport(maxScroll);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Calculates the scroll position of the select's overlay panel.
|
|
870
|
+
*
|
|
871
|
+
* Attempts to center the selected option in the panel. If the option is
|
|
872
|
+
* too high or too low in the panel to be scrolled to the center, it clamps the
|
|
873
|
+
* scroll position to the min or max scroll positions respectively.
|
|
874
|
+
*/
|
|
875
|
+
_calculateOverlayScroll(selectedIndex, scrollBuffer, maxScroll) {
|
|
876
|
+
const itemHeight = this._getItemHeight();
|
|
877
|
+
const optionOffsetFromScrollTop = itemHeight * selectedIndex;
|
|
878
|
+
const halfOptionHeight = itemHeight / 2;
|
|
879
|
+
// Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the
|
|
880
|
+
// scroll container, then subtracts the scroll buffer to scroll the option down to
|
|
881
|
+
// the center of the overlay panel. Half the option height must be re-added to the
|
|
882
|
+
// scrollTop so the option is centered based on its middle, not its top edge.
|
|
883
|
+
const optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
|
|
884
|
+
return Math.min(Math.max(0, optimalScrollPosition), maxScroll);
|
|
885
|
+
}
|
|
886
|
+
/** Returns the aria-label of the select component. */
|
|
887
|
+
_getAriaLabel() {
|
|
888
|
+
// If an ariaLabelledby value has been set by the consumer, the select should not overwrite the
|
|
889
|
+
// `aria-labelledby` value by setting the ariaLabel to the placeholder.
|
|
890
|
+
return this.ariaLabelledby ? null : this.ariaLabel || this.placeholder;
|
|
891
|
+
}
|
|
892
|
+
/** Returns the aria-labelledby of the select component. */
|
|
893
|
+
_getAriaLabelledby() {
|
|
894
|
+
if (this.ariaLabelledby) {
|
|
895
|
+
return this.ariaLabelledby;
|
|
896
|
+
}
|
|
897
|
+
// Note: we use `_getAriaLabel` here, because we want to check whether there's a
|
|
898
|
+
// computed label. `this.ariaLabel` is only the user-specified label.
|
|
899
|
+
if (!this._parentFormField || !this._parentFormField._hasFloatingLabel() ||
|
|
900
|
+
this._getAriaLabel()) {
|
|
907
901
|
return null;
|
|
908
902
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
*/
|
|
916
|
-
_calculateOverlayOffsetX() {
|
|
917
|
-
const overlayRect = this.overlayDir.overlayRef.overlayElement.getBoundingClientRect();
|
|
918
|
-
const viewportSize = this._viewportRuler.getViewportSize();
|
|
919
|
-
const isRtl = this._isRtl();
|
|
920
|
-
const paddingWidth = this.multiple ? SELECT_MULTIPLE_PANEL_PADDING_X + SELECT_PANEL_PADDING_X :
|
|
921
|
-
SELECT_PANEL_PADDING_X * 2;
|
|
922
|
-
let offsetX;
|
|
923
|
-
// Adjust the offset, depending on the option padding.
|
|
924
|
-
if (this.multiple) {
|
|
925
|
-
offsetX = SELECT_MULTIPLE_PANEL_PADDING_X;
|
|
926
|
-
}
|
|
927
|
-
else {
|
|
928
|
-
let selected = this._selectionModel.selected[0] || this.options.first;
|
|
929
|
-
offsetX = selected && selected.group ? SELECT_PANEL_INDENT_PADDING_X : SELECT_PANEL_PADDING_X;
|
|
930
|
-
}
|
|
931
|
-
// Invert the offset in LTR.
|
|
932
|
-
if (!isRtl) {
|
|
933
|
-
offsetX *= -1;
|
|
934
|
-
}
|
|
935
|
-
// Determine how much the select overflows on each side.
|
|
936
|
-
const leftOverflow = 0 - (overlayRect.left + offsetX - (isRtl ? paddingWidth : 0));
|
|
937
|
-
const rightOverflow = overlayRect.right + offsetX - viewportSize.width
|
|
938
|
-
+ (isRtl ? 0 : paddingWidth);
|
|
939
|
-
// If the element overflows on either side, reduce the offset to allow it to fit.
|
|
940
|
-
if (leftOverflow > 0) {
|
|
941
|
-
offsetX += leftOverflow + SELECT_PANEL_VIEWPORT_PADDING;
|
|
942
|
-
}
|
|
943
|
-
else if (rightOverflow > 0) {
|
|
944
|
-
offsetX -= rightOverflow + SELECT_PANEL_VIEWPORT_PADDING;
|
|
945
|
-
}
|
|
946
|
-
// Set the offset directly in order to avoid having to go through change detection and
|
|
947
|
-
// potentially triggering "changed after it was checked" errors. Round the value to avoid
|
|
948
|
-
// blurry content in some browsers.
|
|
949
|
-
this.overlayDir.offsetX = Math.round(offsetX);
|
|
950
|
-
this.overlayDir.overlayRef.updatePosition();
|
|
903
|
+
return this._parentFormField._labelId || null;
|
|
904
|
+
}
|
|
905
|
+
/** Determines the `aria-activedescendant` to be set on the host. */
|
|
906
|
+
_getAriaActiveDescendant() {
|
|
907
|
+
if (this.panelOpen && this._keyManager && this._keyManager.activeItem) {
|
|
908
|
+
return this._keyManager.activeItem.id;
|
|
951
909
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
const selectedDisplayIndex = selectedIndex - firstDisplayedIndex;
|
|
972
|
-
// The first item is partially out of the viewport. Therefore we need to calculate what
|
|
973
|
-
// portion of it is shown in the viewport and account for it in our offset.
|
|
974
|
-
let partialItemHeight = itemHeight - (this._getItemCount() * itemHeight - SELECT_PANEL_MAX_HEIGHT) % itemHeight;
|
|
975
|
-
// Because the panel height is longer than the height of the options alone,
|
|
976
|
-
// there is always extra padding at the top or bottom of the panel. When
|
|
977
|
-
// scrolled to the very bottom, this padding is at the top of the panel and
|
|
978
|
-
// must be added to the offset.
|
|
979
|
-
optionOffsetFromPanelTop = selectedDisplayIndex * itemHeight + partialItemHeight;
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
// If the option was scrolled to the middle of the panel using a scroll buffer,
|
|
983
|
-
// its offset will be the scroll buffer minus the half height that was added to
|
|
984
|
-
// center it.
|
|
985
|
-
optionOffsetFromPanelTop = scrollBuffer - itemHeight / 2;
|
|
986
|
-
}
|
|
987
|
-
// The final offset is the option's offset from the top, adjusted for the height difference,
|
|
988
|
-
// multiplied by -1 to ensure that the overlay moves in the correct direction up the page.
|
|
989
|
-
// The value is rounded to prevent some browsers from blurring the content.
|
|
990
|
-
return Math.round(optionOffsetFromPanelTop * -1 - optionHeightAdjustment);
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Sets the x-offset of the overlay panel in relation to the trigger's top start corner.
|
|
914
|
+
* This must be adjusted to align the selected option text over the trigger text when
|
|
915
|
+
* the panel opens. Will change based on LTR or RTL text direction. Note that the offset
|
|
916
|
+
* can't be calculated until the panel has been attached, because we need to know the
|
|
917
|
+
* content width in order to constrain the panel within the viewport.
|
|
918
|
+
*/
|
|
919
|
+
_calculateOverlayOffsetX() {
|
|
920
|
+
const overlayRect = this.overlayDir.overlayRef.overlayElement.getBoundingClientRect();
|
|
921
|
+
const viewportSize = this._viewportRuler.getViewportSize();
|
|
922
|
+
const isRtl = this._isRtl();
|
|
923
|
+
const paddingWidth = this.multiple ? SELECT_MULTIPLE_PANEL_PADDING_X + SELECT_PANEL_PADDING_X :
|
|
924
|
+
SELECT_PANEL_PADDING_X * 2;
|
|
925
|
+
let offsetX;
|
|
926
|
+
// Adjust the offset, depending on the option padding.
|
|
927
|
+
if (this.multiple) {
|
|
928
|
+
offsetX = SELECT_MULTIPLE_PANEL_PADDING_X;
|
|
991
929
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
* y-offset so the panel can open fully on-screen. If it still won't fit,
|
|
996
|
-
* sets the offset back to 0 to allow the fallback position to take over.
|
|
997
|
-
*/
|
|
998
|
-
_checkOverlayWithinViewport(maxScroll) {
|
|
999
|
-
const itemHeight = this._getItemHeight();
|
|
1000
|
-
const viewportSize = this._viewportRuler.getViewportSize();
|
|
1001
|
-
const topSpaceAvailable = this._triggerRect.top - SELECT_PANEL_VIEWPORT_PADDING;
|
|
1002
|
-
const bottomSpaceAvailable = viewportSize.height - this._triggerRect.bottom - SELECT_PANEL_VIEWPORT_PADDING;
|
|
1003
|
-
const panelHeightTop = Math.abs(this._offsetY);
|
|
1004
|
-
const totalPanelHeight = Math.min(this._getItemCount() * itemHeight, SELECT_PANEL_MAX_HEIGHT);
|
|
1005
|
-
const panelHeightBottom = totalPanelHeight - panelHeightTop - this._triggerRect.height;
|
|
1006
|
-
if (panelHeightBottom > bottomSpaceAvailable) {
|
|
1007
|
-
this._adjustPanelUp(panelHeightBottom, bottomSpaceAvailable);
|
|
1008
|
-
}
|
|
1009
|
-
else if (panelHeightTop > topSpaceAvailable) {
|
|
1010
|
-
this._adjustPanelDown(panelHeightTop, topSpaceAvailable, maxScroll);
|
|
1011
|
-
}
|
|
1012
|
-
else {
|
|
1013
|
-
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1014
|
-
}
|
|
930
|
+
else {
|
|
931
|
+
let selected = this._selectionModel.selected[0] || this.options.first;
|
|
932
|
+
offsetX = selected && selected.group ? SELECT_PANEL_INDENT_PADDING_X : SELECT_PANEL_PADDING_X;
|
|
1015
933
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const distanceBelowViewport = Math.round(panelHeightBottom - bottomSpaceAvailable);
|
|
1020
|
-
// Scrolls the panel up by the distance it was extending past the boundary, then
|
|
1021
|
-
// adjusts the offset by that amount to move the panel up into the viewport.
|
|
1022
|
-
this._scrollTop -= distanceBelowViewport;
|
|
1023
|
-
this._offsetY -= distanceBelowViewport;
|
|
1024
|
-
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1025
|
-
// If the panel is scrolled to the very top, it won't be able to fit the panel
|
|
1026
|
-
// by scrolling, so set the offset to 0 to allow the fallback position to take
|
|
1027
|
-
// effect.
|
|
1028
|
-
if (this._scrollTop <= 0) {
|
|
1029
|
-
this._scrollTop = 0;
|
|
1030
|
-
this._offsetY = 0;
|
|
1031
|
-
this._transformOrigin = `50% bottom 0px`;
|
|
1032
|
-
}
|
|
934
|
+
// Invert the offset in LTR.
|
|
935
|
+
if (!isRtl) {
|
|
936
|
+
offsetX *= -1;
|
|
1033
937
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
this._offsetY += distanceAboveViewport;
|
|
1042
|
-
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1043
|
-
// If the panel is scrolled to the very bottom, it won't be able to fit the
|
|
1044
|
-
// panel by scrolling, so set the offset to 0 to allow the fallback position
|
|
1045
|
-
// to take effect.
|
|
1046
|
-
if (this._scrollTop >= maxScroll) {
|
|
1047
|
-
this._scrollTop = maxScroll;
|
|
1048
|
-
this._offsetY = 0;
|
|
1049
|
-
this._transformOrigin = `50% top 0px`;
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
938
|
+
// Determine how much the select overflows on each side.
|
|
939
|
+
const leftOverflow = 0 - (overlayRect.left + offsetX - (isRtl ? paddingWidth : 0));
|
|
940
|
+
const rightOverflow = overlayRect.right + offsetX - viewportSize.width
|
|
941
|
+
+ (isRtl ? 0 : paddingWidth);
|
|
942
|
+
// If the element overflows on either side, reduce the offset to allow it to fit.
|
|
943
|
+
if (leftOverflow > 0) {
|
|
944
|
+
offsetX += leftOverflow + SELECT_PANEL_VIEWPORT_PADDING;
|
|
1052
945
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
const itemHeight = this._getItemHeight();
|
|
1056
|
-
const optionHeightAdjustment = (itemHeight - this._triggerRect.height) / 2;
|
|
1057
|
-
const originY = Math.abs(this._offsetY) - optionHeightAdjustment + itemHeight / 2;
|
|
1058
|
-
return `50% ${originY}px 0px`;
|
|
946
|
+
else if (rightOverflow > 0) {
|
|
947
|
+
offsetX -= rightOverflow + SELECT_PANEL_VIEWPORT_PADDING;
|
|
1059
948
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
949
|
+
// Set the offset directly in order to avoid having to go through change detection and
|
|
950
|
+
// potentially triggering "changed after it was checked" errors. Round the value to avoid
|
|
951
|
+
// blurry content in some browsers.
|
|
952
|
+
this.overlayDir.offsetX = Math.round(offsetX);
|
|
953
|
+
this.overlayDir.overlayRef.updatePosition();
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Calculates the y-offset of the select's overlay panel in relation to the
|
|
957
|
+
* top start corner of the trigger. It has to be adjusted in order for the
|
|
958
|
+
* selected option to be aligned over the trigger when the panel opens.
|
|
959
|
+
*/
|
|
960
|
+
_calculateOverlayOffsetY(selectedIndex, scrollBuffer, maxScroll) {
|
|
961
|
+
const itemHeight = this._getItemHeight();
|
|
962
|
+
const optionHeightAdjustment = (itemHeight - this._triggerRect.height) / 2;
|
|
963
|
+
const maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
|
|
964
|
+
let optionOffsetFromPanelTop;
|
|
965
|
+
// Disable offset if requested by user by returning 0 as value to offset
|
|
966
|
+
if (this._disableOptionCentering) {
|
|
967
|
+
return 0;
|
|
1063
968
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
return this._triggerFontSize * SELECT_ITEM_HEIGHT_EM;
|
|
969
|
+
if (this._scrollTop === 0) {
|
|
970
|
+
optionOffsetFromPanelTop = selectedIndex * itemHeight;
|
|
1067
971
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
972
|
+
else if (this._scrollTop === maxScroll) {
|
|
973
|
+
const firstDisplayedIndex = this._getItemCount() - maxOptionsDisplayed;
|
|
974
|
+
const selectedDisplayIndex = selectedIndex - firstDisplayedIndex;
|
|
975
|
+
// The first item is partially out of the viewport. Therefore we need to calculate what
|
|
976
|
+
// portion of it is shown in the viewport and account for it in our offset.
|
|
977
|
+
let partialItemHeight = itemHeight - (this._getItemCount() * itemHeight - SELECT_PANEL_MAX_HEIGHT) % itemHeight;
|
|
978
|
+
// Because the panel height is longer than the height of the options alone,
|
|
979
|
+
// there is always extra padding at the top or bottom of the panel. When
|
|
980
|
+
// scrolled to the very bottom, this padding is at the top of the panel and
|
|
981
|
+
// must be added to the offset.
|
|
982
|
+
optionOffsetFromPanelTop = selectedDisplayIndex * itemHeight + partialItemHeight;
|
|
1074
983
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
this.focus();
|
|
1081
|
-
this.open();
|
|
984
|
+
else {
|
|
985
|
+
// If the option was scrolled to the middle of the panel using a scroll buffer,
|
|
986
|
+
// its offset will be the scroll buffer minus the half height that was added to
|
|
987
|
+
// center it.
|
|
988
|
+
optionOffsetFromPanelTop = scrollBuffer - itemHeight / 2;
|
|
1082
989
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
990
|
+
// The final offset is the option's offset from the top, adjusted for the height difference,
|
|
991
|
+
// multiplied by -1 to ensure that the overlay moves in the correct direction up the page.
|
|
992
|
+
// The value is rounded to prevent some browsers from blurring the content.
|
|
993
|
+
return Math.round(optionOffsetFromPanelTop * -1 - optionHeightAdjustment);
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Checks that the attempted overlay position will fit within the viewport.
|
|
997
|
+
* If it will not fit, tries to adjust the scroll position and the associated
|
|
998
|
+
* y-offset so the panel can open fully on-screen. If it still won't fit,
|
|
999
|
+
* sets the offset back to 0 to allow the fallback position to take over.
|
|
1000
|
+
*/
|
|
1001
|
+
_checkOverlayWithinViewport(maxScroll) {
|
|
1002
|
+
const itemHeight = this._getItemHeight();
|
|
1003
|
+
const viewportSize = this._viewportRuler.getViewportSize();
|
|
1004
|
+
const topSpaceAvailable = this._triggerRect.top - SELECT_PANEL_VIEWPORT_PADDING;
|
|
1005
|
+
const bottomSpaceAvailable = viewportSize.height - this._triggerRect.bottom - SELECT_PANEL_VIEWPORT_PADDING;
|
|
1006
|
+
const panelHeightTop = Math.abs(this._offsetY);
|
|
1007
|
+
const totalPanelHeight = Math.min(this._getItemCount() * itemHeight, SELECT_PANEL_MAX_HEIGHT);
|
|
1008
|
+
const panelHeightBottom = totalPanelHeight - panelHeightTop - this._triggerRect.height;
|
|
1009
|
+
if (panelHeightBottom > bottomSpaceAvailable) {
|
|
1010
|
+
this._adjustPanelUp(panelHeightBottom, bottomSpaceAvailable);
|
|
1011
|
+
}
|
|
1012
|
+
else if (panelHeightTop > topSpaceAvailable) {
|
|
1013
|
+
this._adjustPanelDown(panelHeightTop, topSpaceAvailable, maxScroll);
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
/** Adjusts the overlay panel up to fit in the viewport. */
|
|
1020
|
+
_adjustPanelUp(panelHeightBottom, bottomSpaceAvailable) {
|
|
1021
|
+
// Browsers ignore fractional scroll offsets, so we need to round.
|
|
1022
|
+
const distanceBelowViewport = Math.round(panelHeightBottom - bottomSpaceAvailable);
|
|
1023
|
+
// Scrolls the panel up by the distance it was extending past the boundary, then
|
|
1024
|
+
// adjusts the offset by that amount to move the panel up into the viewport.
|
|
1025
|
+
this._scrollTop -= distanceBelowViewport;
|
|
1026
|
+
this._offsetY -= distanceBelowViewport;
|
|
1027
|
+
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1028
|
+
// If the panel is scrolled to the very top, it won't be able to fit the panel
|
|
1029
|
+
// by scrolling, so set the offset to 0 to allow the fallback position to take
|
|
1030
|
+
// effect.
|
|
1031
|
+
if (this._scrollTop <= 0) {
|
|
1032
|
+
this._scrollTop = 0;
|
|
1033
|
+
this._offsetY = 0;
|
|
1034
|
+
this._transformOrigin = `50% bottom 0px`;
|
|
1089
1035
|
}
|
|
1090
1036
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1037
|
+
/** Adjusts the overlay panel down to fit in the viewport. */
|
|
1038
|
+
_adjustPanelDown(panelHeightTop, topSpaceAvailable, maxScroll) {
|
|
1039
|
+
// Browsers ignore fractional scroll offsets, so we need to round.
|
|
1040
|
+
const distanceAboveViewport = Math.round(panelHeightTop - topSpaceAvailable);
|
|
1041
|
+
// Scrolls the panel down by the distance it was extending past the boundary, then
|
|
1042
|
+
// adjusts the offset by that amount to move the panel down into the viewport.
|
|
1043
|
+
this._scrollTop += distanceAboveViewport;
|
|
1044
|
+
this._offsetY += distanceAboveViewport;
|
|
1045
|
+
this._transformOrigin = this._getOriginBasedOnOption();
|
|
1046
|
+
// If the panel is scrolled to the very bottom, it won't be able to fit the
|
|
1047
|
+
// panel by scrolling, so set the offset to 0 to allow the fallback position
|
|
1048
|
+
// to take effect.
|
|
1049
|
+
if (this._scrollTop >= maxScroll) {
|
|
1050
|
+
this._scrollTop = maxScroll;
|
|
1051
|
+
this._offsetY = 0;
|
|
1052
|
+
this._transformOrigin = `50% top 0px`;
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
/** Sets the transform origin point based on the selected option. */
|
|
1057
|
+
_getOriginBasedOnOption() {
|
|
1058
|
+
const itemHeight = this._getItemHeight();
|
|
1059
|
+
const optionHeightAdjustment = (itemHeight - this._triggerRect.height) / 2;
|
|
1060
|
+
const originY = Math.abs(this._offsetY) - optionHeightAdjustment + itemHeight / 2;
|
|
1061
|
+
return `50% ${originY}px 0px`;
|
|
1062
|
+
}
|
|
1063
|
+
/** Calculates the amount of items in the select. This includes options and group labels. */
|
|
1064
|
+
_getItemCount() {
|
|
1065
|
+
return this.options.length + this.optionGroups.length;
|
|
1066
|
+
}
|
|
1067
|
+
/** Calculates the height of the select's options. */
|
|
1068
|
+
_getItemHeight() {
|
|
1069
|
+
return this._triggerFontSize * SELECT_ITEM_HEIGHT_EM;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Implemented as part of MatFormFieldControl.
|
|
1073
|
+
* @docs-private
|
|
1074
|
+
*/
|
|
1075
|
+
setDescribedByIds(ids) {
|
|
1076
|
+
this._ariaDescribedby = ids.join(' ');
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Implemented as part of MatFormFieldControl.
|
|
1080
|
+
* @docs-private
|
|
1081
|
+
*/
|
|
1082
|
+
onContainerClick() {
|
|
1083
|
+
this.focus();
|
|
1084
|
+
this.open();
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Implemented as part of MatFormFieldControl.
|
|
1088
|
+
* @docs-private
|
|
1089
|
+
*/
|
|
1090
|
+
get shouldLabelFloat() {
|
|
1091
|
+
return this._panelOpen || !this.empty;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
MatSelect.decorators = [
|
|
1095
|
+
{ type: Component, args: [{
|
|
1096
|
+
selector: 'mat-select',
|
|
1097
|
+
exportAs: 'matSelect',
|
|
1098
|
+
template: "<div cdk-overlay-origin\n class=\"mat-select-trigger\"\n aria-hidden=\"true\"\n (click)=\"toggle()\"\n #origin=\"cdkOverlayOrigin\"\n #trigger>\n <div class=\"mat-select-value\" [ngSwitch]=\"empty\">\n <span class=\"mat-select-placeholder\" *ngSwitchCase=\"true\">{{placeholder || '\\u00A0'}}</span>\n <span class=\"mat-select-value-text\" *ngSwitchCase=\"false\" [ngSwitch]=\"!!customTrigger\">\n <span *ngSwitchDefault>{{triggerValue || '\\u00A0'}}</span>\n <ng-content select=\"mat-select-trigger\" *ngSwitchCase=\"true\"></ng-content>\n </span>\n </div>\n\n <div class=\"mat-select-arrow-wrapper\"><div class=\"mat-select-arrow\"></div></div>\n</div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayLockPosition\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayScrollStrategy]=\"_scrollStrategy\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayPositions]=\"_positions\"\n [cdkConnectedOverlayMinWidth]=\"_triggerRect?.width\"\n [cdkConnectedOverlayOffsetY]=\"_offsetY\"\n (backdropClick)=\"close()\"\n (attach)=\"_onAttached()\"\n (detach)=\"close()\">\n <div class=\"mat-select-panel-wrap\" [@transformPanelWrap]>\n <div\n #panel\n [attr.id]=\"id + '-panel'\"\n class=\"mat-select-panel {{ _getPanelTheme() }}\"\n [ngClass]=\"panelClass\"\n [@transformPanel]=\"multiple ? 'showing-multiple' : 'showing'\"\n (@transformPanel.done)=\"_panelDoneAnimatingStream.next($event.toState)\"\n [style.transformOrigin]=\"_transformOrigin\"\n [style.font-size.px]=\"_triggerFontSize\"\n (keydown)=\"_handleKeydown($event)\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n",
|
|
1099
|
+
inputs: ['disabled', 'disableRipple', 'tabIndex'],
|
|
1100
|
+
encapsulation: ViewEncapsulation.None,
|
|
1101
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1102
|
+
host: {
|
|
1103
|
+
'role': 'listbox',
|
|
1104
|
+
'[attr.id]': 'id',
|
|
1105
|
+
'[attr.tabindex]': 'tabIndex',
|
|
1106
|
+
'[attr.aria-label]': '_getAriaLabel()',
|
|
1107
|
+
'[attr.aria-labelledby]': '_getAriaLabelledby()',
|
|
1108
|
+
'[attr.aria-required]': 'required.toString()',
|
|
1109
|
+
'[attr.aria-disabled]': 'disabled.toString()',
|
|
1110
|
+
'[attr.aria-invalid]': 'errorState',
|
|
1111
|
+
'[attr.aria-owns]': 'panelOpen ? _optionIds : null',
|
|
1112
|
+
'[attr.aria-multiselectable]': 'multiple',
|
|
1113
|
+
'[attr.aria-describedby]': '_ariaDescribedby || null',
|
|
1114
|
+
'[attr.aria-activedescendant]': '_getAriaActiveDescendant()',
|
|
1115
|
+
'[class.mat-select-disabled]': 'disabled',
|
|
1116
|
+
'[class.mat-select-invalid]': 'errorState',
|
|
1117
|
+
'[class.mat-select-required]': 'required',
|
|
1118
|
+
'[class.mat-select-empty]': 'empty',
|
|
1119
|
+
'class': 'mat-select',
|
|
1120
|
+
'(keydown)': '_handleKeydown($event)',
|
|
1121
|
+
'(focus)': '_onFocus()',
|
|
1122
|
+
'(blur)': '_onBlur()',
|
|
1123
|
+
},
|
|
1124
|
+
animations: [
|
|
1125
|
+
matSelectAnimations.transformPanelWrap,
|
|
1126
|
+
matSelectAnimations.transformPanel
|
|
1127
|
+
],
|
|
1128
|
+
providers: [
|
|
1129
|
+
{ provide: MatFormFieldControl, useExisting: MatSelect },
|
|
1130
|
+
{ provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect }
|
|
1131
|
+
],
|
|
1132
|
+
styles: [".mat-select{display:inline-block;width:100%;outline:none}.mat-select-trigger{display:inline-table;cursor:pointer;position:relative;box-sizing:border-box}.mat-select-disabled .mat-select-trigger{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.mat-select-value{display:table-cell;max-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mat-select-value-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mat-select-arrow-wrapper{display:table-cell;vertical-align:middle}.mat-form-field-appearance-fill .mat-select-arrow-wrapper{transform:translateY(-50%)}.mat-form-field-appearance-outline .mat-select-arrow-wrapper{transform:translateY(-25%)}.mat-form-field-appearance-standard.mat-form-field-has-label .mat-select:not(.mat-select-empty) .mat-select-arrow-wrapper{transform:translateY(-50%)}.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper{transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}._mat-animation-noopable.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper{transition:none}.mat-select-arrow{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid;margin:0 4px}.mat-select-panel-wrap{flex-basis:100%}.mat-select-panel{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;padding-top:0;padding-bottom:0;max-height:256px;min-width:100%;border-radius:4px}.cdk-high-contrast-active .mat-select-panel{outline:solid 1px}.mat-select-panel .mat-optgroup-label,.mat-select-panel .mat-option{font-size:inherit;line-height:3em;height:3em}.mat-form-field-type-mat-select:not(.mat-form-field-disabled) .mat-form-field-flex{cursor:pointer}.mat-form-field-type-mat-select .mat-form-field-label{width:calc(100% - 18px)}.mat-select-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}._mat-animation-noopable .mat-select-placeholder{transition:none}.mat-form-field-hide-placeholder .mat-select-placeholder{color:transparent;-webkit-text-fill-color:transparent;transition:none;display:block}\n"]
|
|
1133
|
+
},] }
|
|
1134
|
+
];
|
|
1135
|
+
MatSelect.ctorParameters = () => [
|
|
1136
|
+
{ type: ViewportRuler },
|
|
1137
|
+
{ type: ChangeDetectorRef },
|
|
1138
|
+
{ type: NgZone },
|
|
1139
|
+
{ type: ErrorStateMatcher },
|
|
1140
|
+
{ type: ElementRef },
|
|
1141
|
+
{ type: Directionality, decorators: [{ type: Optional }] },
|
|
1142
|
+
{ type: NgForm, decorators: [{ type: Optional }] },
|
|
1143
|
+
{ type: FormGroupDirective, decorators: [{ type: Optional }] },
|
|
1144
|
+
{ type: MatFormField, decorators: [{ type: Optional }, { type: Inject, args: [MAT_FORM_FIELD,] }] },
|
|
1145
|
+
{ type: NgControl, decorators: [{ type: Self }, { type: Optional }] },
|
|
1146
|
+
{ type: String, decorators: [{ type: Attribute, args: ['tabindex',] }] },
|
|
1147
|
+
{ type: undefined, decorators: [{ type: Inject, args: [MAT_SELECT_SCROLL_STRATEGY,] }] },
|
|
1148
|
+
{ type: LiveAnnouncer },
|
|
1149
|
+
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAT_SELECT_CONFIG,] }] }
|
|
1150
|
+
];
|
|
1151
|
+
MatSelect.propDecorators = {
|
|
1152
|
+
trigger: [{ type: ViewChild, args: ['trigger',] }],
|
|
1153
|
+
panel: [{ type: ViewChild, args: ['panel',] }],
|
|
1154
|
+
overlayDir: [{ type: ViewChild, args: [CdkConnectedOverlay,] }],
|
|
1155
|
+
options: [{ type: ContentChildren, args: [MatOption, { descendants: true },] }],
|
|
1156
|
+
optionGroups: [{ type: ContentChildren, args: [MAT_OPTGROUP, { descendants: true },] }],
|
|
1157
|
+
panelClass: [{ type: Input }],
|
|
1158
|
+
customTrigger: [{ type: ContentChild, args: [MAT_SELECT_TRIGGER,] }],
|
|
1159
|
+
placeholder: [{ type: Input }],
|
|
1160
|
+
required: [{ type: Input }],
|
|
1161
|
+
multiple: [{ type: Input }],
|
|
1162
|
+
disableOptionCentering: [{ type: Input }],
|
|
1163
|
+
compareWith: [{ type: Input }],
|
|
1164
|
+
value: [{ type: Input }],
|
|
1165
|
+
ariaLabel: [{ type: Input, args: ['aria-label',] }],
|
|
1166
|
+
ariaLabelledby: [{ type: Input, args: ['aria-labelledby',] }],
|
|
1167
|
+
errorStateMatcher: [{ type: Input }],
|
|
1168
|
+
typeaheadDebounceInterval: [{ type: Input }],
|
|
1169
|
+
sortComparator: [{ type: Input }],
|
|
1170
|
+
id: [{ type: Input }],
|
|
1171
|
+
openedChange: [{ type: Output }],
|
|
1172
|
+
_openedStream: [{ type: Output, args: ['opened',] }],
|
|
1173
|
+
_closedStream: [{ type: Output, args: ['closed',] }],
|
|
1174
|
+
selectionChange: [{ type: Output }],
|
|
1175
|
+
valueChange: [{ type: Output }]
|
|
1176
|
+
};
|
|
1176
1177
|
|
|
1177
1178
|
/**
|
|
1178
1179
|
* @license
|
|
@@ -1181,31 +1182,28 @@ let MatSelect = /** @class */ (() => {
|
|
|
1181
1182
|
* Use of this source code is governed by an MIT-style license that can be
|
|
1182
1183
|
* found in the LICENSE file at https://angular.io/license
|
|
1183
1184
|
*/
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
];
|
|
1207
|
-
return MatSelectModule;
|
|
1208
|
-
})();
|
|
1185
|
+
class MatSelectModule {
|
|
1186
|
+
}
|
|
1187
|
+
MatSelectModule.decorators = [
|
|
1188
|
+
{ type: NgModule, args: [{
|
|
1189
|
+
imports: [
|
|
1190
|
+
CommonModule,
|
|
1191
|
+
OverlayModule,
|
|
1192
|
+
MatOptionModule,
|
|
1193
|
+
MatCommonModule,
|
|
1194
|
+
],
|
|
1195
|
+
exports: [
|
|
1196
|
+
CdkScrollableModule,
|
|
1197
|
+
MatFormFieldModule,
|
|
1198
|
+
MatSelect,
|
|
1199
|
+
MatSelectTrigger,
|
|
1200
|
+
MatOptionModule,
|
|
1201
|
+
MatCommonModule
|
|
1202
|
+
],
|
|
1203
|
+
declarations: [MatSelect, MatSelectTrigger],
|
|
1204
|
+
providers: [MAT_SELECT_SCROLL_STRATEGY_PROVIDER]
|
|
1205
|
+
},] }
|
|
1206
|
+
];
|
|
1209
1207
|
|
|
1210
1208
|
/**
|
|
1211
1209
|
* @license
|
|
@@ -1219,5 +1217,5 @@ let MatSelectModule = /** @class */ (() => {
|
|
|
1219
1217
|
* Generated bundle index. Do not edit.
|
|
1220
1218
|
*/
|
|
1221
1219
|
|
|
1222
|
-
export { MAT_SELECT_CONFIG, MAT_SELECT_SCROLL_STRATEGY, MAT_SELECT_SCROLL_STRATEGY_PROVIDER, MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY, MatSelect, MatSelectChange, MatSelectModule, MatSelectTrigger, SELECT_ITEM_HEIGHT_EM, SELECT_MULTIPLE_PANEL_PADDING_X, SELECT_PANEL_INDENT_PADDING_X, SELECT_PANEL_MAX_HEIGHT, SELECT_PANEL_PADDING_X, SELECT_PANEL_VIEWPORT_PADDING, matSelectAnimations };
|
|
1220
|
+
export { MAT_SELECT_CONFIG, MAT_SELECT_SCROLL_STRATEGY, MAT_SELECT_SCROLL_STRATEGY_PROVIDER, MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY, MAT_SELECT_TRIGGER, MatSelect, MatSelectChange, MatSelectModule, MatSelectTrigger, SELECT_ITEM_HEIGHT_EM, SELECT_MULTIPLE_PANEL_PADDING_X, SELECT_PANEL_INDENT_PADDING_X, SELECT_PANEL_MAX_HEIGHT, SELECT_PANEL_PADDING_X, SELECT_PANEL_VIEWPORT_PADDING, matSelectAnimations };
|
|
1223
1221
|
//# sourceMappingURL=select.js.map
|