@js-smart/ng-kit 21.7.1 → 21.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ChangeDetectorRef, input, signal, output, effect, ChangeDetectionStrategy, Component, Pipe, Injectable, HostListener, ViewChild, viewChild, computed, forwardRef,
|
|
2
|
+
import { inject, ChangeDetectorRef, input, signal, output, effect, ChangeDetectionStrategy, Component, Pipe, Injectable, HostListener, ViewChild, viewChild, computed, forwardRef, ElementRef, Renderer2, DestroyRef, Directive, DOCUMENT, Input, ViewContainerRef, Inject } from '@angular/core';
|
|
3
3
|
import { trigger, state, transition, style, animate } from '@angular/animations';
|
|
4
4
|
import { BehaviorSubject, Subject, throttleTime } from 'rxjs';
|
|
5
5
|
import { filter, takeUntil } from 'rxjs/operators';
|
|
@@ -8,9 +8,9 @@ import * as i1$1 from '@angular/material/progress-spinner';
|
|
|
8
8
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
9
9
|
import { NgClass } from '@angular/common';
|
|
10
10
|
import * as i1$2 from '@angular/forms';
|
|
11
|
-
import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
11
|
+
import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';
|
|
12
12
|
import * as i2 from '@angular/material/autocomplete';
|
|
13
|
-
import { MatAutocompleteTrigger, MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
13
|
+
import { MatAutocompleteTrigger, MatAutocomplete, MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
14
14
|
import * as i1$4 from '@angular/material/button';
|
|
15
15
|
import { MatButtonModule, MatAnchor, MatButton } from '@angular/material/button';
|
|
16
16
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
@@ -421,6 +421,8 @@ class AutocompleteComponent {
|
|
|
421
421
|
constructor() {
|
|
422
422
|
/** Gets reference to the MatAutocompleteTrigger to programmatically open/close the panel */
|
|
423
423
|
this.autocompleteTrigger = viewChild.required(MatAutocompleteTrigger);
|
|
424
|
+
/** MatAutocomplete instance (used to scroll the selected option into view when the panel opens) */
|
|
425
|
+
this.matAutocomplete = viewChild.required(MatAutocomplete);
|
|
424
426
|
/** Gets reference to the input element for re-focusing after clear */
|
|
425
427
|
this.inputElement = viewChild.required('inputEl');
|
|
426
428
|
/** Label of the autocomplete form field */
|
|
@@ -447,8 +449,10 @@ class AutocompleteComponent {
|
|
|
447
449
|
this.noOptionsText = input('No values found', ...(ngDevMode ? [{ debugName: "noOptionsText" }] : []));
|
|
448
450
|
/** Emits the selected value when an option is picked from the dropdown */
|
|
449
451
|
this.selectionChange = output();
|
|
452
|
+
/** Emits the raw text in the input on each keystroke (filter text while typing) */
|
|
453
|
+
this.onInputChange = output();
|
|
450
454
|
/** Internal form control for the autocomplete input */
|
|
451
|
-
this.control = new FormControl(
|
|
455
|
+
this.control = new FormControl(null);
|
|
452
456
|
/** Signal that tracks whether the autocomplete panel is currently open */
|
|
453
457
|
this.isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
|
|
454
458
|
/** Signal that tracks the current filter text typed by the user */
|
|
@@ -468,7 +472,7 @@ class AutocompleteComponent {
|
|
|
468
472
|
* selected value in the input field. Returns empty string for null/undefined values.
|
|
469
473
|
*/
|
|
470
474
|
this.displayFn = (value) => {
|
|
471
|
-
if (value == null) {
|
|
475
|
+
if (value == null || value === '') {
|
|
472
476
|
return '';
|
|
473
477
|
}
|
|
474
478
|
return this.displayWith()(value);
|
|
@@ -487,7 +491,9 @@ class AutocompleteComponent {
|
|
|
487
491
|
* when the form control value is set programmatically.
|
|
488
492
|
*/
|
|
489
493
|
writeValue(value) {
|
|
490
|
-
|
|
494
|
+
// Use null (not '') so MatAutocompleteTrigger clears mat-option selection and stays in sync with the parent CVA.
|
|
495
|
+
const internal = value == null ? null : value;
|
|
496
|
+
this.control.setValue(internal, { emitEvent: false });
|
|
491
497
|
}
|
|
492
498
|
/**
|
|
493
499
|
* Registers a callback function that is called when the control's value
|
|
@@ -519,18 +525,38 @@ class AutocompleteComponent {
|
|
|
519
525
|
onInput(event) {
|
|
520
526
|
const value = event.target.value;
|
|
521
527
|
this.filterText.set(value);
|
|
528
|
+
this.onInputChange.emit(value);
|
|
522
529
|
}
|
|
523
530
|
/**
|
|
524
531
|
* Clears the input value, resets the filter, notifies the parent form,
|
|
525
532
|
* and re-focuses the input element.
|
|
526
533
|
*/
|
|
527
534
|
clearInput(event) {
|
|
528
|
-
|
|
535
|
+
event.preventDefault();
|
|
536
|
+
event.stopPropagation();
|
|
537
|
+
this.autocompleteTrigger().closePanel();
|
|
538
|
+
this.control.setValue(null, { emitEvent: false });
|
|
529
539
|
this.filterText.set('');
|
|
530
540
|
this.onChange(null);
|
|
531
541
|
this.onTouched();
|
|
532
|
-
|
|
533
|
-
|
|
542
|
+
queueMicrotask(() => this.inputElement().nativeElement.focus());
|
|
543
|
+
}
|
|
544
|
+
/** Runs when the autocomplete overlay opens: keep expanded state and scroll the selected option into view. */
|
|
545
|
+
onPanelOpened() {
|
|
546
|
+
this.isExpanded.set(true);
|
|
547
|
+
this.scrollSelectedOptionIntoView();
|
|
548
|
+
}
|
|
549
|
+
scrollSelectedOptionIntoView() {
|
|
550
|
+
requestAnimationFrame(() => {
|
|
551
|
+
requestAnimationFrame(() => {
|
|
552
|
+
const panelEl = this.matAutocomplete().panel?.nativeElement;
|
|
553
|
+
if (!panelEl) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const selected = panelEl.querySelector('.mat-mdc-option.mdc-list-item--selected');
|
|
557
|
+
selected?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
558
|
+
});
|
|
559
|
+
});
|
|
534
560
|
}
|
|
535
561
|
/** Opens the autocomplete panel programmatically */
|
|
536
562
|
openPanel() {
|
|
@@ -547,13 +573,13 @@ class AutocompleteComponent {
|
|
|
547
573
|
this.selectionChange.emit(value);
|
|
548
574
|
}
|
|
549
575
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
550
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: AutocompleteComponent, isStandalone: true, selector: "autocomplete, lib-autocomplete", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, noOptionsText: { classPropertyName: "noOptionsText", publicName: "noOptionsText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, providers: [
|
|
576
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: AutocompleteComponent, isStandalone: true, selector: "autocomplete, lib-autocomplete", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, noOptionsText: { classPropertyName: "noOptionsText", publicName: "noOptionsText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", onInputChange: "onInputChange" }, providers: [
|
|
551
577
|
{
|
|
552
578
|
provide: NG_VALUE_ACCESSOR,
|
|
553
579
|
useExisting: forwardRef(() => AutocompleteComponent),
|
|
554
580
|
multi: true,
|
|
555
581
|
},
|
|
556
|
-
], viewQueries: [{ propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true, isSignal: true }, { propertyName: "inputElement", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field\n\t#origin=\"matAutocompleteOrigin\"\n\t[appearance]=\"appearance()\"\n\t[ngClass]=\"classes()\"\n\tmatAutocompleteOrigin\n\tsubscriptSizing=\"dynamic\">\n\t<mat-label>{{ label() }}</mat-label>\n\n\t<input\n\t\t#inputEl\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t(click)=\"trigger.openPanel()\"\n\t\t(input)=\"onInput($event)\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocompleteConnectedTo]=\"origin\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeholder()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t<div class=\"autocomplete-suffix\" matSuffix>\n\t\t@if (control.value) {\n\t\t\t<button type=\"button\" (click)=\"clearInput($event)\" class=\"suffix-action-btn\" mat-icon-button>\n\t\t\t\t<mat-icon>close</mat-icon>\n\t\t\t</button>\n\t\t} @else {\n\t\t\t<span aria-hidden=\"true\" class=\"suffix-placeholder\"></span>\n\t\t}\n\t\t<button\n\t\t\t(click)=\"trigger.panelOpen ? trigger.closePanel() : trigger.openPanel(); $event.stopPropagation()\"\n\t\t\t[attr.aria-label]=\"trigger.panelOpen ? 'Close options' : 'Open options'\"\n\t\t\tclass=\"suffix-action-btn\"\n\t\t\tmat-icon-button\n\t\t\ttype=\"button\">\n\t\t\t@if (isExpanded()) {\n\t\t\t\t<mat-icon>arrow_drop_up</mat-icon>\n\t\t\t} @else {\n\t\t\t\t<mat-icon>arrow_drop_down</mat-icon>\n\t\t\t}\n\t\t</button>\n\t</div>\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"isExpanded.set(false)\"\n\t\t(opened)=\"
|
|
582
|
+
], viewQueries: [{ propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true, isSignal: true }, { propertyName: "matAutocomplete", first: true, predicate: MatAutocomplete, descendants: true, isSignal: true }, { propertyName: "inputElement", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field\n\t#origin=\"matAutocompleteOrigin\"\n\t[appearance]=\"appearance()\"\n\t[ngClass]=\"classes()\"\n\tmatAutocompleteOrigin\n\tsubscriptSizing=\"dynamic\">\n\t<mat-label>{{ label() }}</mat-label>\n\n\t<input\n\t\t#inputEl\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t(click)=\"trigger.openPanel()\"\n\t\t(input)=\"onInput($event)\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocompleteConnectedTo]=\"origin\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeholder()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t<div class=\"autocomplete-suffix\" matSuffix>\n\t\t@if (control.value) {\n\t\t\t<button type=\"button\" (click)=\"clearInput($event)\" class=\"suffix-action-btn\" mat-icon-button>\n\t\t\t\t<mat-icon>close</mat-icon>\n\t\t\t</button>\n\t\t} @else {\n\t\t\t<span aria-hidden=\"true\" class=\"suffix-placeholder\"></span>\n\t\t}\n\t\t<button\n\t\t\t(click)=\"trigger.panelOpen ? trigger.closePanel() : trigger.openPanel(); $event.stopPropagation()\"\n\t\t\t[attr.aria-label]=\"trigger.panelOpen ? 'Close options' : 'Open options'\"\n\t\t\tclass=\"suffix-action-btn\"\n\t\t\tmat-icon-button\n\t\t\ttype=\"button\">\n\t\t\t@if (isExpanded()) {\n\t\t\t\t<mat-icon>arrow_drop_up</mat-icon>\n\t\t\t} @else {\n\t\t\t\t<mat-icon>arrow_drop_down</mat-icon>\n\t\t\t}\n\t\t</button>\n\t</div>\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"isExpanded.set(false)\"\n\t\t(opened)=\"onPanelOpened()\"\n\t\t(optionSelected)=\"onOptionSelected($event.option.value)\"\n\t\t[displayWith]=\"displayFn\">\n\t\t@if (loading()) {\n\t\t\t<mat-option disabled>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 8px\">\n\t\t\t\t\t<mat-spinner diameter=\"20\"></mat-spinner>\n\t\t\t\t\t<span>{{ loadingText() }}</span>\n\t\t\t\t</div>\n\t\t\t</mat-option>\n\t\t} @else {\n\t\t\t@for (option of filteredOptions(); track option) {\n\t\t\t\t<mat-option [value]=\"option\">{{ displayWith()(option) }}</mat-option>\n\t\t\t} @empty {\n\t\t\t\t<mat-option disabled>{{ noOptionsText() }}</mat-option>\n\t\t\t}\n\t\t}\n\t</mat-autocomplete>\n</mat-form-field>\n", styles: [".autocomplete-suffix{display:flex;align-items:center}.suffix-action-btn{width:40px;height:40px;padding:0}.suffix-placeholder{display:inline-block;width:40px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "directive", type: i2.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i1$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
|
|
557
583
|
}
|
|
558
584
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteComponent, decorators: [{
|
|
559
585
|
type: Component,
|
|
@@ -572,8 +598,194 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
|
|
|
572
598
|
useExisting: forwardRef(() => AutocompleteComponent),
|
|
573
599
|
multi: true,
|
|
574
600
|
},
|
|
575
|
-
], template: "<mat-form-field\n\t#origin=\"matAutocompleteOrigin\"\n\t[appearance]=\"appearance()\"\n\t[ngClass]=\"classes()\"\n\tmatAutocompleteOrigin\n\tsubscriptSizing=\"dynamic\">\n\t<mat-label>{{ label() }}</mat-label>\n\n\t<input\n\t\t#inputEl\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t(click)=\"trigger.openPanel()\"\n\t\t(input)=\"onInput($event)\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocompleteConnectedTo]=\"origin\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeholder()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t<div class=\"autocomplete-suffix\" matSuffix>\n\t\t@if (control.value) {\n\t\t\t<button type=\"button\" (click)=\"clearInput($event)\" class=\"suffix-action-btn\" mat-icon-button>\n\t\t\t\t<mat-icon>close</mat-icon>\n\t\t\t</button>\n\t\t} @else {\n\t\t\t<span aria-hidden=\"true\" class=\"suffix-placeholder\"></span>\n\t\t}\n\t\t<button\n\t\t\t(click)=\"trigger.panelOpen ? trigger.closePanel() : trigger.openPanel(); $event.stopPropagation()\"\n\t\t\t[attr.aria-label]=\"trigger.panelOpen ? 'Close options' : 'Open options'\"\n\t\t\tclass=\"suffix-action-btn\"\n\t\t\tmat-icon-button\n\t\t\ttype=\"button\">\n\t\t\t@if (isExpanded()) {\n\t\t\t\t<mat-icon>arrow_drop_up</mat-icon>\n\t\t\t} @else {\n\t\t\t\t<mat-icon>arrow_drop_down</mat-icon>\n\t\t\t}\n\t\t</button>\n\t</div>\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"isExpanded.set(false)\"\n\t\t(opened)=\"
|
|
576
|
-
}], propDecorators: { autocompleteTrigger: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatAutocompleteTrigger), { isSignal: true }] }], inputElement: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], noOptionsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noOptionsText", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
|
|
601
|
+
], template: "<mat-form-field\n\t#origin=\"matAutocompleteOrigin\"\n\t[appearance]=\"appearance()\"\n\t[ngClass]=\"classes()\"\n\tmatAutocompleteOrigin\n\tsubscriptSizing=\"dynamic\">\n\t<mat-label>{{ label() }}</mat-label>\n\n\t<input\n\t\t#inputEl\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t(click)=\"trigger.openPanel()\"\n\t\t(input)=\"onInput($event)\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocompleteConnectedTo]=\"origin\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeholder()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t<div class=\"autocomplete-suffix\" matSuffix>\n\t\t@if (control.value) {\n\t\t\t<button type=\"button\" (click)=\"clearInput($event)\" class=\"suffix-action-btn\" mat-icon-button>\n\t\t\t\t<mat-icon>close</mat-icon>\n\t\t\t</button>\n\t\t} @else {\n\t\t\t<span aria-hidden=\"true\" class=\"suffix-placeholder\"></span>\n\t\t}\n\t\t<button\n\t\t\t(click)=\"trigger.panelOpen ? trigger.closePanel() : trigger.openPanel(); $event.stopPropagation()\"\n\t\t\t[attr.aria-label]=\"trigger.panelOpen ? 'Close options' : 'Open options'\"\n\t\t\tclass=\"suffix-action-btn\"\n\t\t\tmat-icon-button\n\t\t\ttype=\"button\">\n\t\t\t@if (isExpanded()) {\n\t\t\t\t<mat-icon>arrow_drop_up</mat-icon>\n\t\t\t} @else {\n\t\t\t\t<mat-icon>arrow_drop_down</mat-icon>\n\t\t\t}\n\t\t</button>\n\t</div>\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"isExpanded.set(false)\"\n\t\t(opened)=\"onPanelOpened()\"\n\t\t(optionSelected)=\"onOptionSelected($event.option.value)\"\n\t\t[displayWith]=\"displayFn\">\n\t\t@if (loading()) {\n\t\t\t<mat-option disabled>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 8px\">\n\t\t\t\t\t<mat-spinner diameter=\"20\"></mat-spinner>\n\t\t\t\t\t<span>{{ loadingText() }}</span>\n\t\t\t\t</div>\n\t\t\t</mat-option>\n\t\t} @else {\n\t\t\t@for (option of filteredOptions(); track option) {\n\t\t\t\t<mat-option [value]=\"option\">{{ displayWith()(option) }}</mat-option>\n\t\t\t} @empty {\n\t\t\t\t<mat-option disabled>{{ noOptionsText() }}</mat-option>\n\t\t\t}\n\t\t}\n\t</mat-autocomplete>\n</mat-form-field>\n", styles: [".autocomplete-suffix{display:flex;align-items:center}.suffix-action-btn{width:40px;height:40px;padding:0}.suffix-placeholder{display:inline-block;width:40px}\n"] }]
|
|
602
|
+
}], propDecorators: { autocompleteTrigger: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatAutocompleteTrigger), { isSignal: true }] }], matAutocomplete: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatAutocomplete), { isSignal: true }] }], inputElement: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], noOptionsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noOptionsText", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], onInputChange: [{ type: i0.Output, args: ["onInputChange"] }] } });
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Single directive that adds clear and dropdown-toggle icon buttons to a
|
|
606
|
+
* Material autocomplete input. Unlike {@link LibAutocompleteActionsDirective},
|
|
607
|
+
* this directive is applied directly to the `input` element and does not require
|
|
608
|
+
* an anchor directive or a separate suffix component.
|
|
609
|
+
*
|
|
610
|
+
* Usage:
|
|
611
|
+
* ```html
|
|
612
|
+
* <mat-form-field appearance="outline">
|
|
613
|
+
* <mat-label>City</mat-label>
|
|
614
|
+
* <input matInput [matAutocomplete]="auto" formControlName="city" autocompleteSuffix />
|
|
615
|
+
* <mat-autocomplete #auto="matAutocomplete"> … </mat-autocomplete>
|
|
616
|
+
* </mat-form-field>
|
|
617
|
+
* ```
|
|
618
|
+
*
|
|
619
|
+
* @author Pavan Kumar Jadda
|
|
620
|
+
* @since 21.8.0
|
|
621
|
+
*/
|
|
622
|
+
class AutocompleteSuffixDirective {
|
|
623
|
+
constructor() {
|
|
624
|
+
this.trigger = inject(MatAutocompleteTrigger);
|
|
625
|
+
this.el = inject((ElementRef));
|
|
626
|
+
this.renderer = inject(Renderer2);
|
|
627
|
+
this.destroyRef = inject(DestroyRef);
|
|
628
|
+
this.ngControl = inject(NgControl, { optional: true, self: true });
|
|
629
|
+
this.clearBtn = null;
|
|
630
|
+
this.clearPlaceholder = null;
|
|
631
|
+
this.dropdownIconSpan = null;
|
|
632
|
+
this.isExpanded = false;
|
|
633
|
+
this.unlisten = [];
|
|
634
|
+
}
|
|
635
|
+
ngAfterViewInit() {
|
|
636
|
+
this.createSuffixElements();
|
|
637
|
+
this.setupListeners();
|
|
638
|
+
this.updateClearButtonVisibility();
|
|
639
|
+
}
|
|
640
|
+
createSuffixElements() {
|
|
641
|
+
const formField = this.el.nativeElement.closest('mat-form-field');
|
|
642
|
+
if (!formField) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const flexContainer = formField.querySelector('.mat-mdc-form-field-flex');
|
|
646
|
+
if (!flexContainer) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
// Find or create the suffix wrapper
|
|
650
|
+
let suffixWrapper = flexContainer.querySelector('.mat-mdc-form-field-icon-suffix');
|
|
651
|
+
if (!suffixWrapper) {
|
|
652
|
+
suffixWrapper = this.renderer.createElement('div');
|
|
653
|
+
this.renderer.addClass(suffixWrapper, 'mat-mdc-form-field-icon-suffix');
|
|
654
|
+
this.renderer.setAttribute(suffixWrapper, 'data-mat-icon-type', 'font');
|
|
655
|
+
this.renderer.appendChild(flexContainer, suffixWrapper);
|
|
656
|
+
}
|
|
657
|
+
const container = this.renderer.createElement('div');
|
|
658
|
+
this.renderer.setStyle(container, 'display', 'flex');
|
|
659
|
+
this.renderer.setStyle(container, 'align-items', 'center');
|
|
660
|
+
// Clear button (hidden when input is empty)
|
|
661
|
+
this.clearBtn = this.createIconButton('close', 'Clear value', (e) => this.clearInput(e));
|
|
662
|
+
this.renderer.setStyle(this.clearBtn, 'display', 'none');
|
|
663
|
+
// Placeholder keeps layout stable when clear button is hidden
|
|
664
|
+
this.clearPlaceholder = this.renderer.createElement('span');
|
|
665
|
+
this.renderer.setStyle(this.clearPlaceholder, 'display', 'inline-block');
|
|
666
|
+
this.renderer.setStyle(this.clearPlaceholder, 'width', '35px');
|
|
667
|
+
// Dropdown toggle button
|
|
668
|
+
const dropdownBtn = this.createIconButton('arrow_drop_down', 'Open options', (e) => this.togglePanel(e));
|
|
669
|
+
this.dropdownIconSpan = dropdownBtn.querySelector('.material-icons');
|
|
670
|
+
this.renderer.appendChild(container, this.clearBtn);
|
|
671
|
+
this.renderer.appendChild(container, this.clearPlaceholder);
|
|
672
|
+
this.renderer.appendChild(container, dropdownBtn);
|
|
673
|
+
this.renderer.appendChild(suffixWrapper, container);
|
|
674
|
+
}
|
|
675
|
+
createIconButton(iconName, ariaLabel, handler) {
|
|
676
|
+
const button = this.renderer.createElement('button');
|
|
677
|
+
this.renderer.setAttribute(button, 'type', 'button');
|
|
678
|
+
this.renderer.setAttribute(button, 'aria-label', ariaLabel);
|
|
679
|
+
this.renderer.setStyle(button, 'width', '35px');
|
|
680
|
+
this.renderer.setStyle(button, 'height', '35px');
|
|
681
|
+
this.renderer.setStyle(button, 'padding', '0');
|
|
682
|
+
this.renderer.setStyle(button, 'border', 'none');
|
|
683
|
+
this.renderer.setStyle(button, 'background', 'transparent');
|
|
684
|
+
this.renderer.setStyle(button, 'cursor', 'pointer');
|
|
685
|
+
this.renderer.setStyle(button, 'display', 'inline-flex');
|
|
686
|
+
this.renderer.setStyle(button, 'align-items', 'center');
|
|
687
|
+
this.renderer.setStyle(button, 'justify-content', 'center');
|
|
688
|
+
this.renderer.setStyle(button, 'border-radius', '50%');
|
|
689
|
+
this.renderer.setStyle(button, 'color', 'inherit');
|
|
690
|
+
const icon = this.renderer.createElement('span');
|
|
691
|
+
this.renderer.addClass(icon, 'material-icons');
|
|
692
|
+
this.renderer.setStyle(icon, 'font-size', '24px');
|
|
693
|
+
this.renderer.appendChild(icon, this.renderer.createText(iconName));
|
|
694
|
+
this.renderer.appendChild(button, icon);
|
|
695
|
+
this.unlisten.push(this.renderer.listen(button, 'click', handler));
|
|
696
|
+
return button;
|
|
697
|
+
}
|
|
698
|
+
setupListeners() {
|
|
699
|
+
// Track user typing
|
|
700
|
+
this.unlisten.push(this.renderer.listen(this.el.nativeElement, 'input', () => this.updateClearButtonVisibility()));
|
|
701
|
+
const autocomplete = this.trigger.autocomplete;
|
|
702
|
+
// Track autocomplete panel open/close
|
|
703
|
+
const openedSub = autocomplete.opened.subscribe(() => {
|
|
704
|
+
this.isExpanded = true;
|
|
705
|
+
this.updateDropdownIcon();
|
|
706
|
+
this.scrollSelectedOptionIntoView();
|
|
707
|
+
});
|
|
708
|
+
const closedSub = autocomplete.closed.subscribe(() => {
|
|
709
|
+
this.isExpanded = false;
|
|
710
|
+
this.updateDropdownIcon();
|
|
711
|
+
this.updateClearButtonVisibility();
|
|
712
|
+
});
|
|
713
|
+
// Track option selection
|
|
714
|
+
const selectedSub = autocomplete.optionSelected.subscribe(() => this.updateClearButtonVisibility());
|
|
715
|
+
// Track programmatic value changes via NgControl
|
|
716
|
+
let valueChangesSub = null;
|
|
717
|
+
if (this.ngControl?.control) {
|
|
718
|
+
valueChangesSub = this.ngControl.control.valueChanges.subscribe(() => this.updateClearButtonVisibility());
|
|
719
|
+
}
|
|
720
|
+
this.destroyRef.onDestroy(() => {
|
|
721
|
+
this.unlisten.forEach((fn) => fn());
|
|
722
|
+
openedSub.unsubscribe();
|
|
723
|
+
closedSub.unsubscribe();
|
|
724
|
+
selectedSub.unsubscribe();
|
|
725
|
+
valueChangesSub?.unsubscribe();
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
clearInput(event) {
|
|
729
|
+
event.preventDefault();
|
|
730
|
+
event.stopPropagation();
|
|
731
|
+
this.trigger.closePanel();
|
|
732
|
+
this.el.nativeElement.value = '';
|
|
733
|
+
if (this.ngControl?.control) {
|
|
734
|
+
this.ngControl.control.setValue(null, { emitEvent: true });
|
|
735
|
+
this.ngControl.control.markAsTouched();
|
|
736
|
+
}
|
|
737
|
+
this.updateClearButtonVisibility();
|
|
738
|
+
queueMicrotask(() => this.el.nativeElement.focus());
|
|
739
|
+
}
|
|
740
|
+
togglePanel(event) {
|
|
741
|
+
event.stopPropagation();
|
|
742
|
+
if (this.trigger.panelOpen) {
|
|
743
|
+
this.trigger.closePanel();
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
this.trigger.openPanel();
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
updateClearButtonVisibility() {
|
|
750
|
+
const hasValue = !!(this.el.nativeElement.value || this.ngControl?.control?.value);
|
|
751
|
+
if (this.clearBtn) {
|
|
752
|
+
this.renderer.setStyle(this.clearBtn, 'display', hasValue ? 'inline-flex' : 'none');
|
|
753
|
+
}
|
|
754
|
+
if (this.clearPlaceholder) {
|
|
755
|
+
this.renderer.setStyle(this.clearPlaceholder, 'display', hasValue ? 'none' : 'inline-block');
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
scrollSelectedOptionIntoView() {
|
|
759
|
+
requestAnimationFrame(() => {
|
|
760
|
+
requestAnimationFrame(() => {
|
|
761
|
+
const panelEl = this.trigger.autocomplete.panel?.nativeElement;
|
|
762
|
+
if (!panelEl) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const selected = panelEl.querySelector('.mat-mdc-option.mdc-list-item--selected');
|
|
766
|
+
selected?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
updateDropdownIcon() {
|
|
771
|
+
if (this.dropdownIconSpan) {
|
|
772
|
+
this.dropdownIconSpan.textContent = this.isExpanded ? 'arrow_drop_up' : 'arrow_drop_down';
|
|
773
|
+
}
|
|
774
|
+
const button = this.dropdownIconSpan?.parentElement;
|
|
775
|
+
if (button) {
|
|
776
|
+
this.renderer.setAttribute(button, 'aria-label', this.isExpanded ? 'Close options' : 'Open options');
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteSuffixDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
780
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.0", type: AutocompleteSuffixDirective, isStandalone: true, selector: "input[matAutocomplete][autocompleteSuffix]", ngImport: i0 }); }
|
|
781
|
+
}
|
|
782
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteSuffixDirective, decorators: [{
|
|
783
|
+
type: Directive,
|
|
784
|
+
args: [{
|
|
785
|
+
selector: 'input[matAutocomplete][autocompleteSuffix]',
|
|
786
|
+
standalone: true,
|
|
787
|
+
}]
|
|
788
|
+
}] });
|
|
577
789
|
|
|
578
790
|
class PrintOptions {
|
|
579
791
|
constructor(options) {
|
|
@@ -2427,5 +2639,5 @@ const markError = (progressState, message) => {
|
|
|
2427
2639
|
* Generated bundle index. Do not edit.
|
|
2428
2640
|
*/
|
|
2429
2641
|
|
|
2430
|
-
export { AlertComponent, AutocompleteComponent, BaseButtonDirective, BsLinkButtonComponent, BsLinkButtonDirective, CloseButtonDirective, ConfirmDialogComponent, DeleteButtonComponent, DeleteButtonDirective, EditBsButtonComponent, EditBsButtonDirective, EditButtonComponent, EditButtonDirective, EditSolidSvgComponent, EditSvgIconButtonComponent, EditSvgIconButtonDirective, EntityStore, ExcelExportButtonComponent, ExcelExportButtonDirective, ManageButtonComponent, ManageButtonDirective, MatSnackBarService, NgxPrintDirective, NgxSpinnerComponent, NgxSpinnerService, PdfExportButtonComponent, PdfExportButtonDirective, PreventMultipleClicksDirective, PrimaryButtonComponent, PrimaryButtonDirective, SavePrimaryButtonComponent, SavePrimaryButtonDirective, SearchButtonComponent, SpinnerComponent, Store, SuccessButtonComponent, SuccessButtonDirective, ViewButtonComponent, ViewButtonDirective, ViewPrimaryButtonComponent, ViewPrimaryButtonDirective, initializeState, markError, markLoading, markSuccess };
|
|
2642
|
+
export { AlertComponent, AutocompleteComponent, AutocompleteSuffixDirective, BaseButtonDirective, BsLinkButtonComponent, BsLinkButtonDirective, CloseButtonDirective, ConfirmDialogComponent, DeleteButtonComponent, DeleteButtonDirective, EditBsButtonComponent, EditBsButtonDirective, EditButtonComponent, EditButtonDirective, EditSolidSvgComponent, EditSvgIconButtonComponent, EditSvgIconButtonDirective, EntityStore, ExcelExportButtonComponent, ExcelExportButtonDirective, ManageButtonComponent, ManageButtonDirective, MatSnackBarService, NgxPrintDirective, NgxSpinnerComponent, NgxSpinnerService, PdfExportButtonComponent, PdfExportButtonDirective, PreventMultipleClicksDirective, PrimaryButtonComponent, PrimaryButtonDirective, SavePrimaryButtonComponent, SavePrimaryButtonDirective, SearchButtonComponent, SpinnerComponent, Store, SuccessButtonComponent, SuccessButtonDirective, ViewButtonComponent, ViewButtonDirective, ViewPrimaryButtonComponent, ViewPrimaryButtonDirective, initializeState, markError, markLoading, markSuccess };
|
|
2431
2643
|
//# sourceMappingURL=js-smart-ng-kit.mjs.map
|