select.mjs 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. import * as i8 from '@angular/cdk/overlay';
  2. import { Overlay, CdkConnectedOverlay, CdkOverlayOrigin, OverlayModule } from '@angular/cdk/overlay';
  3. import * as i7 from '@angular/common';
  4. import { CommonModule } from '@angular/common';
  5. import * as i0 from '@angular/core';
  6. import { InjectionToken, EventEmitter, Directive, Optional, Inject, Self, Attribute, Input, ViewChild, Output, Component, ViewEncapsulation, ChangeDetectionStrategy, ContentChildren, ContentChild, NgModule } from '@angular/core';
  7. import * as i2 from '@angular/material/core';
  8. import { mixinDisableRipple, mixinTabIndex, mixinDisabled, mixinErrorState, _countGroupLabelsBeforeOption, _getOptionScrollPosition, MAT_OPTION_PARENT_COMPONENT, MatOption, MAT_OPTGROUP, MatOptionModule, MatCommonModule } from '@angular/material/core';
  9. import * as i6 from '@angular/material/form-field';
  10. import { MAT_FORM_FIELD, MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field';
  11. import * as i1 from '@angular/cdk/scrolling';
  12. import { CdkScrollableModule } from '@angular/cdk/scrolling';
  13. import * as i5 from '@angular/cdk/a11y';
  14. import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
  15. import * as i3 from '@angular/cdk/bidi';
  16. import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
  17. import { SelectionModel } from '@angular/cdk/collections';
  18. import { DOWN_ARROW, UP_ARROW, LEFT_ARROW, RIGHT_ARROW, ENTER, SPACE, hasModifierKey, A } from '@angular/cdk/keycodes';
  19. import * as i4 from '@angular/forms';
  20. import { Validators } from '@angular/forms';
  21. import { Subject, defer, merge } from 'rxjs';
  22. import { startWith, switchMap, take, filter, map, distinctUntilChanged, takeUntil } from 'rxjs/operators';
  23. import { trigger, transition, query, animateChild, state, style, animate } from '@angular/animations';
  24. /**
  25. * The following are all the animations for the mat-select component, with each
  26. * const containing the metadata for one animation.
  27. *
  28. * The values below match the implementation of the AngularJS Material mat-select animation.
  29. * @docs-private
  30. */
  31. const matSelectAnimations = {
  32. /**
  33. * This animation ensures the select's overlay panel animation (transformPanel) is called when
  34. * closing the select.
  35. * This is needed due to https://github.com/angular/angular/issues/23302
  36. */
  37. transformPanelWrap: trigger('transformPanelWrap', [
  38. transition('* => void', query('@transformPanel', [animateChild()], { optional: true })),
  39. ]),
  40. /** This animation transforms the select's overlay panel on and off the page. */
  41. transformPanel: trigger('transformPanel', [
  42. state('void', style({
  43. opacity: 0,
  44. transform: 'scale(1, 0.8)',
  45. })),
  46. transition('void => showing', animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
  47. opacity: 1,
  48. transform: 'scale(1, 1)',
  49. }))),
  50. transition('* => void', animate('100ms linear', style({ opacity: 0 }))),
  51. ]),
  52. };
  53. // Note that these have been copied over verbatim from
  54. // `material/select` so that we don't have to expose them publicly.
  55. /**
  56. * Returns an exception to be thrown when attempting to change a select's `multiple` option
  57. * after initialization.
  58. * @docs-private
  59. */
  60. function getMatSelectDynamicMultipleError() {
  61. return Error('Cannot change `multiple` mode of select after initialization.');
  62. }
  63. /**
  64. * Returns an exception to be thrown when attempting to assign a non-array value to a select
  65. * in `multiple` mode. Note that `undefined` and `null` are still valid values to allow for
  66. * resetting the value.
  67. * @docs-private
  68. */
  69. function getMatSelectNonArrayValueError() {
  70. return Error('Value must be an array in multiple-selection mode.');
  71. }
  72. /**
  73. * Returns an exception to be thrown when assigning a non-function value to the comparator
  74. * used to determine if a value corresponds to an option. Note that whether the function
  75. * actually takes two values and returns a boolean is not checked.
  76. */
  77. function getMatSelectNonFunctionValueError() {
  78. return Error('`compareWith` must be a function.');
  79. }
  80. let nextUniqueId = 0;
  81. /** Injection token that determines the scroll handling while a select is open. */
  82. const MAT_SELECT_SCROLL_STRATEGY = new InjectionToken('mat-select-scroll-strategy');
  83. /** @docs-private */
  84. function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
  85. return () => overlay.scrollStrategies.reposition();
  86. }
  87. /** Injection token that can be used to provide the default options the select module. */
  88. const MAT_SELECT_CONFIG = new InjectionToken('MAT_SELECT_CONFIG');
  89. /** @docs-private */
  90. const MAT_SELECT_SCROLL_STRATEGY_PROVIDER = {
  91. provide: MAT_SELECT_SCROLL_STRATEGY,
  92. deps: [Overlay],
  93. useFactory: MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY,
  94. };
  95. /**
  96. * Injection token that can be used to reference instances of `MatSelectTrigger`. It serves as
  97. * alternative token to the actual `MatSelectTrigger` class which could cause unnecessary
  98. * retention of the class and its directive metadata.
  99. */
  100. const MAT_SELECT_TRIGGER = new InjectionToken('MatSelectTrigger');
  101. /** Change event object that is emitted when the select value has changed. */
  102. class MatSelectChange {
  103. constructor(
  104. /** Reference to the select that emitted the change event. */
  105. source,
  106. /** Current value of the select that emitted the event. */
  107. value) {
  108. this.source = source;
  109. this.value = value;
  110. }
  111. }
  112. // Boilerplate for applying mixins to MatSelect.
  113. /** @docs-private */
  114. const _MatSelectMixinBase = mixinDisableRipple(mixinTabIndex(mixinDisabled(mixinErrorState(class {
  115. constructor(_elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup,
  116. /**
  117. * Form control bound to the component.
  118. * Implemented as part of `MatFormFieldControl`.
  119. * @docs-private
  120. */
  121. ngControl) {
  122. this._elementRef = _elementRef;
  123. this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
  124. this._parentForm = _parentForm;
  125. this._parentFormGroup = _parentFormGroup;
  126. this.ngControl = ngControl;
  127. /**
  128. * Emits whenever the component state changes and should cause the parent
  129. * form-field to update. Implemented as part of `MatFormFieldControl`.
  130. * @docs-private
  131. */
  132. this.stateChanges = new Subject();
  133. }
  134. }))));
  135. /** Base class with all of the `MatSelect` functionality. */
  136. class _MatSelectBase extends _MatSelectMixinBase {
  137. /** Whether the select is focused. */
  138. get focused() {
  139. return this._focused || this._panelOpen;
  140. }
  141. /** Placeholder to be shown if no value has been selected. */
  142. get placeholder() {
  143. return this._placeholder;
  144. }
  145. set placeholder(value) {
  146. this._placeholder = value;
  147. this.stateChanges.next();
  148. }
  149. /** Whether the component is required. */
  150. get required() {
  151. return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
  152. }
  153. set required(value) {
  154. this._required = coerceBooleanProperty(value);
  155. this.stateChanges.next();
  156. }
  157. /** Whether the user should be allowed to select multiple options. */
  158. get multiple() {
  159. return this._multiple;
  160. }
  161. set multiple(value) {
  162. if (this._selectionModel && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  163. throw getMatSelectDynamicMultipleError();
  164. }
  165. this._multiple = coerceBooleanProperty(value);
  166. }
  167. /** Whether to center the active option over the trigger. */
  168. get disableOptionCentering() {
  169. return this._disableOptionCentering;
  170. }
  171. set disableOptionCentering(value) {
  172. this._disableOptionCentering = coerceBooleanProperty(value);
  173. }
  174. /**
  175. * Function to compare the option values with the selected values. The first argument
  176. * is a value from an option. The second is a value from the selection. A boolean
  177. * should be returned.
  178. */
  179. get compareWith() {
  180. return this._compareWith;
  181. }
  182. set compareWith(fn) {
  183. if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  184. throw getMatSelectNonFunctionValueError();
  185. }
  186. this._compareWith = fn;
  187. if (this._selectionModel) {
  188. // A different comparator means the selection could change.
  189. this._initializeSelection();
  190. }
  191. }
  192. /** Value of the select control. */
  193. get value() {
  194. return this._value;
  195. }
  196. set value(newValue) {
  197. const hasAssigned = this._assignValue(newValue);
  198. if (hasAssigned) {
  199. this._onChange(newValue);
  200. }
  201. }
  202. /** Time to wait in milliseconds after the last keystroke before moving focus to an item. */
  203. get typeaheadDebounceInterval() {
  204. return this._typeaheadDebounceInterval;
  205. }
  206. set typeaheadDebounceInterval(value) {
  207. this._typeaheadDebounceInterval = coerceNumberProperty(value);
  208. }
  209. /** Unique id of the element. */
  210. get id() {
  211. return this._id;
  212. }
  213. set id(value) {
  214. this._id = value || this._uid;
  215. this.stateChanges.next();
  216. }
  217. constructor(_viewportRuler, _changeDetectorRef, _ngZone, _defaultErrorStateMatcher, elementRef, _dir, _parentForm, _parentFormGroup, _parentFormField, ngControl, tabIndex, scrollStrategyFactory, _liveAnnouncer, _defaultOptions) {
  218. super(elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
  219. this._viewportRuler = _viewportRuler;
  220. this._changeDetectorRef = _changeDetectorRef;
  221. this._ngZone = _ngZone;
  222. this._dir = _dir;
  223. this._parentFormField = _parentFormField;
  224. this._liveAnnouncer = _liveAnnouncer;
  225. this._defaultOptions = _defaultOptions;
  226. /** Whether or not the overlay panel is open. */
  227. this._panelOpen = false;
  228. /** Comparison function to specify which option is displayed. Defaults to object equality. */
  229. this._compareWith = (o1, o2) => o1 === o2;
  230. /** Unique id for this input. */
  231. this._uid = `mat-select-${nextUniqueId++}`;
  232. /** Current `aria-labelledby` value for the select trigger. */
  233. this._triggerAriaLabelledBy = null;
  234. /** Emits whenever the component is destroyed. */
  235. this._destroy = new Subject();
  236. /** `View -> model callback called when value changes` */
  237. this._onChange = () => { };
  238. /** `View -> model callback called when select has been touched` */
  239. this._onTouched = () => { };
  240. /** ID for the DOM node containing the select's value. */
  241. this._valueId = `mat-select-value-${nextUniqueId++}`;
  242. /** Emits when the panel element is finished transforming in. */
  243. this._panelDoneAnimatingStream = new Subject();
  244. this._overlayPanelClass = this._defaultOptions?.overlayPanelClass || '';
  245. this._focused = false;
  246. /** A name for this control that can be used by `mat-form-field`. */
  247. this.controlType = 'mat-select';
  248. this._multiple = false;
  249. this._disableOptionCentering = this._defaultOptions?.disableOptionCentering ?? false;
  250. /** Aria label of the select. */
  251. this.ariaLabel = '';
  252. /** Combined stream of all of the child options' change events. */
  253. this.optionSelectionChanges = defer(() => {
  254. const options = this.options;
  255. if (options) {
  256. return options.changes.pipe(startWith(options), switchMap(() => merge(...options.map(option => option.onSelectionChange))));
  257. }
  258. return this._ngZone.onStable.pipe(take(1), switchMap(() => this.optionSelectionChanges));
  259. });
  260. /** Event emitted when the select panel has been toggled. */
  261. this.openedChange = new EventEmitter();
  262. /** Event emitted when the select has been opened. */
  263. this._openedStream = this.openedChange.pipe(filter(o => o), map(() => { }));
  264. /** Event emitted when the select has been closed. */
  265. this._closedStream = this.openedChange.pipe(filter(o => !o), map(() => { }));
  266. /** Event emitted when the selected value has been changed by the user. */
  267. this.selectionChange = new EventEmitter();
  268. /**
  269. * Event that emits whenever the raw value of the select changes. This is here primarily
  270. * to facilitate the two-way binding for the `value` input.
  271. * @docs-private
  272. */
  273. this.valueChange = new EventEmitter();
  274. if (this.ngControl) {
  275. // Note: we provide the value accessor through here, instead of
  276. // the `providers` to avoid running into a circular import.
  277. this.ngControl.valueAccessor = this;
  278. }
  279. // Note that we only want to set this when the defaults pass it in, otherwise it should
  280. // stay as `undefined` so that it falls back to the default in the key manager.
  281. if (_defaultOptions?.typeaheadDebounceInterval != null) {
  282. this._typeaheadDebounceInterval = _defaultOptions.typeaheadDebounceInterval;
  283. }
  284. this._scrollStrategyFactory = scrollStrategyFactory;
  285. this._scrollStrategy = this._scrollStrategyFactory();
  286. this.tabIndex = parseInt(tabIndex) || 0;
  287. // Force setter to be called in case id was not specified.
  288. this.id = this.id;
  289. }
  290. ngOnInit() {
  291. this._selectionModel = new SelectionModel(this.multiple);
  292. this.stateChanges.next();
  293. // We need `distinctUntilChanged` here, because some browsers will
  294. // fire the animation end event twice for the same animation. See:
  295. // https://github.com/angular/angular/issues/24084
  296. this._panelDoneAnimatingStream
  297. .pipe(distinctUntilChanged(), takeUntil(this._destroy))
  298. .subscribe(() => this._panelDoneAnimating(this.panelOpen));
  299. }
  300. ngAfterContentInit() {
  301. this._initKeyManager();
  302. this._selectionModel.changed.pipe(takeUntil(this._destroy)).subscribe(event => {
  303. event.added.forEach(option => option.select());
  304. event.removed.forEach(option => option.deselect());
  305. });
  306. this.options.changes.pipe(startWith(null), takeUntil(this._destroy)).subscribe(() => {
  307. this._resetOptions();
  308. this._initializeSelection();
  309. });
  310. }
  311. ngDoCheck() {
  312. const newAriaLabelledby = this._getTriggerAriaLabelledby();
  313. const ngControl = this.ngControl;
  314. // We have to manage setting the `aria-labelledby` ourselves, because part of its value
  315. // is computed as a result of a content query which can cause this binding to trigger a
  316. // "changed after checked" error.
  317. if (newAriaLabelledby !== this._triggerAriaLabelledBy) {
  318. const element = this._elementRef.nativeElement;
  319. this._triggerAriaLabelledBy = newAriaLabelledby;
  320. if (newAriaLabelledby) {
  321. element.setAttribute('aria-labelledby', newAriaLabelledby);
  322. }
  323. else {
  324. element.removeAttribute('aria-labelledby');
  325. }
  326. }
  327. if (ngControl) {
  328. // The disabled state might go out of sync if the form group is swapped out. See #17860.
  329. if (this._previousControl !== ngControl.control) {
  330. if (this._previousControl !== undefined &&
  331. ngControl.disabled !== null &&
  332. ngControl.disabled !== this.disabled) {
  333. this.disabled = ngControl.disabled;
  334. }
  335. this._previousControl = ngControl.control;
  336. }
  337. this.updateErrorState();
  338. }
  339. }
  340. ngOnChanges(changes) {
  341. // Updating the disabled state is handled by `mixinDisabled`, but we need to additionally let
  342. // the parent form field know to run change detection when the disabled state changes.
  343. if (changes['disabled'] || changes['userAriaDescribedBy']) {
  344. this.stateChanges.next();
  345. }
  346. if (changes['typeaheadDebounceInterval'] && this._keyManager) {
  347. this._keyManager.withTypeAhead(this._typeaheadDebounceInterval);
  348. }
  349. }
  350. ngOnDestroy() {
  351. this._keyManager?.destroy();
  352. this._destroy.next();
  353. this._destroy.complete();
  354. this.stateChanges.complete();
  355. }
  356. /** Toggles the overlay panel open or closed. */
  357. toggle() {
  358. this.panelOpen ? this.close() : this.open();
  359. }
  360. /** Opens the overlay panel. */
  361. open() {
  362. if (this._canOpen()) {
  363. this._panelOpen = true;
  364. this._keyManager.withHorizontalOrientation(null);
  365. this._highlightCorrectOption();
  366. this._changeDetectorRef.markForCheck();
  367. }
  368. }
  369. /** Closes the overlay panel and focuses the host element. */
  370. close() {
  371. if (this._panelOpen) {
  372. this._panelOpen = false;
  373. this._keyManager.withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr');
  374. this._changeDetectorRef.markForCheck();
  375. this._onTouched();
  376. }
  377. }
  378. /**
  379. * Sets the select's value. Part of the ControlValueAccessor interface
  380. * required to integrate with Angular's core forms API.
  381. *
  382. * @param value New value to be written to the model.
  383. */
  384. writeValue(value) {
  385. this._assignValue(value);
  386. }
  387. /**
  388. * Saves a callback function to be invoked when the select's value
  389. * changes from user input. Part of the ControlValueAccessor interface
  390. * required to integrate with Angular's core forms API.
  391. *
  392. * @param fn Callback to be triggered when the value changes.
  393. */
  394. registerOnChange(fn) {
  395. this._onChange = fn;
  396. }
  397. /**
  398. * Saves a callback function to be invoked when the select is blurred
  399. * by the user. Part of the ControlValueAccessor interface required
  400. * to integrate with Angular's core forms API.
  401. *
  402. * @param fn Callback to be triggered when the component has been touched.
  403. */
  404. registerOnTouched(fn) {
  405. this._onTouched = fn;
  406. }
  407. /**
  408. * Disables the select. Part of the ControlValueAccessor interface required
  409. * to integrate with Angular's core forms API.
  410. *
  411. * @param isDisabled Sets whether the component is disabled.
  412. */
  413. setDisabledState(isDisabled) {
  414. this.disabled = isDisabled;
  415. this._changeDetectorRef.markForCheck();
  416. this.stateChanges.next();
  417. }
  418. /** Whether or not the overlay panel is open. */
  419. get panelOpen() {
  420. return this._panelOpen;
  421. }
  422. /** The currently selected option. */
  423. get selected() {
  424. return this.multiple ? this._selectionModel?.selected || [] : this._selectionModel?.selected[0];
  425. }
  426. /** The value displayed in the trigger. */
  427. get triggerValue() {
  428. if (this.empty) {
  429. return '';
  430. }
  431. if (this._multiple) {
  432. const selectedOptions = this._selectionModel.selected.map(option => option.viewValue);
  433. if (this._isRtl()) {
  434. selectedOptions.reverse();
  435. }
  436. // TODO(crisbeto): delimiter should be configurable for proper localization.
  437. return selectedOptions.join(', ');
  438. }
  439. return this._selectionModel.selected[0].viewValue;
  440. }
  441. /** Whether the element is in RTL mode. */
  442. _isRtl() {
  443. return this._dir ? this._dir.value === 'rtl' : false;
  444. }
  445. /** Handles all keydown events on the select. */
  446. _handleKeydown(event) {
  447. if (!this.disabled) {
  448. this.panelOpen ? this._handleOpenKeydown(event) : this._handleClosedKeydown(event);
  449. }
  450. }
  451. /** Handles keyboard events while the select is closed. */
  452. _handleClosedKeydown(event) {
  453. const keyCode = event.keyCode;
  454. const isArrowKey = keyCode === DOWN_ARROW ||
  455. keyCode === UP_ARROW ||
  456. keyCode === LEFT_ARROW ||
  457. keyCode === RIGHT_ARROW;
  458. const isOpenKey = keyCode === ENTER || keyCode === SPACE;
  459. const manager = this._keyManager;
  460. // Open the select on ALT + arrow key to match the native <select>
  461. if ((!manager.isTyping() && isOpenKey && !hasModifierKey(event)) ||
  462. ((this.multiple || event.altKey) && isArrowKey)) {
  463. event.preventDefault(); // prevents the page from scrolling down when pressing space
  464. this.open();
  465. }
  466. else if (!this.multiple) {
  467. const previouslySelectedOption = this.selected;
  468. manager.onKeydown(event);
  469. const selectedOption = this.selected;
  470. // Since the value has changed, we need to announce it ourselves.
  471. if (selectedOption && previouslySelectedOption !== selectedOption) {
  472. // We set a duration on the live announcement, because we want the live element to be
  473. // cleared after a while so that users can't navigate to it using the arrow keys.
  474. this._liveAnnouncer.announce(selectedOption.viewValue, 10000);
  475. }
  476. }
  477. }
  478. /** Handles keyboard events when the selected is open. */
  479. _handleOpenKeydown(event) {
  480. const manager = this._keyManager;
  481. const keyCode = event.keyCode;
  482. const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW;
  483. const isTyping = manager.isTyping();
  484. if (isArrowKey && event.altKey) {
  485. // Close the select on ALT + arrow key to match the native <select>
  486. event.preventDefault();
  487. this.close();
  488. // Don't do anything in this case if the user is typing,
  489. // because the typing sequence can include the space key.
  490. }
  491. else if (!isTyping &&
  492. (keyCode === ENTER || keyCode === SPACE) &&
  493. manager.activeItem &&
  494. !hasModifierKey(event)) {
  495. event.preventDefault();
  496. manager.activeItem._selectViaInteraction();
  497. }
  498. else if (!isTyping && this._multiple && keyCode === A && event.ctrlKey) {
  499. event.preventDefault();
  500. const hasDeselectedOptions = this.options.some(opt => !opt.disabled && !opt.selected);
  501. this.options.forEach(option => {
  502. if (!option.disabled) {
  503. hasDeselectedOptions ? option.select() : option.deselect();
  504. }
  505. });
  506. }
  507. else {
  508. const previouslyFocusedIndex = manager.activeItemIndex;
  509. manager.onKeydown(event);
  510. if (this._multiple &&
  511. isArrowKey &&
  512. event.shiftKey &&
  513. manager.activeItem &&
  514. manager.activeItemIndex !== previouslyFocusedIndex) {
  515. manager.activeItem._selectViaInteraction();
  516. }
  517. }
  518. }
  519. _onFocus() {
  520. if (!this.disabled) {
  521. this._focused = true;
  522. this.stateChanges.next();
  523. }
  524. }
  525. /**
  526. * Calls the touched callback only if the panel is closed. Otherwise, the trigger will
  527. * "blur" to the panel when it opens, causing a false positive.
  528. */
  529. _onBlur() {
  530. this._focused = false;
  531. this._keyManager?.cancelTypeahead();
  532. if (!this.disabled && !this.panelOpen) {
  533. this._onTouched();
  534. this._changeDetectorRef.markForCheck();
  535. this.stateChanges.next();
  536. }
  537. }
  538. /**
  539. * Callback that is invoked when the overlay panel has been attached.
  540. */
  541. _onAttached() {
  542. this._overlayDir.positionChange.pipe(take(1)).subscribe(() => {
  543. this._changeDetectorRef.detectChanges();
  544. this._positioningSettled();
  545. });
  546. }
  547. /** Returns the theme to be used on the panel. */
  548. _getPanelTheme() {
  549. return this._parentFormField ? `mat-${this._parentFormField.color}` : '';
  550. }
  551. /** Whether the select has a value. */
  552. get empty() {
  553. return !this._selectionModel || this._selectionModel.isEmpty();
  554. }
  555. _initializeSelection() {
  556. // Defer setting the value in order to avoid the "Expression
  557. // has changed after it was checked" errors from Angular.
  558. Promise.resolve().then(() => {
  559. if (this.ngControl) {
  560. this._value = this.ngControl.value;
  561. }
  562. this._setSelectionByValue(this._value);
  563. this.stateChanges.next();
  564. });
  565. }
  566. /**
  567. * Sets the selected option based on a value. If no option can be
  568. * found with the designated value, the select trigger is cleared.
  569. */
  570. _setSelectionByValue(value) {
  571. this.options.forEach(option => option.setInactiveStyles());
  572. this._selectionModel.clear();
  573. if (this.multiple && value) {
  574. if (!Array.isArray(value) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  575. throw getMatSelectNonArrayValueError();
  576. }
  577. value.forEach((currentValue) => this._selectOptionByValue(currentValue));
  578. this._sortValues();
  579. }
  580. else {
  581. const correspondingOption = this._selectOptionByValue(value);
  582. // Shift focus to the active item. Note that we shouldn't do this in multiple
  583. // mode, because we don't know what option the user interacted with last.
  584. if (correspondingOption) {
  585. this._keyManager.updateActiveItem(correspondingOption);
  586. }
  587. else if (!this.panelOpen) {
  588. // Otherwise reset the highlighted option. Note that we only want to do this while
  589. // closed, because doing it while open can shift the user's focus unnecessarily.
  590. this._keyManager.updateActiveItem(-1);
  591. }
  592. }
  593. this._changeDetectorRef.markForCheck();
  594. }
  595. /**
  596. * Finds and selects and option based on its value.
  597. * @returns Option that has the corresponding value.
  598. */
  599. _selectOptionByValue(value) {
  600. const correspondingOption = this.options.find((option) => {
  601. // Skip options that are already in the model. This allows us to handle cases
  602. // where the same primitive value is selected multiple times.
  603. if (this._selectionModel.isSelected(option)) {
  604. return false;
  605. }
  606. try {
  607. // Treat null as a special reset value.
  608. return option.value != null && this._compareWith(option.value, value);
  609. }
  610. catch (error) {
  611. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  612. // Notify developers of errors in their comparator.
  613. console.warn(error);
  614. }
  615. return false;
  616. }
  617. });
  618. if (correspondingOption) {
  619. this._selectionModel.select(correspondingOption);
  620. }
  621. return correspondingOption;
  622. }
  623. /** Assigns a specific value to the select. Returns whether the value has changed. */
  624. _assignValue(newValue) {
  625. // Always re-assign an array, because it might have been mutated.
  626. if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {
  627. if (this.options) {
  628. this._setSelectionByValue(newValue);
  629. }
  630. this._value = newValue;
  631. return true;
  632. }
  633. return false;
  634. }
  635. _skipPredicate(item) {
  636. return item.disabled;
  637. }
  638. /** Sets up a key manager to listen to keyboard events on the overlay panel. */
  639. _initKeyManager() {
  640. this._keyManager = new ActiveDescendantKeyManager(this.options)
  641. .withTypeAhead(this._typeaheadDebounceInterval)
  642. .withVerticalOrientation()
  643. .withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr')
  644. .withHomeAndEnd()
  645. .withPageUpDown()
  646. .withAllowedModifierKeys(['shiftKey'])
  647. .skipPredicate(this._skipPredicate);
  648. this._keyManager.tabOut.subscribe(() => {
  649. if (this.panelOpen) {
  650. // Select the active item when tabbing away. This is consistent with how the native
  651. // select behaves. Note that we only want to do this in single selection mode.
  652. if (!this.multiple && this._keyManager.activeItem) {
  653. this._keyManager.activeItem._selectViaInteraction();
  654. }
  655. // Restore focus to the trigger before closing. Ensures that the focus
  656. // position won't be lost if the user got focus into the overlay.
  657. this.focus();
  658. this.close();
  659. }
  660. });
  661. this._keyManager.change.subscribe(() => {
  662. if (this._panelOpen && this.panel) {
  663. this._scrollOptionIntoView(this._keyManager.activeItemIndex || 0);
  664. }
  665. else if (!this._panelOpen && !this.multiple && this._keyManager.activeItem) {
  666. this._keyManager.activeItem._selectViaInteraction();
  667. }
  668. });
  669. }
  670. /** Drops current option subscriptions and IDs and resets from scratch. */
  671. _resetOptions() {
  672. const changedOrDestroyed = merge(this.options.changes, this._destroy);
  673. this.optionSelectionChanges.pipe(takeUntil(changedOrDestroyed)).subscribe(event => {
  674. this._onSelect(event.source, event.isUserInput);
  675. if (event.isUserInput && !this.multiple && this._panelOpen) {
  676. this.close();
  677. this.focus();
  678. }
  679. });
  680. // Listen to changes in the internal state of the options and react accordingly.
  681. // Handles cases like the labels of the selected options changing.
  682. merge(...this.options.map(option => option._stateChanges))
  683. .pipe(takeUntil(changedOrDestroyed))
  684. .subscribe(() => {
  685. // `_stateChanges` can fire as a result of a change in the label's DOM value which may
  686. // be the result of an expression changing. We have to use `detectChanges` in order
  687. // to avoid "changed after checked" errors (see #14793).
  688. this._changeDetectorRef.detectChanges();
  689. this.stateChanges.next();
  690. });
  691. }
  692. /** Invoked when an option is clicked. */
  693. _onSelect(option, isUserInput) {
  694. const wasSelected = this._selectionModel.isSelected(option);
  695. if (option.value == null && !this._multiple) {
  696. option.deselect();
  697. this._selectionModel.clear();
  698. if (this.value != null) {
  699. this._propagateChanges(option.value);
  700. }
  701. }
  702. else {
  703. if (wasSelected !== option.selected) {
  704. option.selected
  705. ? this._selectionModel.select(option)
  706. : this._selectionModel.deselect(option);
  707. }
  708. if (isUserInput) {
  709. this._keyManager.setActiveItem(option);
  710. }
  711. if (this.multiple) {
  712. this._sortValues();
  713. if (isUserInput) {
  714. // In case the user selected the option with their mouse, we
  715. // want to restore focus back to the trigger, in order to
  716. // prevent the select keyboard controls from clashing with
  717. // the ones from `mat-option`.
  718. this.focus();
  719. }
  720. }
  721. }
  722. if (wasSelected !== this._selectionModel.isSelected(option)) {
  723. this._propagateChanges();
  724. }
  725. this.stateChanges.next();
  726. }
  727. /** Sorts the selected values in the selected based on their order in the panel. */
  728. _sortValues() {
  729. if (this.multiple) {
  730. const options = this.options.toArray();
  731. this._selectionModel.sort((a, b) => {
  732. return this.sortComparator
  733. ? this.sortComparator(a, b, options)
  734. : options.indexOf(a) - options.indexOf(b);
  735. });
  736. this.stateChanges.next();
  737. }
  738. }
  739. /** Emits change event to set the model value. */
  740. _propagateChanges(fallbackValue) {
  741. let valueToEmit = null;
  742. if (this.multiple) {
  743. valueToEmit = this.selected.map(option => option.value);
  744. }
  745. else {
  746. valueToEmit = this.selected ? this.selected.value : fallbackValue;
  747. }
  748. this._value = valueToEmit;
  749. this.valueChange.emit(valueToEmit);
  750. this._onChange(valueToEmit);
  751. this.selectionChange.emit(this._getChangeEvent(valueToEmit));
  752. this._changeDetectorRef.markForCheck();
  753. }
  754. /**
  755. * Highlights the selected item. If no option is selected, it will highlight
  756. * the first *enabled* option.
  757. */
  758. _highlightCorrectOption() {
  759. if (this._keyManager) {
  760. if (this.empty) {
  761. // Find the index of the first *enabled* option. Avoid calling `_keyManager.setActiveItem`
  762. // because it activates the first option that passes the skip predicate, rather than the
  763. // first *enabled* option.
  764. let firstEnabledOptionIndex = -1;
  765. for (let index = 0; index < this.options.length; index++) {
  766. const option = this.options.get(index);
  767. if (!option.disabled) {
  768. firstEnabledOptionIndex = index;
  769. break;
  770. }
  771. }
  772. this._keyManager.setActiveItem(firstEnabledOptionIndex);
  773. }
  774. else {
  775. this._keyManager.setActiveItem(this._selectionModel.selected[0]);
  776. }
  777. }
  778. }
  779. /** Whether the panel is allowed to open. */
  780. _canOpen() {
  781. return !this._panelOpen && !this.disabled && this.options?.length > 0;
  782. }
  783. /** Focuses the select element. */
  784. focus(options) {
  785. this._elementRef.nativeElement.focus(options);
  786. }
  787. /** Gets the aria-labelledby for the select panel. */
  788. _getPanelAriaLabelledby() {
  789. if (this.ariaLabel) {
  790. return null;
  791. }
  792. const labelId = this._parentFormField?.getLabelId();
  793. const labelExpression = labelId ? labelId + ' ' : '';
  794. return this.ariaLabelledby ? labelExpression + this.ariaLabelledby : labelId;
  795. }
  796. /** Determines the `aria-activedescendant` to be set on the host. */
  797. _getAriaActiveDescendant() {
  798. if (this.panelOpen && this._keyManager && this._keyManager.activeItem) {
  799. return this._keyManager.activeItem.id;
  800. }
  801. return null;
  802. }
  803. /** Gets the aria-labelledby of the select component trigger. */
  804. _getTriggerAriaLabelledby() {
  805. if (this.ariaLabel) {
  806. return null;
  807. }
  808. const labelId = this._parentFormField?.getLabelId();
  809. let value = (labelId ? labelId + ' ' : '') + this._valueId;
  810. if (this.ariaLabelledby) {
  811. value += ' ' + this.ariaLabelledby;
  812. }
  813. return value;
  814. }
  815. /** Called when the overlay panel is done animating. */
  816. _panelDoneAnimating(isOpen) {
  817. this.openedChange.emit(isOpen);
  818. }
  819. /**
  820. * Implemented as part of MatFormFieldControl.
  821. * @docs-private
  822. */
  823. setDescribedByIds(ids) {
  824. if (ids.length) {
  825. this._elementRef.nativeElement.setAttribute('aria-describedby', ids.join(' '));
  826. }
  827. else {
  828. this._elementRef.nativeElement.removeAttribute('aria-describedby');
  829. }
  830. }
  831. /**
  832. * Implemented as part of MatFormFieldControl.
  833. * @docs-private
  834. */
  835. onContainerClick() {
  836. this.focus();
  837. this.open();
  838. }
  839. /**
  840. * Implemented as part of MatFormFieldControl.
  841. * @docs-private
  842. */
  843. get shouldLabelFloat() {
  844. return this._panelOpen || !this.empty || (this._focused && !!this._placeholder);
  845. }
  846. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: _MatSelectBase, deps: [{ token: i1.ViewportRuler }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i2.ErrorStateMatcher }, { token: i0.ElementRef }, { token: i3.Directionality, optional: true }, { token: i4.NgForm, optional: true }, { token: i4.FormGroupDirective, optional: true }, { token: MAT_FORM_FIELD, optional: true }, { token: i4.NgControl, optional: true, self: true }, { token: 'tabindex', attribute: true }, { token: MAT_SELECT_SCROLL_STRATEGY }, { token: i5.LiveAnnouncer }, { token: MAT_SELECT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
  847. static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: _MatSelectBase, inputs: { userAriaDescribedBy: ["aria-describedby", "userAriaDescribedBy"], panelClass: "panelClass", placeholder: "placeholder", required: "required", multiple: "multiple", disableOptionCentering: "disableOptionCentering", compareWith: "compareWith", value: "value", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], errorStateMatcher: "errorStateMatcher", typeaheadDebounceInterval: "typeaheadDebounceInterval", sortComparator: "sortComparator", id: "id" }, outputs: { openedChange: "openedChange", _openedStream: "opened", _closedStream: "closed", selectionChange: "selectionChange", valueChange: "valueChange" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true }, { propertyName: "_overlayDir", first: true, predicate: CdkConnectedOverlay, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
  848. }
  849. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: _MatSelectBase, decorators: [{
  850. type: Directive
  851. }], ctorParameters: function () { return [{ type: i1.ViewportRuler }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i2.ErrorStateMatcher }, { type: i0.ElementRef }, { type: i3.Directionality, decorators: [{
  852. type: Optional
  853. }] }, { type: i4.NgForm, decorators: [{
  854. type: Optional
  855. }] }, { type: i4.FormGroupDirective, decorators: [{
  856. type: Optional
  857. }] }, { type: i6.MatFormField, decorators: [{
  858. type: Optional
  859. }, {
  860. type: Inject,
  861. args: [MAT_FORM_FIELD]
  862. }] }, { type: i4.NgControl, decorators: [{
  863. type: Self
  864. }, {
  865. type: Optional
  866. }] }, { type: undefined, decorators: [{
  867. type: Attribute,
  868. args: ['tabindex']
  869. }] }, { type: undefined, decorators: [{
  870. type: Inject,
  871. args: [MAT_SELECT_SCROLL_STRATEGY]
  872. }] }, { type: i5.LiveAnnouncer }, { type: undefined, decorators: [{
  873. type: Optional
  874. }, {
  875. type: Inject,
  876. args: [MAT_SELECT_CONFIG]
  877. }] }]; }, propDecorators: { userAriaDescribedBy: [{
  878. type: Input,
  879. args: ['aria-describedby']
  880. }], trigger: [{
  881. type: ViewChild,
  882. args: ['trigger']
  883. }], panel: [{
  884. type: ViewChild,
  885. args: ['panel']
  886. }], _overlayDir: [{
  887. type: ViewChild,
  888. args: [CdkConnectedOverlay]
  889. }], panelClass: [{
  890. type: Input
  891. }], placeholder: [{
  892. type: Input
  893. }], required: [{
  894. type: Input
  895. }], multiple: [{
  896. type: Input
  897. }], disableOptionCentering: [{
  898. type: Input
  899. }], compareWith: [{
  900. type: Input
  901. }], value: [{
  902. type: Input
  903. }], ariaLabel: [{
  904. type: Input,
  905. args: ['aria-label']
  906. }], ariaLabelledby: [{
  907. type: Input,
  908. args: ['aria-labelledby']
  909. }], errorStateMatcher: [{
  910. type: Input
  911. }], typeaheadDebounceInterval: [{
  912. type: Input
  913. }], sortComparator: [{
  914. type: Input
  915. }], id: [{
  916. type: Input
  917. }], openedChange: [{
  918. type: Output
  919. }], _openedStream: [{
  920. type: Output,
  921. args: ['opened']
  922. }], _closedStream: [{
  923. type: Output,
  924. args: ['closed']
  925. }], selectionChange: [{
  926. type: Output
  927. }], valueChange: [{
  928. type: Output
  929. }] } });
  930. /**
  931. * Allows the user to customize the trigger that is displayed when the select has a value.
  932. */
  933. class MatSelectTrigger {
  934. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelectTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
  935. static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: MatSelectTrigger, selector: "mat-select-trigger", providers: [{ provide: MAT_SELECT_TRIGGER, useExisting: MatSelectTrigger }], ngImport: i0 }); }
  936. }
  937. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelectTrigger, decorators: [{
  938. type: Directive,
  939. args: [{
  940. selector: 'mat-select-trigger',
  941. providers: [{ provide: MAT_SELECT_TRIGGER, useExisting: MatSelectTrigger }],
  942. }]
  943. }] });
  944. class MatSelect extends _MatSelectBase {
  945. constructor() {
  946. super(...arguments);
  947. this._positions = [
  948. {
  949. originX: 'start',
  950. originY: 'bottom',
  951. overlayX: 'start',
  952. overlayY: 'top',
  953. },
  954. {
  955. originX: 'start',
  956. originY: 'top',
  957. overlayX: 'start',
  958. overlayY: 'bottom',
  959. panelClass: 'mat-mdc-select-panel-above',
  960. },
  961. ];
  962. this._hideSingleSelectionIndicator = this._defaultOptions?.hideSingleSelectionIndicator ?? false;
  963. // `skipPredicate` determines if key manager should avoid putting a given option in the tab
  964. // order. Allow disabled list items to receive focus via keyboard to align with WAI ARIA
  965. // recommendation.
  966. //
  967. // Normally WAI ARIA's instructions are to exclude disabled items from the tab order, but it
  968. // makes a few exceptions for compound widgets.
  969. //
  970. // From [Developing a Keyboard Interface](
  971. // https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/):
  972. // "For the following composite widget elements, keep them focusable when disabled: Options in a
  973. // Listbox..."
  974. //
  975. // The user can focus disabled options using the keyboard, but the user cannot click disabled
  976. // options.
  977. this._skipPredicate = (option) => {
  978. if (this.panelOpen) {
  979. // Support keyboard focusing disabled options in an ARIA listbox.
  980. return false;
  981. }
  982. // When the panel is closed, skip over disabled options. Support options via the UP/DOWN arrow
  983. // keys on a closed select. ARIA listbox interaction pattern is less relevant when the panel is
  984. // closed.
  985. return option.disabled;
  986. };
  987. }
  988. get shouldLabelFloat() {
  989. // Since the panel doesn't overlap the trigger, we
  990. // want the label to only float when there's a value.
  991. return this.panelOpen || !this.empty || (this.focused && !!this.placeholder);
  992. }
  993. ngOnInit() {
  994. super.ngOnInit();
  995. this._viewportRuler
  996. .change()
  997. .pipe(takeUntil(this._destroy))
  998. .subscribe(() => {
  999. if (this.panelOpen) {
  1000. this._overlayWidth = this._getOverlayWidth();
  1001. this._changeDetectorRef.detectChanges();
  1002. }
  1003. });
  1004. }
  1005. ngAfterViewInit() {
  1006. // Note that it's important that we read this in `ngAfterViewInit`, because
  1007. // reading it earlier will cause the form field to return a different element.
  1008. if (this._parentFormField) {
  1009. this._preferredOverlayOrigin = this._parentFormField.getConnectedOverlayOrigin();
  1010. }
  1011. }
  1012. open() {
  1013. this._overlayWidth = this._getOverlayWidth();
  1014. super.open();
  1015. // Required for the MDC form field to pick up when the overlay has been opened.
  1016. this.stateChanges.next();
  1017. }
  1018. close() {
  1019. super.close();
  1020. // Required for the MDC form field to pick up when the overlay has been closed.
  1021. this.stateChanges.next();
  1022. }
  1023. /** Scrolls the active option into view. */
  1024. _scrollOptionIntoView(index) {
  1025. const option = this.options.toArray()[index];
  1026. if (option) {
  1027. const panel = this.panel.nativeElement;
  1028. const labelCount = _countGroupLabelsBeforeOption(index, this.options, this.optionGroups);
  1029. const element = option._getHostElement();
  1030. if (index === 0 && labelCount === 1) {
  1031. // If we've got one group label before the option and we're at the top option,
  1032. // scroll the list to the top. This is better UX than scrolling the list to the
  1033. // top of the option, because it allows the user to read the top group's label.
  1034. panel.scrollTop = 0;
  1035. }
  1036. else {
  1037. panel.scrollTop = _getOptionScrollPosition(element.offsetTop, element.offsetHeight, panel.scrollTop, panel.offsetHeight);
  1038. }
  1039. }
  1040. }
  1041. _positioningSettled() {
  1042. this._scrollOptionIntoView(this._keyManager.activeItemIndex || 0);
  1043. }
  1044. _getChangeEvent(value) {
  1045. return new MatSelectChange(this, value);
  1046. }
  1047. /** Gets how wide the overlay panel should be. */
  1048. _getOverlayWidth() {
  1049. const refToMeasure = this._preferredOverlayOrigin instanceof CdkOverlayOrigin
  1050. ? this._preferredOverlayOrigin.elementRef
  1051. : this._preferredOverlayOrigin || this._elementRef;
  1052. return refToMeasure.nativeElement.getBoundingClientRect().width;
  1053. }
  1054. /** Whether checkmark indicator for single-selection options is hidden. */
  1055. get hideSingleSelectionIndicator() {
  1056. return this._hideSingleSelectionIndicator;
  1057. }
  1058. set hideSingleSelectionIndicator(value) {
  1059. this._hideSingleSelectionIndicator = coerceBooleanProperty(value);
  1060. this._syncParentProperties();
  1061. }
  1062. /** Syncs the parent state with the individual options. */
  1063. _syncParentProperties() {
  1064. if (this.options) {
  1065. for (const option of this.options) {
  1066. option._changeDetectorRef.markForCheck();
  1067. }
  1068. }
  1069. }
  1070. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelect, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
  1071. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: MatSelect, selector: "mat-select", inputs: { disabled: "disabled", disableRipple: "disableRipple", tabIndex: "tabIndex", hideSingleSelectionIndicator: "hideSingleSelectionIndicator" }, host: { attributes: { "role": "combobox", "aria-autocomplete": "none", "aria-haspopup": "listbox", "ngSkipHydration": "" }, listeners: { "keydown": "_handleKeydown($event)", "focus": "_onFocus()", "blur": "_onBlur()" }, properties: { "attr.id": "id", "attr.tabindex": "tabIndex", "attr.aria-controls": "panelOpen ? id + \"-panel\" : null", "attr.aria-expanded": "panelOpen", "attr.aria-label": "ariaLabel || null", "attr.aria-required": "required.toString()", "attr.aria-disabled": "disabled.toString()", "attr.aria-invalid": "errorState", "attr.aria-activedescendant": "_getAriaActiveDescendant()", "class.mat-mdc-select-disabled": "disabled", "class.mat-mdc-select-invalid": "errorState", "class.mat-mdc-select-required": "required", "class.mat-mdc-select-empty": "empty", "class.mat-mdc-select-multiple": "multiple" }, classAttribute: "mat-mdc-select" }, providers: [
  1072. { provide: MatFormFieldControl, useExisting: MatSelect },
  1073. { provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect },
  1074. ], queries: [{ propertyName: "customTrigger", first: true, predicate: MAT_SELECT_TRIGGER, descendants: true }, { propertyName: "options", predicate: MatOption, descendants: true }, { propertyName: "optionGroups", predicate: MAT_OPTGROUP, descendants: true }], exportAs: ["matSelect"], usesInheritance: true, ngImport: i0, template: "<!--\n Note that the select trigger element specifies `aria-owns` pointing to the listbox overlay.\n While aria-owns is not required for the ARIA 1.2 `role=\"combobox\"` interaction pattern,\n it fixes an issue with VoiceOver when the select appears inside of an `aria-model=\"true\"`\n element (e.g. a dialog). Without this `aria-owns`, the `aria-modal` on a dialog prevents\n VoiceOver from \"seeing\" the select's listbox overlay for aria-activedescendant.\n Using `aria-owns` re-parents the select overlay so that it works again.\n See https://github.com/angular/components/issues/20694\n-->\n<div cdk-overlay-origin\n [attr.aria-owns]=\"panelOpen ? id + '-panel' : null\"\n class=\"mat-mdc-select-trigger\"\n (click)=\"toggle()\"\n #fallbackOverlayOrigin=\"cdkOverlayOrigin\"\n #trigger>\n <div class=\"mat-mdc-select-value\" [ngSwitch]=\"empty\" [attr.id]=\"_valueId\">\n <span class=\"mat-mdc-select-placeholder mat-mdc-select-min-line\" *ngSwitchCase=\"true\">{{placeholder}}</span>\n <span class=\"mat-mdc-select-value-text\" *ngSwitchCase=\"false\" [ngSwitch]=\"!!customTrigger\">\n <span class=\"mat-mdc-select-min-line\" *ngSwitchDefault>{{triggerValue}}</span>\n <ng-content select=\"mat-select-trigger\" *ngSwitchCase=\"true\"></ng-content>\n </span>\n </div>\n\n <div class=\"mat-mdc-select-arrow-wrapper\">\n <div class=\"mat-mdc-select-arrow\">\n <!-- Use an inline SVG, because it works better than a CSS triangle in high contrast mode. -->\n <svg viewBox=\"0 0 24 24\" width=\"24px\" height=\"24px\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M7 10l5 5 5-5z\"/>\n </svg>\n </div>\n </div>\n</div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayLockPosition\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPanelClass]=\"_overlayPanelClass\"\n [cdkConnectedOverlayScrollStrategy]=\"_scrollStrategy\"\n [cdkConnectedOverlayOrigin]=\"_preferredOverlayOrigin || fallbackOverlayOrigin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayPositions]=\"_positions\"\n [cdkConnectedOverlayWidth]=\"_overlayWidth\"\n (backdropClick)=\"close()\"\n (attach)=\"_onAttached()\"\n (detach)=\"close()\">\n <div\n #panel\n role=\"listbox\"\n tabindex=\"-1\"\n class=\"mat-mdc-select-panel mdc-menu-surface mdc-menu-surface--open {{ _getPanelTheme() }}\"\n [attr.id]=\"id + '-panel'\"\n [attr.aria-multiselectable]=\"multiple\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"_getPanelAriaLabelledby()\"\n [ngClass]=\"panelClass\"\n [@transformPanel]=\"'showing'\"\n (@transformPanel.done)=\"_panelDoneAnimatingStream.next($event.toState)\"\n (keydown)=\"_handleKeydown($event)\">\n <ng-content></ng-content>\n </div>\n</ng-template>\n", styles: [".mdc-menu-surface{display:none;position:absolute;box-sizing:border-box;margin:0;padding:0;transform:scale(1);transform-origin:top left;opacity:0;overflow:auto;will-change:transform,opacity;transform-origin-left:top left;transform-origin-right:top right}.mdc-menu-surface:focus{outline:none}.mdc-menu-surface--animating-open{display:inline-block;transform:scale(0.8);opacity:0}.mdc-menu-surface--open{display:inline-block;transform:scale(1);opacity:1}.mdc-menu-surface--animating-closed{display:inline-block;opacity:0}[dir=rtl] .mdc-menu-surface,.mdc-menu-surface[dir=rtl]{transform-origin-left:top right;transform-origin-right:top left}.mdc-menu-surface--anchor{position:relative;overflow:visible}.mdc-menu-surface--fixed{position:fixed}.mdc-menu-surface--fullwidth{width:100%}.mdc-menu-surface{max-width:calc(100vw - 32px);max-width:var(--mdc-menu-max-width, calc(100vw - 32px));max-height:calc(100vh - 32px);max-height:var(--mdc-menu-max-height, calc(100vh - 32px));z-index:8;border-radius:4px;border-radius:var(--mdc-shape-medium, 4px)}.mat-mdc-select{display:inline-block;width:100%;outline:none}.mat-mdc-select-trigger{display:inline-flex;align-items:center;cursor:pointer;position:relative;box-sizing:border-box;width:100%}.mat-mdc-select-disabled .mat-mdc-select-trigger{-webkit-user-select:none;user-select:none;cursor:default}.mat-mdc-select-value{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mat-mdc-select-value-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mat-mdc-select-arrow-wrapper{height:24px;flex-shrink:0;display:inline-flex;align-items:center}.mat-form-field-appearance-fill .mat-mdc-select-arrow-wrapper{transform:translateY(-8px)}.mat-form-field-appearance-fill .mdc-text-field--no-label .mat-mdc-select-arrow-wrapper{transform:none}.mat-mdc-select-arrow{width:10px;height:5px;position:relative}.mat-mdc-select-arrow svg{fill:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.cdk-high-contrast-active .mat-mdc-select-arrow svg{fill:CanvasText}.mat-mdc-select-disabled .cdk-high-contrast-active .mat-mdc-select-arrow svg{fill:GrayText}.mdc-menu-surface.mat-mdc-select-panel{width:100%;max-height:275px;position:static;outline:0;margin:0;padding:8px 0;list-style-type:none}.mdc-menu-surface.mat-mdc-select-panel:focus{outline:none}.cdk-high-contrast-active .mdc-menu-surface.mat-mdc-select-panel{outline:solid 1px}.cdk-overlay-pane:not(.mat-mdc-select-panel-above) .mdc-menu-surface.mat-mdc-select-panel{border-top-left-radius:0;border-top-right-radius:0;transform-origin:top center}.mat-mdc-select-panel-above .mdc-menu-surface.mat-mdc-select-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;transform-origin:bottom center}.mat-mdc-select-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}._mat-animation-noopable .mat-mdc-select-placeholder{transition:none}.mat-form-field-hide-placeholder .mat-mdc-select-placeholder{color:rgba(0,0,0,0);-webkit-text-fill-color:rgba(0,0,0,0);transition:none;display:block}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-fill .mat-mdc-floating-label{max-width:calc(100% - 18px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-fill .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 24px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-outline .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-outline .mdc-text-field--label-floating .mdc-notched-outline__notch{max-width:calc(100% - 24px)}.mat-mdc-select-min-line:empty::before{content:\" \";white-space:pre;width:1px;display:inline-block;visibility:hidden}"], dependencies: [{ kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i7.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i7.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i8.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i8.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], animations: [matSelectAnimations.transformPanel], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
  1075. }
  1076. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelect, decorators: [{
  1077. type: Component,
  1078. args: [{ selector: 'mat-select', exportAs: 'matSelect', inputs: ['disabled', 'disableRipple', 'tabIndex'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
  1079. 'role': 'combobox',
  1080. 'aria-autocomplete': 'none',
  1081. 'aria-haspopup': 'listbox',
  1082. 'class': 'mat-mdc-select',
  1083. '[attr.id]': 'id',
  1084. '[attr.tabindex]': 'tabIndex',
  1085. '[attr.aria-controls]': 'panelOpen ? id + "-panel" : null',
  1086. '[attr.aria-expanded]': 'panelOpen',
  1087. '[attr.aria-label]': 'ariaLabel || null',
  1088. '[attr.aria-required]': 'required.toString()',
  1089. '[attr.aria-disabled]': 'disabled.toString()',
  1090. '[attr.aria-invalid]': 'errorState',
  1091. '[attr.aria-activedescendant]': '_getAriaActiveDescendant()',
  1092. 'ngSkipHydration': '',
  1093. '[class.mat-mdc-select-disabled]': 'disabled',
  1094. '[class.mat-mdc-select-invalid]': 'errorState',
  1095. '[class.mat-mdc-select-required]': 'required',
  1096. '[class.mat-mdc-select-empty]': 'empty',
  1097. '[class.mat-mdc-select-multiple]': 'multiple',
  1098. '(keydown)': '_handleKeydown($event)',
  1099. '(focus)': '_onFocus()',
  1100. '(blur)': '_onBlur()',
  1101. }, animations: [matSelectAnimations.transformPanel], providers: [
  1102. { provide: MatFormFieldControl, useExisting: MatSelect },
  1103. { provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect },
  1104. ], template: "<!--\n Note that the select trigger element specifies `aria-owns` pointing to the listbox overlay.\n While aria-owns is not required for the ARIA 1.2 `role=\"combobox\"` interaction pattern,\n it fixes an issue with VoiceOver when the select appears inside of an `aria-model=\"true\"`\n element (e.g. a dialog). Without this `aria-owns`, the `aria-modal` on a dialog prevents\n VoiceOver from \"seeing\" the select's listbox overlay for aria-activedescendant.\n Using `aria-owns` re-parents the select overlay so that it works again.\n See https://github.com/angular/components/issues/20694\n-->\n<div cdk-overlay-origin\n [attr.aria-owns]=\"panelOpen ? id + '-panel' : null\"\n class=\"mat-mdc-select-trigger\"\n (click)=\"toggle()\"\n #fallbackOverlayOrigin=\"cdkOverlayOrigin\"\n #trigger>\n <div class=\"mat-mdc-select-value\" [ngSwitch]=\"empty\" [attr.id]=\"_valueId\">\n <span class=\"mat-mdc-select-placeholder mat-mdc-select-min-line\" *ngSwitchCase=\"true\">{{placeholder}}</span>\n <span class=\"mat-mdc-select-value-text\" *ngSwitchCase=\"false\" [ngSwitch]=\"!!customTrigger\">\n <span class=\"mat-mdc-select-min-line\" *ngSwitchDefault>{{triggerValue}}</span>\n <ng-content select=\"mat-select-trigger\" *ngSwitchCase=\"true\"></ng-content>\n </span>\n </div>\n\n <div class=\"mat-mdc-select-arrow-wrapper\">\n <div class=\"mat-mdc-select-arrow\">\n <!-- Use an inline SVG, because it works better than a CSS triangle in high contrast mode. -->\n <svg viewBox=\"0 0 24 24\" width=\"24px\" height=\"24px\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M7 10l5 5 5-5z\"/>\n </svg>\n </div>\n </div>\n</div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayLockPosition\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPanelClass]=\"_overlayPanelClass\"\n [cdkConnectedOverlayScrollStrategy]=\"_scrollStrategy\"\n [cdkConnectedOverlayOrigin]=\"_preferredOverlayOrigin || fallbackOverlayOrigin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayPositions]=\"_positions\"\n [cdkConnectedOverlayWidth]=\"_overlayWidth\"\n (backdropClick)=\"close()\"\n (attach)=\"_onAttached()\"\n (detach)=\"close()\">\n <div\n #panel\n role=\"listbox\"\n tabindex=\"-1\"\n class=\"mat-mdc-select-panel mdc-menu-surface mdc-menu-surface--open {{ _getPanelTheme() }}\"\n [attr.id]=\"id + '-panel'\"\n [attr.aria-multiselectable]=\"multiple\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"_getPanelAriaLabelledby()\"\n [ngClass]=\"panelClass\"\n [@transformPanel]=\"'showing'\"\n (@transformPanel.done)=\"_panelDoneAnimatingStream.next($event.toState)\"\n (keydown)=\"_handleKeydown($event)\">\n <ng-content></ng-content>\n </div>\n</ng-template>\n", styles: [".mdc-menu-surface{display:none;position:absolute;box-sizing:border-box;margin:0;padding:0;transform:scale(1);transform-origin:top left;opacity:0;overflow:auto;will-change:transform,opacity;transform-origin-left:top left;transform-origin-right:top right}.mdc-menu-surface:focus{outline:none}.mdc-menu-surface--animating-open{display:inline-block;transform:scale(0.8);opacity:0}.mdc-menu-surface--open{display:inline-block;transform:scale(1);opacity:1}.mdc-menu-surface--animating-closed{display:inline-block;opacity:0}[dir=rtl] .mdc-menu-surface,.mdc-menu-surface[dir=rtl]{transform-origin-left:top right;transform-origin-right:top left}.mdc-menu-surface--anchor{position:relative;overflow:visible}.mdc-menu-surface--fixed{position:fixed}.mdc-menu-surface--fullwidth{width:100%}.mdc-menu-surface{max-width:calc(100vw - 32px);max-width:var(--mdc-menu-max-width, calc(100vw - 32px));max-height:calc(100vh - 32px);max-height:var(--mdc-menu-max-height, calc(100vh - 32px));z-index:8;border-radius:4px;border-radius:var(--mdc-shape-medium, 4px)}.mat-mdc-select{display:inline-block;width:100%;outline:none}.mat-mdc-select-trigger{display:inline-flex;align-items:center;cursor:pointer;position:relative;box-sizing:border-box;width:100%}.mat-mdc-select-disabled .mat-mdc-select-trigger{-webkit-user-select:none;user-select:none;cursor:default}.mat-mdc-select-value{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mat-mdc-select-value-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mat-mdc-select-arrow-wrapper{height:24px;flex-shrink:0;display:inline-flex;align-items:center}.mat-form-field-appearance-fill .mat-mdc-select-arrow-wrapper{transform:translateY(-8px)}.mat-form-field-appearance-fill .mdc-text-field--no-label .mat-mdc-select-arrow-wrapper{transform:none}.mat-mdc-select-arrow{width:10px;height:5px;position:relative}.mat-mdc-select-arrow svg{fill:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.cdk-high-contrast-active .mat-mdc-select-arrow svg{fill:CanvasText}.mat-mdc-select-disabled .cdk-high-contrast-active .mat-mdc-select-arrow svg{fill:GrayText}.mdc-menu-surface.mat-mdc-select-panel{width:100%;max-height:275px;position:static;outline:0;margin:0;padding:8px 0;list-style-type:none}.mdc-menu-surface.mat-mdc-select-panel:focus{outline:none}.cdk-high-contrast-active .mdc-menu-surface.mat-mdc-select-panel{outline:solid 1px}.cdk-overlay-pane:not(.mat-mdc-select-panel-above) .mdc-menu-surface.mat-mdc-select-panel{border-top-left-radius:0;border-top-right-radius:0;transform-origin:top center}.mat-mdc-select-panel-above .mdc-menu-surface.mat-mdc-select-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;transform-origin:bottom center}.mat-mdc-select-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}._mat-animation-noopable .mat-mdc-select-placeholder{transition:none}.mat-form-field-hide-placeholder .mat-mdc-select-placeholder{color:rgba(0,0,0,0);-webkit-text-fill-color:rgba(0,0,0,0);transition:none;display:block}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-fill .mat-mdc-floating-label{max-width:calc(100% - 18px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-fill .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 24px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-outline .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mat-mdc-form-field-type-mat-select.mat-form-field-appearance-outline .mdc-text-field--label-floating .mdc-notched-outline__notch{max-width:calc(100% - 24px)}.mat-mdc-select-min-line:empty::before{content:\" \";white-space:pre;width:1px;display:inline-block;visibility:hidden}"] }]
  1105. }], propDecorators: { options: [{
  1106. type: ContentChildren,
  1107. args: [MatOption, { descendants: true }]
  1108. }], optionGroups: [{
  1109. type: ContentChildren,
  1110. args: [MAT_OPTGROUP, { descendants: true }]
  1111. }], customTrigger: [{
  1112. type: ContentChild,
  1113. args: [MAT_SELECT_TRIGGER]
  1114. }], hideSingleSelectionIndicator: [{
  1115. type: Input
  1116. }] } });
  1117. class MatSelectModule {
  1118. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  1119. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: MatSelectModule, declarations: [MatSelect, MatSelectTrigger], imports: [CommonModule, OverlayModule, MatOptionModule, MatCommonModule], exports: [CdkScrollableModule,
  1120. MatFormFieldModule,
  1121. MatSelect,
  1122. MatSelectTrigger,
  1123. MatOptionModule,
  1124. MatCommonModule] }); }
  1125. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelectModule, providers: [MAT_SELECT_SCROLL_STRATEGY_PROVIDER], imports: [CommonModule, OverlayModule, MatOptionModule, MatCommonModule, CdkScrollableModule,
  1126. MatFormFieldModule,
  1127. MatOptionModule,
  1128. MatCommonModule] }); }
  1129. }
  1130. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MatSelectModule, decorators: [{
  1131. type: NgModule,
  1132. args: [{
  1133. imports: [CommonModule, OverlayModule, MatOptionModule, MatCommonModule],
  1134. exports: [
  1135. CdkScrollableModule,
  1136. MatFormFieldModule,
  1137. MatSelect,
  1138. MatSelectTrigger,
  1139. MatOptionModule,
  1140. MatCommonModule,
  1141. ],
  1142. declarations: [MatSelect, MatSelectTrigger],
  1143. providers: [MAT_SELECT_SCROLL_STRATEGY_PROVIDER],
  1144. }]
  1145. }] });
  1146. /**
  1147. * Generated bundle index. Do not edit.
  1148. */
  1149. 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, _MatSelectBase, matSelectAnimations };
  1150. //# sourceMappingURL=select.mjs.map