@js-smart/ng-kit 21.3.1 → 21.5.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, forwardRef, Input, Optional, DOCUMENT, Directive, ElementRef, ViewContainerRef, Inject, computed } from '@angular/core';
2
+ import { inject, ChangeDetectorRef, input, signal, output, effect, ChangeDetectionStrategy, Component, Pipe, Injectable, HostListener, ViewChild, DestroyRef, forwardRef, DOCUMENT, Input, Directive, ElementRef, ViewContainerRef, Inject, computed } 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, startWith, map } from 'rxjs/operators';
@@ -7,6 +7,7 @@ import * as i1 from '@angular/platform-browser';
7
7
  import * as i1$1 from '@angular/material/progress-spinner';
8
8
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
9
9
  import { AsyncPipe } from '@angular/common';
10
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
11
  import * as i1$2 from '@angular/forms';
11
12
  import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
12
13
  import * as i3 from '@angular/material/autocomplete';
@@ -420,7 +421,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
420
421
  */
421
422
  class AutocompleteComponent {
422
423
  constructor() {
423
- this.cdRef = inject(ChangeDetectorRef);
424
+ this.destroyRef = inject(DestroyRef);
424
425
  /**
425
426
  * Internal form control for the autocomplete
426
427
  */
@@ -452,7 +453,7 @@ class AutocompleteComponent {
452
453
  /**
453
454
  * Function that maps an option's control value to its display value in the trigger.
454
455
  */
455
- this.displayWith = null;
456
+ this.displayWith = input(null, ...(ngDevMode ? [{ debugName: "displayWith" }] : []));
456
457
  /**
457
458
  * Specifies if the autocomplete is required. Default is not required.
458
459
  */
@@ -461,6 +462,18 @@ class AutocompleteComponent {
461
462
  * Specifies if the autocomplete is disabled. Default is not required.
462
463
  */
463
464
  this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
465
+ /**
466
+ * Text displayed when no options match the input. Defaults to 'No options'
467
+ */
468
+ this.noOptionsText = input('No options', ...(ngDevMode ? [{ debugName: "noOptionsText" }] : []));
469
+ /**
470
+ * Whether the autocomplete is in a loading state. Shows a loading message instead of options
471
+ */
472
+ this.loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
473
+ /**
474
+ * Text displayed when the autocomplete is in a loading state. Defaults to 'Loading...'
475
+ */
476
+ this.loadingText = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingText" }] : []));
464
477
  /**
465
478
  * List of Objects that need to be bind and searched for
466
479
  */
@@ -470,24 +483,34 @@ class AutocompleteComponent {
470
483
  */
471
484
  this.onSelectionChange = output();
472
485
  /**
473
- * BehaviorSubject that shows the current active arrow icon
486
+ * Signal that tracks the current arrow icon state
474
487
  */
475
- this.arrowIconSubject = new BehaviorSubject('arrow_drop_down');
476
- // ControlValueAccessor implementation
488
+ this.arrowIcon = signal('arrow_drop_down', ...(ngDevMode ? [{ debugName: "arrowIcon" }] : []));
477
489
  this.onChange = () => { };
478
490
  this.onTouched = () => { };
479
491
  }
492
+ /**
493
+ * Writes a new value to the control
494
+ */
480
495
  writeValue(value) {
481
496
  this.control.setValue(value, { emitEvent: false });
482
497
  }
498
+ /**
499
+ * Registers a callback function that is called when the control's value changes
500
+ */
483
501
  registerOnChange(fn) {
484
502
  this.onChange = fn;
485
- // Forward value changes from internal control to parent form
486
- this.control.valueChanges.subscribe((value) => fn(value));
503
+ this.control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => fn(value));
487
504
  }
505
+ /**
506
+ * Registers a callback function that is called when the control is touched
507
+ */
488
508
  registerOnTouched(fn) {
489
509
  this.onTouched = fn;
490
510
  }
511
+ /**
512
+ * Sets the disabled state of the control
513
+ */
491
514
  setDisabledState(isDisabled) {
492
515
  if (isDisabled) {
493
516
  this.control.disable();
@@ -496,25 +519,44 @@ class AutocompleteComponent {
496
519
  this.control.enable();
497
520
  }
498
521
  }
499
- ngAfterContentChecked() {
500
- this.cdRef.detectChanges();
501
- }
522
+ /**
523
+ * Initializes the filtered options observable pipeline
524
+ */
502
525
  ngOnInit() {
503
- this.filteredOptions = this.control.valueChanges.pipe(startWith(''), map((value) => (typeof value === 'string' ? value : value !== null ? value[this.bindLabel()] : '')), map((propertyName) => this.data()?.filter((option) => {
504
- return typeof option === 'string'
505
- ? option?.toLowerCase().startsWith(propertyName.toLowerCase())
506
- : option[this.bindLabel()]?.toLowerCase().indexOf(propertyName.toLowerCase()) === 0;
507
- }) ?? this.data()?.slice()));
526
+ this.filteredOptions = this.control.valueChanges.pipe(startWith(''), map((value) => (typeof value === 'string' ? value : '')), map((propertyName) => {
527
+ if (!propertyName) {
528
+ return this.data()?.slice();
529
+ }
530
+ // If the value exactly matches an existing option, show all options
531
+ const isSelectedValue = this.data()?.some((option) => typeof option === 'string' && option === propertyName);
532
+ if (isSelectedValue) {
533
+ return this.data()?.slice();
534
+ }
535
+ return (this.data()?.filter((option) => {
536
+ return typeof option === 'string'
537
+ ? option?.toLowerCase().includes(propertyName.toLowerCase())
538
+ : option[this.bindLabel()]?.toLowerCase().includes(propertyName.toLowerCase());
539
+ }) ?? this.data()?.slice());
540
+ }));
508
541
  }
542
+ /**
543
+ * Binds the displayFn to the component context on input changes
544
+ */
509
545
  ngOnChanges(_changes) {
510
546
  this.displayFn = this.displayFn.bind(this);
511
547
  }
548
+ /**
549
+ * Clears the input value, resets the control, and re-focuses the input
550
+ */
512
551
  clearInput(evt) {
513
552
  evt.stopPropagation();
514
553
  this.control.reset();
515
554
  this.onChange(null);
516
555
  this.inputAutoComplete?.nativeElement.focus();
517
556
  }
557
+ /**
558
+ * Toggles the autocomplete panel open or closed
559
+ */
518
560
  openOrClosePanel(evt, trigger) {
519
561
  evt.stopPropagation();
520
562
  if (trigger.panelOpen) {
@@ -524,49 +566,62 @@ class AutocompleteComponent {
524
566
  trigger.openPanel();
525
567
  }
526
568
  }
569
+ /**
570
+ * Returns the display value for the given option. Uses custom displayWith function if provided,
571
+ * otherwise falls back to the bindLabel property or the string value itself.
572
+ */
527
573
  displayFn(object) {
528
- if (this.displayWith !== undefined && this.displayWith !== null && typeof this.displayWith === 'function') {
529
- this.displayFn = this.displayWith.bind(this);
530
- return this.displayWith(object);
574
+ const customDisplayWith = this.displayWith();
575
+ if (customDisplayWith) {
576
+ return customDisplayWith(object);
531
577
  }
532
- else {
533
- if (typeof object === 'string') {
534
- return object;
535
- }
536
- return object?.[this.bindLabel()] ? object[this.bindLabel()] : '';
578
+ if (typeof object === 'string') {
579
+ return object;
537
580
  }
581
+ return object?.[this.bindLabel()] ? object[this.bindLabel()] : '';
538
582
  }
583
+ /**
584
+ * Emits the selected value and notifies the parent form of the selection change
585
+ */
539
586
  emitSelectedValue($event) {
540
587
  this.onSelectionChange.emit($event.source.value);
541
588
  this.onChange($event.source.value);
542
589
  this.onTouched();
543
590
  }
591
+ /**
592
+ * Updates the arrow icon to point up when the panel opens
593
+ */
594
+ onPanelOpened() {
595
+ this.arrowIcon.set('arrow_drop_up');
596
+ }
597
+ /**
598
+ * Updates the arrow icon to point down when the panel closes
599
+ */
600
+ onPanelClosed() {
601
+ this.arrowIcon.set('arrow_drop_down');
602
+ }
544
603
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
545
- 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 }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, providers: [
604
+ 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 }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, noOptionsText: { classPropertyName: "noOptionsText", publicName: "noOptionsText", 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 }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, providers: [
546
605
  {
547
606
  provide: NG_VALUE_ACCESSOR,
548
607
  useExisting: forwardRef(() => AutocompleteComponent),
549
608
  multi: true,
550
609
  },
551
- ], viewQueries: [{ propertyName: "inputAutoComplete", first: true, predicate: ["inputAutoComplete"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div>\n\t<mat-form-field appearance=\"fill\" class=\"{{ classes() }}\">\n\t\t<mat-label>{{ label() }}</mat-label>\n\t\t<input\n\t\t\t#inputAutoComplete\n\t\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t\t[formControl]=\"control\"\n\t\t\t[matAutocomplete]=\"auto\"\n\t\t\t[placeholder]=\"placeHolder()\"\n\t\t\t[required]=\"required()\"\n\t\t\tmatInput\n\t\t\ttype=\"text\" />\n\n\t\t<div matSuffix style=\"display: flex\">\n\t\t\t@if (control.value) {\n\t\t\t\t<button (click)=\"clearInput($event)\" aria-label=\"Clear\" mat-icon-button type=\"button\">\n\t\t\t\t\t<mat-icon>clear</mat-icon>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<button (click)=\"openOrClosePanel($event, trigger)\" aria-label=\"Clear\" mat-icon-button type=\"button\">\n\t\t\t\t<mat-icon>{{ arrowIconSubject.getValue() }}</mat-icon>\n\t\t\t</button>\n\t\t</div>\n\n\t\t<mat-autocomplete\n\t\t\t#auto=\"matAutocomplete\"\n\t\t\t(closed)=\"arrowIconSubject.next('arrow_drop_down')\"\n\t\t\t(opened)=\"arrowIconSubject.next('arrow_drop_up')\"\n\t\t\t(optionSelected)=\"arrowIconSubject.next('arrow_drop_down')\"\n\t\t\t[displayWith]=\"displayFn\">\n\t\t\t@for (option of filteredOptions | async; track option[bindValue()]) {\n\t\t\t\t<mat-option (onSelectionChange)=\"emitSelectedValue($event)\" [value]=\"option\">\n\t\t\t\t\t@if (typeof option === 'string') {\n\t\t\t\t\t\t<ng-container>{{ option }}</ng-container>\n\t\t\t\t\t} @else if (typeof option === 'object') {\n\t\t\t\t\t\t<ng-container>{{ option[bindLabel()] }}</ng-container>\n\t\t\t\t\t}\n\t\t\t\t</mat-option>\n\t\t\t}\n\t\t</mat-autocomplete>\n\t</mat-form-field>\n</div>\n", dependencies: [{ 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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i3.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: i3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i3.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
610
+ ], viewQueries: [{ propertyName: "inputAutoComplete", first: true, predicate: ["inputAutoComplete"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<mat-form-field [appearance]=\"appearance()\" [class]=\"classes()\">\n\t<mat-label>{{ label() }}</mat-label>\n\t<input\n\t\t#inputAutoComplete\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeHolder()\"\n\t\t[required]=\"required()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t@if (!control.disabled) {\n\t\t<div matSuffix style=\"display: flex\">\n\t\t\t<button\n\t\t\t\t(click)=\"clearInput($event)\"\n\t\t\t\t[style.visibility]=\"control.value ? 'visible' : 'hidden'\"\n\t\t\t\taria-label=\"Clear\"\n\t\t\t\tmat-icon-button\n\t\t\t\ttype=\"button\">\n\t\t\t\t<mat-icon>clear</mat-icon>\n\t\t\t</button>\n\t\t\t<button (click)=\"openOrClosePanel($event, trigger)\" aria-label=\"Toggle dropdown\" mat-icon-button type=\"button\">\n\t\t\t\t<mat-icon>{{ arrowIcon() }}</mat-icon>\n\t\t\t</button>\n\t\t</div>\n\t}\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"onPanelClosed()\"\n\t\t(opened)=\"onPanelOpened()\"\n\t\t(optionSelected)=\"onPanelClosed()\"\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 | async; track typeof option === 'string' ? option : option[bindValue()]) {\n\t\t\t\t<mat-option (onSelectionChange)=\"emitSelectedValue($event)\" [value]=\"option\">\n\t\t\t\t\t@if (typeof option === 'string') {\n\t\t\t\t\t\t<ng-container>{{ option }}</ng-container>\n\t\t\t\t\t} @else if (typeof option === 'object') {\n\t\t\t\t\t\t<ng-container>{{ option[bindLabel()] }}</ng-container>\n\t\t\t\t\t}\n\t\t\t\t</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", dependencies: [{ 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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i3.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: i3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i3.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i1$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
552
611
  }
553
612
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AutocompleteComponent, decorators: [{
554
613
  type: Component,
555
- args: [{ selector: 'autocomplete, lib-autocomplete', imports: [ReactiveFormsModule, MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatButtonModule, MatIconModule, AsyncPipe], providers: [
614
+ args: [{ selector: 'autocomplete, lib-autocomplete', imports: [AsyncPipe, ReactiveFormsModule, MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule], providers: [
556
615
  {
557
616
  provide: NG_VALUE_ACCESSOR,
558
617
  useExisting: forwardRef(() => AutocompleteComponent),
559
618
  multi: true,
560
619
  },
561
- ], template: "<div>\n\t<mat-form-field appearance=\"fill\" class=\"{{ classes() }}\">\n\t\t<mat-label>{{ label() }}</mat-label>\n\t\t<input\n\t\t\t#inputAutoComplete\n\t\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t\t[formControl]=\"control\"\n\t\t\t[matAutocomplete]=\"auto\"\n\t\t\t[placeholder]=\"placeHolder()\"\n\t\t\t[required]=\"required()\"\n\t\t\tmatInput\n\t\t\ttype=\"text\" />\n\n\t\t<div matSuffix style=\"display: flex\">\n\t\t\t@if (control.value) {\n\t\t\t\t<button (click)=\"clearInput($event)\" aria-label=\"Clear\" mat-icon-button type=\"button\">\n\t\t\t\t\t<mat-icon>clear</mat-icon>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<button (click)=\"openOrClosePanel($event, trigger)\" aria-label=\"Clear\" mat-icon-button type=\"button\">\n\t\t\t\t<mat-icon>{{ arrowIconSubject.getValue() }}</mat-icon>\n\t\t\t</button>\n\t\t</div>\n\n\t\t<mat-autocomplete\n\t\t\t#auto=\"matAutocomplete\"\n\t\t\t(closed)=\"arrowIconSubject.next('arrow_drop_down')\"\n\t\t\t(opened)=\"arrowIconSubject.next('arrow_drop_up')\"\n\t\t\t(optionSelected)=\"arrowIconSubject.next('arrow_drop_down')\"\n\t\t\t[displayWith]=\"displayFn\">\n\t\t\t@for (option of filteredOptions | async; track option[bindValue()]) {\n\t\t\t\t<mat-option (onSelectionChange)=\"emitSelectedValue($event)\" [value]=\"option\">\n\t\t\t\t\t@if (typeof option === 'string') {\n\t\t\t\t\t\t<ng-container>{{ option }}</ng-container>\n\t\t\t\t\t} @else if (typeof option === 'object') {\n\t\t\t\t\t\t<ng-container>{{ option[bindLabel()] }}</ng-container>\n\t\t\t\t\t}\n\t\t\t\t</mat-option>\n\t\t\t}\n\t\t</mat-autocomplete>\n\t</mat-form-field>\n</div>\n" }]
620
+ ], template: "<mat-form-field [appearance]=\"appearance()\" [class]=\"classes()\">\n\t<mat-label>{{ label() }}</mat-label>\n\t<input\n\t\t#inputAutoComplete\n\t\t#trigger=\"matAutocompleteTrigger\"\n\t\t[formControl]=\"control\"\n\t\t[matAutocomplete]=\"auto\"\n\t\t[placeholder]=\"placeHolder()\"\n\t\t[required]=\"required()\"\n\t\tmatInput\n\t\ttype=\"text\" />\n\n\t@if (!control.disabled) {\n\t\t<div matSuffix style=\"display: flex\">\n\t\t\t<button\n\t\t\t\t(click)=\"clearInput($event)\"\n\t\t\t\t[style.visibility]=\"control.value ? 'visible' : 'hidden'\"\n\t\t\t\taria-label=\"Clear\"\n\t\t\t\tmat-icon-button\n\t\t\t\ttype=\"button\">\n\t\t\t\t<mat-icon>clear</mat-icon>\n\t\t\t</button>\n\t\t\t<button (click)=\"openOrClosePanel($event, trigger)\" aria-label=\"Toggle dropdown\" mat-icon-button type=\"button\">\n\t\t\t\t<mat-icon>{{ arrowIcon() }}</mat-icon>\n\t\t\t</button>\n\t\t</div>\n\t}\n\n\t<mat-autocomplete\n\t\t#auto=\"matAutocomplete\"\n\t\t(closed)=\"onPanelClosed()\"\n\t\t(opened)=\"onPanelOpened()\"\n\t\t(optionSelected)=\"onPanelClosed()\"\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 | async; track typeof option === 'string' ? option : option[bindValue()]) {\n\t\t\t\t<mat-option (onSelectionChange)=\"emitSelectedValue($event)\" [value]=\"option\">\n\t\t\t\t\t@if (typeof option === 'string') {\n\t\t\t\t\t\t<ng-container>{{ option }}</ng-container>\n\t\t\t\t\t} @else if (typeof option === 'object') {\n\t\t\t\t\t\t<ng-container>{{ option[bindLabel()] }}</ng-container>\n\t\t\t\t\t}\n\t\t\t\t</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" }]
562
621
  }], propDecorators: { inputAutoComplete: [{
563
622
  type: ViewChild,
564
623
  args: ['inputAutoComplete']
565
- }], 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 }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], displayWith: [{
566
- type: Input
567
- }, {
568
- type: Optional
569
- }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }] } });
624
+ }], 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 }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], noOptionsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noOptionsText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }] } });
570
625
 
