ngx-opalbytes-components 1.18.0 → 1.20.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.
Files changed (78) hide show
  1. package/README.md +103 -0
  2. package/cli/cao-comp.cjs +186 -0
  3. package/fesm2022/ngx-opalbytes-components.mjs +331 -76
  4. package/fesm2022/ngx-opalbytes-components.mjs.map +1 -1
  5. package/package.json +4 -1
  6. package/src/lib/shared/components/autocomplete/autocomplete.component.html +126 -0
  7. package/src/lib/shared/components/autocomplete/autocomplete.component.scss +150 -0
  8. package/src/lib/shared/components/autocomplete/autocomplete.component.ts +552 -0
  9. package/src/lib/shared/components/base-button/base-button.component.html +33 -0
  10. package/src/lib/shared/components/base-button/base-button.component.scss +14 -0
  11. package/src/lib/shared/components/base-button/base-button.component.spec.ts +64 -0
  12. package/src/lib/shared/components/base-button/base-button.component.ts +48 -0
  13. package/src/lib/shared/components/base-icon/base-icon.css +0 -0
  14. package/src/lib/shared/components/base-icon/base-icon.html +11 -0
  15. package/src/lib/shared/components/base-icon/base-icon.spec.ts +23 -0
  16. package/src/lib/shared/components/base-icon/base-icon.ts +18 -0
  17. package/src/lib/shared/components/base-input/base-input.css +193 -0
  18. package/src/lib/shared/components/base-input/base-input.html +43 -0
  19. package/src/lib/shared/components/base-input/base-input.spec.ts +146 -0
  20. package/src/lib/shared/components/base-input/base-input.ts +133 -0
  21. package/src/lib/shared/components/base-time-range/base-time-range.css +27 -0
  22. package/src/lib/shared/components/base-time-range/base-time-range.html +23 -0
  23. package/src/lib/shared/components/base-time-range/base-time-range.spec.ts +27 -0
  24. package/src/lib/shared/components/base-time-range/base-time-range.ts +61 -0
  25. package/src/lib/shared/components/base-toggle/base-toggle.component.html +28 -0
  26. package/src/lib/shared/components/base-toggle/base-toggle.component.scss +45 -0
  27. package/src/lib/shared/components/base-toggle/base-toggle.component.spec.ts +22 -0
  28. package/src/lib/shared/components/base-toggle/base-toggle.component.ts +138 -0
  29. package/src/lib/shared/components/card/card.component.css +264 -0
  30. package/src/lib/shared/components/card/card.component.html +103 -0
  31. package/src/lib/shared/components/card/card.component.ts +63 -0
  32. package/src/lib/shared/components/date-picker/date-picker.html +82 -0
  33. package/src/lib/shared/components/date-picker/date-picker.scss +8 -0
  34. package/src/lib/shared/components/date-picker/date-picker.spec.ts +23 -0
  35. package/src/lib/shared/components/date-picker/date-picker.ts +165 -0
  36. package/src/lib/shared/components/drop-down/drop-down.css +61 -0
  37. package/src/lib/shared/components/drop-down/drop-down.html +96 -0
  38. package/src/lib/shared/components/drop-down/drop-down.spec.ts +335 -0
  39. package/src/lib/shared/components/drop-down/drop-down.ts +335 -0
  40. package/src/lib/shared/components/footer/footer.css +29 -0
  41. package/src/lib/shared/components/footer/footer.html +10 -0
  42. package/src/lib/shared/components/footer/footer.spec.ts +22 -0
  43. package/src/lib/shared/components/footer/footer.ts +15 -0
  44. package/src/lib/shared/components/index.ts +19 -0
  45. package/src/lib/shared/components/kpi/kpi.css +0 -0
  46. package/src/lib/shared/components/kpi/kpi.html +11 -0
  47. package/src/lib/shared/components/kpi/kpi.spec.ts +38 -0
  48. package/src/lib/shared/components/kpi/kpi.ts +25 -0
  49. package/src/lib/shared/components/links-button/links-button.css +70 -0
  50. package/src/lib/shared/components/links-button/links-button.html +23 -0
  51. package/src/lib/shared/components/links-button/links-button.spec.ts +139 -0
  52. package/src/lib/shared/components/links-button/links-button.ts +45 -0
  53. package/src/lib/shared/components/paginator/paginator.css +0 -0
  54. package/src/lib/shared/components/paginator/paginator.html +10 -0
  55. package/src/lib/shared/components/paginator/paginator.spec.ts +23 -0
  56. package/src/lib/shared/components/paginator/paginator.ts +25 -0
  57. package/src/lib/shared/components/stepper/step/step.css +8 -0
  58. package/src/lib/shared/components/stepper/step/step.html +1 -0
  59. package/src/lib/shared/components/stepper/step/step.spec.ts +131 -0
  60. package/src/lib/shared/components/stepper/step/step.ts +14 -0
  61. package/src/lib/shared/components/stepper/stepper.css +17 -0
  62. package/src/lib/shared/components/stepper/stepper.html +11 -0
  63. package/src/lib/shared/components/stepper/stepper.spec.ts +238 -0
  64. package/src/lib/shared/components/stepper/stepper.ts +57 -0
  65. package/src/lib/shared/components/tab-group/tab-group.component.html +84 -0
  66. package/src/lib/shared/components/tab-group/tab-group.component.scss +151 -0
  67. package/src/lib/shared/components/tab-group/tab-group.spec.ts +22 -0
  68. package/src/lib/shared/components/tab-group/tab-group.ts +218 -0
  69. package/src/lib/shared/components/tab-panel/tab-content.directive.ts +7 -0
  70. package/src/lib/shared/components/tab-panel/tab-label.directive.ts +7 -0
  71. package/src/lib/shared/components/tab-panel/tab-panel.css +0 -0
  72. package/src/lib/shared/components/tab-panel/tab-panel.spec.ts +22 -0
  73. package/src/lib/shared/components/tab-panel/tab-panel.ts +31 -0
  74. package/src/lib/shared/components/time-picker/time-picker.css +84 -0
  75. package/src/lib/shared/components/time-picker/time-picker.html +21 -0
  76. package/src/lib/shared/components/time-picker/time-picker.spec.ts +23 -0
  77. package/src/lib/shared/components/time-picker/time-picker.ts +90 -0
  78. package/types/ngx-opalbytes-components.d.ts +70 -13
