@tolle_/tolle-ui 0.0.1-beta

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 (77) hide show
  1. package/README.md +35 -0
  2. package/esm2022/lib/accordion-item.component.mjs +78 -0
  3. package/esm2022/lib/accordion.component.mjs +60 -0
  4. package/esm2022/lib/badge.component.mjs +76 -0
  5. package/esm2022/lib/button-group.component.mjs +25 -0
  6. package/esm2022/lib/button.component.mjs +70 -0
  7. package/esm2022/lib/calendar.component.mjs +315 -0
  8. package/esm2022/lib/card.component.mjs +94 -0
  9. package/esm2022/lib/checkbox.component.mjs +100 -0
  10. package/esm2022/lib/data-table.component.mjs +332 -0
  11. package/esm2022/lib/date-picker.component.mjs +232 -0
  12. package/esm2022/lib/date-range-picker.component.mjs +208 -0
  13. package/esm2022/lib/input.component.mjs +134 -0
  14. package/esm2022/lib/masked-input.component.mjs +179 -0
  15. package/esm2022/lib/modal-ref.mjs +31 -0
  16. package/esm2022/lib/modal-stack.service.mjs +26 -0
  17. package/esm2022/lib/modal.component.mjs +98 -0
  18. package/esm2022/lib/modal.mjs +27 -0
  19. package/esm2022/lib/modal.service.mjs +65 -0
  20. package/esm2022/lib/multi-select.component.mjs +231 -0
  21. package/esm2022/lib/pagination.component.mjs +279 -0
  22. package/esm2022/lib/range-calendar.component.mjs +285 -0
  23. package/esm2022/lib/select-group.component.mjs +28 -0
  24. package/esm2022/lib/select-item.component.mjs +84 -0
  25. package/esm2022/lib/select-separator.component.mjs +24 -0
  26. package/esm2022/lib/select.component.mjs +261 -0
  27. package/esm2022/lib/select.service.mjs +21 -0
  28. package/esm2022/lib/skeleton.component.mjs +34 -0
  29. package/esm2022/lib/switch.component.mjs +133 -0
  30. package/esm2022/lib/toast.service.mjs +59 -0
  31. package/esm2022/lib/tolle-cell.directive.mjs +22 -0
  32. package/esm2022/lib/tolle-config.mjs +11 -0
  33. package/esm2022/lib/tooltip.directive.mjs +71 -0
  34. package/esm2022/lib/types/date-range.mjs +2 -0
  35. package/esm2022/lib/utils/cn.mjs +6 -0
  36. package/esm2022/public-api.mjs +36 -0
  37. package/esm2022/tolle_-tolle-ui.mjs +5 -0
  38. package/fesm2022/tolle_-tolle-ui.mjs +3553 -0
  39. package/fesm2022/tolle_-tolle-ui.mjs.map +1 -0
  40. package/index.d.ts +5 -0
  41. package/lib/accordion-item.component.d.ts +13 -0
  42. package/lib/accordion.component.d.ts +14 -0
  43. package/lib/badge.component.d.ts +14 -0
  44. package/lib/button-group.component.d.ts +8 -0
  45. package/lib/button.component.d.ts +16 -0
  46. package/lib/calendar.component.d.ts +35 -0
  47. package/lib/card.component.d.ts +32 -0
  48. package/lib/checkbox.component.d.ts +23 -0
  49. package/lib/data-table.component.d.ts +45 -0
  50. package/lib/date-picker.component.d.ts +35 -0
  51. package/lib/date-range-picker.component.d.ts +36 -0
  52. package/lib/input.component.d.ts +27 -0
  53. package/lib/masked-input.component.d.ts +36 -0
  54. package/lib/modal-ref.d.ts +16 -0
  55. package/lib/modal-stack.service.d.ts +12 -0
  56. package/lib/modal.component.d.ts +19 -0
  57. package/lib/modal.d.ts +29 -0
  58. package/lib/modal.service.d.ts +18 -0
  59. package/lib/multi-select.component.d.ts +47 -0
  60. package/lib/pagination.component.d.ts +36 -0
  61. package/lib/range-calendar.component.d.ts +37 -0
  62. package/lib/select-group.component.d.ts +8 -0
  63. package/lib/select-item.component.d.ts +18 -0
  64. package/lib/select-separator.component.d.ts +8 -0
  65. package/lib/select.component.d.ts +45 -0
  66. package/lib/select.service.d.ts +10 -0
  67. package/lib/skeleton.component.d.ts +10 -0
  68. package/lib/switch.component.d.ts +39 -0
  69. package/lib/toast.service.d.ts +24 -0
  70. package/lib/tolle-cell.directive.d.ts +9 -0
  71. package/lib/tolle-config.d.ts +9 -0
  72. package/lib/tooltip.directive.d.ts +15 -0
  73. package/lib/types/date-range.d.ts +4 -0
  74. package/lib/utils/cn.d.ts +2 -0
  75. package/package.json +32 -0
  76. package/public-api.d.ts +32 -0
  77. package/theme.css +211 -0