571
626
  class PrintOptions {
572
627
  constructor(options) {
@@ -889,6 +944,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
889
944
  class BaseButtonDirective {
890
945
  constructor() {
891
946
  this.icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : []));
947
+ this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
892
948
  this.loadingLabel = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingLabel" }] : []));
893
949
  this.loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
894
950
  this.elementRef = inject(ElementRef);
@@ -897,6 +953,12 @@ class BaseButtonDirective {
897
953
  this.iconSpan = signal(null, ...(ngDevMode ? [{ debugName: "iconSpan" }] : []));
898
954
  this.elementRef.nativeElement.classList.add('btn');
899
955
  effect(() => {
956
+ // If a consumer provides a label input, always use it. Otherwise, fall back to the initially captured host text.
957
+ const nextText = this.label() || this.originalText();
958
+ this.originalText.set(nextText);
959
+ // Keep the icon element in sync with [icon]
960
+ this.createIcon();
961
+ // Re-render on any relevant signal change
900
962
  this.updateContent();
901
963
  });
902
964
  }
@@ -906,9 +968,6 @@ class BaseButtonDirective {
906
968
  // Create icon after capturing text
907
969
  this.createIcon();
908
970
  }
909
- /**
910
- * Create icon element if icon name is provided
911
- */
912
971
  createIcon() {
913
972
  if (this.icon()) {
914
973
  const iconElement = this.document.createElement('mat-icon');
@@ -917,9 +976,6 @@ class BaseButtonDirective {
917
976
  this.iconSpan.set(iconElement);
918
977
  }
919
978
  }
920
- /**
921
- * Update content of the button
922
- */
923
979
  updateContent() {
924
980
  const element = this.elementRef.nativeElement;
925
981
  element.innerHTML = '';
@@ -930,39 +986,28 @@ class BaseButtonDirective {
930
986
  this.showNormalState(element);
931
987
  }
932
988
  }
933
- /**
934
- * Show loading state. Add spinner and loadingLabel text
935
- */
936
989
  showLoadingState(element) {
937
- // Create a new span element
938
990
  const newSpan = this.document.createElement('span');
939
- // Set its text content
940
991
  newSpan.classList.add('spinner-border', 'spinner-border-sm', 'me-2');
941
992
  newSpan.setAttribute('role', 'status');
942
- // Append the new element to the host element
943
993
  element.appendChild(newSpan);
944
994
  element.appendChild(this.document.createTextNode(this.loadingLabel()));
945
995
  element.setAttribute('disabled', 'true');
946
996
  }
947
- /**
948
- * Show normal state. Add icon and original text
949
- */
950
997
  showNormalState(element) {
951
- // Add icon and original text
952
998
  const iconElement = this.iconSpan();
953
999
  if (iconElement) {
954
1000
  element.appendChild(iconElement);
955
1001
  }
956
- // Append text node instead of setting textContent (which overwrites the icon)
957
1002
  element.appendChild(this.document.createTextNode(this.originalText()));
958
1003
  element.removeAttribute('disabled');
959
1004
  }
960
1005
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: BaseButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
961
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.0", type: BaseButtonDirective, isStandalone: true, inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
1006
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.0", type: BaseButtonDirective, isStandalone: true, inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
962
1007
  }
963
1008
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: BaseButtonDirective, decorators: [{
964
1009
  type: Directive
965
- }], ctorParameters: () => [], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
1010
+ }], ctorParameters: () => [], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
966
1011
 