@@ -0,0 +1,63 @@
1
+ import { CommonModule } from "@angular/common";
2
+ import { Component, EventEmitter, Input, Output } from "@angular/core";
3
+ import { MatTooltip } from "@angular/material/tooltip";
4
+
5
+ export type CaoCardVariant = "horizontal" | "square";
6
+
7
+ export interface ICaoCardBadge {
8
+ label: string;
9
+ color?: string;
10
+ borderColor?: string;
11
+ bg?: string;
12
+ }
13
+
14
+ export interface ICaoCardMeta {
15
+ icon: string;
16
+ label: string;
17
+ }
18
+
19
+ export interface ICaoCardAvatar {
20
+ initials?: string;
21
+ src?: string;
22
+ color?: string;
23
+ }
24
+
25
+
26
+ @Component({
27
+ selector: "cao-card",
28
+ templateUrl: "./card.component.html",
29
+ styleUrl: "./card.component.css",
30
+ imports: [CommonModule, MatTooltip],
31
+ })
32
+ export class CaoCardComponent {
33
+ @Input() variant: CaoCardVariant = "horizontal";
34
+ @Input() title?: string;
35
+ @Input() subtitle?: string;
36
+ @Input() detail?: string;
37
+ @Input() detailColor?: string;
38
+ @Input() icon?: string;
39
+ @Input() avatar?: ICaoCardAvatar;
40
+ @Input() meta?: ICaoCardMeta[];
41
+ @Input() badge?: ICaoCardBadge;
42
+ @Input() selected = false;
43
+ @Input() clickable = false;
44
+ @Input() bgColor="bg-white"
45
+ @Input() borderColor="border-gray-200"
46
+
47
+ @Output() readonly cardClick = new EventEmitter<void>();
48
+
49
+ get avatarBg(): string {
50
+ return this.avatar?.color ?? "bg-orange-400";
51
+ }
52
+
53
+ handleClick(): void {
54
+ if (this.clickable) {this.cardClick.emit();}
55
+ }
56
+
57
+ handleKeydown(event: KeyboardEvent): void {
58
+ if (this.clickable && (event.key === "Enter" || event.key === " ")) {
59
+ event.preventDefault();
60
+ this.cardClick.emit();
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,82 @@
1
+ <div class="form-field input-component" [class.search-mode]="searchMode">
2
+ <mat-form-field class="datepicker-form-field">
3
+ <div
4
+ class="input-wrapper"
5
+ [class.has-leading-icon]="_leadingIcon"
6
+ [class.has-trailing-icon]="_trailingIcon"
7
+ [class.focused]="isFocused">
8
+
9
+ @if (_leadingIcon) {
10
+ @if (isLucideIcon) {
11
+ <div class="icon"
12
+ tabindex="0"
13
+ (click)="onLeadingIconClick($event)"
14
+ (keydown.enter)="onLeadingIconClick($event)"
15
+ >
16
+ <svg [lucideIcon]="_leadingIcon" [style.color]="iconColor"></svg>
17
+ </div>
18
+ } @else {
19
+ <div class="icon"
20
+ tabindex="0"
21
+ (click)="onLeadingIconClick($event)"
22
+ (keydown.enter)="onLeadingIconClick($event)">
23
+ <img alt="ícone de início" [src]="_leadingIcon" />
24
+ </div>
25
+ }
26
+ }
27
+
28
+ <input
29
+ matTooltip="{{ tooltip }}"
30
+ matTooltipPosition="below"
31
+ matTooltipClass="custom-arrow-tooltip"
32
+ matInput
33
+ [disabled]="isDisabled"
34
+ [matDatepicker]="pickerCao"
35
+ [attr.data-cy]="dataCy"
36
+ [placeholder]="placeholder"
37
+ [ngClass]="[
38
+ inputClass,
39
+ control?.touched && control?.invalid ? 'invalid' : '',
40
+ control?.touched && control?.valid && control?.value ? 'valid' : ''
41
+ ]"
42
+ [min]="minDate"
43
+ [max]="maxDate"
44
+ [(ngModel)]="value"
45
+ (input)="onInput($event)"
46
+ (change)="onInputChange($event)"
47
+ (focus)="onFocus()"
48
+ (blur)="onBlur()" />
49
+
50
+ @if (dateHint) {
51
+ <mat-hint>{{ dateHint }}</mat-hint>
52
+ }
53
+
54
+ <mat-datepicker-toggle matIconSuffix [for]="pickerCao" />
55
+
56
+ <mat-datepicker
57
+ #pickerCao
58
+ [startAt]="value || null" />
59
+
60
+ @if (_trailingIcon) {
61
+ @if (isLucideIcon) {
62
+ <div class="icon trailing-icon"
63
+ tabindex="0"
64
+ (click)="onTrailingIconClick($event)"
65
+ (keydown.enter)="onTrailingIconClick($event)"
66
+ >
67
+ <svg [lucideIcon]="_trailingIcon" [style.color]="iconColor"></svg>
68
+ </div>
69
+ } @else {
70
+ <div class="icon trailing-icon"
71
+ tabindex="0"
72
+ (click)="onTrailingIconClick($event)"
73
+ (keydown.enter)="onTrailingIconClick($event)"
74
+ >
75
+ <img alt="ícone de fim" [src]="_trailingIcon" />
76
+ </div>
77
+ }
78
+ }
79
+
80
+ </div>
81
+ </mat-form-field>
82
+ </div>
@@ -0,0 +1,8 @@
1
+ @use '@angular/material' as mat;
2
+
3
+
4
+ ::ng-deep .datepicker-form-field {
5
+ --mat-form-field-outlined-outline-color: transparent;
6
+ --mat-form-field-outlined-hover-outline-color: transparent;
7
+ --mat-form-field-outlined-focus-outline-color: transparent;
8
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CaoDatePicker } from './date-picker';
4
+
5
+ describe('CaoDatePicker', () => {
6
+ let component: CaoDatePicker;
7
+ let fixture: ComponentFixture<CaoDatePicker>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CaoDatePicker]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(CaoDatePicker);
16
+ component = fixture.componentInstance;
17
+ await fixture.whenStable();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,165 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
3
+ import { AbstractControl, ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
4
+ import { MatDatepicker } from '@angular/material/datepicker';
5
+ import { MatTooltipModule } from '@angular/material/tooltip';
6
+
7
+ import { LucideDynamicIcon } from '@lucide/angular';
8
+
9
+ import { MaterialModule } from "../../../material.module";
10
+
11
+ @Component({
12
+ selector: 'cao-date-picker',
13
+ imports: [CommonModule, FormsModule, MatTooltipModule, LucideDynamicIcon, MaterialModule],
14
+ templateUrl: './date-picker.html',
15
+ styleUrl: './date-picker.scss',
16
+ providers: [
17
+ {
18
+ provide: NG_VALUE_ACCESSOR,
19
+ useExisting: CaoDatePicker,
20
+ multi: true,
21
+ },
22
+ ],
23
+ })
24
+ export class CaoDatePicker implements ControlValueAccessor {
25
+ @Input() placeholder = "";
26
+ @Input() inputClass = "";
27
+ @Input() value: string | number | boolean | Date = "";
28
+ @Input() errorMessage = "";
29
+ @Input() isDisabled = false;
30
+ @Input() maxLength?: number;
31
+ @Input() searchMode = false;
32
+ @Input() showBorder = false;
33
+ @Input() isLucideIcon = false;
34
+ @Input() iconColor = "";
35
+ @Input() control?: AbstractControl | null;
36
+ @Input() tooltip = "";
37
+ @Input() dataCy?: string = "";
38
+ @Input() dateHint?: string;
39
+ @Input() controlName = "";
40
+
41
+ @Input() openOnFocus = true;
42
+
43
+ @Input() minDate: Date | null = null;
44
+ @Input() maxDate: Date | null = null;
45
+
46
+ @Input() set leadingIcon(value: string) {
47
+ this._leadingIcon = value;
48
+ this.icon = true;
49
+ }
50
+
51
+ @Input() set trailingIcon(value: string) {
52
+ this._trailingIcon = value;
53
+ this.icon = true;
54
+ }
55
+
56
+ @Output() readonly valueChange = new EventEmitter<string>();
57
+ @Output() readonly searchClick = new EventEmitter<void>();
58
+ @Output() readonly inputChange = new EventEmitter<string>();
59
+ @Output() readonly leadingIconClick = new EventEmitter<MouseEvent | Event>();
60
+ @Output() readonly trailingIconClick = new EventEmitter<MouseEvent | Event>();
61
+
62
+ @ViewChild('pickerCao') picker!: MatDatepicker<Date>;
63
+
64
+ isFocused = false;
65
+ icon = false;
66
+ _leadingIcon?: string;
67
+ _trailingIcon?: string;
68
+
69
+ onChange: (value: any) => void = () => {};
70
+ onTouched: () => void = () => {};
71
+
72
+ get hasError(): boolean {
73
+ return !!this.errorMessage;
74
+ }
75
+
76
+ get controlNameValue(): string {
77
+ return this.controlName;
78
+ }
79
+
80
+ onInput(event: Event): void {
81
+ const newValue = (event.target as HTMLInputElement).value;
82
+ this.value = newValue;
83
+ this.onChange(newValue);
84
+ this.valueChange.emit(newValue);
85
+ }
86
+
87
+ onInputChange(event: Event): void {
88
+ const newValue = (event.target as HTMLInputElement).value;
89
+ this.value = newValue;
90
+ this.inputChange.emit(newValue);
91
+ }
92
+
93
+ onFocus(): void {
94
+ this.isFocused = true;
95
+
96
+ if (this.openOnFocus && this.picker && !this.picker.opened) {
97
+ this.picker.open();
98
+ }
99
+
100
+ this.onTouched();
101
+ }
102
+
103
+ onBlur(): void {
104
+ this.isFocused = false;
105
+ this.onTouched();
106
+
107
+ if (this.control?.touched && this.control?.valid && this.control?.value) {
108
+ setTimeout(() => {
109
+ const active = document.activeElement as HTMLElement;
110
+ const current = document.querySelector(`[formcontrolname="${this.controlNameValue}"]`);
111
+ if (!current || !active || !current.contains(active)) {
112
+ this.control?.markAsUntouched();
113
+ }
114
+ });
115
+ }
116
+ }
117
+
118
+ onSearchClick(): void {
119
+ this.searchClick.emit();
120
+ }
121
+
122
+ onLeadingIconClick(event: MouseEvent | Event): void {
123
+ event.stopPropagation();
124
+ this.leadingIconClick.emit(event);
125
+ }
126
+ onTrailingIconClick(event: MouseEvent | Event): void {
127
+ event.stopPropagation();
128
+ this.trailingIconClick.emit(event);
129
+ }
130
+
131
+ openPicker(): void {
132
+ if (this.picker && !this.picker.opened) {
133
+ this.picker.open();
134
+ }
135
+ }
136
+
137
+ closePicker(): void {
138
+ if (this.picker?.opened) {
139
+ this.picker.close();
140
+ }
141
+ }
142
+
143
+ clearValue(): void {
144
+ this.value = "";
145
+ this.onChange(null);
146
+ this.onTouched();
147
+ this.valueChange.emit("");
148
+ }
149
+
150
+ writeValue(value: string | null | undefined): void {
151
+ this.value = value || "";
152
+ }
153
+
154
+ registerOnChange(fn: (value: any) => void): void {
155
+ this.onChange = fn;
156
+ }
157
+
158
+ registerOnTouched(fn: () => void): void {
159
+ this.onTouched = fn;
160
+ }
161
+
162
+ setDisabledState(isDisabled: boolean): void {
163
+ this.isDisabled = isDisabled;
164
+ }
165
+ }
@@ -0,0 +1,61 @@
1
+ /* Add these focus states to your existing CSS */
2
+
3
+ .dropdown-header:focus {
4
+ outline: 2px solid var(--primary);
5
+ outline-offset: 2px;
6
+ }
7
+
8
+ .dropdown-header:focus:not(:focus-visible) {
9
+ outline: none;
10
+ }
11
+
12
+ .dropdown-search input:focus {
13
+ outline: 2px solid var(--primary);
14
+ outline-offset: 2px;
15
+ }
16
+
17
+ .dropdown-item:focus {
18
+ outline: 2px solid var(--primary);
19
+ outline-offset: -2px;
20
+ }
21
+
22
+ /* Enhanced focused state */
23
+ .dropdown-item.focused {
24
+ background-color: var(--hover-drop-down);
25
+ font-weight: bold;
26
+ }
27
+
28
+ /* Ensure proper contrast for disabled state */
29
+ .dropdown-container.disabled {
30
+ opacity: 0.6;
31
+ }
32
+
33
+ /* Scrollbar improvements for better UX */
34
+ .dropdown-list::-webkit-scrollbar {
35
+ width: 8px;
36
+ }
37
+
38
+ .dropdown-list::-webkit-scrollbar-track {
39
+ background: rgba(0, 0, 0, 0.05);
40
+ border-radius: 4px;
41
+ }
42
+
43
+ .dropdown-list::-webkit-scrollbar-thumb {
44
+ background: rgba(0, 0, 0, 0.2);
45
+ border-radius: 4px;
46
+ }
47
+
48
+ .dropdown-list::-webkit-scrollbar-thumb:hover {
49
+ background: rgba(0, 0, 0, 0.3);
50
+ }
51
+
52
+ /* Ensure dropdown doesn't go off-screen on mobile */
53
+ @media screen and (max-width: 768px) {
54
+ .dropdown-list {
55
+ max-height: 180px;
56
+ }
57
+
58
+ .dropdown-list.drop-up {
59
+ bottom: 45px;
60
+ }
61
+ }
@@ -0,0 +1,96 @@
1
+ <div
2
+ class="dropdown-container"
3
+ role="combobox"
4
+ [ngClass]="[
5
+ dropDownClass,
6
+ isDisabled ? 'disabled' : '',
7
+ control?.touched && control?.invalid ? 'invalid' : '',
8
+ (control?.touched && control?.valid && selectedItem && isFocused && !removeValidBorder) ? 'valid' : ''
9
+ ]"
10
+ [ngStyle]="styleDropDown"
11
+ [attr.aria-expanded]="isOpen"
12
+ [attr.aria-haspopup]="'listbox'"
13
+ [attr.aria-controls]="isOpen ? ('dropdown-list-' + dataCy) : null"
14
+ [attr.aria-labelledby]="ariaLabelledBy || null"
15
+ [attr.aria-label]="ariaLabel || null"
16
+ [attr.aria-disabled]="isDisabled"
17
+ [attr.aria-activedescendant]="activeDescendant"
18
+ [attr.data-cy]="dataCy">
19
+
20
+ <div
21
+ class="dropdown-header"
22
+ matTooltipPosition="below"
23
+ matTooltipClass="custom-arrow-tooltip"
24
+ tabindex="0"
25
+ role="button"
26
+ [matTooltip]="tooltip"
27
+ [attr.aria-disabled]="isDisabled"
28
+ (click)="!isDisabled && toggleDropdown()"
29
+ (keydown.enter)="!isDisabled && toggleDropdown()"
30
+ (keydown.space)="!isDisabled && toggleDropdown(); $event.preventDefault()"
31
+ (keydown.arrowdown)="!isDisabled && onArrowDown($event)"
32
+ (keydown.arrowup)="!isDisabled && onArrowUp($event)"
33
+ (keydown.escape)="!isDisabled && closeDropdown()">
34
+ <span id="dropdown-label-{{dataCy}}">{{ selectedItem?.nome ?? textHeader }}</span>
35
+ <mat-icon aria-hidden="true">{{ isOpen ? 'expand_less' : 'expand_more' }}</mat-icon>
36
+ </div>
37
+
38
+ @if (isOpen) {
39
+ <ul
40
+ class="dropdown-list"
41
+ role="listbox"
42
+ [id]="'dropdown-list-' + dataCy"
43
+ [ngClass]="{ 'drop-up': dropDirection === 'up', 'dropdown-secundary': dropDownClass === 'dropdown-secundary' }"
44
+ [attr.aria-label]="listAriaLabel || 'Opções'"
45
+ [attr.aria-labelledby]="'dropdown-label-' + dataCy">
46
+
47
+
48
+ <li class="dropdown-search" role="none">
49
+ <input
50
+ type="text"
51
+ placeholder="Buscar por código ou nome..."
52
+ role="searchbox"
53
+ aria-label="Buscar opções"
54
+ [formControl]="searchControl"
55
+ (keydown.arrowdown)="onArrowDown($event)"
56
+ (keydown.arrowup)="onArrowUp($event)"
57
+ (keydown.enter)="onSearchEnter($event)"
58
+ (keydown.escape)="closeDropdown()" />
59
+ </li>
60
+
61
+
62
+ @for (item of filteredOptions; track $index) {
63
+ @if(item && item.nome) {
64
+ <li
65
+ class="dropdown-item"
66
+ role="option"
67
+ [ngClass]="{
68
+ 'icon-right': item.iconPosition === 'right',
69
+ 'selected': item === selectedItem,
70
+ 'focused': $index === focusedIndex
71
+ }"
72
+ [attr.id]="'option-' + dataCy + '-' + $index"
73
+ [attr.aria-selected]="item === selectedItem"
74
+ [attr.tabindex]="$index === focusedIndex ? 0 : -1"
75
+ [attr.data-cy]="item.dataCy"
76
+ (click)="selectItem(item)"
77
+ (keydown.enter)="selectItem(item)"
78
+ (keydown.space)="selectItem(item); $event.preventDefault()"
79
+ (mouseenter)="focusedIndex = $index">
80
+ @if (item.icon && item.iconPosition !== 'right') {
81
+ <mat-icon class="dropdown-icon" aria-hidden="true">{{ item.icon }}</mat-icon>
82
+ }
83
+ <span>{{ item.nome }}</span>
84
+ @if (item.icon && item.iconPosition === 'right') {
85
+ <mat-icon class="dropdown-icon" aria-hidden="true">{{ item.icon }}</mat-icon>
86
+ }
87
+ </li>
88
+ }
89
+ }
90
+ </ul>
91
+ }
92
+
93
+ @if (control?.touched && control?.invalid && errorText) {
94
+ <div class="message-error">{{ errorText }}</div>
95
+ }
96
+ </div>