option-ChV6uQgD.mjs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. import { _IdGenerator } from '@angular/cdk/a11y';
  2. import { ENTER, SPACE, hasModifierKey } from '@angular/cdk/keycodes';
  3. import * as i0 from '@angular/core';
  4. import { InjectionToken, inject, booleanAttribute, Component, ViewEncapsulation, ChangeDetectionStrategy, Input, ElementRef, ChangeDetectorRef, EventEmitter, isSignal, Output, ViewChild } from '@angular/core';
  5. import { Subject } from 'rxjs';
  6. import { M as MatRipple } from './ripple-BT3tzh6F.mjs';
  7. import { M as MatPseudoCheckbox } from './pseudo-checkbox-CJ7seqQH.mjs';
  8. import { _ as _StructuralStylesLoader } from './structural-styles-BQUT6wsL.mjs';
  9. import { _CdkPrivateStyleLoader, _VisuallyHiddenLoader } from '@angular/cdk/private';
  10. /**
  11. * Injection token used to provide the parent component to options.
  12. */
  13. const MAT_OPTION_PARENT_COMPONENT = new InjectionToken('MAT_OPTION_PARENT_COMPONENT');
  14. // Notes on the accessibility pattern used for `mat-optgroup`.
  15. // The option group has two different "modes": regular and inert. The regular mode uses the
  16. // recommended a11y pattern which has `role="group"` on the group element with `aria-labelledby`
  17. // pointing to the label. This works for `mat-select`, but it seems to hit a bug for autocomplete
  18. // under VoiceOver where the group doesn't get read out at all. The bug appears to be that if
  19. // there's __any__ a11y-related attribute on the group (e.g. `role` or `aria-labelledby`),
  20. // VoiceOver on Safari won't read it out.
  21. // We've introduced the `inert` mode as a workaround. Under this mode, all a11y attributes are
  22. // removed from the group, and we get the screen reader to read out the group label by mirroring it
  23. // inside an invisible element in the option. This is sub-optimal, because the screen reader will
  24. // repeat the group label on each navigation, whereas the default pattern only reads the group when
  25. // the user enters a new group. The following alternate approaches were considered:
  26. // 1. Reading out the group label using the `LiveAnnouncer` solves the problem, but we can't control
  27. // when the text will be read out so sometimes it comes in too late or never if the user
  28. // navigates quickly.
  29. // 2. `<mat-option aria-describedby="groupLabel"` - This works on Safari, but VoiceOver in Chrome
  30. // won't read out the description at all.
  31. // 3. `<mat-option aria-labelledby="optionLabel groupLabel"` - This works on Chrome, but Safari
  32. // doesn't read out the text at all. Furthermore, on
  33. /**
  34. * Injection token that can be used to reference instances of `MatOptgroup`. It serves as
  35. * alternative token to the actual `MatOptgroup` class which could cause unnecessary
  36. * retention of the class and its component metadata.
  37. */
  38. const MAT_OPTGROUP = new InjectionToken('MatOptgroup');
  39. /**
  40. * Component that is used to group instances of `mat-option`.
  41. */
  42. class MatOptgroup {
  43. /** Label for the option group. */
  44. label;
  45. /** whether the option group is disabled. */
  46. disabled = false;
  47. /** Unique id for the underlying label. */
  48. _labelId = inject(_IdGenerator).getId('mat-optgroup-label-');
  49. /** Whether the group is in inert a11y mode. */
  50. _inert;
  51. constructor() {
  52. const parent = inject(MAT_OPTION_PARENT_COMPONENT, { optional: true });
  53. this._inert = parent?.inertGroups ?? false;
  54. }
  55. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatOptgroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
  56. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "19.2.6", type: MatOptgroup, isStandalone: true, selector: "mat-optgroup", inputs: { label: "label", disabled: ["disabled", "disabled", booleanAttribute] }, host: { properties: { "attr.role": "_inert ? null : \"group\"", "attr.aria-disabled": "_inert ? null : disabled.toString()", "attr.aria-labelledby": "_inert ? null : _labelId" }, classAttribute: "mat-mdc-optgroup" }, providers: [{ provide: MAT_OPTGROUP, useExisting: MatOptgroup }], exportAs: ["matOptgroup"], ngImport: i0, template: "<span\n class=\"mat-mdc-optgroup-label\"\n role=\"presentation\"\n [class.mdc-list-item--disabled]=\"disabled\"\n [id]=\"_labelId\">\n <span class=\"mdc-list-item__primary-text\">{{ label }} <ng-content></ng-content></span>\n</span>\n\n<ng-content select=\"mat-option, ng-container\"></ng-content>\n", styles: [".mat-mdc-optgroup{color:var(--mat-optgroup-label-text-color, var(--mat-sys-on-surface-variant));font-family:var(--mat-optgroup-label-text-font, var(--mat-sys-title-small-font));line-height:var(--mat-optgroup-label-text-line-height, var(--mat-sys-title-small-line-height));font-size:var(--mat-optgroup-label-text-size, var(--mat-sys-title-small-size));letter-spacing:var(--mat-optgroup-label-text-tracking, var(--mat-sys-title-small-tracking));font-weight:var(--mat-optgroup-label-text-weight, var(--mat-sys-title-small-weight))}.mat-mdc-optgroup-label{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;min-height:48px;padding:0 16px;outline:none}.mat-mdc-optgroup-label.mdc-list-item--disabled{opacity:.38}.mat-mdc-optgroup-label .mdc-list-item__primary-text{font-size:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;font-family:inherit;text-decoration:inherit;text-transform:inherit;white-space:normal;color:inherit}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  57. }
  58. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatOptgroup, decorators: [{
  59. type: Component,
  60. args: [{ selector: 'mat-optgroup', exportAs: 'matOptgroup', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
  61. 'class': 'mat-mdc-optgroup',
  62. '[attr.role]': '_inert ? null : "group"',
  63. '[attr.aria-disabled]': '_inert ? null : disabled.toString()',
  64. '[attr.aria-labelledby]': '_inert ? null : _labelId',
  65. }, providers: [{ provide: MAT_OPTGROUP, useExisting: MatOptgroup }], template: "<span\n class=\"mat-mdc-optgroup-label\"\n role=\"presentation\"\n [class.mdc-list-item--disabled]=\"disabled\"\n [id]=\"_labelId\">\n <span class=\"mdc-list-item__primary-text\">{{ label }} <ng-content></ng-content></span>\n</span>\n\n<ng-content select=\"mat-option, ng-container\"></ng-content>\n", styles: [".mat-mdc-optgroup{color:var(--mat-optgroup-label-text-color, var(--mat-sys-on-surface-variant));font-family:var(--mat-optgroup-label-text-font, var(--mat-sys-title-small-font));line-height:var(--mat-optgroup-label-text-line-height, var(--mat-sys-title-small-line-height));font-size:var(--mat-optgroup-label-text-size, var(--mat-sys-title-small-size));letter-spacing:var(--mat-optgroup-label-text-tracking, var(--mat-sys-title-small-tracking));font-weight:var(--mat-optgroup-label-text-weight, var(--mat-sys-title-small-weight))}.mat-mdc-optgroup-label{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;min-height:48px;padding:0 16px;outline:none}.mat-mdc-optgroup-label.mdc-list-item--disabled{opacity:.38}.mat-mdc-optgroup-label .mdc-list-item__primary-text{font-size:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;font-family:inherit;text-decoration:inherit;text-transform:inherit;white-space:normal;color:inherit}\n"] }]
  66. }], ctorParameters: () => [], propDecorators: { label: [{
  67. type: Input
  68. }], disabled: [{
  69. type: Input,
  70. args: [{ transform: booleanAttribute }]
  71. }] } });
  72. /** Event object emitted by MatOption when selected or deselected. */
  73. class MatOptionSelectionChange {
  74. source;
  75. isUserInput;
  76. constructor(
  77. /** Reference to the option that emitted the event. */
  78. source,
  79. /** Whether the change in the option's value was a result of a user action. */
  80. isUserInput = false) {
  81. this.source = source;
  82. this.isUserInput = isUserInput;
  83. }
  84. }
  85. /**
  86. * Single option inside of a `<mat-select>` element.
  87. */
  88. class MatOption {
  89. _element = inject(ElementRef);
  90. _changeDetectorRef = inject(ChangeDetectorRef);
  91. _parent = inject(MAT_OPTION_PARENT_COMPONENT, { optional: true });
  92. group = inject(MAT_OPTGROUP, { optional: true });
  93. _signalDisableRipple = false;
  94. _selected = false;
  95. _active = false;
  96. _disabled = false;
  97. _mostRecentViewValue = '';
  98. /** Whether the wrapping component is in multiple selection mode. */
  99. get multiple() {
  100. return this._parent && this._parent.multiple;
  101. }
  102. /** Whether or not the option is currently selected. */
  103. get selected() {
  104. return this._selected;
  105. }
  106. /** The form value of the option. */
  107. value;
  108. /** The unique ID of the option. */
  109. id = inject(_IdGenerator).getId('mat-option-');
  110. /** Whether the option is disabled. */
  111. get disabled() {
  112. return (this.group && this.group.disabled) || this._disabled;
  113. }
  114. set disabled(value) {
  115. this._disabled = value;
  116. }
  117. /** Whether ripples for the option are disabled. */
  118. get disableRipple() {
  119. return this._signalDisableRipple
  120. ? this._parent.disableRipple()
  121. : !!this._parent?.disableRipple;
  122. }
  123. /** Whether to display checkmark for single-selection. */
  124. get hideSingleSelectionIndicator() {
  125. return !!(this._parent && this._parent.hideSingleSelectionIndicator);
  126. }
  127. /** Event emitted when the option is selected or deselected. */
  128. // tslint:disable-next-line:no-output-on-prefix
  129. onSelectionChange = new EventEmitter();
  130. /** Element containing the option's text. */
  131. _text;
  132. /** Emits when the state of the option changes and any parents have to be notified. */
  133. _stateChanges = new Subject();
  134. constructor() {
  135. const styleLoader = inject(_CdkPrivateStyleLoader);
  136. styleLoader.load(_StructuralStylesLoader);
  137. styleLoader.load(_VisuallyHiddenLoader);
  138. this._signalDisableRipple = !!this._parent && isSignal(this._parent.disableRipple);
  139. }
  140. /**
  141. * Whether or not the option is currently active and ready to be selected.
  142. * An active option displays styles as if it is focused, but the
  143. * focus is actually retained somewhere else. This comes in handy
  144. * for components like autocomplete where focus must remain on the input.
  145. */
  146. get active() {
  147. return this._active;
  148. }
  149. /**
  150. * The displayed value of the option. It is necessary to show the selected option in the
  151. * select's trigger.
  152. */
  153. get viewValue() {
  154. // TODO(kara): Add input property alternative for node envs.
  155. return (this._text?.nativeElement.textContent || '').trim();
  156. }
  157. /** Selects the option. */
  158. select(emitEvent = true) {
  159. if (!this._selected) {
  160. this._selected = true;
  161. this._changeDetectorRef.markForCheck();
  162. if (emitEvent) {
  163. this._emitSelectionChangeEvent();
  164. }
  165. }
  166. }
  167. /** Deselects the option. */
  168. deselect(emitEvent = true) {
  169. if (this._selected) {
  170. this._selected = false;
  171. this._changeDetectorRef.markForCheck();
  172. if (emitEvent) {
  173. this._emitSelectionChangeEvent();
  174. }
  175. }
  176. }
  177. /** Sets focus onto this option. */
  178. focus(_origin, options) {
  179. // Note that we aren't using `_origin`, but we need to keep it because some internal consumers
  180. // use `MatOption` in a `FocusKeyManager` and we need it to match `FocusableOption`.
  181. const element = this._getHostElement();
  182. if (typeof element.focus === 'function') {
  183. element.focus(options);
  184. }
  185. }
  186. /**
  187. * This method sets display styles on the option to make it appear
  188. * active. This is used by the ActiveDescendantKeyManager so key
  189. * events will display the proper options as active on arrow key events.
  190. */
  191. setActiveStyles() {
  192. if (!this._active) {
  193. this._active = true;
  194. this._changeDetectorRef.markForCheck();
  195. }
  196. }
  197. /**
  198. * This method removes display styles on the option that made it appear
  199. * active. This is used by the ActiveDescendantKeyManager so key
  200. * events will display the proper options as active on arrow key events.
  201. */
  202. setInactiveStyles() {
  203. if (this._active) {
  204. this._active = false;
  205. this._changeDetectorRef.markForCheck();
  206. }
  207. }
  208. /** Gets the label to be used when determining whether the option should be focused. */
  209. getLabel() {
  210. return this.viewValue;
  211. }
  212. /** Ensures the option is selected when activated from the keyboard. */
  213. _handleKeydown(event) {
  214. if ((event.keyCode === ENTER || event.keyCode === SPACE) && !hasModifierKey(event)) {
  215. this._selectViaInteraction();
  216. // Prevent the page from scrolling down and form submits.
  217. event.preventDefault();
  218. }
  219. }
  220. /**
  221. * `Selects the option while indicating the selection came from the user. Used to
  222. * determine if the select's view -> model callback should be invoked.`
  223. */
  224. _selectViaInteraction() {
  225. if (!this.disabled) {
  226. this._selected = this.multiple ? !this._selected : true;
  227. this._changeDetectorRef.markForCheck();
  228. this._emitSelectionChangeEvent(true);
  229. }
  230. }
  231. /** Returns the correct tabindex for the option depending on disabled state. */
  232. // This method is only used by `MatLegacyOption`. Keeping it here to avoid breaking the types.
  233. // That's because `MatLegacyOption` use `MatOption` type in a few places such as
  234. // `MatOptionSelectionChange`. It is safe to delete this when `MatLegacyOption` is deleted.
  235. _getTabIndex() {
  236. return this.disabled ? '-1' : '0';
  237. }
  238. /** Gets the host DOM element. */
  239. _getHostElement() {
  240. return this._element.nativeElement;
  241. }
  242. ngAfterViewChecked() {
  243. // Since parent components could be using the option's label to display the selected values
  244. // (e.g. `mat-select`) and they don't have a way of knowing if the option's label has changed
  245. // we have to check for changes in the DOM ourselves and dispatch an event. These checks are
  246. // relatively cheap, however we still limit them only to selected options in order to avoid
  247. // hitting the DOM too often.
  248. if (this._selected) {
  249. const viewValue = this.viewValue;
  250. if (viewValue !== this._mostRecentViewValue) {
  251. if (this._mostRecentViewValue) {
  252. this._stateChanges.next();
  253. }
  254. this._mostRecentViewValue = viewValue;
  255. }
  256. }
  257. }
  258. ngOnDestroy() {
  259. this._stateChanges.complete();
  260. }
  261. /** Emits the selection change event. */
  262. _emitSelectionChangeEvent(isUserInput = false) {
  263. this.onSelectionChange.emit(new MatOptionSelectionChange(this, isUserInput));
  264. }
  265. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatOption, deps: [], target: i0.ɵɵFactoryTarget.Component });
  266. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: MatOption, isStandalone: true, selector: "mat-option", inputs: { value: "value", id: "id", disabled: ["disabled", "disabled", booleanAttribute] }, outputs: { onSelectionChange: "onSelectionChange" }, host: { attributes: { "role": "option" }, listeners: { "click": "_selectViaInteraction()", "keydown": "_handleKeydown($event)" }, properties: { "class.mdc-list-item--selected": "selected", "class.mat-mdc-option-multiple": "multiple", "class.mat-mdc-option-active": "active", "class.mdc-list-item--disabled": "disabled", "id": "id", "attr.aria-selected": "selected", "attr.aria-disabled": "disabled.toString()" }, classAttribute: "mat-mdc-option mdc-list-item" }, viewQueries: [{ propertyName: "_text", first: true, predicate: ["text"], descendants: true, static: true }], exportAs: ["matOption"], ngImport: i0, template: "<!-- Set aria-hidden=\"true\" to this DOM node and other decorative nodes in this file. This might\n be contributing to issue where sometimes VoiceOver focuses on a TextNode in the a11y tree instead\n of the Option node (#23202). Most assistive technology will generally ignore non-role,\n non-text-content elements. Adding aria-hidden seems to make VoiceOver behave more consistently. -->\n@if (multiple) {\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox\"\n [disabled]=\"disabled\"\n [state]=\"selected ? 'checked' : 'unchecked'\"\n aria-hidden=\"true\"></mat-pseudo-checkbox>\n}\n\n<ng-content select=\"mat-icon\"></ng-content>\n\n<span class=\"mdc-list-item__primary-text\" #text><ng-content></ng-content></span>\n\n<!-- Render checkmark at the end for single-selection. -->\n@if (!multiple && selected && !hideSingleSelectionIndicator) {\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox\"\n [disabled]=\"disabled\"\n state=\"checked\"\n aria-hidden=\"true\"\n appearance=\"minimal\"></mat-pseudo-checkbox>\n}\n\n<!-- See a11y notes inside optgroup.ts for context behind this element. -->\n@if (group && group._inert) {\n <span class=\"cdk-visually-hidden\">({{ group.label }})</span>\n}\n\n<div class=\"mat-mdc-option-ripple mat-focus-indicator\" aria-hidden=\"true\" mat-ripple\n [matRippleTrigger]=\"_getHostElement()\" [matRippleDisabled]=\"disabled || disableRipple\">\n</div>\n", styles: [".mat-mdc-option{-webkit-user-select:none;user-select:none;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;min-height:48px;padding:0 16px;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--mat-option-label-text-color, var(--mat-sys-on-surface));font-family:var(--mat-option-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-option-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-option-label-text-size, var(--mat-sys-body-large-size));letter-spacing:var(--mat-option-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-option-label-text-weight, var(--mat-sys-body-large-weight))}.mat-mdc-option:hover:not(.mdc-list-item--disabled){background-color:var(--mat-option-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-option:focus.mdc-list-item,.mat-mdc-option.mat-mdc-option-active.mdc-list-item{background-color:var(--mat-option-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent));outline:0}.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled):not(.mat-mdc-option-multiple){background-color:var(--mat-option-selected-state-layer-color, var(--mat-sys-secondary-container))}.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled):not(.mat-mdc-option-multiple) .mdc-list-item__primary-text{color:var(--mat-option-selected-state-label-text-color, var(--mat-sys-on-secondary-container))}.mat-mdc-option .mat-pseudo-checkbox{--mat-minimal-pseudo-checkbox-selected-checkmark-color: var(--mat-option-selected-state-label-text-color, var(--mat-sys-on-secondary-container))}.mat-mdc-option.mdc-list-item{align-items:center;background:rgba(0,0,0,0)}.mat-mdc-option.mdc-list-item--disabled{cursor:default;pointer-events:none}.mat-mdc-option.mdc-list-item--disabled .mat-mdc-option-pseudo-checkbox,.mat-mdc-option.mdc-list-item--disabled .mdc-list-item__primary-text,.mat-mdc-option.mdc-list-item--disabled>mat-icon{opacity:.38}.mat-mdc-optgroup .mat-mdc-option:not(.mat-mdc-option-multiple){padding-left:32px}[dir=rtl] .mat-mdc-optgroup .mat-mdc-option:not(.mat-mdc-option-multiple){padding-left:16px;padding-right:32px}.mat-mdc-option .mat-icon,.mat-mdc-option .mat-pseudo-checkbox-full{margin-right:16px;flex-shrink:0}[dir=rtl] .mat-mdc-option .mat-icon,[dir=rtl] .mat-mdc-option .mat-pseudo-checkbox-full{margin-right:0;margin-left:16px}.mat-mdc-option .mat-pseudo-checkbox-minimal{margin-left:16px;flex-shrink:0}[dir=rtl] .mat-mdc-option .mat-pseudo-checkbox-minimal{margin-right:16px;margin-left:0}.mat-mdc-option .mat-mdc-option-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}.mat-mdc-option .mdc-list-item__primary-text{white-space:normal;font-size:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;font-family:inherit;text-decoration:inherit;text-transform:inherit;margin-right:auto}[dir=rtl] .mat-mdc-option .mdc-list-item__primary-text{margin-right:0;margin-left:auto}@media(forced-colors: active){.mat-mdc-option.mdc-list-item--selected:not(:has(.mat-mdc-option-pseudo-checkbox))::after{content:\"\";position:absolute;top:50%;right:16px;transform:translateY(-50%);width:10px;height:0;border-bottom:solid 10px;border-radius:10px}[dir=rtl] .mat-mdc-option.mdc-list-item--selected:not(:has(.mat-mdc-option-pseudo-checkbox))::after{right:auto;left:16px}}.mat-mdc-option-multiple{--mdc-list-list-item-selected-container-color:var(--mdc-list-list-item-container-color, transparent)}.mat-mdc-option-active .mat-focus-indicator::before{content:\"\"}\n"], dependencies: [{ kind: "component", type: MatPseudoCheckbox, selector: "mat-pseudo-checkbox", inputs: ["state", "disabled", "appearance"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  267. }
  268. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatOption, decorators: [{
  269. type: Component,
  270. args: [{ selector: 'mat-option', exportAs: 'matOption', host: {
  271. 'role': 'option',
  272. '[class.mdc-list-item--selected]': 'selected',
  273. '[class.mat-mdc-option-multiple]': 'multiple',
  274. '[class.mat-mdc-option-active]': 'active',
  275. '[class.mdc-list-item--disabled]': 'disabled',
  276. '[id]': 'id',
  277. // Set aria-selected to false for non-selected items and true for selected items. Conform to
  278. // [WAI ARIA Listbox authoring practices guide](
  279. // https://www.w3.org/WAI/ARIA/apg/patterns/listbox/), "If any options are selected, each
  280. // selected option has either aria-selected or aria-checked set to true. All options that are
  281. // selectable but not selected have either aria-selected or aria-checked set to false." Align
  282. // aria-selected implementation of Chips and List components.
  283. //
  284. // Set `aria-selected="false"` on not-selected listbox options to fix VoiceOver announcing
  285. // every option as "selected" (#21491).
  286. '[attr.aria-selected]': 'selected',
  287. '[attr.aria-disabled]': 'disabled.toString()',
  288. '(click)': '_selectViaInteraction()',
  289. '(keydown)': '_handleKeydown($event)',
  290. 'class': 'mat-mdc-option mdc-list-item',
  291. }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatPseudoCheckbox, MatRipple], template: "<!-- Set aria-hidden=\"true\" to this DOM node and other decorative nodes in this file. This might\n be contributing to issue where sometimes VoiceOver focuses on a TextNode in the a11y tree instead\n of the Option node (#23202). Most assistive technology will generally ignore non-role,\n non-text-content elements. Adding aria-hidden seems to make VoiceOver behave more consistently. -->\n@if (multiple) {\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox\"\n [disabled]=\"disabled\"\n [state]=\"selected ? 'checked' : 'unchecked'\"\n aria-hidden=\"true\"></mat-pseudo-checkbox>\n}\n\n<ng-content select=\"mat-icon\"></ng-content>\n\n<span class=\"mdc-list-item__primary-text\" #text><ng-content></ng-content></span>\n\n<!-- Render checkmark at the end for single-selection. -->\n@if (!multiple && selected && !hideSingleSelectionIndicator) {\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox\"\n [disabled]=\"disabled\"\n state=\"checked\"\n aria-hidden=\"true\"\n appearance=\"minimal\"></mat-pseudo-checkbox>\n}\n\n<!-- See a11y notes inside optgroup.ts for context behind this element. -->\n@if (group && group._inert) {\n <span class=\"cdk-visually-hidden\">({{ group.label }})</span>\n}\n\n<div class=\"mat-mdc-option-ripple mat-focus-indicator\" aria-hidden=\"true\" mat-ripple\n [matRippleTrigger]=\"_getHostElement()\" [matRippleDisabled]=\"disabled || disableRipple\">\n</div>\n", styles: [".mat-mdc-option{-webkit-user-select:none;user-select:none;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;min-height:48px;padding:0 16px;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--mat-option-label-text-color, var(--mat-sys-on-surface));font-family:var(--mat-option-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-option-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-option-label-text-size, var(--mat-sys-body-large-size));letter-spacing:var(--mat-option-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-option-label-text-weight, var(--mat-sys-body-large-weight))}.mat-mdc-option:hover:not(.mdc-list-item--disabled){background-color:var(--mat-option-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-option:focus.mdc-list-item,.mat-mdc-option.mat-mdc-option-active.mdc-list-item{background-color:var(--mat-option-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent));outline:0}.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled):not(.mat-mdc-option-multiple){background-color:var(--mat-option-selected-state-layer-color, var(--mat-sys-secondary-container))}.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled):not(.mat-mdc-option-multiple) .mdc-list-item__primary-text{color:var(--mat-option-selected-state-label-text-color, var(--mat-sys-on-secondary-container))}.mat-mdc-option .mat-pseudo-checkbox{--mat-minimal-pseudo-checkbox-selected-checkmark-color: var(--mat-option-selected-state-label-text-color, var(--mat-sys-on-secondary-container))}.mat-mdc-option.mdc-list-item{align-items:center;background:rgba(0,0,0,0)}.mat-mdc-option.mdc-list-item--disabled{cursor:default;pointer-events:none}.mat-mdc-option.mdc-list-item--disabled .mat-mdc-option-pseudo-checkbox,.mat-mdc-option.mdc-list-item--disabled .mdc-list-item__primary-text,.mat-mdc-option.mdc-list-item--disabled>mat-icon{opacity:.38}.mat-mdc-optgroup .mat-mdc-option:not(.mat-mdc-option-multiple){padding-left:32px}[dir=rtl] .mat-mdc-optgroup .mat-mdc-option:not(.mat-mdc-option-multiple){padding-left:16px;padding-right:32px}.mat-mdc-option .mat-icon,.mat-mdc-option .mat-pseudo-checkbox-full{margin-right:16px;flex-shrink:0}[dir=rtl] .mat-mdc-option .mat-icon,[dir=rtl] .mat-mdc-option .mat-pseudo-checkbox-full{margin-right:0;margin-left:16px}.mat-mdc-option .mat-pseudo-checkbox-minimal{margin-left:16px;flex-shrink:0}[dir=rtl] .mat-mdc-option .mat-pseudo-checkbox-minimal{margin-right:16px;margin-left:0}.mat-mdc-option .mat-mdc-option-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}.mat-mdc-option .mdc-list-item__primary-text{white-space:normal;font-size:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;font-family:inherit;text-decoration:inherit;text-transform:inherit;margin-right:auto}[dir=rtl] .mat-mdc-option .mdc-list-item__primary-text{margin-right:0;margin-left:auto}@media(forced-colors: active){.mat-mdc-option.mdc-list-item--selected:not(:has(.mat-mdc-option-pseudo-checkbox))::after{content:\"\";position:absolute;top:50%;right:16px;transform:translateY(-50%);width:10px;height:0;border-bottom:solid 10px;border-radius:10px}[dir=rtl] .mat-mdc-option.mdc-list-item--selected:not(:has(.mat-mdc-option-pseudo-checkbox))::after{right:auto;left:16px}}.mat-mdc-option-multiple{--mdc-list-list-item-selected-container-color:var(--mdc-list-list-item-container-color, transparent)}.mat-mdc-option-active .mat-focus-indicator::before{content:\"\"}\n"] }]
  292. }], ctorParameters: () => [], propDecorators: { value: [{
  293. type: Input
  294. }], id: [{
  295. type: Input
  296. }], disabled: [{
  297. type: Input,
  298. args: [{ transform: booleanAttribute }]
  299. }], onSelectionChange: [{
  300. type: Output
  301. }], _text: [{
  302. type: ViewChild,
  303. args: ['text', { static: true }]
  304. }] } });
  305. /**
  306. * Counts the amount of option group labels that precede the specified option.
  307. * @param optionIndex Index of the option at which to start counting.
  308. * @param options Flat list of all of the options.
  309. * @param optionGroups Flat list of all of the option groups.
  310. * @docs-private
  311. */
  312. function _countGroupLabelsBeforeOption(optionIndex, options, optionGroups) {
  313. if (optionGroups.length) {
  314. let optionsArray = options.toArray();
  315. let groups = optionGroups.toArray();
  316. let groupCounter = 0;
  317. for (let i = 0; i < optionIndex + 1; i++) {
  318. if (optionsArray[i].group && optionsArray[i].group === groups[groupCounter]) {
  319. groupCounter++;
  320. }
  321. }
  322. return groupCounter;
  323. }
  324. return 0;
  325. }
  326. /**
  327. * Determines the position to which to scroll a panel in order for an option to be into view.
  328. * @param optionOffset Offset of the option from the top of the panel.
  329. * @param optionHeight Height of the options.
  330. * @param currentScrollPosition Current scroll position of the panel.
  331. * @param panelHeight Height of the panel.
  332. * @docs-private
  333. */
  334. function _getOptionScrollPosition(optionOffset, optionHeight, currentScrollPosition, panelHeight) {
  335. if (optionOffset < currentScrollPosition) {
  336. return optionOffset;
  337. }
  338. if (optionOffset + optionHeight > currentScrollPosition + panelHeight) {
  339. return Math.max(0, optionOffset - panelHeight + optionHeight);
  340. }
  341. return currentScrollPosition;
  342. }
  343. export { MatOption as M, _countGroupLabelsBeforeOption as _, MatOptgroup as a, _getOptionScrollPosition as b, MAT_OPTION_PARENT_COMPONENT as c, MAT_OPTGROUP as d, MatOptionSelectionChange as e };
  344. //# sourceMappingURL=option-ChV6uQgD.mjs.map