967
1012
  class BaseButtonComponent {
968
1013
  constructor() {
@@ -1867,18 +1912,19 @@ class SuccessButtonDirective extends BaseButtonDirective {
1867
1912
  constructor() {
1868
1913
  super();
1869
1914
  this.icon = input('save', ...(ngDevMode ? [{ debugName: "icon" }] : []));
1915
+ this.label = input('Update', ...(ngDevMode ? [{ debugName: "label" }] : []));
1870
1916
  this.loadingLabel = input('Updating...', ...(ngDevMode ? [{ debugName: "loadingLabel" }] : []));
1871
1917
  this.elementRef.nativeElement.classList.add('success-button');
1872
1918
  }
1873
1919
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: SuccessButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1874
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.0", type: SuccessButtonDirective, isStandalone: true, selector: "[successButton]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
1920
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.0", type: SuccessButtonDirective, isStandalone: true, selector: "[successButton]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
1875
1921
  }
1876
1922
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: SuccessButtonDirective, decorators: [{
1877
1923
  type: Directive,
1878
1924
  args: [{
1879
1925
  selector: '[successButton]',
1880
1926
  }]
1881
- }], ctorParameters: () => [], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }] } });
1927
+ }], ctorParameters: () => [], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }] } });
1882
1928
 
1883
1929
  class ViewButtonComponent extends BaseButtonComponent {
1884
1930
  constructor() {