@@ -0,0 +1,279 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, inject, Input, Output } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { cn } from './utils/cn';
4
+ import { SelectItemComponent, SelectComponent } from '@tolle/ui';
5
+ import { FormsModule } from '@angular/forms';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common";
8
+ import * as i2 from "@angular/forms";
9
+ export class PaginationComponent {
10
+ class = '';
11
+ showPageLinks = true;
12
+ showPageOptions = true;
13
+ showCurrentPageInfo = true;
14
+ currentPageInfoTemplate;
15
+ totalRecords = 0;
16
+ currentPageSize = 10;
17
+ currentPage = 1;
18
+ pageSizeOptions = [10, 20, 30, 50];
19
+ onPageNumberChange = new EventEmitter();
20
+ onPageSizeChange = new EventEmitter();
21
+ totalPages = 0;
22
+ first = 0;
23
+ last = 0;
24
+ displayPageIndex = [];
25
+ pageReport = '';
26
+ initialized = false;
27
+ cd = inject(ChangeDetectorRef);
28
+ cn = cn;
29
+ navBtnClass = 'h-8 w-8 p-0 flex items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed';
30
+ ngOnInit() {
31
+ this.initializePagination();
32
+ }
33
+ ngOnChanges(changes) {
34
+ // Only re-init if meaningful data changes
35
+ if (changes['totalRecords'] || changes['currentPage'] || changes['currentPageSize']) {
36
+ this.initializePagination();
37
+ }
38
+ }
39
+ initializePagination() {
40
+ this.calcPagination();
41
+ if (!this.initialized) {
42
+ this.initialized = true;
43
+ }
44
+ this.cd.detectChanges();
45
+ }
46
+ nextPage() {
47
+ if (this.totalPages > this.currentPage) {
48
+ this.currentPage++;
49
+ this.emitChange();
50
+ }
51
+ }
52
+ previousPage() {
53
+ if (this.currentPage > 1) {
54
+ this.currentPage--;
55
+ this.emitChange();
56
+ }
57
+ }
58
+ selectPage(page) {
59
+ if (this.currentPage === page)
60
+ return;
61
+ this.currentPage = page;
62
+ this.emitChange();
63
+ }
64
+ sizeChange(size) {
65
+ this.currentPageSize = size;
66
+ this.currentPage = 1; // Reset to page 1 on size change
67
+ this.emitChange();
68
+ }
69
+ emitChange() {
70
+ this.calcPagination();
71
+ this.onPageNumberChange.emit(this.currentPage);
72
+ this.onPageSizeChange.emit(this.currentPageSize);
73
+ this.cd.detectChanges();
74
+ }
75
+ calcPagination() {
76
+ this.totalPages = Math.ceil(this.totalRecords / this.currentPageSize) || 0;
77
+ // Bounds check
78
+ if (this.currentPage > this.totalPages && this.totalPages > 0) {
79
+ this.currentPage = this.totalPages;
80
+ }
81
+ this.first = this.totalRecords === 0 ? 0 : (this.currentPage - 1) * this.currentPageSize + 1;
82
+ this.last = Math.min(this.totalRecords, this.currentPage * this.currentPageSize);
83
+ // Calculate Sliding Window for Page Numbers (Max 5 visible)
84
+ const pages = Array.from({ length: this.totalPages }, (_, i) => i + 1);
85
+ if (this.totalPages <= 5) {
86
+ this.displayPageIndex = pages;
87
+ }
88
+ else {
89
+ let start = Math.max(0, this.currentPage - 3);
90
+ let end = start + 5;
91
+ if (end > this.totalPages) {
92
+ end = this.totalPages;
93
+ start = end - 5;
94
+ }
95
+ this.displayPageIndex = pages.slice(start, end);
96
+ }
97
+ // Template Parsing
98
+ if (this.currentPageInfoTemplate) {
99
+ this.pageReport = this.currentPageInfoTemplate.replace(/{first}|{last}|{totalRecords}|{currentPage}|{currentPageSize}|{totalPages}/g, (match) => {
100
+ switch (match) {
101
+ case '{first}': return `${this.first}`;
102
+ case '{last}': return `${this.last}`;
103
+ case '{totalRecords}': return `${this.totalRecords}`;
104
+ case '{totalPages}': return `${this.totalPages}`;
105
+ case '{currentPage}': return `${this.currentPage}`;
106
+ case '{currentPageSize}': return `${this.currentPageSize}`;
107
+ default: return match;
108
+ }
109
+ });
110
+ }
111
+ }
112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
113
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PaginationComponent, isStandalone: true, selector: "tolle-pagination", inputs: { class: "class", showPageLinks: "showPageLinks", showPageOptions: "showPageOptions", showCurrentPageInfo: "showCurrentPageInfo", currentPageInfoTemplate: "currentPageInfoTemplate", totalRecords: "totalRecords", currentPageSize: "currentPageSize", currentPage: "currentPage", pageSizeOptions: "pageSizeOptions" }, outputs: { onPageNumberChange: "onPageNumberChange", onPageSizeChange: "onPageSizeChange" }, usesOnChanges: true, ngImport: i0, template: `
114
+ <div [class]="cn('flex items-center justify-between px-2 py-4', class)">
115
+
116
+ <div *ngIf="showCurrentPageInfo" class="text-sm text-muted-foreground">
117
+ <ng-container *ngIf="currentPageInfoTemplate; else defaultReport">
118
+ {{ pageReport }}
119
+ </ng-container>
120
+ <ng-template #defaultReport>
121
+ Showing {{ first }} to {{ last }} of {{ totalRecords }} entries
122
+ </ng-template>
123
+ </div>
124
+
125
+ <div class="flex items-center space-x-6 lg:space-x-8">
126
+
127
+ <div *ngIf="showPageOptions" class="flex items-center space-x-2">
128
+ <p class="text-sm font-medium">Rows per page</p>
129
+ <tolle-select
130
+ class="w-[70px]"
131
+ size="sm"
132
+ [ngModel]="currentPageSize"
133
+ (ngModelChange)="sizeChange($event)"
134
+ >
135
+ <tolle-select-item *ngFor="let opt of pageSizeOptions" [value]="opt">
136
+ {{ opt }}
137
+ </tolle-select-item>
138
+ </tolle-select>
139
+ </div>
140
+
141
+ <div class="flex items-center space-x-2">
142
+ <div *ngIf="!showPageLinks" class="flex w-[100px] items-center justify-center text-sm font-medium">
143
+ Page {{ currentPage }} of {{ totalPages }}
144
+ </div>
145
+
146
+ <div *ngIf="showPageLinks" class="flex items-center space-x-1">
147
+ <button
148
+ (click)="previousPage()"
149
+ [disabled]="currentPage === 1"
150
+ [class]="navBtnClass"
151
+ >
152
+ <i class="ri-arrow-left-s-line"></i>
153
+ </button>
154
+
155
+ <button
156
+ *ngFor="let page of displayPageIndex"
157
+ (click)="selectPage(page)"
158
+ [class]="cn(
159
+ 'h-8 w-8 text-sm rounded-md flex items-center justify-center transition-colors',
160
+ currentPage === page
161
+ ? 'bg-primary text-primary-foreground font-medium'
162
+ : 'hover:bg-accent hover:text-accent-foreground'
163
+ )"
164
+ >
165
+ {{ page }}
166
+ </button>
167
+
168
+ <button
169
+ (click)="nextPage()"
170
+ [disabled]="currentPage === totalPages || totalPages === 0"
171
+ [class]="navBtnClass"
172
+ >
173
+ <i class="ri-arrow-right-s-line"></i>
174
+ </button>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SelectComponent, selector: "tolle-select", inputs: ["placeholder", "class", "disabled", "searchable", "size"] }, { kind: "component", type: SelectItemComponent, selector: "tolle-select-item", inputs: ["value", "class", "selected"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
180
+ }
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
182
+ type: Component,
183
+ args: [{
184
+ selector: 'tolle-pagination',
185
+ standalone: true,
186
+ imports: [CommonModule, SelectComponent, SelectItemComponent, FormsModule],
187
+ template: `
188
+ <div [class]="cn('flex items-center justify-between px-2 py-4', class)">
189
+
190
+ <div *ngIf="showCurrentPageInfo" class="text-sm text-muted-foreground">
191
+ <ng-container *ngIf="currentPageInfoTemplate; else defaultReport">
192
+ {{ pageReport }}
193
+ </ng-container>
194
+ <ng-template #defaultReport>
195
+ Showing {{ first }} to {{ last }} of {{ totalRecords }} entries
196
+ </ng-template>
197
+ </div>
198
+
199
+ <div class="flex items-center space-x-6 lg:space-x-8">
200
+
201
+ <div *ngIf="showPageOptions" class="flex items-center space-x-2">
202
+ <p class="text-sm font-medium">Rows per page</p>
203
+ <tolle-select
204
+ class="w-[70px]"
205
+ size="sm"
206
+ [ngModel]="currentPageSize"
207
+ (ngModelChange)="sizeChange($event)"
208
+ >
209
+ <tolle-select-item *ngFor="let opt of pageSizeOptions" [value]="opt">
210
+ {{ opt }}
211
+ </tolle-select-item>
212
+ </tolle-select>
213
+ </div>
214
+
215
+ <div class="flex items-center space-x-2">
216
+ <div *ngIf="!showPageLinks" class="flex w-[100px] items-center justify-center text-sm font-medium">
217
+ Page {{ currentPage }} of {{ totalPages }}
218
+ </div>
219
+
220
+ <div *ngIf="showPageLinks" class="flex items-center space-x-1">
221
+ <button
222
+ (click)="previousPage()"
223
+ [disabled]="currentPage === 1"
224
+ [class]="navBtnClass"
225
+ >
226
+ <i class="ri-arrow-left-s-line"></i>
227
+ </button>
228
+
229
+ <button
230
+ *ngFor="let page of displayPageIndex"
231
+ (click)="selectPage(page)"
232
+ [class]="cn(
233
+ 'h-8 w-8 text-sm rounded-md flex items-center justify-center transition-colors',
234
+ currentPage === page
235
+ ? 'bg-primary text-primary-foreground font-medium'
236
+ : 'hover:bg-accent hover:text-accent-foreground'
237
+ )"
238
+ >
239
+ {{ page }}
240
+ </button>
241
+
242
+ <button
243
+ (click)="nextPage()"
244
+ [disabled]="currentPage === totalPages || totalPages === 0"
245
+ [class]="navBtnClass"
246
+ >
247
+ <i class="ri-arrow-right-s-line"></i>
248
+ </button>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ `,
254
+ changeDetection: ChangeDetectionStrategy.OnPush
255
+ }]
256
+ }], propDecorators: { class: [{
257
+ type: Input
258
+ }], showPageLinks: [{
259
+ type: Input
260
+ }], showPageOptions: [{
261
+ type: Input
262
+ }], showCurrentPageInfo: [{
263
+ type: Input
264
+ }], currentPageInfoTemplate: [{
265
+ type: Input
266
+ }], totalRecords: [{
267
+ type: Input
268
+ }], currentPageSize: [{
269
+ type: Input
270
+ }], currentPage: [{
271
+ type: Input
272
+ }], pageSizeOptions: [{
273
+ type: Input
274
+ }], onPageNumberChange: [{
275
+ type: Output
276
+ }], onPageSizeChange: [{
277
+ type: Output
278
+ }] } });
279
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy90b2xsZS9zcmMvbGliL3BhZ2luYXRpb24uY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFHTCxNQUFNLEVBRVAsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDaEMsT0FBTyxFQUFDLG1CQUFtQixFQUFFLGVBQWUsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUMvRCxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUEyRTNDLE1BQU0sT0FBTyxtQkFBbUI7SUFDckIsS0FBSyxHQUFHLEVBQUUsQ0FBQztJQUNYLGFBQWEsR0FBRyxJQUFJLENBQUM7SUFDckIsZUFBZSxHQUFHLElBQUksQ0FBQztJQUN2QixtQkFBbUIsR0FBRyxJQUFJLENBQUM7SUFDM0IsdUJBQXVCLENBQVU7SUFFakMsWUFBWSxHQUFHLENBQUMsQ0FBQztJQUNqQixlQUFlLEdBQUcsRUFBRSxDQUFDO0lBQ3JCLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDaEIsZUFBZSxHQUFhLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFNUMsa0JBQWtCLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztJQUNoRCxnQkFBZ0IsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBRXhELFVBQVUsR0FBRyxDQUFDLENBQUM7SUFDZixLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNULGdCQUFn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QUFyQixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUNHLHVCQUF1QjtzQkFBL0IsS0FBSztnQkFFRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVJLGtCQUFrQjtzQkFBM0IsTUFBTTtnQkFDRyxnQkFBZ0I7c0JBQXpCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBpbmplY3QsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IGNuIH0gZnJvbSAnLi91dGlscy9jbic7XG5pbXBvcnQge1NlbGVjdEl0ZW1Db21wb25lbnQsIFNlbGVjdENvbXBvbmVudH0gZnJvbSAnQHRvbGxlL3VpJztcbmltcG9ydCB7Rm9ybXNNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndG9sbGUtcGFnaW5hdGlvbicsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIFNlbGVjdENvbXBvbmVudCwgU2VsZWN0SXRlbUNvbXBvbmVudCwgRm9ybXNNb2R1bGVdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgW2NsYXNzXT1cImNuKCdmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gcHgtMiBweS00JywgY2xhc3MpXCI+XG5cbiAgICAgIDxkaXYgKm5nSWY9XCJzaG93Q3VycmVudFBhZ2VJbmZvXCIgY2xhc3M9XCJ0ZXh0LXNtIHRleHQtbXV0ZWQtZm9yZWdyb3VuZFwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiY3VycmVudFBhZ2VJbmZvVGVtcGxhdGU7IGVsc2UgZGVmYXVsdFJlcG9ydFwiPlxuICAgICAgICAgIHt7IHBhZ2VSZXBvcnQgfX1cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjZGVmYXVsdFJlcG9ydD5cbiAgICAgICAgICBTaG93aW5nIHt7IGZpcnN0IH19IHRvIHt7IGxhc3QgfX0gb2Yge3sgdG90YWxSZWNvcmRzIH19IGVudHJpZXNcbiAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgc3BhY2UteC02IGxnOnNwYWNlLXgtOFwiPlxuXG4gICAgICAgIDxkaXYgKm5nSWY9XCJzaG93UGFnZU9wdGlvbnNcIiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIHNwYWNlLXgtMlwiPlxuICAgICAgICAgIDxwIGNsYXNzPVwidGV4dC1zbSBmb250LW1lZGl1bVwiPlJvd3MgcGVyIHBhZ2U8L3A+XG4gICAgICAgICAgPHRvbGxlLXNlbGVjdFxuICAgICAgICAgICAgY2xhc3M9XCJ3LVs3MHB4XVwiXG4gICAgICAgICAgICBzaXplPVwic21cIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwiY3VycmVudFBhZ2VTaXplXCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInNpemVDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHRvbGxlLXNlbGVjdC1pdGVtICpuZ0Zvcj1cImxldCBvcHQgb2YgcGFnZVNpemVPcHRpb25zXCIgW3ZhbHVlXT1cIm9wdFwiPlxuICAgICAgICAgICAgICB7eyBvcHQgfX1cbiAgICAgICAgICAgIDwvdG9sbGUtc2VsZWN0LWl0ZW0+XG4gICAgICAgICAgPC90b2xsZS1zZWxlY3Q+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmbGV4IGl0ZW1zLWNlbnRlciBzcGFjZS14LTJcIj5cbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIXNob3dQYWdlTGlua3NcIiBjbGFzcz1cImZsZXggdy1bMTAwcHhdIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciB0ZXh0LXNtIGZvbnQtbWVkaXVtXCI+XG4gICAgICAgICAgICBQYWdlIHt7IGN1cnJlbnRQYWdlIH19IG9mIHt7IHRvdGFsUGFnZXMgfX1cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJzaG93UGFnZUxpbmtzXCIgY2xhc3M9XCJmbGV4IGl0ZW1zLWNlbnRlciBzcGFjZS14LTFcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgKGNsaWNrKT1cInByZXZpb3VzUGFnZSgpXCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImN1cnJlbnRQYWdlID09PSAxXCJcbiAgICAgICAgICAgICAgW2NsYXNzXT1cIm5hdkJ0bkNsYXNzXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGkgY2xhc3M9XCJyaS1hcnJvdy1sZWZ0LXMtbGluZVwiPjwvaT5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBwYWdlIG9mIGRpc3BsYXlQYWdlSW5kZXhcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0UGFnZShwYWdlKVwiXG4gICAgICAgICAgICAgIFtjbGFzc109XCJjbihcbiAgICAgICAgICAgICAgICAnaC04IHctOCB0ZXh0LXNtIHJvdW5kZWQtbWQgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgdHJhbnNpdGlvbi1jb2xvcnMnLFxuICAgICAgICAgICAgICAgIGN1cnJlbnRQYWdlID09PSBwYWdlXG4gICAgICAgICAgICAgICAgICA/ICdiZy1wcmltYXJ5IHRleHQtcHJpbWFyeS1mb3JlZ3JvdW5kIGZvbnQtbWVkaXVtJ1xuICAgICAgICAgICAgICAgICAgOiAnaG92ZXI6YmctYWNjZW50IGhvdmVyOnRleHQtYWNjZW50LWZvcmVncm91bmQnXG4gICAgICAgICAgICAgIClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyBwYWdlIH19XG4gICAgICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAoY2xpY2spPVwibmV4dFBhZ2UoKVwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJjdXJyZW50UGFnZSA9PT0gdG90YWxQYWdlcyB8fCB0b3RhbFBhZ2VzID09PSAwXCJcbiAgICAgICAgICAgICAgW2NsYXNzXT1cIm5hdkJ0bkNsYXNzXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGkgY2xhc3M9XCJyaS1hcnJvdy1yaWdodC1zLWxpbmVcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgYCxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgUGFnaW5hdGlvbkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcbiAgQElucHV0KCkgY2xhc3MgPSAnJztcbiAgQElucHV0KCkgc2hvd1BhZ2VMaW5rcyA9IHRydWU7XG4gIEBJbnB1dCgpIHNob3dQYWdlT3B0aW9ucyA9IHRydWU7XG4gIEBJbnB1dCgpIHNob3dDdXJyZW50UGFnZUluZm8gPSB0cnVlO1xuICBASW5wdXQoKSBjdXJyZW50UGFnZUluZm9UZW1wbGF0ZT86IHN0cmluZztcblxuICBASW5wdXQoKSB0b3RhbFJlY29yZHMgPSAwO1xuICBASW5wdXQoKSBjdXJyZW50UGFnZVNpemUgPSAxMDtcbiAgQElucHV0KCkgY3VycmVudFBhZ2UgPSAxO1xuICBASW5wdXQoKSBwYWdlU2l6ZU9wdGlvbnM6IG51bWJlcltdID0gWzEwLCAyMCwgMzAsIDUwXTtcblxuICBAT3V0cHV0KCkgb25QYWdlTnVtYmVyQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG4gIEBPdXRwdXQoKSBvblBhZ2VTaXplQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cbiAgdG90YWxQYWdlcyA9IDA7XG4gIGZpcnN0ID0gMDtcbiAgbGFzdCA9IDA7XG4gIGRpc3BsYXlQYWdlSW5kZXg6IG51bWJlcltdID0gW107XG4gIHBhZ2VSZXBvcnQgPSAnJztcblxuICBwcml2YXRlIGluaXRpYWxpemVkID0gZmFsc2U7XG4gIHByaXZhdGUgY2QgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuICBwcm90ZWN0ZWQgY24gPSBjbjtcblxuICBuYXZCdG5DbGFzcyA9ICdoLTggdy04IHAtMCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLW1kIGJvcmRlciBib3JkZXItaW5wdXQgYmctYmFja2dyb3VuZCBob3ZlcjpiZy1hY2NlbnQgaG92ZXI6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCBkaXNhYmxlZDpvcGFjaXR5LTUwIGRpc2FibGVkOmN1cnNvci1ub3QtYWxsb3dlZCc7XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5pbml0aWFsaXplUGFnaW5hdGlvbigpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIC8vIE9ubHkgcmUtaW5pdCBpZiBtZWFuaW5nZnVsIGRhdGEgY2hhbmdlc1xuICAgIGlmIChjaGFuZ2VzWyd0b3RhbFJlY29yZHMnXSB8fCBjaGFuZ2VzWydjdXJyZW50UGFnZSddIHx8IGNoYW5nZXNbJ2N1cnJlbnRQYWdlU2l6ZSddKSB7XG4gICAgICB0aGlzLmluaXRpYWxpemVQYWdpbmF0aW9uKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplUGFnaW5hdGlvbigpOiB2b2lkIHtcbiAgICB0aGlzLmNhbGNQYWdpbmF0aW9uKCk7XG4gICAgaWYgKCF0aGlzLmluaXRpYWxpemVkKSB7XG4gICAgICB0aGlzLmluaXRpYWxpemVkID0gdHJ1ZTtcbiAgICB9XG4gICAgdGhpcy5jZC5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cblxuICBuZXh0UGFnZSgpIHtcbiAgICBpZiAodGhpcy50b3RhbFBhZ2VzID4gdGhpcy5jdXJyZW50UGFnZSkge1xuICAgICAgdGhpcy5jdXJyZW50UGFnZSsrO1xuICAgICAgdGhpcy5lbWl0Q2hhbmdlKCk7XG4gICAgfVxuICB9XG5cbiAgcHJldmlvdXNQYWdlKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYWdlID4gMSkge1xuICAgICAgdGhpcy5jdXJyZW50UGFnZS0tO1xuICAgICAgdGhpcy5lbWl0Q2hhbmdlKCk7XG4gICAgfVxuICB9XG5cbiAgc2VsZWN0UGFnZShwYWdlOiBudW1iZXIpIHtcbiAgICBpZiAodGhpcy5jdXJyZW50UGFnZSA9PT0gcGFnZSkgcmV0dXJuO1xuICAgIHRoaXMuY3VycmVudFBhZ2UgPSBwYWdlO1xuICAgIHRoaXMuZW1pdENoYW5nZSgpO1xuICB9XG5cbiAgc2l6ZUNoYW5nZShzaXplOiBudW1iZXIpIHtcbiAgICB0aGlzLmN1cnJlbnRQYWdlU2l6ZSA9IHNpemU7XG4gICAgdGhpcy5jdXJyZW50UGFnZSA9IDE7IC8vIFJlc2V0IHRvIHBhZ2UgMSBvbiBzaXplIGNoYW5nZVxuICAgIHRoaXMuZW1pdENoYW5nZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbWl0Q2hhbmdlKCk6IHZvaWQge1xuICAgIHRoaXMuY2FsY1BhZ2luYXRpb24oKTtcbiAgICB0aGlzLm9uUGFnZU51bWJlckNoYW5nZS5lbWl0KHRoaXMuY3VycmVudFBhZ2UpO1xuICAgIHRoaXMub25QYWdlU2l6ZUNoYW5nZS5lbWl0KHRoaXMuY3VycmVudFBhZ2VTaXplKTtcbiAgICB0aGlzLmNkLmRldGVjdENoYW5nZXMoKTtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY1BhZ2luYXRpb24oKTogdm9pZCB7XG4gICAgdGhpcy50b3RhbFBhZ2VzID0gTWF0aC5jZWlsKHRoaXMudG90YWxSZWNvcmRzIC8gdGhpcy5jdXJyZW50UGFnZVNpemUpIHx8IDA7XG5cbiAgICAvLyBCb3VuZHMgY2hlY2tcbiAgICBpZiAodGhpcy5jdXJyZW50UGFnZSA+IHRoaXMudG90YWxQYWdlcyAmJiB0aGlzLnRvdGFsUGFnZXMgPiAwKSB7XG4gICAgICB0aGlzLmN1cnJlbnRQYWdlID0gdGhpcy50b3RhbFBhZ2VzO1xuICAgIH1cblxuICAgIHRoaXMuZmlyc3QgPSB0aGlzLnRvdGFsUmVjb3JkcyA9PT0gMCA/IDAgOiAodGhpcy5jdXJyZW50UGFnZSAtIDEpICogdGhpcy5jdXJyZW50UGFnZVNpemUgKyAxO1xuICAgIHRoaXMubGFzdCA9IE1hdGgubWluKHRoaXMudG90YWxSZWNvcmRzLCB0aGlzLmN1cnJlbnRQYWdlICogdGhpcy5jdXJyZW50UGFnZVNpemUpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIFNsaWRpbmcgV2luZG93IGZvciBQYWdlIE51bWJlcnMgKE1heCA1IHZpc2libGUpXG4gICAgY29uc3QgcGFnZXM6IG51bWJlcltdID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogdGhpcy50b3RhbFBhZ2VzIH0sIChfLCBpKSA9PiBpICsgMSk7XG5cbiAgICBpZiAodGhpcy50b3RhbFBhZ2VzIDw9IDUpIHtcbiAgICAgIHRoaXMuZGlzcGxheVBhZ2VJbmRleCA9IHBhZ2VzO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgc3RhcnQgPSBNYXRoLm1heCgwLCB0aGlzLmN1cnJlbnRQYWdlIC0gMyk7XG4gICAgICBsZXQgZW5kID0gc3RhcnQgKyA1O1xuXG4gICAgICBpZiAoZW5kID4gdGhpcy50b3RhbFBhZ2VzKSB7XG4gICAgICAgIGVuZCA9IHRoaXMudG90YWxQYWdlcztcbiAgICAgICAgc3RhcnQgPSBlbmQgLSA1O1xuICAgICAgfVxuICAgICAgdGhpcy5kaXNwbGF5UGFnZUluZGV4ID0gcGFnZXMuc2xpY2Uoc3RhcnQsIGVuZCk7XG4gICAgfVxuXG4gICAgLy8gVGVtcGxhdGUgUGFyc2luZ1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYWdlSW5mb1RlbXBsYXRlKSB7XG4gICAgICB0aGlzLnBhZ2VSZXBvcnQgPSB0aGlzLmN1cnJlbnRQYWdlSW5mb1RlbXBsYXRlLnJlcGxhY2UoXG4gICAgICAgIC97Zmlyc3R9fHtsYXN0fXx7dG90YWxSZWNvcmRzfXx7Y3VycmVudFBhZ2V9fHtjdXJyZW50UGFnZVNpemV9fHt0b3RhbFBhZ2VzfS9nLFxuICAgICAgICAobWF0Y2gpID0+IHtcbiAgICAgICAgICBzd2l0Y2ggKG1hdGNoKSB7XG4gICAgICAgICAgICBjYXNlICd7Zmlyc3R9JzogcmV0dXJuIGAke3RoaXMuZmlyc3R9YDtcbiAgICAgICAgICAgIGNhc2UgJ3tsYXN0fSc6IHJldHVybiBgJHt0aGlzLmxhc3R9YDtcbiAgICAgICAgICAgIGNhc2UgJ3t0b3RhbFJlY29yZHN9JzogcmV0dXJuIGAke3RoaXMudG90YWxSZWNvcmRzfWA7XG4gICAgICAgICAgICBjYXNlICd7dG90YWxQYWdlc30nOiByZXR1cm4gYCR7dGhpcy50b3RhbFBhZ2VzfWA7XG4gICAgICAgICAgICBjYXNlICd7Y3VycmVudFBhZ2V9JzogcmV0dXJuIGAke3RoaXMuY3VycmVudFBhZ2V9YDtcbiAgICAgICAgICAgIGNhc2UgJ3tjdXJyZW50UGFnZVNpemV9JzogcmV0dXJuIGAke3RoaXMuY3VycmVudFBhZ2VTaXplfWA7XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gbWF0Y2g7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuIl19
@@ -0,0 +1,285 @@
1
+ import { Component, Input, forwardRef, Output, EventEmitter } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
+ import { addMonths, subMonths, startOfMonth, endOfMonth, startOfWeek, endOfWeek, eachDayOfInterval, isSameMonth, isSameDay, isToday, setMonth, setYear, addYears, subYears, isBefore, startOfDay, isWithinInterval } from 'date-fns';
5
+ import { cn } from './utils/cn';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common";
8
+ export class RangeCalendarComponent {
9
+ class = '';
10
+ disablePastDates = false;
11
+ rangeSelect = new EventEmitter(); // Emits whenever selection changes
12
+ currentView = 'date';
13
+ viewDate = new Date();
14
+ // The Range Value
15
+ value = { start: null, end: null };
16
+ weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
17
+ daysInMonth = [];
18
+ months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
19
+ years = [];
20
+ navBtnClass = cn('h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 border border-input rounded-md flex items-center justify-center hover:bg-accent hover:text-accent-foreground transition-all');
21
+ onTouched = () => { };
22
+ onChange = () => { };
23
+ cn = cn;
24
+ ngOnInit() {
25
+ this.generateDays();
26
+ this.generateYears();
27
+ }
28
+ // --- Date Generation Logic (Same as Calendar) ---
29
+ generateDays() {
30
+ const start = startOfWeek(startOfMonth(this.viewDate));
31
+ const end = endOfWeek(endOfMonth(this.viewDate));
32
+ this.daysInMonth = eachDayOfInterval({ start, end });
33
+ }
34
+ generateYears() {
35
+ const currentYear = this.viewDate.getFullYear();
36
+ this.years = Array.from({ length: 16 }, (_, i) => currentYear - 6 + i);
37
+ }
38
+ setView(view) {
39
+ this.currentView = view;
40
+ if (view === 'year')
41
+ this.generateYears();
42
+ }
43
+ prev() {
44
+ if (this.currentView === 'date') {
45
+ this.viewDate = subMonths(this.viewDate, 1);
46
+ this.generateDays();
47
+ }
48
+ else if (this.currentView === 'year') {
49
+ this.viewDate = subYears(this.viewDate, 16);
50
+ this.generateYears();
51
+ }
52
+ else if (this.currentView === 'month') {
53
+ this.viewDate = subYears(this.viewDate, 1);
54
+ }
55
+ }
56
+ next() {
57
+ if (this.currentView === 'date') {
58
+ this.viewDate = addMonths(this.viewDate, 1);
59
+ this.generateDays();
60
+ }
61
+ else if (this.currentView === 'year') {
62
+ this.viewDate = addYears(this.viewDate, 16);
63
+ this.generateYears();
64
+ }
65
+ else if (this.currentView === 'month') {
66
+ this.viewDate = addYears(this.viewDate, 1);
67
+ }
68
+ }
69
+ // --- Range Selection Logic ---
70
+ selectDate(date) {
71
+ if (this.isDateDisabled(date))
72
+ return;
73
+ const { start, end } = this.value;
74
+ // 1. If start exists but end doesn't
75
+ if (start && !end) {
76
+ if (isBefore(date, start)) {
77
+ // User clicked earlier date -> Reset start
78
+ this.value = { start: date, end: null };
79
+ }
80
+ else {
81
+ // User clicked later date -> Complete range
82
+ this.value = { start, end: date };
83
+ }
84
+ }
85
+ // 2. If neither exist OR both exist (reset)
86
+ else {
87
+ this.value = { start: date, end: null };
88
+ }
89
+ if (!isSameMonth(date, this.viewDate)) {
90
+ this.viewDate = date;
91
+ this.generateDays();
92
+ }
93
+ this.onChange(this.value);
94
+ this.rangeSelect.emit(this.value);
95
+ this.onTouched();
96
+ }
97
+ selectMonth(monthIndex) {
98
+ this.viewDate = setMonth(this.viewDate, monthIndex);
99
+ this.currentView = 'date';
100
+ this.generateDays();
101
+ }
102
+ selectYear(year) {
103
+ this.viewDate = setYear(this.viewDate, year);
104
+ this.currentView = 'date';
105
+ this.generateDays();
106
+ }
107
+ // --- Visual Styling for Range ---
108
+ getDayClass(date) {
109
+ const { start, end } = this.value;
110
+ const isOutside = !isSameMonth(date, this.viewDate);
111
+ const isDisabled = this.isDateDisabled(date);
112
+ // Range Checks
113
+ const isStart = start && isSameDay(date, start);
114
+ const isEnd = end && isSameDay(date, end);
115
+ const isInside = start && end && isWithinInterval(date, { start, end });
116
+ const isTodayDate = isToday(date);
117
+ return cn(
118
+ // Base: h-9 w-9, but we remove margins/rounding for the 'strip' effect
119
+ 'h-9 w-9 p-0 font-normal text-sm transition-all flex items-center justify-center relative z-10',
120
+ // Default State (Not selected, Not disabled)
121
+ !isInside && !isStart && !isEnd && !isDisabled && 'hover:bg-accent hover:text-accent-foreground rounded-md',
122
+ // The "Caps": Start and End
123
+ (isStart || isEnd) && 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
124
+ // The "Strip": Dates between start and end
125
+ isInside && !isStart && !isEnd && 'bg-accent text-accent-foreground rounded-none',
126
+ // Connecting the Caps to the Strip (Rectangular inside edges)
127
+ isStart && end && 'rounded-l-md rounded-r-none', isEnd && start && 'rounded-r-md rounded-l-none',
128
+ // If no end date yet, Start should be fully rounded
129
+ isStart && !end && 'rounded-md',
130
+ // Muted/Disabled logic
131
+ !isInside && isTodayDate && !isStart && !isEnd && 'bg-accent/50 text-accent-foreground rounded-md', (isOutside || isDisabled) && 'text-muted-foreground opacity-50', isDisabled && 'cursor-not-allowed');
132
+ }
133
+ isDateDisabled(date) {
134
+ return this.disablePastDates ? isBefore(date, startOfDay(new Date())) : false;
135
+ }
136
+ // --- CVA Implementation ---
137
+ writeValue(val) {
138
+ if (val) {
139
+ this.value = val;
140
+ if (val.start)
141
+ this.viewDate = val.start;
142
+ this.generateDays();
143
+ this.generateYears();
144
+ }
145
+ }
146
+ registerOnChange(fn) { this.onChange = fn; }
147
+ registerOnTouched(fn) { this.onTouched = fn; }
148
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RangeCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
149
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: RangeCalendarComponent, isStandalone: true, selector: "tolle-range-calendar", inputs: { class: "class", disablePastDates: "disablePastDates" }, outputs: { rangeSelect: "rangeSelect" }, providers: [
150
+ {
151
+ provide: NG_VALUE_ACCESSOR,
152
+ useExisting: forwardRef(() => RangeCalendarComponent),
153
+ multi: true
154
+ }
155
+ ], ngImport: i0, template: `
156
+ <div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block min-w-fit', class)">
157
+
158
+ <div class="flex items-center justify-between pt-1 pb-4 gap-2">
159
+ <div class="flex items-center gap-1">
160
+ <button type="button" (click)="setView('month')"
161
+ [class]="cn('text-sm font-semibold px-2 py-1 rounded transition-colors', currentView === 'month' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground')">
162
+ {{ viewDate | date: 'MMMM' }}
163
+ </button>
164
+ <button type="button" (click)="setView('year')"
165
+ [class]="cn('text-sm font-semibold px-2 py-1 rounded transition-colors', currentView === 'year' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground')">
166
+ {{ viewDate | date: 'yyyy' }}
167
+ </button>
168
+ </div>
169
+ <div class="flex items-center space-x-1">
170
+ <button type="button" (click)="prev()" [class]="navBtnClass"><i class="ri-arrow-left-s-line text-lg"></i></button>
171
+ <button type="button" (click)="next()" [class]="navBtnClass"><i class="ri-arrow-right-s-line text-lg"></i></button>
172
+ </div>
173
+ </div>
174
+
175
+ <div *ngIf="currentView === 'date'" class="space-y-2 animate-in fade-in zoom-in-95 duration-200">
176
+ <div class="grid grid-cols-7 gap-y-1 w-full">
177
+ <span *ngFor="let day of weekDays" class="text-[0.8rem] text-muted-foreground font-normal text-center w-9">
178
+ {{ day }}
179
+ </span>
180
+ </div>
181
+ <div class="grid grid-cols-7 gap-y-1 w-full">
182
+ <button
183
+ *ngFor="let date of daysInMonth"
184
+ type="button"
185
+ (click)="selectDate(date)"
186
+ [disabled]="isDateDisabled(date)"
187
+ [class]="getDayClass(date)"
188
+ >
189
+ {{ date | date: 'd' }}
190
+ </button>
191
+ </div>
192
+ </div>
193
+
194
+ <div *ngIf="currentView === 'month'" class="grid grid-cols-3 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
195
+ <button *ngFor="let month of months; let i = index" type="button" (click)="selectMonth(i)"
196
+ [class]="cn('text-sm py-2.5 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors', i === viewDate.getMonth() ? 'bg-primary text-primary-foreground' : '')">
197
+ {{ month }}
198
+ </button>
199
+ </div>
200
+
201
+ <div *ngIf="currentView === 'year'" class="grid grid-cols-4 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
202
+ <button *ngFor="let year of years" type="button" (click)="selectYear(year)"
203
+ [class]="cn('text-sm py-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors', year === viewDate.getFullYear() ? 'bg-primary text-primary-foreground' : '')">
204
+ {{ year }}
205
+ </button>
206
+ </div>
207
+ </div>
208
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
209
+ }
210
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RangeCalendarComponent, decorators: [{
211
+ type: Component,
212
+ args: [{
213
+ selector: 'tolle-range-calendar',
214
+ standalone: true,
215
+ imports: [CommonModule],
216
+ providers: [
217
+ {
218
+ provide: NG_VALUE_ACCESSOR,
219
+ useExisting: forwardRef(() => RangeCalendarComponent),
220
+ multi: true
221
+ }
222
+ ],
223
+ template: `
224
+ <div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block min-w-fit', class)">
225
+
226
+ <div class="flex items-center justify-between pt-1 pb-4 gap-2">
227
+ <div class="flex items-center gap-1">
228
+ <button type="button" (click)="setView('month')"
229
+ [class]="cn('text-sm font-semibold px-2 py-1 rounded transition-colors', currentView === 'month' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground')">
230
+ {{ viewDate | date: 'MMMM' }}
231
+ </button>
232
+ <button type="button" (click)="setView('year')"
233
+ [class]="cn('text-sm font-semibold px-2 py-1 rounded transition-colors', currentView === 'year' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground')">
234
+ {{ viewDate | date: 'yyyy' }}
235
+ </button>
236
+ </div>
237
+ <div class="flex items-center space-x-1">
238
+ <button type="button" (click)="prev()" [class]="navBtnClass"><i class="ri-arrow-left-s-line text-lg"></i></button>
239
+ <button type="button" (click)="next()" [class]="navBtnClass"><i class="ri-arrow-right-s-line text-lg"></i></button>
240
+ </div>
241
+ </div>
242
+
243
+ <div *ngIf="currentView === 'date'" class="space-y-2 animate-in fade-in zoom-in-95 duration-200">
244
+ <div class="grid grid-cols-7 gap-y-1 w-full">
245
+ <span *ngFor="let day of weekDays" class="text-[0.8rem] text-muted-foreground font-normal text-center w-9">
246
+ {{ day }}
247
+ </span>
248
+ </div>
249
+ <div class="grid grid-cols-7 gap-y-1 w-full">
250
+ <button
251
+ *ngFor="let date of daysInMonth"
252
+ type="button"
253
+ (click)="selectDate(date)"
254
+ [disabled]="isDateDisabled(date)"
255
+ [class]="getDayClass(date)"
256
+ >
257
+ {{ date | date: 'd' }}
258
+ </button>
259
+ </div>
260
+ </div>
261
+
262
+ <div *ngIf="currentView === 'month'" class="grid grid-cols-3 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
263
+ <button *ngFor="let month of months; let i = index" type="button" (click)="selectMonth(i)"
264
+ [class]="cn('text-sm py-2.5 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors', i === viewDate.getMonth() ? 'bg-primary text-primary-foreground' : '')">
265
+ {{ month }}
266
+ </button>
267
+ </div>
268
+
269
+ <div *ngIf="currentView === 'year'" class="grid grid-cols-4 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
270
+ <button *ngFor="let year of years" type="button" (click)="selectYear(year)"
271
+ [class]="cn('text-sm py-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors', year === viewDate.getFullYear() ? 'bg-primary text-primary-foreground' : '')">
272
+ {{ year }}
273
+ </button>
274
+ </div>
275
+ </div>
276
+ `
277
+ }]
278
+ }], propDecorators: { class: [{
279
+ type: Input
280
+ }], disablePastDates: [{
281
+ type: Input
282
+ }], rangeSelect: [{
283
+ type: Output
284
+ }] } });
285
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFuZ2UtY2FsZW5kYXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdG9sbGUvc3JjL2xpYi9yYW5nZS1jYWxlbmRhci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQVUsVUFBVSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0YsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RSxPQUFPLEVBQ0wsU0FBUyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUM5QyxXQUFXLEVBQUUsU0FBUyxFQUFFLGlCQUFpQixFQUFFLFdBQVcsRUFDdEQsU0FBUyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQ3pELFFBQVEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQ3ZDLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxZQUFZLENBQUM7OztBQXFFaEMsTUFBTSxPQUFPLHNCQUFzQjtJQUN4QixLQUFLLEdBQUcsRUFBRSxDQUFDO0lBQ1gsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQ3hCLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDLENBQUMsbUNBQW1DO0lBRTFGLFdBQVcsR0FBOEIsTUFBTSxDQUFDO0lBQ2hELFFBQVEsR0FBUyxJQUFJLElBQUksRUFBRSxDQUFDO0lBRTVCLGtCQUFrQjtJQUNsQixLQUFLLEdBQWMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUU5QyxRQUFRLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUks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SSxXQUFXO3NCQUFwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT25Jbml0LCBmb3J3YXJkUmVmLCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7XG4gIGFkZE1vbnRocywgc3ViTW9udGhzLCBzdGFydE9mTW9udGgsIGVuZE9mTW9udGgsXG4gIHN0YXJ0T2ZXZWVrLCBlbmRPZldlZWssIGVhY2hEYXlPZkludGVydmFsLCBpc1NhbWVNb250aCxcbiAgaXNTYW1lRGF5LCBpc1RvZGF5LCBzZXRNb250aCwgc2V0WWVhciwgYWRkWWVhcnMsIHN1YlllYXJzLFxuICBpc0JlZm9yZSwgc3RhcnRPZkRheSwgaXNXaXRoaW5JbnRlcnZhbCwgaXNBZnRlclxufSBmcm9tICdkYXRlLWZucyc7XG5pbXBvcnQgeyBjbiB9IGZyb20gJy4vdXRpbHMvY24nO1xuaW1wb3J0IHtEYXRlUmFuZ2V9IGZyb20gJ0B0b2xsZS91aS90eXBlcy9kYXRlLXJhbmdlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndG9sbGUtcmFuZ2UtY2FsZW5kYXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBSYW5nZUNhbGVuZGFyQ29tcG9uZW50KSxcbiAgICAgIG11bHRpOiB0cnVlXG4gICAgfVxuICBdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgW2NsYXNzXT1cImNuKCdwLTMgYm9yZGVyIHJvdW5kZWQtbWQgYmctYmFja2dyb3VuZCB0ZXh0LXBvcG92ZXItZm9yZWdyb3VuZCBzaGFkb3ctc20gaW5saW5lLWJsb2NrIG1pbi13LWZpdCcsIGNsYXNzKVwiPlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIHB0LTEgcGItNCBnYXAtMlwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTFcIj5cbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwic2V0VmlldygnbW9udGgnKVwiXG4gICAgICAgICAgICBbY2xhc3NdPVwiY24oJ3RleHQtc20gZm9udC1zZW1pYm9sZCBweC0yIHB5LTEgcm91bmRlZCB0cmFuc2l0aW9uLWNvbG9ycycsIGN1cnJlbnRWaWV3ID09PSAnbW9udGgnID8gJ2JnLXNlY29uZGFyeSB0ZXh0LXNlY29uZGFyeS1mb3JlZ3JvdW5kJyA6ICdob3ZlcjpiZy1hY2NlbnQgaG92ZXI6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCcpXCI+XG4gICAgICAgICAgICB7eyB2aWV3RGF0ZSB8IGRhdGU6ICdNTU1NJyB9fVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJzZXRWaWV3KCd5ZWFyJylcIlxuICAgICAgICAgICAgW2NsYXNzXT1cImNuKCd0ZXh0LXNtIGZvbnQtc2VtaWJvbGQgcHgtMiBweS0xIHJvdW5kZWQgdHJhbnNpdGlvbi1jb2xvcnMnLCBjdXJyZW50VmlldyA9PT0gJ3llYXInID8gJ2JnLXNlY29uZGFyeSB0ZXh0LXNlY29uZGFyeS1mb3JlZ3JvdW5kJyA6ICdob3ZlcjpiZy1hY2NlbnQgaG92ZXI6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCcpXCI+XG4gICAgICAgICAgICB7eyB2aWV3RGF0ZSB8IGRhdGU6ICd5eXl5JyB9fVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIHNwYWNlLXgtMVwiPlxuICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJwcmV2KClcIiBbY2xhc3NdPVwibmF2QnRuQ2xhc3NcIj48aSBjbGFzcz1cInJpLWFycm93LWxlZnQtcy1saW5lIHRleHQtbGdcIj48L2k+PC9idXR0b24+XG4gICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgKGNsaWNrKT1cIm5leHQoKVwiIFtjbGFzc109XCJuYXZCdG5DbGFzc1wiPjxpIGNsYXNzPVwicmktYXJyb3ctcmlnaHQtcy1saW5lIHRleHQtbGdcIj48L2k+PC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgKm5nSWY9XCJjdXJyZW50VmlldyA9PT0gJ2RhdGUnXCIgY2xhc3M9XCJzcGFjZS15LTIgYW5pbWF0ZS1pbiBmYWRlLWluIHpvb20taW4tOTUgZHVyYXRpb24tMjAwXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJncmlkIGdyaWQtY29scy03IGdhcC15LTEgdy1mdWxsXCI+XG4gICAgICAgICAgPHNwYW4gKm5nRm9yPVwibGV0IGRheSBvZiB3ZWVrRGF5c1wiIGNsYXNzPVwidGV4dC1bMC44cmVtXSB0ZXh0LW11dGVkLWZvcmVncm91bmQgZm9udC1ub3JtYWwgdGV4dC1jZW50ZXIgdy05XCI+XG4gICAgICAgICAgICB7eyBkYXkgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JpZCBncmlkLWNvbHMtNyBnYXAteS0xIHctZnVsbFwiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0Zvcj1cImxldCBkYXRlIG9mIGRheXNJbk1vbnRoXCJcbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgKGNsaWNrKT1cInNlbGVjdERhdGUoZGF0ZSlcIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cImlzRGF0ZURpc2FibGVkKGRhdGUpXCJcbiAgICAgICAgICAgIFtjbGFzc109XCJnZXREYXlDbGFzcyhkYXRlKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgZGF0ZSB8IGRhdGU6ICdkJyB9fVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2ICpuZ0lmPVwiY3VycmVudFZpZXcgPT09ICdtb250aCdcIiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTMgZ2FwLTIgdy02NCBhbmltYXRlLWluIGZhZGUtaW4gem9vbS1pbi05NSBkdXJhdGlvbi0yMDBcIj5cbiAgICAgICAgPGJ1dHRvbiAqbmdGb3I9XCJsZXQgbW9udGggb2YgbW9udGhzOyBsZXQgaSA9IGluZGV4XCIgdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJzZWxlY3RNb250aChpKVwiXG4gICAgICAgICAgW2NsYXNzXT1cImNuKCd0ZXh0LXNtIHB5LTIuNSByb3VuZGVkLW1kIGhvdmVyOmJnLWFjY2VudCBob3Zlcjp0ZXh0LWFjY2VudC1mb3JlZ3JvdW5kIHRyYW5zaXRpb24tY29sb3JzJywgaSA9PT0gdmlld0RhdGUuZ2V0TW9udGgoKSA/ICdiZy1wcmltYXJ5IHRleHQtcHJpbWFyeS1mb3JlZ3JvdW5kJyA6ICcnKVwiPlxuICAgICAgICAgIHt7IG1vbnRoIH19XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgKm5nSWY9XCJjdXJyZW50VmlldyA9PT0gJ3llYXInXCIgY2xhc3M9XCJncmlkIGdyaWQtY29scy00IGdhcC0yIHctNjQgYW5pbWF0ZS1pbiBmYWRlLWluIHpvb20taW4tOTUgZHVyYXRpb24tMjAwXCI+XG4gICAgICAgIDxidXR0b24gKm5nRm9yPVwibGV0IHllYXIgb2YgeWVhcnNcIiB0eXBlPVwiYnV0dG9uXCIgKGNsaWNrKT1cInNlbGVjdFllYXIoeWVhcilcIlxuICAgICAgICAgIFtjbGFzc109XCJjbigndGV4dC1zbSBweS0yIHJvdW5kZWQtbWQgaG92ZXI6YmctYWNjZW50IGhvdmVyOnRleHQtYWNjZW50LWZvcmVncm91bmQgdHJhbnNpdGlvbi1jb2xvcnMnLCB5ZWFyID09PSB2aWV3RGF0ZS5nZXRGdWxsWWVhcigpID8gJ2JnLXByaW1hcnkgdGV4dC1wcmltYXJ5LWZvcmVncm91bmQnIDogJycpXCI+XG4gICAgICAgICAge3sgeWVhciB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgXG59KVxuZXhwb3J0IGNsYXNzIFJhbmdlQ2FsZW5kYXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgQElucHV0KCkgY2xhc3MgPSAnJztcbiAgQElucHV0KCkgZGlzYWJsZVBhc3REYXRlcyA9IGZhbHNlO1xuICBAT3V0cHV0KCkgcmFuZ2VTZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPERhdGVSYW5nZT4oKTsgLy8gRW1pdHMgd2hlbmV2ZXIgc2VsZWN0aW9uIGNoYW5nZXNcblxuICBjdXJyZW50VmlldzogJ2RhdGUnIHwgJ21vbnRoJyB8ICd5ZWFyJyA9ICdkYXRlJztcbiAgdmlld0RhdGU6IERhdGUgPSBuZXcgRGF0ZSgpO1xuXG4gIC8vIFRoZSBSYW5nZSBWYWx1ZVxuICB2YWx1ZTogRGF0ZVJhbmdlID0geyBzdGFydDogbnVsbCwgZW5kOiBudWxsIH07XG5cbiAgd2Vla0RheXMgPSBbJ1N1JywgJ01vJywgJ1R1JywgJ1dlJywgJ1RoJywgJ0ZyJywgJ1NhJ107XG4gIGRheXNJbk1vbnRoOiBEYXRlW10gPSBbXTtcbiAgbW9udGhzID0gWydKYW4nLCAnRmViJywgJ01hcicsICdBcHInLCAnTWF5JywgJ0p1bicsICdKdWwnLCAnQXVnJywgJ1NlcCcsICdPY3QnLCAnTm92JywgJ0RlYyddO1xuICB5ZWFyczogbnVtYmVyW10gPSBbXTtcblxuICBuYXZCdG5DbGFzcyA9IGNuKCdoLTcgdy03IGJnLXRyYW5zcGFyZW50IHAtMCBvcGFjaXR5LTUwIGhvdmVyOm9wYWNpdHktMTAwIGJvcmRlciBib3JkZXItaW5wdXQgcm91bmRlZC1tZCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBob3ZlcjpiZy1hY2NlbnQgaG92ZXI6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCB0cmFuc2l0aW9uLWFsbCcpO1xuXG4gIG9uVG91Y2hlZDogKCkgPT4gdm9pZCA9ICgpID0+IHt9O1xuICBvbkNoYW5nZTogKHZhbHVlOiBEYXRlUmFuZ2UpID0+IHZvaWQgPSAoKSA9PiB7fTtcbiAgcHJvdGVjdGVkIGNuID0gY247XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5nZW5lcmF0ZURheXMoKTtcbiAgICB0aGlzLmdlbmVyYXRlWWVhcnMoKTtcbiAgfVxuXG4gIC8vIC0tLSBEYXRlIEdlbmVyYXRpb24gTG9naWMgKFNhbWUgYXMgQ2FsZW5kYXIpIC0tLVxuICBnZW5lcmF0ZURheXMoKSB7XG4gICAgY29uc3Qgc3RhcnQgPSBzdGFydE9mV2VlayhzdGFydE9mTW9udGgodGhpcy52aWV3RGF0ZSkpO1xuICAgIGNvbnN0IGVuZCA9IGVuZE9mV2VlayhlbmRPZk1vbnRoKHRoaXMudmlld0RhdGUpKTtcbiAgICB0aGlzLmRheXNJbk1vbnRoID0gZWFjaERheU9mSW50ZXJ2YWwoeyBzdGFydCwgZW5kIH0pO1xuICB9XG5cbiAgZ2VuZXJhdGVZZWFycygpIHtcbiAgICBjb25zdCBjdXJyZW50WWVhciA9IHRoaXMudmlld0RhdGUuZ2V0RnVsbFllYXIoKTtcbiAgICB0aGlzLnllYXJzID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogMTYgfSwgKF8sIGkpID0+IGN1cnJlbnRZZWFyIC0gNiArIGkpO1xuICB9XG5cbiAgc2V0Vmlldyh2aWV3OiAnZGF0ZScgfCAnbW9udGgnIHwgJ3llYXInKSB7XG4gICAgdGhpcy5jdXJyZW50VmlldyA9IHZpZXc7XG4gICAgaWYgKHZpZXcgPT09ICd5ZWFyJykgdGhpcy5nZW5lcmF0ZVllYXJzKCk7XG4gIH1cblxuICBwcmV2KCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRWaWV3ID09PSAnZGF0ZScpIHtcbiAgICAgIHRoaXMudmlld0RhdGUgPSBzdWJNb250aHModGhpcy52aWV3RGF0ZSwgMSk7XG4gICAgICB0aGlzLmdlbmVyYXRlRGF5cygpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5jdXJyZW50VmlldyA9PT0gJ3llYXInKSB7XG4gICAgICB0aGlzLnZpZXdEYXRlID0gc3ViWWVhcnModGhpcy52aWV3RGF0ZSwgMTYpO1xuICAgICAgdGhpcy5nZW5lcmF0ZVllYXJzKCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmN1cnJlbnRWaWV3ID09PSAnbW9udGgnKSB7XG4gICAgICB0aGlzLnZpZXdEYXRlID0gc3ViWWVhcnModGhpcy52aWV3RGF0ZSwgMSk7XG4gICAgfVxuICB9XG5cbiAgbmV4dCgpIHtcbiAgICBpZiAodGhpcy5jdXJyZW50VmlldyA9PT0gJ2RhdGUnKSB7XG4gICAgICB0aGlzLnZpZXdEYXRlID0gYWRkTW9udGhzKHRoaXMudmlld0RhdGUsIDEpO1xuICAgICAgdGhpcy5nZW5lcmF0ZURheXMoKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuY3VycmVudFZpZXcgPT09ICd5ZWFyJykge1xuICAgICAgdGhpcy52aWV3RGF0ZSA9IGFkZFllYXJzKHRoaXMudmlld0RhdGUsIDE2KTtcbiAgICAgIHRoaXMuZ2VuZXJhdGVZZWFycygpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5jdXJyZW50VmlldyA9PT0gJ21vbnRoJykge1xuICAgICAgdGhpcy52aWV3RGF0ZSA9IGFkZFllYXJzKHRoaXMudmlld0RhdGUsIDEpO1xuICAgIH1cbiAgfVxuXG4gIC8vIC0tLSBSYW5nZSBTZWxlY3Rpb24gTG9naWMgLS0tXG5cbiAgc2VsZWN0RGF0ZShkYXRlOiBEYXRlKSB7XG4gICAgaWYgKHRoaXMuaXNEYXRlRGlzYWJsZWQoZGF0ZSkpIHJldHVybjtcblxuICAgIGNvbnN0IHsgc3RhcnQsIGVuZCB9ID0gdGhpcy52YWx1ZTtcblxuICAgIC8vIDEuIElmIHN0YXJ0IGV4aXN0cyBidXQgZW5kIGRvZXNuJ3RcbiAgICBpZiAoc3RhcnQgJiYgIWVuZCkge1xuICAgICAgaWYgKGlzQmVmb3JlKGRhdGUsIHN0YXJ0KSkge1xuICAgICAgICAvLyBVc2VyIGNsaWNrZWQgZWFybGllciBkYXRlIC0+IFJlc2V0IHN0YXJ0XG4gICAgICAgIHRoaXMudmFsdWUgPSB7IHN0YXJ0OiBkYXRlLCBlbmQ6IG51bGwgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFVzZXIgY2xpY2tlZCBsYXRlciBkYXRlIC0+IENvbXBsZXRlIHJhbmdlXG4gICAgICAgIHRoaXMudmFsdWUgPSB7IHN0YXJ0LCBlbmQ6IGRhdGUgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gMi4gSWYgbmVpdGhlciBleGlzdCBPUiBib3RoIGV4aXN0IChyZXNldClcbiAgICBlbHNlIHtcbiAgICAgIHRoaXMudmFsdWUgPSB7IHN0YXJ0OiBkYXRlLCBlbmQ6IG51bGwgfTtcbiAgICB9XG5cbiAgICBpZiAoIWlzU2FtZU1vbnRoKGRhdGUsIHRoaXMudmlld0RhdGUpKSB7XG4gICAgICB0aGlzLnZpZXdEYXRlID0gZGF0ZTtcbiAgICAgIHRoaXMuZ2VuZXJhdGVEYXlzKCk7XG4gICAgfVxuXG4gICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICB0aGlzLnJhbmdlU2VsZWN0LmVtaXQodGhpcy52YWx1ZSk7XG4gICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgfVxuXG4gIHNlbGVjdE1vbnRoKG1vbnRoSW5kZXg6IG51bWJlcikge1xuICAgIHRoaXMudmlld0RhdGUgPSBzZXRNb250aCh0aGlzLnZpZXdEYXRlLCBtb250aEluZGV4KTtcbiAgICB0aGlzLmN1cnJlbnRWaWV3ID0gJ2RhdGUnO1xuICAgIHRoaXMuZ2VuZXJhdGVEYXlzKCk7XG4gIH1cblxuICBzZWxlY3RZZWFyKHllYXI6IG51bWJlcikge1xuICAgIHRoaXMudmlld0RhdGUgPSBzZXRZZWFyKHRoaXMudmlld0RhdGUsIHllYXIpO1xuICAgIHRoaXMuY3VycmVudFZpZXcgPSAnZGF0ZSc7XG4gICAgdGhpcy5nZW5lcmF0ZURheXMoKTtcbiAgfVxuXG4gIC8vIC0tLSBWaXN1YWwgU3R5bGluZyBmb3IgUmFuZ2UgLS0tXG5cbiAgZ2V0RGF5Q2xhc3MoZGF0ZTogRGF0ZSkge1xuICAgIGNvbnN0IHsgc3RhcnQsIGVuZCB9ID0gdGhpcy52YWx1ZTtcbiAgICBjb25zdCBpc091dHNpZGUgPSAhaXNTYW1lTW9udGgoZGF0ZSwgdGhpcy52aWV3RGF0ZSk7XG4gICAgY29uc3QgaXNEaXNhYmxlZCA9IHRoaXMuaXNEYXRlRGlzYWJsZWQoZGF0ZSk7XG5cbiAgICAvLyBSYW5nZSBDaGVja3NcbiAgICBjb25zdCBpc1N0YXJ0ID0gc3RhcnQgJiYgaXNTYW1lRGF5KGRhdGUsIHN0YXJ0KTtcbiAgICBjb25zdCBpc0VuZCA9IGVuZCAmJiBpc1NhbWVEYXkoZGF0ZSwgZW5kKTtcbiAgICBjb25zdCBpc0luc2lkZSA9IHN0YXJ0ICYmIGVuZCAmJiBpc1dpdGhpbkludGVydmFsKGRhdGUsIHsgc3RhcnQsIGVuZCB9KTtcbiAgICBjb25zdCBpc1RvZGF5RGF0ZSA9IGlzVG9kYXkoZGF0ZSk7XG5cbiAgICByZXR1cm4gY24oXG4gICAgICAvLyBCYXNlOiBoLTkgdy05LCBidXQgd2UgcmVtb3ZlIG1hcmdpbnMvcm91bmRpbmcgZm9yIHRoZSAnc3RyaXAnIGVmZmVjdFxuICAgICAgJ2gtOSB3LTkgcC0wIGZvbnQtbm9ybWFsIHRleHQtc20gdHJhbnNpdGlvbi1hbGwgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgcmVsYXRpdmUgei0xMCcsXG5cbiAgICAgIC8vIERlZmF1bHQgU3RhdGUgKE5vdCBzZWxlY3RlZCwgTm90IGRpc2FibGVkKVxuICAgICAgIWlzSW5zaWRlICYmICFpc1N0YXJ0ICYmICFpc0VuZCAmJiAhaXNEaXNhYmxlZCAmJiAnaG92ZXI6YmctYWNjZW50IGhvdmVyOnRleHQtYWNjZW50LWZvcmVncm91bmQgcm91bmRlZC1tZCcsXG5cbiAgICAgIC8vIFRoZSBcIkNhcHNcIjogU3RhcnQgYW5kIEVuZFxuICAgICAgKGlzU3RhcnQgfHwgaXNFbmQpICYmICdiZy1wcmltYXJ5IHRleHQtcHJpbWFyeS1mb3JlZ3JvdW5kIGhvdmVyOmJnLXByaW1hcnkgaG92ZXI6dGV4dC1wcmltYXJ5LWZvcmVncm91bmQgZm9jdXM6YmctcHJpbWFyeSBmb2N1czp0ZXh0LXByaW1hcnktZm9yZWdyb3VuZCcsXG5cbiAgICAgIC8vIFRoZSBcIlN0cmlwXCI6IERhdGVzIGJldHdlZW4gc3RhcnQgYW5kIGVuZFxuICAgICAgaXNJbnNpZGUgJiYgIWlzU3RhcnQgJiYgIWlzRW5kICYmICdiZy1hY2NlbnQgdGV4dC1hY2NlbnQtZm9yZWdyb3VuZCByb3VuZGVkLW5vbmUnLFxuXG4gICAgICAvLyBDb25uZWN0aW5nIHRoZSBDYXBzIHRvIHRoZSBTdHJpcCAoUmVjdGFuZ3VsYXIgaW5zaWRlIGVkZ2VzKVxuICAgICAgaXNTdGFydCAmJiBlbmQgJiYgJ3JvdW5kZWQtbC1tZCByb3VuZGVkLXItbm9uZScsXG4gICAgICBpc0VuZCAmJiBzdGFydCAmJiAncm91bmRlZC1yLW1kIHJvdW5kZWQtbC1ub25lJyxcbiAgICAgIC8vIElmIG5vIGVuZCBkYXRlIHlldCwgU3RhcnQgc2hvdWxkIGJlIGZ1bGx5IHJvdW5kZWRcbiAgICAgIGlzU3RhcnQgJiYgIWVuZCAmJiAncm91bmRlZC1tZCcsXG5cbiAgICAgIC8vIE11dGVkL0Rpc2FibGVkIGxvZ2ljXG4gICAgICAhaXNJbnNpZGUgJiYgaXNUb2RheURhdGUgJiYgIWlzU3RhcnQgJiYgIWlzRW5kICYmICdiZy1hY2NlbnQvNTAgdGV4dC1hY2NlbnQtZm9yZWdyb3VuZCByb3VuZGVkLW1kJyxcbiAgICAgIChpc091dHNpZGUgfHwgaXNEaXNhYmxlZCkgJiYgJ3RleHQtbXV0ZWQtZm9yZWdyb3VuZCBvcGFjaXR5LTUwJyxcbiAgICAgIGlzRGlzYWJsZWQgJiYgJ2N1cnNvci1ub3QtYWxsb3dlZCdcbiAgICApO1xuICB9XG5cbiAgaXNEYXRlRGlzYWJsZWQoZGF0ZTogRGF0ZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRpc2FibGVQYXN0RGF0ZXMgPyBpc0JlZm9yZShkYXRlLCBzdGFydE9mRGF5KG5ldyBEYXRlKCkpKSA6IGZhbHNlO1xuICB9XG5cbiAgLy8gLS0tIENWQSBJbXBsZW1lbnRhdGlvbiAtLS1cbiAgd3JpdGVWYWx1ZSh2YWw6IERhdGVSYW5nZSB8IG51bGwpOiB2b2lkIHtcbiAgICBpZiAodmFsKSB7XG4gICAgICB0aGlzLnZhbHVlID0gdmFsO1xuICAgICAgaWYgKHZhbC5zdGFydCkgdGhpcy52aWV3RGF0ZSA9IHZhbC5zdGFydDtcbiAgICAgIHRoaXMuZ2VuZXJhdGVEYXlzKCk7XG4gICAgICB0aGlzLmdlbmVyYXRlWWVhcnMoKTtcbiAgICB9XG4gIH1cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KTogdm9pZCB7IHRoaXMub25DaGFuZ2UgPSBmbjsgfVxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7IHRoaXMub25Ub3VjaGVkID0gZm47IH1cbn1cbiJdfQ==