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,218 @@
1
+ import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
2
+ import {
3
+ Component,
4
+ ContentChildren,
5
+ QueryList,
6
+ AfterContentInit,
7
+ OnDestroy,
8
+ Input,
9
+ Output,
10
+ EventEmitter,
11
+ signal,
12
+ WritableSignal,
13
+ inject,
14
+ PLATFORM_ID,
15
+ ElementRef,
16
+ ViewChildren,
17
+ ViewChild,
18
+ HostBinding,
19
+ } from '@angular/core';
20
+
21
+ import { LucideDynamicIcon } from '@lucide/angular';
22
+ import { Subscription } from 'rxjs';
23
+
24
+ import { CaoTabPanel } from '../tab-panel/tab-panel';
25
+
26
+
27
+ export interface ICaoTabChangeEvent {
28
+ previousIndex: number;
29
+ index: number;
30
+ tab: CaoTabPanel;
31
+ }
32
+
33
+ @Component({
34
+ selector: 'cao-tab-group',
35
+ standalone: true,
36
+ imports: [NgTemplateOutlet, LucideDynamicIcon],
37
+ templateUrl: './tab-group.component.html',
38
+ styleUrl: './tab-group.component.scss',
39
+ host: { class: 'cao-tab-group' },
40
+ })
41
+ export class CaoTabGroup implements AfterContentInit, OnDestroy {
42
+ @HostBinding('style')
43
+ get _hostStyles(): Record<string, string> {
44
+ return {
45
+ '--cao-tab-label-height': this.labelHeight,
46
+ '--cao-tab-label-px': this.labelPaddingX,
47
+ '--cao-tab-label-gap': this.labelGap,
48
+ '--cao-tab-color-text': this.colorText,
49
+ '--cao-tab-color-active': this.colorActive,
50
+ '--cao-tab-color-hover-bg': this.colorHoverBg,
51
+ '--cao-tab-color-disabled': this.colorDisabled,
52
+ '--cao-tab-color-ink-bar': this.colorInkBar,
53
+ '--cao-tab-color-header-border': this.colorHeaderBorder,
54
+ '--cao-tab-ink-bar-height': this.inkBarHeight,
55
+ '--cao-tab-content-pt': this.contentPaddingTop,
56
+ '--cao-tab-radius': this.labelRadius,
57
+ };
58
+ }
59
+ @Input()
60
+ set selectedIndex(val: number) {
61
+ this.selectIndex(val, false);
62
+ }
63
+ get selectedIndex(): number {
64
+ return this.activeIndex();
65
+ }
66
+
67
+ @Input() labelHeight = '48px';
68
+ @Input() labelPaddingX = '16px';
69
+ @Input() labelGap = '6px';
70
+ @Input() colorText = '#6b7280';
71
+ @Input() colorActive = '#4f46e5';
72
+ @Input() colorHoverBg = '#f3f4f6';
73
+ @Input() colorDisabled = '#d1d5db';
74
+ @Input() colorInkBar = '#4f46e5';
75
+ @Input() colorHeaderBorder = '#e5e7eb';
76
+ @Input() inkBarHeight = '2px';
77
+ @Input() contentPaddingTop = '20px';
78
+ @Input() labelRadius = '4px';
79
+ @Input() animationDuration = '300ms';
80
+ @Input() dynamicHeight = false;
81
+
82
+ @Input() labelAlign: 'start' | 'center' | 'end' = 'start';
83
+ @Input() iconColorActive = ''
84
+ @Input() iconColorInactive = ''
85
+ @Input() strokeWidthIcon = 1
86
+
87
+ @Output() readonly selectedTabChange = new EventEmitter<ICaoTabChangeEvent>();
88
+
89
+ @Output() readonly focusChange = new EventEmitter<number>();
90
+
91
+ @ContentChildren(CaoTabPanel) tabs!: QueryList<CaoTabPanel>;
92
+ @ViewChildren('tabBtn') tabBtns!: QueryList<ElementRef<HTMLButtonElement>>;
93
+ @ViewChild('inkBar') inkBar!: ElementRef<HTMLElement>;
94
+
95
+ readonly activeIndex: WritableSignal<number> = signal(0);
96
+
97
+ private activatedSet = new Set<number>();
98
+
99
+ tabList: CaoTabPanel[] = [];
100
+
101
+ private subs = new Subscription();
102
+ private isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
103
+
104
+ ngAfterContentInit(): void {
105
+ this.tabList = this.tabs.toArray();
106
+ this.activatedSet.add(this.activeIndex());
107
+
108
+ this.subs.add(
109
+ this.tabs.changes.subscribe(() => {
110
+ this.tabList = this.tabs.toArray();
111
+ const safe = Math.min(this.activeIndex(), this.tabList.length - 1);
112
+ this.activeIndex.set(Math.max(0, safe));
113
+ this.scheduleInkBar();
114
+ })
115
+ );
116
+
117
+ this.scheduleInkBar();
118
+ }
119
+
120
+ ngOnDestroy(): void {
121
+ this.subs.unsubscribe();
122
+ }
123
+
124
+ selectTab(index: number): void {
125
+ this.selectIndex(index, true);
126
+ }
127
+
128
+ get activeTab(): CaoTabPanel | null {
129
+ return this.tabList[this.activeIndex()] ?? null;
130
+ }
131
+
132
+ isActive(index: number): boolean {
133
+ return this.activeIndex() === index;
134
+ }
135
+ wasActivated(index: number): boolean {
136
+ return this.activatedSet.has(index);
137
+ }
138
+
139
+ onTabClick(index: number): void {
140
+ if (this.tabList[index]?.isDisabled) {return;}
141
+ this.selectIndex(index, true);
142
+ }
143
+
144
+ onKeydown(event: KeyboardEvent, currentIndex: number): void {
145
+ let next = currentIndex;
146
+
147
+ switch (event.key) {
148
+ case 'ArrowRight': next = this.nextEnabled(currentIndex, 1); break;
149
+ case 'ArrowLeft': next = this.nextEnabled(currentIndex, -1); break;
150
+ case 'Home': next = this.nextEnabled(-1, 1); break;
151
+ case 'End': next = this.nextEnabled(this.tabList.length, -1); break;
152
+ default: return;
153
+ }
154
+
155
+ event.preventDefault();
156
+ this.selectIndex(next, true);
157
+ this.focusTab(next);
158
+ }
159
+
160
+ onFocus(index: number): void {
161
+ this.focusChange.emit(index);
162
+ }
163
+
164
+ private nextEnabled(from: number, dir: 1 | -1): number {
165
+ const tabs = this.tabList;
166
+ let idx = from + dir;
167
+ while (idx >= 0 && idx < tabs.length) {
168
+ if (!tabs[idx].isDisabled) {return idx;}
169
+ idx += dir;
170
+ }
171
+ return from;
172
+ }
173
+
174
+ private selectIndex(index: number, emit: boolean): void {
175
+ if (!this.tabList) {
176
+ this.activeIndex.set(Math.max(0, index));
177
+ return;
178
+ }
179
+ const clamped = Math.max(0, Math.min(index, this.tabList.length - 1));
180
+ const previous = this.activeIndex();
181
+ if (clamped === previous && emit) {return;}
182
+
183
+ this.activeIndex.set(clamped);
184
+ this.activatedSet.add(clamped);
185
+
186
+ if (emit) {
187
+ this.selectedTabChange.emit({
188
+ previousIndex: previous,
189
+ index: clamped,
190
+ tab: this.tabList[clamped],
191
+ });
192
+ }
193
+
194
+ this.scheduleInkBar();
195
+ }
196
+
197
+ private focusTab(index: number): void {
198
+ this.tabBtns?.toArray()[index]?.nativeElement?.focus();
199
+ }
200
+
201
+ scheduleInkBar(): void {
202
+ if (!this.isBrowser) {return;}
203
+ requestAnimationFrame(() => this.updateInkBar());
204
+ }
205
+
206
+ private updateInkBar(): void {
207
+ const btns = this.tabBtns?.toArray();
208
+ const bar = this.inkBar?.nativeElement;
209
+ if (!btns || !bar) {return;}
210
+
211
+ const btn = btns[this.activeIndex()]?.nativeElement;
212
+ if (!btn) {return;}
213
+
214
+ bar.style.width = `${btn.offsetWidth}px`;
215
+ bar.style.transform = `translateX(${btn.offsetLeft}px)`;
216
+ bar.style.transitionDuration = this.animationDuration;
217
+ }
218
+ }
@@ -0,0 +1,7 @@
1
+ import { Directive } from '@angular/core';
2
+
3
+ @Directive({
4
+ selector: '[caoTabContent]',
5
+ standalone: true,
6
+ })
7
+ export class CaoTabContentDirective {}
@@ -0,0 +1,7 @@
1
+ import { Directive } from '@angular/core';
2
+
3
+ @Directive({
4
+ selector: '[caoTabLabel]',
5
+ standalone: true,
6
+ })
7
+ export class CaoTabLabelDirective {}
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from "@angular/core/testing";
2
+
3
+ import { CaoTabPanel } from "./tab-panel";
4
+
5
+ describe("CaoTabPanel", () => {
6
+ let component: CaoTabPanel;
7
+ let fixture: ComponentFixture<CaoTabPanel>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CaoTabPanel],
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(CaoTabPanel);
15
+ component = fixture.componentInstance;
16
+ await fixture.whenStable();
17
+ });
18
+
19
+ it("should create", () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,31 @@
1
+ import { Component, ContentChild, Input, TemplateRef, ViewChild } from "@angular/core"
2
+
3
+ import { CaoTabContentDirective } from "./tab-content.directive"
4
+ import { CaoTabLabelDirective } from "./tab-label.directive"
5
+
6
+ @Component({
7
+ selector: "cao-tab-panel",
8
+ imports: [],
9
+ template: `
10
+ <ng-template #implicitContent>
11
+ <ng-content />
12
+ </ng-template>
13
+ `,
14
+ styleUrl: "./tab-panel.css",
15
+ })
16
+ export class CaoTabPanel {
17
+ @Input() label = ''
18
+ @Input() isLucideIcon = true
19
+ @Input() trailingIcon: string | null = null
20
+ @Input() leadingIcon: string | null = null
21
+ @Input() isDisabled = false
22
+
23
+ @ContentChild(CaoTabLabelDirective, { read: TemplateRef })
24
+ labelTemplate?: TemplateRef<unknown>;
25
+
26
+ @ContentChild(CaoTabContentDirective, { read: TemplateRef })
27
+ lazyContent?: TemplateRef<unknown>;
28
+
29
+ @ViewChild('implicitContent', { static: true })
30
+ content!: TemplateRef<unknown>;
31
+ }
@@ -0,0 +1,84 @@
1
+ .time-picker-wrapper {
2
+ width: 130px;
3
+ display: flex;
4
+ flex-direction: column;
5
+ position: relative;
6
+ }
7
+
8
+ .custom-timepicker {
9
+ width: 100%;
10
+ }
11
+
12
+ .custom-timepicker .mat-mdc-text-field-wrapper {
13
+ border: 1px solid transparent;
14
+ border-radius: 8px;
15
+ padding: 0;
16
+ height: 43px;
17
+ display: flex;
18
+ align-items: center;
19
+ background-color: var(--input-background);
20
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
21
+ transition: border-color 0.2s ease-in-out;
22
+ }
23
+
24
+ .custom-timepicker.invalid .mat-mdc-text-field-wrapper {
25
+ border-color: var(--error);
26
+ }
27
+
28
+ /* só aplica o verde de success enquanto estiver focado */
29
+ .custom-timepicker.valid.mat-focused .mat-mdc-text-field-wrapper {
30
+ border-color: var(--success);
31
+ }
32
+
33
+ /* após perder o foco, "neutraliza" o success para transparente */
34
+ .custom-timepicker.valid:not(.mat-focused) .mat-mdc-text-field-wrapper {
35
+ border-color: transparent;
36
+ }
37
+
38
+ .custom-timepicker .mdc-line-ripple {
39
+ display: none;
40
+ }
41
+
42
+ .custom-timepicker .mat-mdc-input-element {
43
+ font-size: 16px;
44
+ padding-left: 16px;
45
+ caret-color: transparent;
46
+ background: transparent;
47
+ }
48
+
49
+ .custom-timepicker .mat-mdc-icon-button.mat-mdc-button-base {
50
+ padding: 0;
51
+ border-left: 1px solid var(--line-color);
52
+ border-radius: 0;
53
+ margin: 0;
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ }
58
+
59
+ .custom-timepicker .mat-timepicker-toggle-default-icon {
60
+ color: var(--primary);
61
+ }
62
+
63
+ .custom-timepicker .mat-mdc-form-field-flex {
64
+ background-color: var(--input-background);
65
+ }
66
+
67
+ /* oculta label flutuante e subscript conforme seu estilo */
68
+ .mat-mdc-form-field:not(.mat-form-field-disabled) .mat-mdc-floating-label.mdc-floating-label {
69
+ display: none;
70
+ }
71
+
72
+ .mat-mdc-form-field-subscript-wrapper,
73
+ .mat-mdc-form-field-bottom-align::before {
74
+ display: none;
75
+ }
76
+
77
+ .custom-timepicker .mat-mdc-form-field-infix {
78
+ padding: 18px 0 !important;
79
+ }
80
+
81
+ /* remove qualquer box-shadow remanescente no outline quando focado */
82
+ .custom-timepicker.mat-form-field-appearance-outline.mat-focused .mat-form-field-outline-thick {
83
+ box-shadow: none !important;
84
+ }
@@ -0,0 +1,21 @@
1
+ <div class="time-picker-wrapper">
2
+ <mat-form-field
3
+ class="custom-timepicker"
4
+ [ngClass]="{
5
+ 'invalid': control?.touched && control?.invalid,
6
+ 'valid': control?.touched && control?.valid
7
+ }">
8
+ <input
9
+ matInput
10
+ placeholder="00:00"
11
+ [formControl]="control"
12
+ [matTimepicker]="picker"
13
+ [min]="min"
14
+ [max]="max"
15
+ [disabled]="isDisabled"
16
+ [attr.data-cy]="dataCy"
17
+ (blur)="control?.markAsTouched()" />
18
+ <mat-timepicker-toggle matSuffix [for]="picker" />
19
+ <mat-timepicker #picker [options]="customOptions" (selected)="timeChange.emit($event.value)" />
20
+ </mat-form-field>
21
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { TimePicker } from './time-picker';
4
+
5
+ describe('TimePicker', () => {
6
+ let component: TimePicker;
7
+ let fixture: ComponentFixture<TimePicker>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [TimePicker]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(TimePicker);
16
+ component = fixture.componentInstance;
17
+ await fixture.whenStable();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,90 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
3
+ import { FormControl, ReactiveFormsModule } from '@angular/forms';
4
+ import { DateAdapter } from '@angular/material/core';
5
+ import { MatTimepickerOption } from '@angular/material/timepicker';
6
+
7
+ import { MaterialModule } from '../../../material.module';
8
+
9
+ @Component({
10
+ selector: 'cao-time-picker',
11
+ imports: [ MaterialModule, CommonModule, ReactiveFormsModule, ],
12
+ templateUrl: './time-picker.html',
13
+ styleUrl: './time-picker.css',
14
+ changeDetection: ChangeDetectionStrategy.OnPush,
15
+ encapsulation: ViewEncapsulation.None,
16
+ })
17
+ export class TimePicker {
18
+ @Input() control: FormControl<Date | null> = new FormControl<Date | null>(null);
19
+ @Input() isDisabled = false;
20
+ @Input() dataCy?: string;
21
+ @Input() set min(v: string) {
22
+ this._min = v;
23
+ this.minInNumber = this.convertStringInNumber(v)
24
+ this.customOptions = this.generateTimeOptions().filter((option) => option.label >= this._min);
25
+ }
26
+ @Input() set max(v: string) {
27
+ this._max = v;
28
+ this.maxInNumber = this.convertStringInNumber(v)
29
+ this.customOptions = this.generateTimeOptions().filter((option) => option.label <= this._max);
30
+ }
31
+
32
+ minInNumber = 7;
33
+ maxInNumber = 23;
34
+
35
+ @Output() readonly timeChange = new EventEmitter<Date>();
36
+
37
+ private _min = "07:00";
38
+ private _max = "23:00";
39
+
40
+ customOptions: MatTimepickerOption<Date>[] = this.generateTimeOptions();
41
+
42
+ constructor(private _adapter: DateAdapter<any>) {
43
+ this._adapter.setLocale("pt-BR");
44
+ }
45
+
46
+ get errorText(): string | null {
47
+ if (!this.control) {return null;}
48
+
49
+ if (this.control.hasError("required") || (this.control.touched && !this.control.value)) {
50
+ return "*Campo obrigatório";
51
+ }
52
+ if (this.control.hasError("quarterHour") && this.control.touched) {
53
+ return "Formato inválido";
54
+ }
55
+ return null;
56
+ }
57
+
58
+ private convertStringInNumber(hour: string): number{
59
+ const explodedHour = parseInt(hour.split(":")[0])
60
+ if(typeof explodedHour !== 'number'){
61
+ return explodedHour
62
+ }
63
+ return explodedHour
64
+ }
65
+
66
+ private generateTimeOptions(): MatTimepickerOption<Date>[] {
67
+ const options: MatTimepickerOption<Date>[] = [];
68
+ const baseDate = new Date(2025, 0, 1);
69
+
70
+ for (let hour = this.minInNumber; hour <= this.maxInNumber; hour++) {
71
+ for (let minute = 0; minute < 60; minute += 15) {
72
+ if (hour === this.maxInNumber && minute > 0) {continue;}
73
+ const date = new Date(baseDate);
74
+ date.setHours(hour, minute, 0);
75
+ const label = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
76
+ options.push({ label, value: date });
77
+ }
78
+ }
79
+
80
+ return options;
81
+ }
82
+
83
+ updateTimeOptions(options: MatTimepickerOption<Date>[]): void {
84
+ this.customOptions = options;
85
+ }
86
+
87
+ setDisabledState(isDisabled: boolean): void {
88
+ this.isDisabled = isDisabled;
89
+ }
90
+ }
@@ -1,8 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { OnInit, EventEmitter, OnChanges, SimpleChanges, OnDestroy, ElementRef, ChangeDetectorRef, Signal, AfterContentInit, QueryList, TemplateRef, WritableSignal, AfterViewInit } from '@angular/core';
2
+ import { OnInit, EventEmitter, OnChanges, OnDestroy, AfterViewInit, ElementRef, TemplateRef, SimpleChanges, ChangeDetectorRef, Signal, AfterContentInit, QueryList, WritableSignal } from '@angular/core';
3
3
  import { ControlValueAccessor, AbstractControl, FormControl } from '@angular/forms';
4
4
  import { MatDateRangeInput } from '@angular/material/datepicker';
5
- import { MatAutocompleteTrigger, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
6
5
  import * as rxjs from 'rxjs';
7
6
  import { Observable } from 'rxjs';
8
7
  import { Router, ActivatedRoute } from '@angular/router';
@@ -30,10 +29,11 @@ declare class CaoBaseButtonComponent implements OnInit {
30
29
  iconColor?: string;
31
30
  strokeWidthIcon: number;
32
31
  minTextToTooltip: number;
32
+ iconSize: number;
33
33
  ngOnInit(): void;
34
34
  onClick(): void;
35
35
  static ɵfac: i0.ɵɵFactoryDeclaration<CaoBaseButtonComponent, never>;
36
- static ɵcmp: i0.ɵɵComponentDeclaration<CaoBaseButtonComponent, "cao-button", never, { "buttonText": { "alias": "buttonText"; "required": false; }; "isDarkMode": { "alias": "isDarkMode"; "required": false; }; "isDisabled": { "alias": "isDisabled"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "btnClass": { "alias": "btnClass"; "required": false; }; "tooltip": { "alias": "tooltip"; "required": false; }; "trailingIcon": { "alias": "trailingIcon"; "required": false; }; "leadingIcon": { "alias": "leadingIcon"; "required": false; }; "isLucideIcon": { "alias": "isLucideIcon"; "required": false; }; "dataCy": { "alias": "dataCy"; "required": false; }; "iconColor": { "alias": "iconColor"; "required": false; }; "strokeWidthIcon": { "alias": "strokeWidthIcon"; "required": false; }; "minTextToTooltip": { "alias": "minTextToTooltip"; "required": false; }; }, { "buttonClick": "buttonClick"; }, never, never, true, never>;
36
+ static ɵcmp: i0.ɵɵComponentDeclaration<CaoBaseButtonComponent, "cao-button", never, { "buttonText": { "alias": "buttonText"; "required": false; }; "isDarkMode": { "alias": "isDarkMode"; "required": false; }; "isDisabled": { "alias": "isDisabled"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "btnClass": { "alias": "btnClass"; "required": false; }; "tooltip": { "alias": "tooltip"; "required": false; }; "trailingIcon": { "alias": "trailingIcon"; "required": false; }; "leadingIcon": { "alias": "leadingIcon"; "required": false; }; "isLucideIcon": { "alias": "isLucideIcon"; "required": false; }; "dataCy": { "alias": "dataCy"; "required": false; }; "iconColor": { "alias": "iconColor"; "required": false; }; "strokeWidthIcon": { "alias": "strokeWidthIcon"; "required": false; }; "minTextToTooltip": { "alias": "minTextToTooltip"; "required": false; }; "iconSize": { "alias": "iconSize"; "required": false; }; }, { "buttonClick": "buttonClick"; }, never, never, true, never>;
37
37
  }
38
38
 
39
39
  type CaoTypeInputs = 'text' | 'textarea' | 'number' | 'password' | 'date';
@@ -110,7 +110,7 @@ interface ICaoAutoCompleteOption {
110
110
  icon?: string;
111
111
  iconPosition?: string;
112
112
  }
113
- declare class CaoAutocompleteComponent implements OnInit, OnChanges, ControlValueAccessor {
113
+ declare class CaoAutocompleteComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit, ControlValueAccessor {
114
114
  label: string;
115
115
  placeholder: string;
116
116
  options: ICaoAutoCompleteOption[];
@@ -127,43 +127,83 @@ declare class CaoAutocompleteComponent implements OnInit, OnChanges, ControlValu
127
127
  autocompleteBgColor: string;
128
128
  strokeWidthIcon: number;
129
129
  isDisabled: boolean;
130
+ inputHeigth: string;
131
+ iconSize: number;
132
+ checkIcon: string;
133
+ showCheckIcon: boolean;
134
+ isLucideCheckIcon: boolean;
130
135
  readonly itemSelected: EventEmitter<ICaoAutoCompleteOption>;
131
136
  readonly blurEvent: EventEmitter<void>;
132
137
  readonly focusEvent: EventEmitter<void>;
133
138
  readonly leadingIconClick: EventEmitter<Event | MouseEvent>;
134
139
  readonly trailingIconClick: EventEmitter<Event | MouseEvent>;
135
- autocompleteTrigger: MatAutocompleteTrigger;
140
+ inputEl: ElementRef<HTMLInputElement>;
141
+ wrapperEl: ElementRef<HTMLDivElement>;
142
+ panelTemplate: TemplateRef<any>;
143
+ /** controla apenas o texto digitado / exibido no input */
136
144
  internalControl: FormControl<string | null>;
137
145
  filteredOptions$: Observable<ICaoAutoCompleteOption[]>;
146
+ filteredOptionsList: ICaoAutoCompleteOption[];
138
147
  isFocused: boolean;
139
- icon: boolean;
148
+ isPanelOpen: boolean;
149
+ activeIndex: number;
150
+ private static uidSeq;
151
+ readonly listboxId: string;
140
152
  private selectedOption;
141
153
  private options$;
154
+ /** indica se o valor atual do internalControl foi digitado pelo usuário (e não escrito programaticamente) */
155
+ private isUserTyping;
142
156
  private el;
157
+ private cdr;
158
+ private renderer;
159
+ private overlay;
160
+ private viewContainerRef;
161
+ private scrollDispatcher;
162
+ private sub;
163
+ private overlayRef;
164
+ private portal;
143
165
  private onChange;
144
166
  private onTouched;
145
167
  ngOnInit(): void;
146
- private setStyle;
168
+ ngAfterViewInit(): void;
147
169
  ngOnChanges(changes: SimpleChanges): void;
170
+ ngOnDestroy(): void;
171
+ private setupOverlay;
172
+ private closeOverlay;
173
+ private openOverlay;
174
+ private setStyle;
175
+ openPanel(): void;
176
+ closePanel(): void;
177
+ onDocumentClick(event: MouseEvent): void;
148
178
  onFocus(): void;
149
179
  onBlur(): void;
180
+ onInputKeydown(event: KeyboardEvent): void;
181
+ private moveActiveIndex;
150
182
  selectItem(option: ICaoAutoCompleteOption): void;
151
- onOptionSelected(event: MatAutocompleteSelectedEvent): void;
152
183
  selectOption(option: ICaoAutoCompleteOption): void;
153
- closePanel(): void;
154
184
  clearSelection(): void;
155
185
  onLeadingIconClick(event: MouseEvent | Event): void;
156
186
  onTrailingIconClick(event: MouseEvent | Event): void;
157
187
  private filter;
188
+ /** Move a opção selecionada para o início da lista, mantendo a ordem das demais */
189
+ private moveSelectedToTop;
190
+ private writeDisplayValue;
191
+ /** Marca que o usuário está digitando manualmente no campo (ativa o filtro por texto) */
192
+ onUserInput(): void;
158
193
  displayFn(option: ICaoAutoCompleteOption): string;
194
+ isOptionSelected(option: ICaoAutoCompleteOption): boolean;
195
+ trackByOptionId(_: number, option: ICaoAutoCompleteOption): string | number;
196
+ optionId(option: ICaoAutoCompleteOption): string;
197
+ get activeOptionId(): string | null;
159
198
  get errorText(): string | null;
160
199
  get controlNameValue(): string;
161
200
  writeValue(value: ICaoAutoCompleteOption | string): void;
162
201
  registerOnChange(fn: (value: ICaoAutoCompleteOption | string | null) => void): void;
163
202
  registerOnTouched(fn: () => void): void;
164
- setInputHeight(height: string): void;
203
+ setDisabledState?(isDisabled: boolean): void;
204
+ setInputHeight(): void;
165
205
  static ɵfac: i0.ɵɵFactoryDeclaration<CaoAutocompleteComponent, never>;
166
- static ɵcmp: i0.ɵɵComponentDeclaration<CaoAutocompleteComponent, "cao-autocomplete", never, { "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "options": { "alias": "options"; "required": false; }; "control": { "alias": "control"; "required": false; }; "dataCy": { "alias": "dataCy"; "required": false; }; "controlName": { "alias": "controlName"; "required": false; }; "isLucideIcon": { "alias": "isLucideIcon"; "required": false; }; "iconColor": { "alias": "iconColor"; "required": false; }; "_leadingIcon": { "alias": "_leadingIcon"; "required": false; }; "_trailingIcon": { "alias": "_trailingIcon"; "required": false; }; "optionIcon": { "alias": "optionIcon"; "required": false; }; "optionIConColor": { "alias": "optionIConColor"; "required": false; }; "isLucideOptionIcon": { "alias": "isLucideOptionIcon"; "required": false; }; "autocompleteBgColor": { "alias": "autocompleteBgColor"; "required": false; }; "strokeWidthIcon": { "alias": "strokeWidthIcon"; "required": false; }; "isDisabled": { "alias": "isDisabled"; "required": false; }; }, { "itemSelected": "itemSelected"; "blurEvent": "blurEvent"; "focusEvent": "focusEvent"; "leadingIconClick": "leadingIconClick"; "trailingIconClick": "trailingIconClick"; }, never, never, true, never>;
206
+ static ɵcmp: i0.ɵɵComponentDeclaration<CaoAutocompleteComponent, "cao-autocomplete", never, { "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "options": { "alias": "options"; "required": false; }; "control": { "alias": "control"; "required": false; }; "dataCy": { "alias": "dataCy"; "required": false; }; "controlName": { "alias": "controlName"; "required": false; }; "isLucideIcon": { "alias": "isLucideIcon"; "required": false; }; "iconColor": { "alias": "iconColor"; "required": false; }; "_leadingIcon": { "alias": "_leadingIcon"; "required": false; }; "_trailingIcon": { "alias": "_trailingIcon"; "required": false; }; "optionIcon": { "alias": "optionIcon"; "required": false; }; "optionIConColor": { "alias": "optionIConColor"; "required": false; }; "isLucideOptionIcon": { "alias": "isLucideOptionIcon"; "required": false; }; "autocompleteBgColor": { "alias": "autocompleteBgColor"; "required": false; }; "strokeWidthIcon": { "alias": "strokeWidthIcon"; "required": false; }; "isDisabled": { "alias": "isDisabled"; "required": false; }; "inputHeigth": { "alias": "inputHeigth"; "required": false; }; "iconSize": { "alias": "iconSize"; "required": false; }; "checkIcon": { "alias": "checkIcon"; "required": false; }; "showCheckIcon": { "alias": "showCheckIcon"; "required": false; }; "isLucideCheckIcon": { "alias": "isLucideCheckIcon"; "required": false; }; }, { "itemSelected": "itemSelected"; "blurEvent": "blurEvent"; "focusEvent": "focusEvent"; "leadingIconClick": "leadingIconClick"; "trailingIconClick": "trailingIconClick"; }, never, never, true, never>;
167
207
  }
168
208
 
169
209
  interface ICaoDropDownOption {
@@ -403,6 +443,23 @@ declare class CaoBaseIcon {
403
443
  static ɵcmp: i0.ɵɵComponentDeclaration<CaoBaseIcon, "cao-base-icon", never, { "imgSource": { "alias": "imgSource"; "required": false; }; "isLucideIcon": { "alias": "isLucideIcon"; "required": false; }; "strokeWidthIcon": { "alias": "strokeWidthIcon"; "required": false; }; "iconColor": { "alias": "iconColor"; "required": false; }; "size": { "alias": "size"; "required": false; }; }, {}, never, never, true, never>;
404
444
  }
405
445
 
446
+ interface ICaoImage {
447
+ src: string;
448
+ alt: string;
449
+ }
450
+ interface ICaoKPI {
451
+ title: string;
452
+ value: string;
453
+ textColor: string;
454
+ borderColor: string;
455
+ icon: ICaoImage;
456
+ }
457
+ declare class CaoKpi {
458
+ readonly kpiData: i0.InputSignal<ICaoKPI>;
459
+ static ɵfac: i0.ɵɵFactoryDeclaration<CaoKpi, never>;
460
+ static ɵcmp: i0.ɵɵComponentDeclaration<CaoKpi, "cao-kpi", never, { "kpiData": { "alias": "kpiData"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
461
+ }
462
+
406
463
  type ModalType = "validation" | "finger" | "facial" | "clinic" | "graph" | "restriction" | "default";
407
464
  interface IModal {
408
465
  status: boolean;
@@ -795,5 +852,5 @@ declare class BaseAlertService {
795
852
  static ɵprov: i0.ɵɵInjectableDeclaration<BaseAlertService>;
796
853
  }
797
854
 
798
- export { BaseAlert, BaseAlertService, BaseDialog, BaseDialogService, BaseFilterTablePaginatedService, BaseFilterTableService, BaseModal, BaseModalService, BasePaginationService, BaseTable, BaseTablePaginated, BaseTableService, BaseTimeRange, CaoAutocompleteComponent, CaoBaseButtonComponent, CaoBaseIcon, CaoBaseInput, CaoDropDownComponent, CaoTabGroup, CaoTabPanel, Footer, LinksButton, Paginator, StepComponent, StepperComponent, TablePaginatedService, TimePicker, getPtBrPaginatorIntlBasePaginated, getPtBrPaginatorIntlBaseTable };
799
- export type { AlertType, CaoTypeInputs, DialogType, IAlertConfig, ICaoAutoCompleteOption, ICaoDropDownOption, ICaoTabChangeEvent, IColumnButton, IColumnConfig, IColumnPaginatedButton, IColumnPaginatedConfig, IDialogConfig, IModal, INavContent, INavLink, ITableConfig, ITablePaginatedConfig, ModalType, ModalTypeClass, ModalTypeSize };
855
+ export { BaseAlert, BaseAlertService, BaseDialog, BaseDialogService, BaseFilterTablePaginatedService, BaseFilterTableService, BaseModal, BaseModalService, BasePaginationService, BaseTable, BaseTablePaginated, BaseTableService, BaseTimeRange, CaoAutocompleteComponent, CaoBaseButtonComponent, CaoBaseIcon, CaoBaseInput, CaoDropDownComponent, CaoKpi, CaoTabGroup, CaoTabPanel, Footer, LinksButton, Paginator, StepComponent, StepperComponent, TablePaginatedService, TimePicker, getPtBrPaginatorIntlBasePaginated, getPtBrPaginatorIntlBaseTable };
856
+ export type { AlertType, CaoTypeInputs, DialogType, IAlertConfig, ICaoAutoCompleteOption, ICaoDropDownOption, ICaoImage, ICaoKPI, ICaoTabChangeEvent, IColumnButton, IColumnConfig, IColumnPaginatedButton, IColumnPaginatedConfig, IDialogConfig, IModal, INavContent, INavLink, ITableConfig, ITablePaginatedConfig, ModalType, ModalTypeClass, ModalTypeSize };