|
| 1 | +/** |
| 2 | + * @license |
| 3 | + * Copyright Google LLC All Rights Reserved. |
| 4 | + * |
| 5 | + * Use of this source code is governed by an MIT-style license that can be |
| 6 | + * found in the LICENSE file at https://angular.dev/license |
| 7 | + */ |
| 8 | + |
| 9 | +import {afterRenderEffect, Directive, ElementRef, inject} from '@angular/core'; |
| 10 | +import {ComboboxDialogPattern} from '../private'; |
| 11 | +import {Combobox} from './combobox'; |
| 12 | +import {ComboboxPopup} from './combobox-popup'; |
| 13 | + |
| 14 | +/** |
| 15 | + * Integrates a native `<dialog>` element with the combobox, allowing for |
| 16 | + * a modal or non-modal popup experience. It handles the opening and closing of the dialog |
| 17 | + * based on the combobox's expanded state. |
| 18 | + * |
| 19 | + * ```html |
| 20 | + * <ng-template ngComboboxPopupContainer> |
| 21 | + * <dialog ngComboboxDialog class="example-dialog"> |
| 22 | + * <!-- ... dialog content ... --> |
| 23 | + * </dialog> |
| 24 | + * </ng-template> |
| 25 | + * ``` |
| 26 | + * |
| 27 | + * @developerPreview 21.0 |
| 28 | + */ |
| 29 | +@Directive({ |
| 30 | + selector: 'dialog[ngComboboxDialog]', |
| 31 | + exportAs: 'ngComboboxDialog', |
| 32 | + host: { |
| 33 | + '[attr.data-open]': 'combobox._pattern.expanded()', |
| 34 | + '(keydown)': '_pattern.onKeydown($event)', |
| 35 | + '(click)': '_pattern.onClick($event)', |
| 36 | + }, |
| 37 | + hostDirectives: [ComboboxPopup], |
| 38 | +}) |
| 39 | +export class ComboboxDialog { |
| 40 | + /** The dialog element. */ |
| 41 | + private readonly _elementRef = inject(ElementRef<HTMLDialogElement>); |
| 42 | + |
| 43 | + /** A reference to the dialog element. */ |
| 44 | + readonly element = this._elementRef.nativeElement as HTMLElement; |
| 45 | + |
| 46 | + /** The combobox that the dialog belongs to. */ |
| 47 | + readonly combobox = inject(Combobox); |
| 48 | + |
| 49 | + /** A reference to the parent combobox popup, if one exists. */ |
| 50 | + private readonly _popup = inject<ComboboxPopup<unknown>>(ComboboxPopup, { |
| 51 | + optional: true, |
| 52 | + }); |
| 53 | + |
| 54 | + _pattern: ComboboxDialogPattern; |
| 55 | + |
| 56 | + constructor() { |
| 57 | + this._pattern = new ComboboxDialogPattern({ |
| 58 | + id: () => '', |
| 59 | + element: () => this._elementRef.nativeElement, |
| 60 | + combobox: this.combobox._pattern, |
| 61 | + }); |
| 62 | + |
| 63 | + if (this._popup) { |
| 64 | + this._popup._controls.set(this._pattern); |
| 65 | + } |
| 66 | + |
| 67 | + afterRenderEffect(() => { |
| 68 | + if (this._elementRef) { |
| 69 | + this.combobox._pattern.expanded() |
| 70 | + ? this._elementRef.nativeElement.showModal() |
| 71 | + : this._elementRef.nativeElement.close(); |
| 72 | + } |
| 73 | + }); |
| 74 | + } |
| 75 | + |
| 76 | + close() { |
| 77 | + this._popup?.combobox?._pattern.close(); |
| 78 | + } |
| 79 | +} |
0 commit comments