@brickclay-org/ui 0.0.1

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.
@@ -0,0 +1,2265 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, EventEmitter, HostListener, ViewChildren, Output, Input, Injectable, NgModule } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import { FormsModule } from '@angular/forms';
6
+ import moment from 'moment';
7
+ import { Subject } from 'rxjs';
8
+
9
+ class BrickclayLib {
10
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BrickclayLib, deps: [], target: i0.ɵɵFactoryTarget.Component });
11
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BrickclayLib, isStandalone: true, selector: "lib-brickclay-lib", ngImport: i0, template: `
12
+ <p>
13
+ brickclay-lib works!
14
+ </p>
15
+ `, isInline: true, styles: [""] });
16
+ }
17
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BrickclayLib, decorators: [{
18
+ type: Component,
19
+ args: [{ selector: 'lib-brickclay-lib', imports: [], template: `
20
+ <p>
21
+ brickclay-lib works!
22
+ </p>
23
+ ` }]
24
+ }] });
25
+
26
+ class TimePickerComponent {
27
+ value = '1:00 AM'; // Time in format "H:MM AM/PM"
28
+ label = 'Time';
29
+ placeholder = 'Select time';
30
+ position = 'left';
31
+ pickerId = ''; // Unique ID for this picker
32
+ closePicker = 0; // Close counter from parent (triggers close when changed)
33
+ timeFormat = 12; // Visual mode: 12h or 24h
34
+ showSeconds = false; // Whether to show/edit seconds
35
+ timeChange = new EventEmitter();
36
+ pickerOpened = new EventEmitter(); // Notify parent when opened
37
+ pickerClosed = new EventEmitter(); // Notify parent when closed
38
+ timeScrollElements;
39
+ showPicker = false;
40
+ currentHour = 1;
41
+ currentMinute = 0;
42
+ currentAMPM = 'AM';
43
+ currentSecond = 0;
44
+ ngOnInit() {
45
+ this.parseTimeValue();
46
+ }
47
+ ngAfterViewInit() {
48
+ if (this.showPicker) {
49
+ setTimeout(() => {
50
+ this.scrollToSelectedTimes();
51
+ }, 100);
52
+ }
53
+ }
54
+ parseTimeValue() {
55
+ const parsed = this.parseTimeStringToComponents(this.value);
56
+ this.currentHour = parsed.hour;
57
+ this.currentMinute = parsed.minute;
58
+ this.currentSecond = parsed.second;
59
+ this.currentAMPM = parsed.ampm;
60
+ }
61
+ getHours() {
62
+ // 12-hour: 1-12, 24-hour: 0-23
63
+ if (this.timeFormat === 24) {
64
+ return Array.from({ length: 24 }, (_, i) => i);
65
+ }
66
+ return Array.from({ length: 12 }, (_, i) => i + 1);
67
+ }
68
+ getMinutes() {
69
+ return Array.from({ length: 60 }, (_, i) => i);
70
+ }
71
+ getSeconds() {
72
+ return Array.from({ length: 60 }, (_, i) => i);
73
+ }
74
+ getAMPMOptions() {
75
+ return ['AM', 'PM'];
76
+ }
77
+ parseTimeStringToComponents(timeStr) {
78
+ // Supports:
79
+ // - "H:MM AM/PM"
80
+ // - "H:MM:SS AM/PM"
81
+ // - "HH:MM" (24h)
82
+ // - "HH:MM:SS" (24h)
83
+ if (!timeStr) {
84
+ return {
85
+ hour: this.timeFormat === 24 ? 0 : 12,
86
+ minute: 0,
87
+ second: 0,
88
+ ampm: this.timeFormat === 24 ? '' : 'AM'
89
+ };
90
+ }
91
+ const parts = timeStr.trim().split(' ');
92
+ const timePart = parts[0] || (this.timeFormat === 24 ? '00:00' : '12:00');
93
+ let ampm = (parts[1] || '').toUpperCase();
94
+ const [hoursStr, minutesStr, secondsStr] = timePart.split(':');
95
+ let hour = parseInt(hoursStr || (this.timeFormat === 24 ? '0' : '12'), 10);
96
+ const minute = parseInt(minutesStr || '0', 10);
97
+ const second = parseInt(secondsStr || '0', 10);
98
+ if (this.timeFormat === 24) {
99
+ // In 24-hour mode we ignore AM/PM and keep hour as 0-23
100
+ return {
101
+ hour: isNaN(hour) ? 0 : Math.min(Math.max(hour, 0), 23),
102
+ minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
103
+ second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
104
+ ampm: ''
105
+ };
106
+ }
107
+ // 12-hour mode: normalize AM/PM and convert 24h inputs if needed
108
+ let ampmValue = ampm === 'PM' || ampm === 'AM' ? ampm : '';
109
+ if (!ampmValue) {
110
+ // No AM/PM provided -> interpret as 24-hour and convert to 12-hour with AM/PM
111
+ if (hour >= 12) {
112
+ ampmValue = 'PM';
113
+ if (hour > 12)
114
+ hour -= 12;
115
+ }
116
+ else {
117
+ ampmValue = 'AM';
118
+ if (hour === 0)
119
+ hour = 12;
120
+ }
121
+ }
122
+ // Clamp to 1-12 range
123
+ if (hour < 1)
124
+ hour = 1;
125
+ if (hour > 12)
126
+ hour = 12;
127
+ return {
128
+ hour,
129
+ minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
130
+ second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
131
+ ampm: ampmValue
132
+ };
133
+ }
134
+ formatTimeFromComponents(hour, minute, second, ampm) {
135
+ const hStr = hour.toString().padStart(2, '0');
136
+ const minuteStr = minute.toString().padStart(2, '0');
137
+ const secondStr = second.toString().padStart(2, '0');
138
+ if (this.timeFormat === 24) {
139
+ // "HH:mm" or "HH:mm:ss"
140
+ return this.showSeconds
141
+ ? `${hStr}:${minuteStr}:${secondStr}`
142
+ : `${hStr}:${minuteStr}`;
143
+ }
144
+ // 12-hour: "H:MM" or "H:MM:SS" with AM/PM
145
+ const displayHour = hour; // already 1-12
146
+ return this.showSeconds
147
+ ? `${displayHour}:${minuteStr}:${secondStr} ${ampm}`
148
+ : `${displayHour}:${minuteStr} ${ampm}`;
149
+ }
150
+ togglePicker() {
151
+ if (!this.showPicker) {
152
+ this.showPicker = true;
153
+ this.parseTimeValue();
154
+ this.pickerOpened.emit(this.pickerId);
155
+ setTimeout(() => {
156
+ this.scrollToSelectedTimes();
157
+ }, 100);
158
+ }
159
+ else {
160
+ this.showPicker = false;
161
+ this.pickerClosed.emit(this.pickerId);
162
+ }
163
+ }
164
+ onHourChange(hour) {
165
+ this.currentHour = hour;
166
+ this.updateTime();
167
+ setTimeout(() => {
168
+ this.scrollToSelectedTimes();
169
+ }, 50);
170
+ }
171
+ onMinuteChange(minute) {
172
+ this.currentMinute = minute;
173
+ this.updateTime();
174
+ setTimeout(() => {
175
+ this.scrollToSelectedTimes();
176
+ }, 50);
177
+ }
178
+ onSecondChange(second) {
179
+ this.currentSecond = second;
180
+ this.updateTime();
181
+ setTimeout(() => {
182
+ this.scrollToSelectedTimes();
183
+ }, 50);
184
+ }
185
+ onAMPMChange(ampm) {
186
+ this.currentAMPM = ampm;
187
+ this.updateTime();
188
+ setTimeout(() => {
189
+ this.scrollToSelectedTimes();
190
+ }, 50);
191
+ }
192
+ updateTime() {
193
+ const newTime = this.formatTimeFromComponents(this.currentHour, this.currentMinute, this.currentSecond, this.currentAMPM);
194
+ this.value = newTime;
195
+ this.timeChange.emit(newTime);
196
+ }
197
+ scrollToSelectedTimes() {
198
+ this.timeScrollElements.forEach((elementRef) => {
199
+ const element = elementRef.nativeElement;
200
+ const selectedItem = element.querySelector('.time-item.selected');
201
+ if (selectedItem) {
202
+ const scrollTop = selectedItem.offsetTop - element.offsetHeight / 40 + selectedItem.offsetHeight / 40;
203
+ element.scrollTop = scrollTop;
204
+ }
205
+ });
206
+ }
207
+ onDocumentClick(event) {
208
+ const target = event.target;
209
+ if (!target.closest('.time-picker-wrapper') && this.showPicker) {
210
+ this.showPicker = false;
211
+ this.pickerClosed.emit(this.pickerId);
212
+ }
213
+ }
214
+ previousCloseCounter = 0;
215
+ ngOnChanges(changes) {
216
+ if (changes['value'] && changes['value'].currentValue) {
217
+ this.parseTimeValue();
218
+ }
219
+ if (changes['closePicker'] && this.showPicker) {
220
+ const newCounter = changes['closePicker'].currentValue;
221
+ // If counter increased, close the picker
222
+ if (newCounter > this.previousCloseCounter) {
223
+ this.showPicker = false;
224
+ this.pickerClosed.emit(this.pickerId);
225
+ this.previousCloseCounter = newCounter;
226
+ }
227
+ }
228
+ }
229
+ // Basic keyboard support on the input (combobox behavior)
230
+ onInputKeydown(event) {
231
+ const key = event.key;
232
+ if (key === 'Enter' || key === ' ') {
233
+ event.preventDefault();
234
+ this.togglePicker();
235
+ return;
236
+ }
237
+ if (key === 'Escape' && this.showPicker) {
238
+ this.showPicker = false;
239
+ this.pickerClosed.emit(this.pickerId);
240
+ return;
241
+ }
242
+ // Simple hour increment/decrement when closed
243
+ if (!this.showPicker && (key === 'ArrowUp' || key === 'ArrowDown')) {
244
+ event.preventDefault();
245
+ if (this.timeFormat === 24) {
246
+ if (key === 'ArrowUp') {
247
+ this.currentHour = (this.currentHour + 1) % 24;
248
+ }
249
+ else {
250
+ this.currentHour = this.currentHour <= 0 ? 23 : this.currentHour - 1;
251
+ }
252
+ }
253
+ else {
254
+ if (key === 'ArrowUp') {
255
+ this.currentHour = this.currentHour >= 12 ? 1 : this.currentHour + 1;
256
+ }
257
+ else {
258
+ this.currentHour = this.currentHour <= 1 ? 12 : this.currentHour - 1;
259
+ }
260
+ }
261
+ this.updateTime();
262
+ }
263
+ }
264
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TimePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
265
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: TimePickerComponent, isStandalone: true, selector: "brickclay-time-picker", inputs: { value: "value", label: "label", placeholder: "placeholder", position: "position", pickerId: "pickerId", closePicker: "closePicker", timeFormat: "timeFormat", showSeconds: "showSeconds" }, outputs: { timeChange: "timeChange", pickerOpened: "pickerOpened", pickerClosed: "pickerClosed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "timeScrollElements", predicate: ["timeScroll"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\">\r\n <label *ngIf=\"label\">{{ label }}</label>\r\n <div class=\"time-input-wrapper\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"value\"\r\n [placeholder]=\"placeholder\"\r\n readonly\r\n (click)=\"togglePicker()\">\r\n <span class=\"time-icon\">\r\n <img src=\"assets/calender/timer.svg\" alt=\"timer\" class=\"timer-icon\">\r\n </span>\r\n <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div class=\"custom-time-picker\" [ngClass]=\"position === 'left' ? 'left-position' : 'right-position'\">\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\">\r\n {{ h.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- Minutes Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let m of getMinutes()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n (click)=\"onMinuteChange(m)\">\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- AM/PM Column -->\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\">\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [".time-picker-wrapper{width:100%;font-family:Inter,sans-serif}.time-input-group{display:flex;flex-direction:column;gap:4px}.time-input-group label{font-size:11px;font-weight:500;color:#15191e;text-transform:uppercase;letter-spacing:-.28px}.time-input-wrapper{position:relative;display:flex;align-items:center}.time-input{padding:8px 40px 8px 12px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;font-family:Inter,sans-serif;color:#6f737b;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input:focus{outline:none;border-color:#111827;box-shadow:0 0 0 3px #1118271a}.time-input:hover{border-color:#9ca3af}.time-icon{position:absolute;right:12px;font-size:16px;pointer-events:none;color:#9ca3af;cursor:pointer}.custom-time-picker-wrapper{width:100%;display:flex;justify-content:center}.custom-time-picker{display:flex;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:172px;position:absolute;top:calc(100% + 4px);z-index:1000}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500;box-shadow:0 1px 2px #2563eb4d}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
266
+ }
267
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TimePickerComponent, decorators: [{
268
+ type: Component,
269
+ args: [{ selector: 'brickclay-time-picker', standalone: true, imports: [CommonModule], template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\">\r\n <label *ngIf=\"label\">{{ label }}</label>\r\n <div class=\"time-input-wrapper\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"value\"\r\n [placeholder]=\"placeholder\"\r\n readonly\r\n (click)=\"togglePicker()\">\r\n <span class=\"time-icon\">\r\n <img src=\"assets/calender/timer.svg\" alt=\"timer\" class=\"timer-icon\">\r\n </span>\r\n <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div class=\"custom-time-picker\" [ngClass]=\"position === 'left' ? 'left-position' : 'right-position'\">\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\">\r\n {{ h.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- Minutes Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let m of getMinutes()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n (click)=\"onMinuteChange(m)\">\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- AM/PM Column -->\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\">\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [".time-picker-wrapper{width:100%;font-family:Inter,sans-serif}.time-input-group{display:flex;flex-direction:column;gap:4px}.time-input-group label{font-size:11px;font-weight:500;color:#15191e;text-transform:uppercase;letter-spacing:-.28px}.time-input-wrapper{position:relative;display:flex;align-items:center}.time-input{padding:8px 40px 8px 12px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;font-family:Inter,sans-serif;color:#6f737b;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input:focus{outline:none;border-color:#111827;box-shadow:0 0 0 3px #1118271a}.time-input:hover{border-color:#9ca3af}.time-icon{position:absolute;right:12px;font-size:16px;pointer-events:none;color:#9ca3af;cursor:pointer}.custom-time-picker-wrapper{width:100%;display:flex;justify-content:center}.custom-time-picker{display:flex;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:172px;position:absolute;top:calc(100% + 4px);z-index:1000}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500;box-shadow:0 1px 2px #2563eb4d}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}\n"] }]
270
+ }], propDecorators: { value: [{
271
+ type: Input
272
+ }], label: [{
273
+ type: Input
274
+ }], placeholder: [{
275
+ type: Input
276
+ }], position: [{
277
+ type: Input
278
+ }], pickerId: [{
279
+ type: Input
280
+ }], closePicker: [{
281
+ type: Input
282
+ }], timeFormat: [{
283
+ type: Input
284
+ }], showSeconds: [{
285
+ type: Input
286
+ }], timeChange: [{
287
+ type: Output
288
+ }], pickerOpened: [{
289
+ type: Output
290
+ }], pickerClosed: [{
291
+ type: Output
292
+ }], timeScrollElements: [{
293
+ type: ViewChildren,
294
+ args: ['timeScroll']
295
+ }], onDocumentClick: [{
296
+ type: HostListener,
297
+ args: ['document:click', ['$event']]
298
+ }] } });
299
+
300
+ class CalendarManagerService {
301
+ calendarInstances = new Set();
302
+ closeAllSubject = new Subject();
303
+ closeAll$ = this.closeAllSubject.asObservable();
304
+ /**
305
+ * Register a calendar instance with its close function
306
+ */
307
+ register(closeFn) {
308
+ this.calendarInstances.add(closeFn);
309
+ // Return unregister function
310
+ return () => {
311
+ this.calendarInstances.delete(closeFn);
312
+ };
313
+ }
314
+ /**
315
+ * Close all calendars except the one being opened
316
+ */
317
+ closeAllExcept(exceptCloseFn) {
318
+ this.calendarInstances.forEach(closeFn => {
319
+ if (closeFn !== exceptCloseFn) {
320
+ closeFn();
321
+ }
322
+ });
323
+ }
324
+ /**
325
+ * Close all calendars
326
+ */
327
+ closeAll() {
328
+ this.closeAllSubject.next();
329
+ this.calendarInstances.forEach(closeFn => closeFn());
330
+ }
331
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
332
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, providedIn: 'root' });
333
+ }
334
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, decorators: [{
335
+ type: Injectable,
336
+ args: [{
337
+ providedIn: 'root'
338
+ }]
339
+ }] });
340
+
341
+ class CustomCalendarComponent {
342
+ calendarManager;
343
+ // Basic Options
344
+ enableTimepicker = false;
345
+ autoApply = false;
346
+ closeOnAutoApply = false;
347
+ showCancel = true;
348
+ linkedCalendars = false;
349
+ singleDatePicker = false;
350
+ showWeekNumbers = false;
351
+ showISOWeekNumbers = false;
352
+ customRangeDirection = false;
353
+ lockStartDate = false;
354
+ position = 'left';
355
+ drop = 'down';
356
+ dualCalendar = false;
357
+ showRanges = true;
358
+ timeFormat = 24;
359
+ enableSeconds = false;
360
+ customRanges;
361
+ multiDateSelection = false; // NEW: Enable multi-date selection
362
+ maxDate; // NEW: Maximum selectable date
363
+ minDate; // NEW: Minimum selectable date
364
+ placeholder = 'Select date range'; // NEW: Custom placeholder
365
+ opens = 'left'; // NEW: Popup position
366
+ inline = false; // NEW: Always show calendar inline (no popup)
367
+ isDisplayCrossIcon = true; // NEW: Show/Hide clear (X) icon
368
+ selected = new EventEmitter();
369
+ opened = new EventEmitter();
370
+ closed = new EventEmitter();
371
+ /**
372
+ * External value passed from parent. If provided, component will select these dates on init / change.
373
+ * Accepts { startDate: Date|null, endDate: Date|null, selectedDates?: Date[] }
374
+ */
375
+ selectedValue = null;
376
+ /** Optional display format for the input value. Uses moment formatting tokens. */
377
+ displayFormat = 'MM/DD/YYYY';
378
+ show = false;
379
+ today = new Date();
380
+ month = this.today.getMonth();
381
+ year = this.today.getFullYear();
382
+ calendar = [];
383
+ leftMonth;
384
+ leftYear;
385
+ rightMonth;
386
+ rightYear;
387
+ leftCalendar = [];
388
+ rightCalendar = [];
389
+ startDate = null;
390
+ endDate = null;
391
+ selectedDates = []; // NEW: For multi-date selection
392
+ disableHighlight = false;
393
+ hoveredDate = null; // For hover preview
394
+ // Track raw input values for minutes to allow free typing
395
+ minuteInputValues = {};
396
+ // Time picker for single calendar (12-hour format: 1-12)
397
+ selectedHour = 1;
398
+ selectedMinute = 0;
399
+ selectedSecond = 0;
400
+ selectedAMPM = 'AM';
401
+ // NEW: Separate time pickers for dual calendar (12-hour format: 1-12)
402
+ startHour = 1;
403
+ startMinute = 0;
404
+ startSecond = 0;
405
+ startAMPM = 'AM';
406
+ endHour = 2;
407
+ endMinute = 0;
408
+ endSecond = 0;
409
+ endAMPM = 'AM';
410
+ // Track open time-picker within this calendar (for single-open behavior)
411
+ openTimePickerId = null;
412
+ closePickerCounter = {};
413
+ defaultRanges = {};
414
+ activeRange = null; // Track which range is currently active
415
+ rangeOrder = []; // Maintain order of ranges
416
+ unregisterFn;
417
+ closeAllSubscription;
418
+ closeFn;
419
+ constructor(calendarManager) {
420
+ this.calendarManager = calendarManager;
421
+ }
422
+ onClickOutside(event) {
423
+ // Don't handle click outside if inline mode is enabled
424
+ if (this.inline) {
425
+ return;
426
+ }
427
+ const target = event.target;
428
+ if (this.show && !target.closest('.calendar-container')) {
429
+ this.close();
430
+ }
431
+ }
432
+ ngOnInit() {
433
+ if (!this.customRanges) {
434
+ this.initializeDefaultRanges();
435
+ }
436
+ else {
437
+ // If customRanges is provided via @Input, set the order based on the keys
438
+ // Maintain the desired order if keys match, otherwise use provided order
439
+ const desiredOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
440
+ const providedKeys = Object.keys(this.customRanges);
441
+ // Check if Custom Range exists, if not add it
442
+ if (!this.customRanges['Custom Range']) {
443
+ this.customRanges['Custom Range'] = { start: new Date(), end: new Date() };
444
+ }
445
+ // Build order: first add desired order items that exist, then add any remaining
446
+ this.rangeOrder = desiredOrder.filter(key => providedKeys.includes(key) || key === 'Custom Range');
447
+ const remaining = providedKeys.filter(key => !this.rangeOrder.includes(key));
448
+ this.rangeOrder = [...this.rangeOrder, ...remaining];
449
+ }
450
+ if (this.dualCalendar)
451
+ this.initializeDual();
452
+ else
453
+ this.generateCalendar();
454
+ // Initialize time from existing dates if available
455
+ if (this.startDate) {
456
+ this.initializeTimeFromDate(this.startDate, true);
457
+ }
458
+ if (this.endDate) {
459
+ this.initializeTimeFromDate(this.endDate, false);
460
+ }
461
+ // Check if current dates match any predefined range
462
+ if (this.startDate && this.endDate) {
463
+ this.checkAndSetActiveRange();
464
+ }
465
+ // If inline mode, always show calendar
466
+ if (this.inline) {
467
+ this.show = true;
468
+ }
469
+ // Register this calendar instance with the manager service
470
+ this.closeFn = () => {
471
+ if (this.show && !this.inline) {
472
+ this.close();
473
+ }
474
+ };
475
+ this.unregisterFn = this.calendarManager.register(this.closeFn);
476
+ // Subscribe to close all events (skip if inline)
477
+ this.closeAllSubscription = this.calendarManager.closeAll$.subscribe(() => {
478
+ if (this.show && !this.inline) {
479
+ this.close();
480
+ }
481
+ });
482
+ }
483
+ ngOnChanges(changes) {
484
+ if (changes['selectedValue'] && this.selectedValue) {
485
+ // Normalize incoming values to Date or null
486
+ const s = this.selectedValue;
487
+ this.startDate = s.startDate ? new Date(s.startDate) : null;
488
+ this.endDate = s.endDate ? new Date(s.endDate) : null;
489
+ this.selectedDates = (s.selectedDates || []).map((d) => new Date(d));
490
+ // Update calendar month/year to show the start date (or end date if start missing)
491
+ const focusDate = this.startDate ?? this.endDate ?? new Date();
492
+ this.month = focusDate.getMonth();
493
+ this.year = focusDate.getFullYear();
494
+ if (this.dualCalendar) {
495
+ this.initializeDual();
496
+ }
497
+ else {
498
+ this.generateCalendar();
499
+ }
500
+ // Re-evaluate active range if any
501
+ this.checkAndSetActiveRange();
502
+ }
503
+ }
504
+ ngOnDestroy() {
505
+ // Unregister this calendar instance
506
+ if (this.unregisterFn) {
507
+ this.unregisterFn();
508
+ }
509
+ // Unsubscribe from close all events
510
+ if (this.closeAllSubscription) {
511
+ this.closeAllSubscription.unsubscribe();
512
+ }
513
+ }
514
+ checkAndSetActiveRange() {
515
+ if (!this.customRanges || !this.startDate || !this.endDate)
516
+ return;
517
+ // Normalize dates for comparison (ignore time)
518
+ const normalizeDate = (date) => {
519
+ const d = new Date(date);
520
+ d.setHours(0, 0, 0, 0);
521
+ return d;
522
+ };
523
+ const start = normalizeDate(this.startDate);
524
+ const end = normalizeDate(this.endDate);
525
+ // Check each range (except Custom Range)
526
+ for (const key of this.rangeOrder) {
527
+ if (key === 'Custom Range')
528
+ continue;
529
+ const range = this.customRanges[key];
530
+ if (range) {
531
+ const rangeStart = normalizeDate(range.start);
532
+ const rangeEnd = normalizeDate(range.end);
533
+ if (start.getTime() === rangeStart.getTime() && end.getTime() === rangeEnd.getTime()) {
534
+ this.activeRange = key;
535
+ return;
536
+ }
537
+ }
538
+ }
539
+ // If no match found, it's a custom range
540
+ this.activeRange = 'Custom Range';
541
+ }
542
+ initializeDefaultRanges() {
543
+ const today = new Date();
544
+ this.customRanges = {
545
+ 'Today': { start: new Date(today.getFullYear(), today.getMonth(), today.getDate()), end: new Date(today.getFullYear(), today.getMonth(), today.getDate()) },
546
+ 'Yesterday': { start: this.addDays(today, -1), end: this.addDays(today, -1) },
547
+ 'Last 7 Days': { start: this.addDays(today, -6), end: today },
548
+ 'Last 30 Days': { start: this.addDays(today, -29), end: today },
549
+ 'This Month': { start: new Date(today.getFullYear(), today.getMonth(), 1), end: today },
550
+ 'Last Month': { start: new Date(today.getFullYear(), today.getMonth() - 1, 1), end: new Date(today.getFullYear(), today.getMonth(), 0) },
551
+ 'Custom Range': { start: new Date(), end: new Date() }, // Placeholder, won't be used for selection
552
+ };
553
+ // Set the order of ranges
554
+ this.rangeOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
555
+ }
556
+ initializeTimeFromDate(date, isStart) {
557
+ // Always use 12-hour format
558
+ const hours24 = date.getHours();
559
+ const minutes = date.getMinutes();
560
+ const seconds = date.getSeconds();
561
+ if (isStart) {
562
+ this.startMinute = minutes;
563
+ this.startSecond = seconds;
564
+ if (hours24 >= 12) {
565
+ this.startAMPM = 'PM';
566
+ this.startHour = hours24 > 12 ? hours24 - 12 : 12;
567
+ }
568
+ else {
569
+ this.startAMPM = 'AM';
570
+ this.startHour = hours24 === 0 ? 12 : hours24;
571
+ }
572
+ }
573
+ else {
574
+ this.endMinute = minutes;
575
+ this.endSecond = seconds;
576
+ if (hours24 >= 12) {
577
+ this.endAMPM = 'PM';
578
+ this.endHour = hours24 > 12 ? hours24 - 12 : 12;
579
+ }
580
+ else {
581
+ this.endAMPM = 'AM';
582
+ this.endHour = hours24 === 0 ? 12 : hours24;
583
+ }
584
+ }
585
+ }
586
+ toggle() {
587
+ // Don't toggle if inline mode is enabled
588
+ if (this.inline) {
589
+ return;
590
+ }
591
+ const wasOpen = this.show;
592
+ this.show = !this.show;
593
+ if (this.show) {
594
+ // If opening, close all other calendars first
595
+ if (!wasOpen && this.closeFn) {
596
+ this.calendarManager.closeAllExcept(this.closeFn);
597
+ }
598
+ this.disableHighlight = false;
599
+ this.opened.emit();
600
+ }
601
+ else {
602
+ this.closed.emit();
603
+ }
604
+ }
605
+ close() {
606
+ // Don't close if inline mode is enabled
607
+ if (this.inline) {
608
+ return;
609
+ }
610
+ this.show = false;
611
+ this.closed.emit();
612
+ }
613
+ onDateHover(day, fromRight = false) {
614
+ if (!day || this.singleDatePicker || this.multiDateSelection) {
615
+ this.hoveredDate = null;
616
+ return;
617
+ }
618
+ // Only show hover preview if start date is selected but end date is not
619
+ if (!this.startDate || this.endDate) {
620
+ this.hoveredDate = null;
621
+ return;
622
+ }
623
+ if (!this.dualCalendar) {
624
+ this.hoveredDate = new Date(this.year, this.month, day);
625
+ }
626
+ else {
627
+ this.hoveredDate = fromRight
628
+ ? new Date(this.rightYear, this.rightMonth, day)
629
+ : new Date(this.leftYear, this.leftMonth, day);
630
+ }
631
+ }
632
+ onDateLeave() {
633
+ this.hoveredDate = null;
634
+ }
635
+ selectDate(day, fromRight = false) {
636
+ if (!day)
637
+ return;
638
+ let selected;
639
+ if (!this.dualCalendar) {
640
+ selected = new Date(this.year, this.month, day);
641
+ }
642
+ else {
643
+ selected = fromRight
644
+ ? new Date(this.rightYear, this.rightMonth, day)
645
+ : new Date(this.leftYear, this.leftMonth, day);
646
+ }
647
+ // Clear hover on selection
648
+ this.hoveredDate = null;
649
+ // Check min/max date constraints
650
+ if (this.minDate && selected < this.minDate)
651
+ return;
652
+ if (this.maxDate && selected > this.maxDate)
653
+ return;
654
+ // Multi-date selection mode
655
+ if (this.multiDateSelection) {
656
+ this.handleMultiDateSelection(selected);
657
+ return;
658
+ }
659
+ // Apply time if timepicker is enabled (convert 12-hour to 24-hour)
660
+ if (this.enableTimepicker) {
661
+ if (this.dualCalendar) {
662
+ // For dual calendar, use separate start/end times
663
+ // If no startDate OR endDate exists, we're selecting start date
664
+ const isStart = !this.startDate || !!this.endDate;
665
+ this.applyTimeToDate(selected, isStart);
666
+ }
667
+ else {
668
+ // For single calendar, always use selected time for start
669
+ this.applyTimeToDate(selected, true);
670
+ }
671
+ }
672
+ // Single date picker mode
673
+ if (this.singleDatePicker) {
674
+ this.startDate = selected;
675
+ this.endDate = null;
676
+ // Activate Custom Range when manually selecting dates
677
+ this.activeRange = 'Custom Range';
678
+ // Apply time immediately if timepicker is enabled
679
+ if (this.enableTimepicker) {
680
+ this.applyTimeToDate(this.startDate, true);
681
+ }
682
+ if (this.autoApply) {
683
+ this.apply();
684
+ if (this.closeOnAutoApply && !this.inline)
685
+ this.close();
686
+ }
687
+ else {
688
+ // Always emit selection event even if autoApply is false (especially for inline calendars)
689
+ this.emitSelection();
690
+ }
691
+ return;
692
+ }
693
+ // Range selection mode
694
+ if (!this.startDate || this.endDate) {
695
+ this.startDate = selected;
696
+ this.endDate = null;
697
+ // Activate Custom Range when manually selecting dates
698
+ this.activeRange = 'Custom Range';
699
+ // Keep left calendar on the selected month for better UX
700
+ if (this.dualCalendar) {
701
+ this.leftMonth = selected.getMonth();
702
+ this.leftYear = selected.getFullYear();
703
+ // Reset right calendar to original position (next month after left) when end date is cleared
704
+ this.rightMonth = this.leftMonth + 1;
705
+ this.rightYear = this.leftYear;
706
+ if (this.rightMonth > 11) {
707
+ this.rightMonth = 0;
708
+ this.rightYear++;
709
+ }
710
+ this.generateDualCalendars();
711
+ }
712
+ // Don't overwrite time picker values - keep current values and apply them to the date
713
+ // Time picker values are already set by user, we just apply them to the selected date
714
+ }
715
+ else {
716
+ if (selected < this.startDate && !this.customRangeDirection) {
717
+ this.endDate = this.startDate;
718
+ this.startDate = selected;
719
+ // Activate Custom Range when manually selecting dates
720
+ this.activeRange = 'Custom Range';
721
+ // Swap times if needed
722
+ if (this.dualCalendar && this.enableTimepicker) {
723
+ [this.startHour, this.endHour] = [this.endHour, this.startHour];
724
+ [this.startMinute, this.endMinute] = [this.endMinute, this.startMinute];
725
+ [this.startSecond, this.endSecond] = [this.endSecond, this.startSecond];
726
+ [this.startAMPM, this.endAMPM] = [this.endAMPM, this.startAMPM];
727
+ }
728
+ // Keep left calendar on the selected month
729
+ if (this.dualCalendar) {
730
+ this.leftMonth = selected.getMonth();
731
+ this.leftYear = selected.getFullYear();
732
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
733
+ }
734
+ }
735
+ else {
736
+ this.endDate = selected;
737
+ // Activate Custom Range when manually selecting dates
738
+ this.activeRange = 'Custom Range';
739
+ // Only move right calendar if end date is in a different month than start date
740
+ if (this.dualCalendar) {
741
+ if (this.startDate) {
742
+ const startMonth = this.startDate.getMonth();
743
+ const startYear = this.startDate.getFullYear();
744
+ const endMonth = selected.getMonth();
745
+ const endYear = selected.getFullYear();
746
+ // Only move right calendar if end date is in a different month
747
+ if (endMonth !== startMonth || endYear !== startYear) {
748
+ this.rightMonth = endMonth;
749
+ this.rightYear = endYear;
750
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
751
+ }
752
+ // If both dates are in same month, keep right calendar in its current position
753
+ }
754
+ else {
755
+ // If no start date, move right calendar to end date month
756
+ this.rightMonth = selected.getMonth();
757
+ this.rightYear = selected.getFullYear();
758
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
759
+ }
760
+ }
761
+ // Don't overwrite time picker values - keep current end time values
762
+ // Time picker values are already set by user
763
+ }
764
+ if (this.autoApply) {
765
+ this.apply();
766
+ if (this.closeOnAutoApply && !this.inline)
767
+ this.close();
768
+ }
769
+ else {
770
+ // Check if the selection matches a predefined range
771
+ this.checkAndSetActiveRange();
772
+ // Always emit selection event for inline calendars
773
+ if (this.inline) {
774
+ this.emitSelection();
775
+ }
776
+ }
777
+ }
778
+ }
779
+ handleMultiDateSelection(selected) {
780
+ const dateStr = this.getDateString(selected);
781
+ const existingIndex = this.selectedDates.findIndex(d => this.getDateString(d) === dateStr);
782
+ if (existingIndex >= 0) {
783
+ // Deselect if already selected
784
+ this.selectedDates.splice(existingIndex, 1);
785
+ }
786
+ else {
787
+ // Add to selection
788
+ this.selectedDates.push(new Date(selected));
789
+ this.selectedDates.sort((a, b) => a.getTime() - b.getTime());
790
+ }
791
+ // Update startDate and endDate for compatibility
792
+ if (this.selectedDates.length > 0) {
793
+ this.startDate = new Date(this.selectedDates[0]);
794
+ this.endDate = new Date(this.selectedDates[this.selectedDates.length - 1]);
795
+ // Activate Custom Range when manually selecting dates
796
+ this.activeRange = 'Custom Range';
797
+ }
798
+ else {
799
+ this.startDate = null;
800
+ this.endDate = null;
801
+ this.activeRange = null;
802
+ }
803
+ // Always emit selection event for inline calendars or when autoApply is true
804
+ if (this.autoApply || this.inline) {
805
+ this.emitSelection();
806
+ if (this.closeOnAutoApply && !this.inline)
807
+ this.close();
808
+ }
809
+ }
810
+ getDateString(date) {
811
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
812
+ }
813
+ isDateInMultiSelection(year, month, day) {
814
+ if (!this.multiDateSelection || this.selectedDates.length === 0)
815
+ return false;
816
+ const cellDate = new Date(year, month, day);
817
+ return this.selectedDates.some(d => this.getDateString(d) === this.getDateString(cellDate));
818
+ }
819
+ apply() {
820
+ // Format minute inputs to 2 digits before applying
821
+ this.formatAllMinuteInputs();
822
+ // Apply time to dates
823
+ if (this.enableTimepicker) {
824
+ if (this.dualCalendar) {
825
+ // Dual calendar with separate start/end times (always 12-hour format)
826
+ if (this.startDate) {
827
+ this.applyTimeToDate(this.startDate, true);
828
+ }
829
+ if (this.endDate) {
830
+ this.applyTimeToDate(this.endDate, false);
831
+ }
832
+ }
833
+ else {
834
+ // Single calendar with time (always 12-hour format)
835
+ if (this.startDate) {
836
+ this.applyTimeToDate(this.startDate, true);
837
+ }
838
+ if (this.endDate && !this.singleDatePicker) {
839
+ this.applyTimeToDate(this.endDate, true);
840
+ }
841
+ }
842
+ }
843
+ // Check if the selection matches a predefined range
844
+ this.checkAndSetActiveRange();
845
+ this.emitSelection();
846
+ this.disableHighlight = true;
847
+ this.close();
848
+ }
849
+ cancel() {
850
+ this.startDate = null;
851
+ this.endDate = null;
852
+ this.selectedDates = [];
853
+ this.close();
854
+ }
855
+ clear() {
856
+ this.startDate = null;
857
+ this.endDate = null;
858
+ this.selectedDates = [];
859
+ this.activeRange = null; // Clear active range
860
+ // Reset right calendar to original position (next month after left) when end date is cleared
861
+ if (this.dualCalendar && !this.endDate) {
862
+ this.rightMonth = this.leftMonth + 1;
863
+ this.rightYear = this.leftYear;
864
+ if (this.rightMonth > 11) {
865
+ this.rightMonth = 0;
866
+ this.rightYear++;
867
+ }
868
+ this.generateDualCalendars();
869
+ }
870
+ this.emitSelection();
871
+ }
872
+ chooseRange(key) {
873
+ if (!this.customRanges)
874
+ return;
875
+ // Don't allow selecting "Custom Range" directly - it's only activated when manually selecting dates
876
+ if (key === 'Custom Range')
877
+ return;
878
+ const r = this.customRanges[key];
879
+ if (!r)
880
+ return;
881
+ this.startDate = new Date(r.start);
882
+ this.endDate = new Date(r.end);
883
+ this.selectedDates = [];
884
+ this.activeRange = key; // Set active range
885
+ // Navigate calendars to show the selected date range
886
+ if (this.dualCalendar) {
887
+ // For dual calendar: left always shows start date month
888
+ if (this.startDate) {
889
+ this.leftMonth = this.startDate.getMonth();
890
+ this.leftYear = this.startDate.getFullYear();
891
+ }
892
+ // Right calendar logic
893
+ if (this.endDate && this.startDate) {
894
+ const startMonth = this.startDate.getMonth();
895
+ const startYear = this.startDate.getFullYear();
896
+ const endMonth = this.endDate.getMonth();
897
+ const endYear = this.endDate.getFullYear();
898
+ // Only move right calendar if end date is in a different month than start date
899
+ if (endMonth !== startMonth || endYear !== startYear) {
900
+ this.rightMonth = endMonth;
901
+ this.rightYear = endYear;
902
+ }
903
+ else {
904
+ // If both dates are in same month, reset right calendar to default position (next month after left)
905
+ this.rightMonth = this.leftMonth + 1;
906
+ this.rightYear = this.leftYear;
907
+ if (this.rightMonth > 11) {
908
+ this.rightMonth = 0;
909
+ this.rightYear++;
910
+ }
911
+ }
912
+ }
913
+ else if (this.endDate && !this.startDate) {
914
+ // If only end date exists, show it in right calendar
915
+ this.rightMonth = this.endDate.getMonth();
916
+ this.rightYear = this.endDate.getFullYear();
917
+ }
918
+ else {
919
+ // If no end date, reset right calendar to default position
920
+ this.rightMonth = this.leftMonth + 1;
921
+ this.rightYear = this.leftYear;
922
+ if (this.rightMonth > 11) {
923
+ this.rightMonth = 0;
924
+ this.rightYear++;
925
+ }
926
+ }
927
+ this.generateDualCalendars();
928
+ }
929
+ else {
930
+ // For single calendar: show the start date month (or end date if only end date exists)
931
+ if (this.startDate) {
932
+ this.month = this.startDate.getMonth();
933
+ this.year = this.startDate.getFullYear();
934
+ }
935
+ else if (this.endDate) {
936
+ this.month = this.endDate.getMonth();
937
+ this.year = this.endDate.getFullYear();
938
+ }
939
+ this.generateCalendar();
940
+ }
941
+ this.emitSelection();
942
+ if (this.autoApply || this.closeOnAutoApply) {
943
+ this.close();
944
+ }
945
+ }
946
+ emitSelection() {
947
+ const selection = {
948
+ startDate: this.startDate,
949
+ endDate: this.endDate
950
+ };
951
+ if (this.multiDateSelection) {
952
+ selection.selectedDates = [...this.selectedDates];
953
+ }
954
+ this.selected.emit(selection);
955
+ }
956
+ addDays(date, days) {
957
+ const d = new Date(date);
958
+ d.setDate(d.getDate() + days);
959
+ return d;
960
+ }
961
+ generateCalendar() {
962
+ this.calendar = this.buildCalendar(this.year, this.month);
963
+ }
964
+ nextMonth() {
965
+ if (!this.dualCalendar) {
966
+ this.month++;
967
+ if (this.month > 11) {
968
+ this.month = 0;
969
+ this.year++;
970
+ }
971
+ this.generateCalendar();
972
+ return;
973
+ }
974
+ // For dual calendar, this should not be used - use nextLeftMonth or nextRightMonth instead
975
+ this.nextLeftMonth();
976
+ }
977
+ prevMonth() {
978
+ if (!this.dualCalendar) {
979
+ this.month--;
980
+ if (this.month < 0) {
981
+ this.month = 11;
982
+ this.year--;
983
+ }
984
+ this.generateCalendar();
985
+ return;
986
+ }
987
+ // For dual calendar, this should not be used - use prevLeftMonth or prevRightMonth instead
988
+ this.prevLeftMonth();
989
+ }
990
+ // Independent navigation for left calendar
991
+ nextLeftMonth() {
992
+ this.leftMonth++;
993
+ if (this.leftMonth > 11) {
994
+ this.leftMonth = 0;
995
+ this.leftYear++;
996
+ }
997
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
998
+ }
999
+ prevLeftMonth() {
1000
+ this.leftMonth--;
1001
+ if (this.leftMonth < 0) {
1002
+ this.leftMonth = 11;
1003
+ this.leftYear--;
1004
+ }
1005
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
1006
+ }
1007
+ // Independent navigation for right calendar
1008
+ nextRightMonth() {
1009
+ this.rightMonth++;
1010
+ if (this.rightMonth > 11) {
1011
+ this.rightMonth = 0;
1012
+ this.rightYear++;
1013
+ }
1014
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1015
+ }
1016
+ prevRightMonth() {
1017
+ this.rightMonth--;
1018
+ if (this.rightMonth < 0) {
1019
+ this.rightMonth = 11;
1020
+ this.rightYear--;
1021
+ }
1022
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1023
+ }
1024
+ initializeDual() {
1025
+ this.leftMonth = this.today.getMonth();
1026
+ this.leftYear = this.today.getFullYear();
1027
+ // Initialize right calendar to next month, but they can move independently
1028
+ this.rightMonth = this.leftMonth + 1;
1029
+ this.rightYear = this.leftYear;
1030
+ if (this.rightMonth > 11) {
1031
+ this.rightMonth = 0;
1032
+ this.rightYear++;
1033
+ }
1034
+ this.generateDualCalendars();
1035
+ }
1036
+ generateDualCalendars() {
1037
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
1038
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1039
+ }
1040
+ buildCalendar(year, month) {
1041
+ const firstDay = new Date(year, month, 1).getDay();
1042
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1043
+ const prevMonthDays = new Date(year, month, 0).getDate();
1044
+ const grid = [];
1045
+ let row = [];
1046
+ // Adjust first day (0 = Sunday, 1 = Monday, etc.)
1047
+ const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1; // Make Monday = 0
1048
+ for (let i = adjustedFirstDay - 1; i >= 0; i--) {
1049
+ row.push({ day: prevMonthDays - i, currentMonth: false });
1050
+ }
1051
+ for (let d = 1; d <= daysInMonth; d++) {
1052
+ row.push({ day: d, currentMonth: true });
1053
+ if (row.length === 7) {
1054
+ grid.push(row);
1055
+ row = [];
1056
+ }
1057
+ }
1058
+ let nextMonthDay = 1;
1059
+ while (row.length > 0 && row.length < 7) {
1060
+ row.push({ day: nextMonthDay++, currentMonth: false });
1061
+ }
1062
+ if (row.length)
1063
+ grid.push(row);
1064
+ // Ensure we always have 6 rows (42 cells total) for consistent layout
1065
+ while (grid.length < 6) {
1066
+ const newRow = [];
1067
+ for (let i = 0; i < 7; i++) {
1068
+ newRow.push({ day: nextMonthDay++, currentMonth: false });
1069
+ }
1070
+ grid.push(newRow);
1071
+ }
1072
+ return grid;
1073
+ }
1074
+ isDateSelected(year, month, day) {
1075
+ if (this.disableHighlight)
1076
+ return false;
1077
+ if (!day)
1078
+ return false;
1079
+ // Multi-date selection
1080
+ if (this.multiDateSelection) {
1081
+ return this.isDateInMultiSelection(year, month, day);
1082
+ }
1083
+ const cellDate = new Date(year, month, day);
1084
+ // Check if it's today (highlight today by default if no date selected)
1085
+ const today = new Date();
1086
+ const isToday = cellDate.getFullYear() === today.getFullYear() &&
1087
+ cellDate.getMonth() === today.getMonth() &&
1088
+ cellDate.getDate() === today.getDate();
1089
+ // If no startDate is set and it's today, highlight it
1090
+ if (!this.startDate && isToday) {
1091
+ return true;
1092
+ }
1093
+ if (!this.startDate)
1094
+ return false;
1095
+ // Check if date is disabled
1096
+ if (this.minDate && cellDate < this.minDate)
1097
+ return false;
1098
+ if (this.maxDate && cellDate > this.maxDate)
1099
+ return false;
1100
+ const sameDay = cellDate.getFullYear() === this.startDate.getFullYear() &&
1101
+ cellDate.getMonth() === this.startDate.getMonth() &&
1102
+ cellDate.getDate() === this.startDate.getDate();
1103
+ if (this.singleDatePicker)
1104
+ return sameDay;
1105
+ // For range selection: only highlight start and end dates (not in-between)
1106
+ if (this.startDate && this.endDate) {
1107
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1108
+ const end = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate());
1109
+ return cellDate.getTime() === start.getTime() || cellDate.getTime() === end.getTime();
1110
+ }
1111
+ // If only start date is selected and hovering, check if this is start or hovered end
1112
+ if (this.startDate && !this.endDate && this.hoveredDate) {
1113
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1114
+ const hovered = new Date(this.hoveredDate.getFullYear(), this.hoveredDate.getMonth(), this.hoveredDate.getDate());
1115
+ // Show both start and hovered date as selected (circular black)
1116
+ return cellDate.getTime() === start.getTime() || cellDate.getTime() === hovered.getTime();
1117
+ }
1118
+ return sameDay;
1119
+ }
1120
+ isDateInRange(year, month, day) {
1121
+ if (this.disableHighlight || !day)
1122
+ return false;
1123
+ if (this.singleDatePicker)
1124
+ return false;
1125
+ if (this.multiDateSelection)
1126
+ return false;
1127
+ const cellDate = new Date(year, month, day);
1128
+ // If both start and end are selected, show gray background for dates in between
1129
+ if (this.startDate && this.endDate) {
1130
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1131
+ const end = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate());
1132
+ return cellDate > start && cellDate < end;
1133
+ }
1134
+ // If only start is selected and hovering, show preview range
1135
+ if (this.startDate && !this.endDate && this.hoveredDate) {
1136
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1137
+ const hovered = new Date(this.hoveredDate.getFullYear(), this.hoveredDate.getMonth(), this.hoveredDate.getDate());
1138
+ // Determine which is earlier - show gray background for dates between them
1139
+ const minDate = hovered < start ? hovered : start;
1140
+ const maxDate = hovered >= start ? hovered : start;
1141
+ return cellDate > minDate && cellDate < maxDate;
1142
+ }
1143
+ return false;
1144
+ }
1145
+ isDateDisabled(year, month, day) {
1146
+ if (!day)
1147
+ return false;
1148
+ const cellDate = new Date(year, month, day);
1149
+ if (this.minDate && cellDate < this.minDate)
1150
+ return true;
1151
+ if (this.maxDate && cellDate > this.maxDate)
1152
+ return true;
1153
+ return false;
1154
+ }
1155
+ isToday(year, month, day) {
1156
+ if (!day)
1157
+ return false;
1158
+ const today = new Date();
1159
+ const cellDate = new Date(year, month, day);
1160
+ return cellDate.getFullYear() === today.getFullYear() &&
1161
+ cellDate.getMonth() === today.getMonth() &&
1162
+ cellDate.getDate() === today.getDate();
1163
+ }
1164
+ getDisplayValue() {
1165
+ if (this.multiDateSelection && this.selectedDates.length > 0) {
1166
+ if (this.selectedDates.length === 1) {
1167
+ return moment(this.selectedDates[0]).format(this.displayFormat);
1168
+ }
1169
+ return `${this.selectedDates.length} dates selected`;
1170
+ }
1171
+ if (!this.startDate)
1172
+ return '';
1173
+ // Prefer moment formatting for consistent display
1174
+ let dateStr = moment(this.startDate).format(this.displayFormat);
1175
+ if (this.enableTimepicker && !this.dualCalendar) {
1176
+ const hr = this.startDate.getHours().toString().padStart(2, '0');
1177
+ const min = this.startDate.getMinutes().toString().padStart(2, '0');
1178
+ dateStr += ` ${hr}:${min}`;
1179
+ if (this.enableSeconds) {
1180
+ const sec = this.startDate.getSeconds().toString().padStart(2, '0');
1181
+ dateStr += `:${sec}`;
1182
+ }
1183
+ }
1184
+ if (this.endDate && !this.singleDatePicker) {
1185
+ let endStr = moment(this.endDate).format(this.displayFormat);
1186
+ if (this.enableTimepicker) {
1187
+ if (this.dualCalendar) {
1188
+ const startHr = this.startDate.getHours().toString().padStart(2, '0');
1189
+ const startMin = this.startDate.getMinutes().toString().padStart(2, '0');
1190
+ dateStr += ` ${startHr}:${startMin}`;
1191
+ if (this.enableSeconds) {
1192
+ const startSec = this.startDate.getSeconds().toString().padStart(2, '0');
1193
+ dateStr += `:${startSec}`;
1194
+ }
1195
+ }
1196
+ const endHr = this.endDate.getHours().toString().padStart(2, '0');
1197
+ const endMin = this.endDate.getMinutes().toString().padStart(2, '0');
1198
+ endStr += ` ${endHr}:${endMin}`;
1199
+ if (this.enableSeconds) {
1200
+ const endSec = this.endDate.getSeconds().toString().padStart(2, '0');
1201
+ endStr += `:${endSec}`;
1202
+ }
1203
+ }
1204
+ return `${dateStr} - ${endStr}`;
1205
+ }
1206
+ return dateStr;
1207
+ }
1208
+ // Time picker helpers
1209
+ getTimeInputValue(isStart = true) {
1210
+ const h = isStart ? this.startHour : this.endHour;
1211
+ const m = isStart ? this.startMinute : this.endMinute;
1212
+ return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
1213
+ }
1214
+ getSingleTimeInputValue() {
1215
+ return `${this.selectedHour.toString().padStart(2, '0')}:${this.selectedMinute.toString().padStart(2, '0')}`;
1216
+ }
1217
+ // NEW: Helper to build display value for TimePickerComponent (single calendar)
1218
+ getSingleTimePickerDisplay() {
1219
+ const hour = this.selectedHour || 12;
1220
+ const minuteStr = this.selectedMinute.toString().padStart(2, '0');
1221
+ const ampm = this.selectedAMPM || 'AM';
1222
+ return `${hour}:${minuteStr} ${ampm}`;
1223
+ }
1224
+ // NEW: Helper to build display value for TimePickerComponent (dual calendar)
1225
+ getDualTimePickerDisplay(isStart = true) {
1226
+ const hour = isStart ? (this.startHour || 12) : (this.endHour || 12);
1227
+ const minute = isStart ? this.startMinute : this.endMinute;
1228
+ const ampm = isStart ? (this.startAMPM || 'AM') : (this.endAMPM || 'AM');
1229
+ const minuteStr = minute.toString().padStart(2, '0');
1230
+ return `${hour}:${minuteStr} ${ampm}`;
1231
+ }
1232
+ // Coordination helpers for embedded TimePickerComponent instances
1233
+ onTimePickerOpened(pickerId) {
1234
+ // Close previously open picker inside this calendar
1235
+ if (this.openTimePickerId && this.openTimePickerId !== pickerId) {
1236
+ if (!this.closePickerCounter[this.openTimePickerId]) {
1237
+ this.closePickerCounter[this.openTimePickerId] = 0;
1238
+ }
1239
+ this.closePickerCounter[this.openTimePickerId]++;
1240
+ }
1241
+ this.openTimePickerId = pickerId;
1242
+ }
1243
+ onTimePickerClosed(pickerId) {
1244
+ if (this.openTimePickerId === pickerId) {
1245
+ this.openTimePickerId = null;
1246
+ }
1247
+ }
1248
+ shouldClosePicker(pickerId) {
1249
+ return this.closePickerCounter[pickerId] || 0;
1250
+ }
1251
+ // NEW: Parse "H:MM AM/PM" (or "HH:MM" 24h) from TimePickerComponent
1252
+ parsePickerTimeString(timeStr) {
1253
+ if (!timeStr) {
1254
+ return { hour12: 12, minute: 0, ampm: 'AM' };
1255
+ }
1256
+ const parts = timeStr.trim().split(' ');
1257
+ const timePart = parts[0] || '12:00';
1258
+ let ampmPart = (parts[1] || '').toUpperCase();
1259
+ const [hourStr, minuteStr] = timePart.split(':');
1260
+ let hour = parseInt(hourStr || '12', 10);
1261
+ const minute = parseInt(minuteStr || '0', 10);
1262
+ if (ampmPart !== 'AM' && ampmPart !== 'PM') {
1263
+ // Interpret as 24-hour input and convert
1264
+ if (hour >= 12) {
1265
+ ampmPart = 'PM';
1266
+ if (hour > 12)
1267
+ hour -= 12;
1268
+ }
1269
+ else {
1270
+ ampmPart = 'AM';
1271
+ if (hour === 0)
1272
+ hour = 12;
1273
+ }
1274
+ }
1275
+ // Clamp to 1-12 range just in case
1276
+ if (hour < 1)
1277
+ hour = 1;
1278
+ if (hour > 12)
1279
+ hour = 12;
1280
+ return { hour12: hour, minute, ampm: ampmPart };
1281
+ }
1282
+ // NEW: Handle TimePickerComponent change for single calendar
1283
+ onSingleTimePickerChange(time) {
1284
+ const { hour12, minute, ampm } = this.parsePickerTimeString(time);
1285
+ this.selectedHour = hour12;
1286
+ this.selectedMinute = minute;
1287
+ this.selectedAMPM = ampm;
1288
+ if (this.startDate) {
1289
+ let h24 = hour12;
1290
+ if (ampm === 'PM' && h24 < 12)
1291
+ h24 += 12;
1292
+ if (ampm === 'AM' && h24 === 12)
1293
+ h24 = 0;
1294
+ this.startDate.setHours(h24, minute, this.selectedSecond);
1295
+ this.emitSelection();
1296
+ }
1297
+ }
1298
+ // NEW: Handle TimePickerComponent change for dual calendar
1299
+ onDualTimePickerChange(time, isStart = true) {
1300
+ const { hour12, minute, ampm } = this.parsePickerTimeString(time);
1301
+ if (isStart) {
1302
+ this.startHour = hour12;
1303
+ this.startMinute = minute;
1304
+ this.startAMPM = ampm;
1305
+ if (this.startDate) {
1306
+ let h24 = hour12;
1307
+ if (ampm === 'PM' && h24 < 12)
1308
+ h24 += 12;
1309
+ if (ampm === 'AM' && h24 === 12)
1310
+ h24 = 0;
1311
+ this.startDate.setHours(h24, minute, this.startSecond);
1312
+ }
1313
+ }
1314
+ else {
1315
+ this.endHour = hour12;
1316
+ this.endMinute = minute;
1317
+ this.endAMPM = ampm;
1318
+ if (this.endDate) {
1319
+ let h24 = hour12;
1320
+ if (ampm === 'PM' && h24 < 12)
1321
+ h24 += 12;
1322
+ if (ampm === 'AM' && h24 === 12)
1323
+ h24 = 0;
1324
+ this.endDate.setHours(h24, minute, this.endSecond);
1325
+ }
1326
+ }
1327
+ this.emitSelection();
1328
+ }
1329
+ onTimeChange(event, isStart = true) {
1330
+ const [h, m] = event.target.value.split(':').map(Number);
1331
+ if (isStart) {
1332
+ this.startHour = h;
1333
+ this.startMinute = m;
1334
+ if (this.startDate) {
1335
+ this.startDate.setHours(h, m, this.startSecond);
1336
+ this.emitSelection();
1337
+ }
1338
+ }
1339
+ else {
1340
+ this.endHour = h;
1341
+ this.endMinute = m;
1342
+ if (this.endDate) {
1343
+ this.endDate.setHours(h, m, this.endSecond);
1344
+ this.emitSelection();
1345
+ }
1346
+ }
1347
+ }
1348
+ onSingleTimeChange(event) {
1349
+ const [h, m] = event.target.value.split(':').map(Number);
1350
+ this.selectedHour = h;
1351
+ this.selectedMinute = m;
1352
+ if (this.startDate) {
1353
+ this.startDate.setHours(h, m, this.selectedSecond);
1354
+ this.emitSelection();
1355
+ }
1356
+ }
1357
+ // Custom time picker controls
1358
+ incrementHour(isStart = true) {
1359
+ // 12-hour format: 1-12
1360
+ if (isStart) {
1361
+ this.startHour = this.startHour >= 12 ? 1 : this.startHour + 1;
1362
+ // Toggle AM/PM at 12
1363
+ if (this.startHour === 12) {
1364
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1365
+ }
1366
+ if (this.startDate) {
1367
+ let h = this.startHour;
1368
+ if (this.startAMPM === 'PM' && h < 12)
1369
+ h += 12;
1370
+ if (this.startAMPM === 'AM' && h === 12)
1371
+ h = 0;
1372
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1373
+ }
1374
+ }
1375
+ else {
1376
+ this.endHour = this.endHour >= 12 ? 1 : this.endHour + 1;
1377
+ // Toggle AM/PM at 12
1378
+ if (this.endHour === 12) {
1379
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1380
+ }
1381
+ if (this.endDate) {
1382
+ let h = this.endHour;
1383
+ if (this.endAMPM === 'PM' && h < 12)
1384
+ h += 12;
1385
+ if (this.endAMPM === 'AM' && h === 12)
1386
+ h = 0;
1387
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1388
+ }
1389
+ }
1390
+ this.emitSelection();
1391
+ }
1392
+ decrementHour(isStart = true) {
1393
+ // 12-hour format: 1-12
1394
+ if (isStart) {
1395
+ this.startHour = this.startHour <= 1 ? 12 : this.startHour - 1;
1396
+ // Toggle AM/PM at 12
1397
+ if (this.startHour === 12) {
1398
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1399
+ }
1400
+ if (this.startDate) {
1401
+ let h = this.startHour;
1402
+ if (this.startAMPM === 'PM' && h < 12)
1403
+ h += 12;
1404
+ if (this.startAMPM === 'AM' && h === 12)
1405
+ h = 0;
1406
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1407
+ }
1408
+ }
1409
+ else {
1410
+ this.endHour = this.endHour <= 1 ? 12 : this.endHour - 1;
1411
+ // Toggle AM/PM at 12
1412
+ if (this.endHour === 12) {
1413
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1414
+ }
1415
+ if (this.endDate) {
1416
+ let h = this.endHour;
1417
+ if (this.endAMPM === 'PM' && h < 12)
1418
+ h += 12;
1419
+ if (this.endAMPM === 'AM' && h === 12)
1420
+ h = 0;
1421
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1422
+ }
1423
+ }
1424
+ this.emitSelection();
1425
+ }
1426
+ incrementMinute(isStart = true) {
1427
+ if (isStart) {
1428
+ this.startMinute = (this.startMinute + 1) % 60;
1429
+ if (this.startDate) {
1430
+ let h = this.startHour;
1431
+ if (this.startAMPM === 'PM' && h < 12)
1432
+ h += 12;
1433
+ if (this.startAMPM === 'AM' && h === 12)
1434
+ h = 0;
1435
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1436
+ }
1437
+ }
1438
+ else {
1439
+ this.endMinute = (this.endMinute + 1) % 60;
1440
+ if (this.endDate) {
1441
+ let h = this.endHour;
1442
+ if (this.endAMPM === 'PM' && h < 12)
1443
+ h += 12;
1444
+ if (this.endAMPM === 'AM' && h === 12)
1445
+ h = 0;
1446
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1447
+ }
1448
+ }
1449
+ this.emitSelection();
1450
+ }
1451
+ decrementMinute(isStart = true) {
1452
+ if (isStart) {
1453
+ this.startMinute = this.startMinute <= 0 ? 59 : this.startMinute - 1;
1454
+ if (this.startDate) {
1455
+ let h = this.startHour;
1456
+ if (this.startAMPM === 'PM' && h < 12)
1457
+ h += 12;
1458
+ if (this.startAMPM === 'AM' && h === 12)
1459
+ h = 0;
1460
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1461
+ }
1462
+ }
1463
+ else {
1464
+ this.endMinute = this.endMinute <= 0 ? 59 : this.endMinute - 1;
1465
+ if (this.endDate) {
1466
+ let h = this.endHour;
1467
+ if (this.endAMPM === 'PM' && h < 12)
1468
+ h += 12;
1469
+ if (this.endAMPM === 'AM' && h === 12)
1470
+ h = 0;
1471
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1472
+ }
1473
+ }
1474
+ this.emitSelection();
1475
+ }
1476
+ toggleAMPM(isStart = true) {
1477
+ if (isStart) {
1478
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1479
+ if (this.startDate) {
1480
+ let h = this.startHour;
1481
+ if (this.startAMPM === 'PM' && h < 12)
1482
+ h += 12;
1483
+ if (this.startAMPM === 'AM' && h === 12)
1484
+ h = 0;
1485
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1486
+ }
1487
+ }
1488
+ else {
1489
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1490
+ if (this.endDate) {
1491
+ let h = this.endHour;
1492
+ if (this.endAMPM === 'PM' && h < 12)
1493
+ h += 12;
1494
+ if (this.endAMPM === 'AM' && h === 12)
1495
+ h = 0;
1496
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1497
+ }
1498
+ }
1499
+ this.emitSelection();
1500
+ }
1501
+ // Single calendar time picker controls (12-hour format: 1-12)
1502
+ incrementSingleHour() {
1503
+ this.selectedHour = this.selectedHour >= 12 ? 1 : this.selectedHour + 1;
1504
+ // Toggle AM/PM at 12
1505
+ if (this.selectedHour === 12) {
1506
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1507
+ }
1508
+ if (this.startDate) {
1509
+ let h = this.selectedHour;
1510
+ if (this.selectedAMPM === 'PM' && h < 12)
1511
+ h += 12;
1512
+ if (this.selectedAMPM === 'AM' && h === 12)
1513
+ h = 0;
1514
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1515
+ this.emitSelection();
1516
+ }
1517
+ }
1518
+ decrementSingleHour() {
1519
+ this.selectedHour = this.selectedHour <= 1 ? 12 : this.selectedHour - 1;
1520
+ // Toggle AM/PM at 12
1521
+ if (this.selectedHour === 12) {
1522
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1523
+ }
1524
+ if (this.startDate) {
1525
+ let h = this.selectedHour;
1526
+ if (this.selectedAMPM === 'PM' && h < 12)
1527
+ h += 12;
1528
+ if (this.selectedAMPM === 'AM' && h === 12)
1529
+ h = 0;
1530
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1531
+ this.emitSelection();
1532
+ }
1533
+ }
1534
+ incrementSingleMinute() {
1535
+ this.selectedMinute = (this.selectedMinute + 1) % 60;
1536
+ if (this.startDate) {
1537
+ let h = this.selectedHour;
1538
+ if (this.selectedAMPM === 'PM' && h < 12)
1539
+ h += 12;
1540
+ if (this.selectedAMPM === 'AM' && h === 12)
1541
+ h = 0;
1542
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1543
+ this.emitSelection();
1544
+ }
1545
+ }
1546
+ decrementSingleMinute() {
1547
+ this.selectedMinute = this.selectedMinute <= 0 ? 59 : this.selectedMinute - 1;
1548
+ if (this.startDate) {
1549
+ let h = this.selectedHour;
1550
+ if (this.selectedAMPM === 'PM' && h < 12)
1551
+ h += 12;
1552
+ if (this.selectedAMPM === 'AM' && h === 12)
1553
+ h = 0;
1554
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1555
+ this.emitSelection();
1556
+ }
1557
+ }
1558
+ toggleSingleAMPM() {
1559
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1560
+ if (this.startDate) {
1561
+ let h = this.selectedHour;
1562
+ if (this.selectedAMPM === 'PM' && h < 12)
1563
+ h += 12;
1564
+ if (this.selectedAMPM === 'AM' && h === 12)
1565
+ h = 0;
1566
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1567
+ this.emitSelection();
1568
+ }
1569
+ }
1570
+ getMonthName(month) {
1571
+ const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
1572
+ return months[month];
1573
+ }
1574
+ // Input handlers for direct hour/minute input (12-hour format only)
1575
+ onHourInput(event, isStart = true, isSingle = false) {
1576
+ const inputValue = event.target.value;
1577
+ // Allow empty input while typing
1578
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1579
+ return;
1580
+ }
1581
+ let value = parseInt(inputValue) || 0;
1582
+ // Validate: 1-12 for 12-hour format
1583
+ if (value < 1)
1584
+ value = 1;
1585
+ if (value > 12)
1586
+ value = 12;
1587
+ if (isSingle) {
1588
+ this.selectedHour = value;
1589
+ if (this.startDate) {
1590
+ let h = value;
1591
+ if (this.selectedAMPM === 'PM' && h < 12)
1592
+ h += 12;
1593
+ if (this.selectedAMPM === 'AM' && h === 12)
1594
+ h = 0;
1595
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1596
+ this.emitSelection();
1597
+ }
1598
+ }
1599
+ else if (isStart) {
1600
+ this.startHour = value;
1601
+ if (this.startDate) {
1602
+ let h = value;
1603
+ if (this.startAMPM === 'PM' && h < 12)
1604
+ h += 12;
1605
+ if (this.startAMPM === 'AM' && h === 12)
1606
+ h = 0;
1607
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1608
+ this.emitSelection();
1609
+ }
1610
+ }
1611
+ else {
1612
+ this.endHour = value;
1613
+ if (this.endDate) {
1614
+ let h = value;
1615
+ if (this.endAMPM === 'PM' && h < 12)
1616
+ h += 12;
1617
+ if (this.endAMPM === 'AM' && h === 12)
1618
+ h = 0;
1619
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1620
+ this.emitSelection();
1621
+ }
1622
+ }
1623
+ // Don't format during input, only on blur
1624
+ event.target.value = value.toString();
1625
+ }
1626
+ onHourBlur(event, isStart = true, isSingle = false) {
1627
+ const inputValue = event.target.value;
1628
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1629
+ // If empty, set to current value
1630
+ const currentValue = isSingle ? this.selectedHour : (isStart ? this.startHour : this.endHour);
1631
+ event.target.value = currentValue.toString();
1632
+ return;
1633
+ }
1634
+ let value = parseInt(inputValue) || 0;
1635
+ if (value < 1)
1636
+ value = 1;
1637
+ if (value > 12)
1638
+ value = 12;
1639
+ // Format to single digit (no padding for hours in 12-hour format)
1640
+ event.target.value = value.toString();
1641
+ // Update the value
1642
+ if (isSingle) {
1643
+ this.selectedHour = value;
1644
+ if (this.startDate) {
1645
+ let h = value;
1646
+ if (this.selectedAMPM === 'PM' && h < 12)
1647
+ h += 12;
1648
+ if (this.selectedAMPM === 'AM' && h === 12)
1649
+ h = 0;
1650
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1651
+ this.emitSelection();
1652
+ }
1653
+ }
1654
+ else if (isStart) {
1655
+ this.startHour = value;
1656
+ if (this.startDate) {
1657
+ let h = value;
1658
+ if (this.startAMPM === 'PM' && h < 12)
1659
+ h += 12;
1660
+ if (this.startAMPM === 'AM' && h === 12)
1661
+ h = 0;
1662
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1663
+ this.emitSelection();
1664
+ }
1665
+ }
1666
+ else {
1667
+ this.endHour = value;
1668
+ if (this.endDate) {
1669
+ let h = value;
1670
+ if (this.endAMPM === 'PM' && h < 12)
1671
+ h += 12;
1672
+ if (this.endAMPM === 'AM' && h === 12)
1673
+ h = 0;
1674
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1675
+ this.emitSelection();
1676
+ }
1677
+ }
1678
+ }
1679
+ onMinuteInput(event, isStart = true, isSingle = false) {
1680
+ const inputValue = event.target.value;
1681
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1682
+ // Remove any non-digit characters
1683
+ const digitsOnly = inputValue.replace(/\D/g, '');
1684
+ // Store raw input value for display
1685
+ this.minuteInputValues[key] = digitsOnly;
1686
+ // Allow empty input while typing
1687
+ if (digitsOnly === '' || digitsOnly === null || digitsOnly === undefined) {
1688
+ return; // Don't modify the input, let user clear it
1689
+ }
1690
+ // Allow typing up to 2 digits without formatting
1691
+ let value = parseInt(digitsOnly) || 0;
1692
+ // If user types more than 2 digits, take only first 2
1693
+ if (digitsOnly.length > 2) {
1694
+ value = parseInt(digitsOnly.substring(0, 2));
1695
+ this.minuteInputValues[key] = digitsOnly.substring(0, 2);
1696
+ event.target.value = digitsOnly.substring(0, 2);
1697
+ }
1698
+ // If value exceeds 59, clamp it to 59
1699
+ if (value > 59) {
1700
+ value = 59;
1701
+ this.minuteInputValues[key] = '59';
1702
+ event.target.value = '59';
1703
+ }
1704
+ // Update the internal value silently (don't emit during typing to avoid re-rendering)
1705
+ if (isSingle) {
1706
+ this.selectedMinute = value;
1707
+ }
1708
+ else if (isStart) {
1709
+ this.startMinute = value;
1710
+ }
1711
+ else {
1712
+ this.endMinute = value;
1713
+ }
1714
+ // Don't update dates or emit during typing - wait for blur or apply
1715
+ }
1716
+ onMinuteBlur(event, isStart = true, isSingle = false) {
1717
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1718
+ const inputValue = event.target.value;
1719
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1720
+ // If empty, set to current value
1721
+ const currentValue = isSingle ? this.selectedMinute : (isStart ? this.startMinute : this.endMinute);
1722
+ event.target.value = currentValue.toString().padStart(2, '0');
1723
+ delete this.minuteInputValues[key];
1724
+ return;
1725
+ }
1726
+ const digitsOnly = inputValue.replace(/\D/g, '');
1727
+ let value = parseInt(digitsOnly) || 0;
1728
+ if (value < 0)
1729
+ value = 0;
1730
+ if (value > 59)
1731
+ value = 59;
1732
+ // Format to 2 digits on blur (01-09 becomes 01-09, 10-59 stays as is)
1733
+ event.target.value = value.toString().padStart(2, '0');
1734
+ delete this.minuteInputValues[key]; // Clear raw input, use formatted value
1735
+ // Update the value
1736
+ if (isSingle) {
1737
+ this.selectedMinute = value;
1738
+ if (this.startDate) {
1739
+ let h = this.selectedHour;
1740
+ if (this.selectedAMPM === 'PM' && h < 12)
1741
+ h += 12;
1742
+ if (this.selectedAMPM === 'AM' && h === 12)
1743
+ h = 0;
1744
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1745
+ this.emitSelection();
1746
+ }
1747
+ }
1748
+ else if (isStart) {
1749
+ this.startMinute = value;
1750
+ if (this.startDate) {
1751
+ let h = this.startHour;
1752
+ if (this.startAMPM === 'PM' && h < 12)
1753
+ h += 12;
1754
+ if (this.startAMPM === 'AM' && h === 12)
1755
+ h = 0;
1756
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1757
+ this.emitSelection();
1758
+ }
1759
+ }
1760
+ else {
1761
+ this.endMinute = value;
1762
+ if (this.endDate) {
1763
+ let h = this.endHour;
1764
+ if (this.endAMPM === 'PM' && h < 12)
1765
+ h += 12;
1766
+ if (this.endAMPM === 'AM' && h === 12)
1767
+ h = 0;
1768
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1769
+ this.emitSelection();
1770
+ }
1771
+ }
1772
+ }
1773
+ // Get display value for hour (always 12-hour format)
1774
+ getDisplayHour(hour) {
1775
+ if (hour === 0)
1776
+ return 12;
1777
+ if (hour > 12)
1778
+ return hour - 12;
1779
+ return hour;
1780
+ }
1781
+ // Get display value for minute (formatted only when not actively typing)
1782
+ getMinuteDisplayValue(isStart, isSingle) {
1783
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1784
+ // If user is typing (has raw input), show that, otherwise show formatted value
1785
+ if (this.minuteInputValues[key] !== undefined) {
1786
+ return this.minuteInputValues[key];
1787
+ }
1788
+ // Otherwise return formatted value
1789
+ const value = isSingle ? this.selectedMinute : (isStart ? this.startMinute : this.endMinute);
1790
+ return value.toString().padStart(2, '0');
1791
+ }
1792
+ // Helper method to apply time picker values to a date
1793
+ applyTimeToDate(date, isStart) {
1794
+ if (this.dualCalendar) {
1795
+ if (isStart) {
1796
+ let h = this.startHour;
1797
+ if (this.startAMPM === 'PM' && h < 12)
1798
+ h += 12;
1799
+ if (this.startAMPM === 'AM' && h === 12)
1800
+ h = 0;
1801
+ date.setHours(h, this.startMinute, this.startSecond);
1802
+ }
1803
+ else {
1804
+ let h = this.endHour;
1805
+ if (this.endAMPM === 'PM' && h < 12)
1806
+ h += 12;
1807
+ if (this.endAMPM === 'AM' && h === 12)
1808
+ h = 0;
1809
+ date.setHours(h, this.endMinute, this.endSecond);
1810
+ }
1811
+ }
1812
+ else {
1813
+ let h = this.selectedHour;
1814
+ if (this.selectedAMPM === 'PM' && h < 12)
1815
+ h += 12;
1816
+ if (this.selectedAMPM === 'AM' && h === 12)
1817
+ h = 0;
1818
+ date.setHours(h, this.selectedMinute, this.selectedSecond);
1819
+ }
1820
+ }
1821
+ // Select all text on focus for easy replacement
1822
+ onTimeInputFocus(event) {
1823
+ event.target.select();
1824
+ }
1825
+ // Format all minute inputs to 2 digits (called before Apply)
1826
+ formatAllMinuteInputs() {
1827
+ // Format minute inputs in the DOM - find all minute inputs and format single digits
1828
+ const inputs = document.querySelectorAll('.time-input');
1829
+ inputs.forEach((input) => {
1830
+ const value = parseInt(input.value);
1831
+ // If it's a valid minute value (0-59) and not already formatted (single digit or 2 digits without leading zero)
1832
+ if (!isNaN(value) && value >= 0 && value <= 59) {
1833
+ // Format if it's a single digit (1-9) or if it's 2 digits but the first is not 0
1834
+ if (input.value.length === 1 || (input.value.length === 2 && !input.value.startsWith('0') && value < 10)) {
1835
+ input.value = value.toString().padStart(2, '0');
1836
+ }
1837
+ }
1838
+ });
1839
+ }
1840
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CustomCalendarComponent, deps: [{ token: CalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
1841
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CustomCalendarComponent, isStandalone: true, selector: "brickclay-custom-calendar", inputs: { enableTimepicker: "enableTimepicker", autoApply: "autoApply", closeOnAutoApply: "closeOnAutoApply", showCancel: "showCancel", linkedCalendars: "linkedCalendars", singleDatePicker: "singleDatePicker", showWeekNumbers: "showWeekNumbers", showISOWeekNumbers: "showISOWeekNumbers", customRangeDirection: "customRangeDirection", lockStartDate: "lockStartDate", position: "position", drop: "drop", dualCalendar: "dualCalendar", showRanges: "showRanges", timeFormat: "timeFormat", enableSeconds: "enableSeconds", customRanges: "customRanges", multiDateSelection: "multiDateSelection", maxDate: "maxDate", minDate: "minDate", placeholder: "placeholder", opens: "opens", inline: "inline", isDisplayCrossIcon: "isDisplayCrossIcon", selectedValue: "selectedValue", displayFormat: "displayFormat" }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\">\r\n <!-- Input field -->\r\n <div class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"toggle()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n class=\"calendar-input\">\r\n <!-- *ngIf=\"!getDisplayValue()\" -->\r\n\r\n <span class=\"calendar-icon\" >\r\n <img src=\"assets/calender/calender.svg\" alt=\"calendar\" class=\"calendar-icon-img\">\r\n </span>\r\n <button class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && opens === 'right',\r\n 'position-center': !inline && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"prev\" class=\"h-3 w-3\" />\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"next\" class=\"h-3 w-3\" />\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"single-time\"\r\n [label]=\"''\"\r\n [value]=\"getSingleTimePickerDisplay()\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\r\n (timeChange)=\"onSingleTimePickerChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- DUAL CALENDAR -->\r\n <div class=\"dual-calendar\" *ngIf=\"dualCalendar\">\r\n <!-- LEFT CALENDAR -->\r\n <div class=\"calendar-left\">\r\n <div class=\"header\">\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(leftMonth) }} {{ leftYear }}</span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"dual-start\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(true)\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\r\n (timeChange)=\"onDualTimePickerChange($event, true)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- RIGHT CALENDAR -->\r\n <div class=\"calendar-right\">\r\n <div class=\"header\">\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(rightMonth) }} {{ rightYear }}</span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"dual-end\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(false)\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\r\n (timeChange)=\"onDualTimePickerChange($event, false)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- FOOTER -->\r\n <div class=\"footer\" *ngIf=\"!inline\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n", styles: [".calendar-container,.calendar-container *{font-family:Inter,sans-serif!important}.calendar-container{position:relative;display:inline-block;width:100%}.input-wrapper{position:relative;display:flex;align-items:center}.calendar-input{width:100%;padding:9px 14px 9px 40px;border:1px solid #ddd;border-radius:8px;font-size:14px;cursor:pointer;background:#fff;transition:all .2s}.calendar-input:hover{border-color:#999}.calendar-input:focus{outline:none;border-color:#999;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: TimePickerComponent, selector: "brickclay-time-picker", inputs: ["value", "label", "placeholder", "position", "pickerId", "closePicker", "timeFormat", "showSeconds"], outputs: ["timeChange", "pickerOpened", "pickerClosed"] }] });
1842
+ }
1843
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CustomCalendarComponent, decorators: [{
1844
+ type: Component,
1845
+ args: [{ selector: 'brickclay-custom-calendar', standalone: true, imports: [CommonModule, FormsModule, TimePickerComponent], template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\">\r\n <!-- Input field -->\r\n <div class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"toggle()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n class=\"calendar-input\">\r\n <!-- *ngIf=\"!getDisplayValue()\" -->\r\n\r\n <span class=\"calendar-icon\" >\r\n <img src=\"assets/calender/calender.svg\" alt=\"calendar\" class=\"calendar-icon-img\">\r\n </span>\r\n <button class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && opens === 'right',\r\n 'position-center': !inline && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"prev\" class=\"h-3 w-3\" />\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"next\" class=\"h-3 w-3\" />\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"single-time\"\r\n [label]=\"''\"\r\n [value]=\"getSingleTimePickerDisplay()\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\r\n (timeChange)=\"onSingleTimePickerChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- DUAL CALENDAR -->\r\n <div class=\"dual-calendar\" *ngIf=\"dualCalendar\">\r\n <!-- LEFT CALENDAR -->\r\n <div class=\"calendar-left\">\r\n <div class=\"header\">\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(leftMonth) }} {{ leftYear }}</span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"dual-start\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(true)\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\r\n (timeChange)=\"onDualTimePickerChange($event, true)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- RIGHT CALENDAR -->\r\n <div class=\"calendar-right\">\r\n <div class=\"header\">\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-left.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(rightMonth) }} {{ rightYear }}</span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/chevron-right.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <brickclay-time-picker\r\n pickerId=\"dual-end\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(false)\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\r\n (timeChange)=\"onDualTimePickerChange($event, false)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- FOOTER -->\r\n <div class=\"footer\" *ngIf=\"!inline\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n", styles: [".calendar-container,.calendar-container *{font-family:Inter,sans-serif!important}.calendar-container{position:relative;display:inline-block;width:100%}.input-wrapper{position:relative;display:flex;align-items:center}.calendar-input{width:100%;padding:9px 14px 9px 40px;border:1px solid #ddd;border-radius:8px;font-size:14px;cursor:pointer;background:#fff;transition:all .2s}.calendar-input:hover{border-color:#999}.calendar-input:focus{outline:none;border-color:#999;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}\n"] }]
1846
+ }], ctorParameters: () => [{ type: CalendarManagerService }], propDecorators: { enableTimepicker: [{
1847
+ type: Input
1848
+ }], autoApply: [{
1849
+ type: Input
1850
+ }], closeOnAutoApply: [{
1851
+ type: Input
1852
+ }], showCancel: [{
1853
+ type: Input
1854
+ }], linkedCalendars: [{
1855
+ type: Input
1856
+ }], singleDatePicker: [{
1857
+ type: Input
1858
+ }], showWeekNumbers: [{
1859
+ type: Input
1860
+ }], showISOWeekNumbers: [{
1861
+ type: Input
1862
+ }], customRangeDirection: [{
1863
+ type: Input
1864
+ }], lockStartDate: [{
1865
+ type: Input
1866
+ }], position: [{
1867
+ type: Input
1868
+ }], drop: [{
1869
+ type: Input
1870
+ }], dualCalendar: [{
1871
+ type: Input
1872
+ }], showRanges: [{
1873
+ type: Input
1874
+ }], timeFormat: [{
1875
+ type: Input
1876
+ }], enableSeconds: [{
1877
+ type: Input
1878
+ }], customRanges: [{
1879
+ type: Input
1880
+ }], multiDateSelection: [{
1881
+ type: Input
1882
+ }], maxDate: [{
1883
+ type: Input
1884
+ }], minDate: [{
1885
+ type: Input
1886
+ }], placeholder: [{
1887
+ type: Input
1888
+ }], opens: [{
1889
+ type: Input
1890
+ }], inline: [{
1891
+ type: Input
1892
+ }], isDisplayCrossIcon: [{
1893
+ type: Input
1894
+ }], selected: [{
1895
+ type: Output
1896
+ }], opened: [{
1897
+ type: Output
1898
+ }], closed: [{
1899
+ type: Output
1900
+ }], selectedValue: [{
1901
+ type: Input
1902
+ }], displayFormat: [{
1903
+ type: Input
1904
+ }], onClickOutside: [{
1905
+ type: HostListener,
1906
+ args: ['document:click', ['$event']]
1907
+ }] } });
1908
+
1909
+ class ScheduledDatePickerComponent {
1910
+ timeFormat = 12;
1911
+ enableSeconds = false;
1912
+ scheduled = new EventEmitter();
1913
+ cleared = new EventEmitter();
1914
+ activeTab = 'single';
1915
+ openTimePickerId = null; // Track which time picker is currently open
1916
+ closePickerCounter = {}; // Track close signals for each picker
1917
+ // Single Date
1918
+ singleDate = null;
1919
+ singleAllDay = false;
1920
+ singleStartTime = '1:00 AM';
1921
+ singleEndTime = '2:00 AM';
1922
+ // Multiple Dates
1923
+ multipleDates = [];
1924
+ // Date Range
1925
+ rangeStartDate = null;
1926
+ rangeEndDate = null;
1927
+ rangeAllDay = false;
1928
+ rangeStartTime = '1:00 AM';
1929
+ rangeEndTime = '2:00 AM';
1930
+ ngOnInit() {
1931
+ // Initialize with default time if needed
1932
+ }
1933
+ onTabChange(tab) {
1934
+ this.activeTab = tab;
1935
+ this.openTimePickerId = null; // Close any open pickers when switching tabs
1936
+ }
1937
+ onTimePickerOpened(pickerId) {
1938
+ // Close all other pickers when one opens
1939
+ if (this.openTimePickerId && this.openTimePickerId !== pickerId) {
1940
+ // Increment close counter for the previously open picker
1941
+ if (!this.closePickerCounter[this.openTimePickerId]) {
1942
+ this.closePickerCounter[this.openTimePickerId] = 0;
1943
+ }
1944
+ this.closePickerCounter[this.openTimePickerId]++;
1945
+ }
1946
+ this.openTimePickerId = pickerId;
1947
+ }
1948
+ onTimePickerClosed(pickerId) {
1949
+ // Reset open picker ID if this was the open one
1950
+ if (this.openTimePickerId === pickerId) {
1951
+ this.openTimePickerId = null;
1952
+ }
1953
+ }
1954
+ shouldClosePicker(pickerId) {
1955
+ // Return the counter value for this picker (triggers change detection)
1956
+ return this.closePickerCounter[pickerId] || 0;
1957
+ }
1958
+ // Single Date Handlers
1959
+ onSingleDateSelected(event) {
1960
+ if (event.startDate) {
1961
+ this.singleDate = new Date(event.startDate);
1962
+ // Initialize time if not all day
1963
+ if (!this.singleAllDay) {
1964
+ this.updateSingleDateTimes();
1965
+ }
1966
+ this.emitScheduled();
1967
+ }
1968
+ else {
1969
+ this.singleDate = null;
1970
+ }
1971
+ }
1972
+ onSingleAllDayChange() {
1973
+ this.singleAllDay = !this.singleAllDay;
1974
+ if (this.singleDate) {
1975
+ this.updateSingleDateTimes();
1976
+ this.emitScheduled();
1977
+ }
1978
+ }
1979
+ onSingleStartTimeChange(time) {
1980
+ this.singleStartTime = time;
1981
+ if (this.singleDate) {
1982
+ this.updateSingleDateTimes();
1983
+ this.emitScheduled();
1984
+ }
1985
+ }
1986
+ onSingleEndTimeChange(time) {
1987
+ this.singleEndTime = time;
1988
+ if (this.singleDate) {
1989
+ this.updateSingleDateTimes();
1990
+ this.emitScheduled();
1991
+ }
1992
+ }
1993
+ updateSingleDateTimes() {
1994
+ if (!this.singleDate)
1995
+ return;
1996
+ if (this.singleAllDay) {
1997
+ this.singleDate.setHours(0, 0, 0, 0);
1998
+ }
1999
+ else {
2000
+ const startTime = this.parseTimeString(this.singleStartTime);
2001
+ const endTime = this.parseTimeString(this.singleEndTime);
2002
+ this.singleDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2003
+ }
2004
+ }
2005
+ // Multiple Dates Handlers
2006
+ onMultipleDatesSelected(event) {
2007
+ if (event.selectedDates && event.selectedDates.length > 0) {
2008
+ const newDates = [];
2009
+ event.selectedDates.forEach(date => {
2010
+ const dateStr = this.getDateString(date);
2011
+ const existing = this.multipleDates.find(d => this.getDateString(d.date) === dateStr);
2012
+ if (existing) {
2013
+ newDates.push(existing);
2014
+ }
2015
+ else {
2016
+ // Create new time configuration for this date
2017
+ newDates.push({
2018
+ date: new Date(date),
2019
+ allDay: false,
2020
+ startTime: '1:00 AM',
2021
+ endTime: '2:00 AM'
2022
+ });
2023
+ }
2024
+ });
2025
+ this.multipleDates = newDates;
2026
+ this.emitScheduled();
2027
+ }
2028
+ else {
2029
+ this.multipleDates = [];
2030
+ this.emitScheduled();
2031
+ }
2032
+ }
2033
+ onMultipleDateAllDayChange(index) {
2034
+ if (this.multipleDates[index]) {
2035
+ this.multipleDates[index].allDay = !this.multipleDates[index].allDay;
2036
+ if (this.multipleDates[index].allDay) {
2037
+ this.multipleDates[index].date.setHours(0, 0, 0, 0);
2038
+ }
2039
+ else {
2040
+ const time = this.parseTimeString(this.multipleDates[index].startTime);
2041
+ this.multipleDates[index].date.setHours(time.hours, time.minutes, 0, 0);
2042
+ }
2043
+ this.emitScheduled();
2044
+ }
2045
+ }
2046
+ onMultipleDateStartTimeChange(index, time) {
2047
+ if (this.multipleDates[index]) {
2048
+ this.multipleDates[index].startTime = time;
2049
+ if (!this.multipleDates[index].allDay) {
2050
+ const parsed = this.parseTimeString(time);
2051
+ this.multipleDates[index].date.setHours(parsed.hours, parsed.minutes, 0, 0);
2052
+ }
2053
+ this.emitScheduled();
2054
+ }
2055
+ }
2056
+ onMultipleDateEndTimeChange(index, time) {
2057
+ if (this.multipleDates[index]) {
2058
+ this.multipleDates[index].endTime = time;
2059
+ this.emitScheduled();
2060
+ }
2061
+ }
2062
+ // Date Range Handlers
2063
+ onRangeSelected(event) {
2064
+ if (event.startDate && event.endDate) {
2065
+ this.rangeStartDate = new Date(event.startDate);
2066
+ this.rangeEndDate = new Date(event.endDate);
2067
+ if (!this.rangeAllDay) {
2068
+ this.updateRangeTimes();
2069
+ }
2070
+ this.emitScheduled();
2071
+ }
2072
+ else {
2073
+ this.rangeStartDate = null;
2074
+ this.rangeEndDate = null;
2075
+ }
2076
+ }
2077
+ onRangeAllDayChange() {
2078
+ this.rangeAllDay = !this.rangeAllDay;
2079
+ if (this.rangeStartDate && this.rangeEndDate) {
2080
+ this.updateRangeTimes();
2081
+ this.emitScheduled();
2082
+ }
2083
+ }
2084
+ onRangeStartTimeChange(time) {
2085
+ this.rangeStartTime = time;
2086
+ if (this.rangeStartDate && !this.rangeAllDay) {
2087
+ this.updateRangeTimes();
2088
+ this.emitScheduled();
2089
+ }
2090
+ }
2091
+ onRangeEndTimeChange(time) {
2092
+ this.rangeEndTime = time;
2093
+ if (this.rangeEndDate && !this.rangeAllDay) {
2094
+ this.updateRangeTimes();
2095
+ this.emitScheduled();
2096
+ }
2097
+ }
2098
+ updateRangeTimes() {
2099
+ if (!this.rangeStartDate || !this.rangeEndDate)
2100
+ return;
2101
+ if (this.rangeAllDay) {
2102
+ this.rangeStartDate.setHours(0, 0, 0, 0);
2103
+ this.rangeEndDate.setHours(23, 59, 59, 999);
2104
+ }
2105
+ else {
2106
+ const startTime = this.parseTimeString(this.rangeStartTime);
2107
+ const endTime = this.parseTimeString(this.rangeEndTime);
2108
+ this.rangeStartDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2109
+ this.rangeEndDate.setHours(endTime.hours, endTime.minutes, 0, 0);
2110
+ }
2111
+ }
2112
+ // Utility Methods
2113
+ parseTimeString(timeStr) {
2114
+ // Parse time string like "7:01 AM" or "19:01"
2115
+ const parts = timeStr.split(' ');
2116
+ let timePart = parts[0];
2117
+ const ampm = parts[1];
2118
+ const [hoursStr, minutesStr] = timePart.split(':');
2119
+ let hours = parseInt(hoursStr, 10);
2120
+ const minutes = parseInt(minutesStr || '0', 10);
2121
+ if (ampm) {
2122
+ if (ampm.toUpperCase() === 'PM' && hours !== 12) {
2123
+ hours += 12;
2124
+ }
2125
+ else if (ampm.toUpperCase() === 'AM' && hours === 12) {
2126
+ hours = 0;
2127
+ }
2128
+ }
2129
+ return { hours, minutes };
2130
+ }
2131
+ getDateString(date) {
2132
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
2133
+ }
2134
+ formatDate(date) {
2135
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2136
+ return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
2137
+ }
2138
+ emitScheduled() {
2139
+ const selection = {
2140
+ mode: this.activeTab
2141
+ };
2142
+ if (this.activeTab === 'single' && this.singleDate) {
2143
+ // For single date, create startDate and endDate with same date but different times
2144
+ const startDate = new Date(this.singleDate);
2145
+ const endDate = new Date(this.singleDate);
2146
+ if (!this.singleAllDay) {
2147
+ const startTime = this.parseTimeString(this.singleStartTime);
2148
+ const endTime = this.parseTimeString(this.singleEndTime);
2149
+ startDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2150
+ endDate.setHours(endTime.hours, endTime.minutes, 0, 0);
2151
+ }
2152
+ else {
2153
+ startDate.setHours(0, 0, 0, 0);
2154
+ endDate.setHours(23, 59, 59, 999);
2155
+ }
2156
+ selection.singleDate = {
2157
+ startDate: startDate,
2158
+ endDate: endDate,
2159
+ allDay: this.singleAllDay,
2160
+ startTime: this.singleStartTime,
2161
+ endTime: this.singleEndTime
2162
+ };
2163
+ }
2164
+ else if (this.activeTab === 'multiple') {
2165
+ selection.multipleDates = this.multipleDates.map(d => ({
2166
+ date: new Date(d.date),
2167
+ allDay: d.allDay,
2168
+ startTime: d.startTime,
2169
+ endTime: d.endTime
2170
+ }));
2171
+ }
2172
+ else if (this.activeTab === 'range' && this.rangeStartDate && this.rangeEndDate) {
2173
+ selection.dateRange = {
2174
+ startDate: new Date(this.rangeStartDate),
2175
+ endDate: new Date(this.rangeEndDate),
2176
+ allDay: this.rangeAllDay,
2177
+ startTime: this.rangeStartTime,
2178
+ endTime: this.rangeEndTime
2179
+ };
2180
+ }
2181
+ this.scheduled.emit(selection);
2182
+ }
2183
+ clear() {
2184
+ this.singleDate = null;
2185
+ this.multipleDates = [];
2186
+ this.rangeStartDate = null;
2187
+ this.rangeEndDate = null;
2188
+ this.singleAllDay = false;
2189
+ this.rangeAllDay = false;
2190
+ this.singleStartTime = '1:00 AM';
2191
+ this.singleEndTime = '2:00 AM';
2192
+ this.rangeStartTime = '1:00 AM';
2193
+ this.rangeEndTime = '2:00 AM';
2194
+ this.cleared.emit();
2195
+ }
2196
+ apply() {
2197
+ this.emitScheduled();
2198
+ }
2199
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ScheduledDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2200
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: ScheduledDatePickerComponent, isStandalone: true, selector: "brickclay-scheduled-date-picker", inputs: { timeFormat: "timeFormat", enableSeconds: "enableSeconds" }, outputs: { scheduled: "scheduled", cleared: "cleared" }, ngImport: i0, template: "<div class=\"scheduled-date-picker-container\">\r\n <!-- Header with Tabs -->\r\n\r\n\r\n <!-- Main Content Area -->\r\n\r\n <div class=\"scheduled-content\">\r\n <!-- Left Side: Calendar -->\r\n <div class=\"calendar-section\">\r\n <h2 class=\"scheduled-title\">Scheduled Dates</h2>\r\n <div class=\"tabs\">\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'single'\"\r\n (click)=\"onTabChange('single')\">\r\n Single Date\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'multiple'\"\r\n (click)=\"onTabChange('multiple')\">\r\n Multiple Dates\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'range'\"\r\n (click)=\"onTabChange('range')\">\r\n Date Range\r\n </button>\r\n </div>\r\n <!-- Single Date Calendar -->\r\n <div *ngIf=\"activeTab === 'single'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"true\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select a date\"\r\n (selected)=\"onSingleDateSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n\r\n <!-- Multiple Dates Calendar -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [multiDateSelection]=\"true\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select multiple dates\"\r\n (selected)=\"onMultipleDatesSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n\r\n <!-- Date Range Calendar -->\r\n <div *ngIf=\"activeTab === 'range'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select date range\"\r\n (selected)=\"onRangeSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Time Configuration -->\r\n <div class=\"time-config-section\">\r\n <h3 class=\"time-config-title\">Time Configuration</h3>\r\n\r\n <!-- Single Date Time Configuration -->\r\n <div *ngIf=\"activeTab === 'single'\">\r\n <div *ngIf=\"singleDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(singleDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"singleAllDay\"\r\n (change)=\"onSingleAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!singleAllDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n pickerId=\"single-start\"\r\n label=\"Start Time\"\r\n [value]=\"singleStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('single-start')\"\r\n (timeChange)=\"onSingleStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n pickerId=\"single-end\"\r\n label=\"End Time\"\r\n [value]=\"singleEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('single-end')\"\r\n (timeChange)=\"onSingleEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!singleDate\" class=\"no-selection\">\r\n <p>No date selected. Select a date from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Multiple Dates Time Configuration -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"time-config-list\">\r\n <div\r\n *ngFor=\"let dateConfig of multipleDates; let i = index\"\r\n class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(dateConfig.date) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"dateConfig.allDay\"\r\n (change)=\"onMultipleDateAllDayChange(i)\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!dateConfig.allDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n [pickerId]=\"'multiple-' + i + '-start'\"\r\n label=\"Start Time\"\r\n [value]=\"dateConfig.startTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-start')\"\r\n (timeChange)=\"onMultipleDateStartTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n [pickerId]=\"'multiple-' + i + '-end'\"\r\n label=\"End Time\"\r\n [value]=\"dateConfig.endTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-end')\"\r\n (timeChange)=\"onMultipleDateEndTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"multipleDates.length === 0\" class=\"no-selection\">\r\n <p>No dates selected. Select dates from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Date Range Time Configuration -->\r\n <div *ngIf=\"activeTab === 'range' && rangeStartDate && rangeEndDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(rangeStartDate) }} - {{ formatDate(rangeEndDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"rangeAllDay\"\r\n (change)=\"onRangeAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!rangeAllDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n pickerId=\"range-start\"\r\n label=\"Start Time\"\r\n [value]=\"rangeStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('range-start')\"\r\n (timeChange)=\"onRangeStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n pickerId=\"range-end\"\r\n label=\"End Time\"\r\n [value]=\"rangeEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('range-end')\"\r\n (timeChange)=\"onRangeEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"activeTab === 'range' && (!rangeStartDate || !rangeEndDate)\" class=\"no-selection\">\r\n <p>No date range selected. Select a date range from the calendar.</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n <div class=\"action-buttons\">\r\n <button class=\"btn-clear\" (click)=\"clear()\">Clear</button>\r\n <button class=\"btn-apply\" (click)=\"apply()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n", styles: [".scheduled-date-picker-container{font-family:Inter,sans-serif;background:#fff;border-radius:12px;padding:0;box-shadow:0 2px 8px #0000001a;overflow:hidden;width:100%;max-width:100%;box-sizing:border-box}.scheduled-header{padding:24px 24px 16px;border-bottom:1px solid #e5e7eb;background:#fff}.scheduled-title{font-size:18px;font-weight:500;line-height:26px;color:#111827;letter-spacing:-.28px;margin:0 0 16px}.tabs{display:flex;margin-bottom:16px;border-radius:6px;padding:3px;background-color:#54578e12}.tab-button{padding:5px 11px;border:none;background:transparent;color:#6b7080;font-size:11px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:all .2s;font-family:Inter,sans-serif;flex:1;border-radius:4px}.tab-button.active{color:#15191e;border-color:#42578a26;background:#fff}.scheduled-content{display:flex;gap:0;align-items:stretch}.calendar-section{flex:0 0 55%;max-width:55%;padding:12px;border-right:1px solid #e5e7eb;background:#fff;box-sizing:border-box}.calendar-wrapper-inline{width:100%}.calendar-wrapper-inline app-custom-calendar{width:100%}.time-config-section{flex:0 0 45%;max-width:45%;padding:12px;background:#fff;overflow-y:auto;max-height:600px;box-sizing:border-box}.time-config-title{font-size:16px;font-weight:600;color:#111827;margin:17px 0 14px}.time-config-item{padding:14px;border:1px solid #e5e7eb;border-radius:8px;background:#fff}.time-config-header{display:flex;justify-content:space-between;align-items:center}.date-label{font-size:12px;font-weight:500;color:#15191e;letter-spacing:-.28px}.all-day-toggle{display:flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.all-day-toggle input[type=checkbox]{width:28px;height:16px;appearance:none;background:#bbbdc5;border-radius:10px;position:relative;cursor:pointer;transition:background .2s;margin:0}.all-day-toggle input[type=checkbox]:checked{background:#22973f}.all-day-toggle input[type=checkbox]:before{content:\"\";position:absolute;width:12px;height:12px;border-radius:50%;background:#fff;top:1.5px;left:2.5px;transition:transform .2s;box-shadow:0 1px 3px #0003}.all-day-toggle input[type=checkbox]:checked:before{transform:translate(12px)}.toggle-label{font-size:12px;font-weight:500;color:#111827}.all-day-toggle input[type=checkbox]:checked+.toggle-label{color:#111827}.time-inputs{display:flex;gap:14px;margin-top:12px}.time-config-list{display:flex;flex-direction:column;gap:14px;max-height:350px;overflow-y:auto;padding-right:4px}.time-config-list::-webkit-scrollbar{width:6px;height:6px}.time-config-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb{background:#b4b4b4;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb:hover{background:#9b9b9b}.no-selection{padding:24px;text-align:center;color:#9ca3af;font-size:14px}.action-buttons{display:flex;justify-content:flex-end;gap:12px;padding:12px;border-top:1px solid #e5e7eb;background:#fff}.btn-clear,.btn-apply{padding:10px 20px;border:none;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;font-family:Inter,sans-serif;min-width:80px}.btn-clear{background:#fff;color:#6b7280;border:1px solid #d1d5db}.btn-clear:hover{background:#f9fafb;border-color:#9ca3af}.btn-apply{background:#111827;color:#fff}.btn-apply:hover{background:#374151}@media (max-width: 1200px){.calendar-section{flex:0 0 52%;max-width:52%}.time-config-section{flex:0 0 48%;max-width:48%}}@media (max-width: 1024px){.scheduled-content{flex-direction:column}.calendar-section{flex:1 1 auto;max-width:100%;border-right:none;border-bottom:1px solid #e5e7eb}.time-config-section{flex:1 1 auto;max-width:100%;max-height:none}.time-config-list{max-height:320px}}@media (max-width: 768px){.scheduled-date-picker-container{border-radius:0}.scheduled-header{padding:16px}.calendar-section,.time-config-section{padding:12px 16px}.tabs{overflow-x:auto}.tab-button{white-space:nowrap;font-size:12px;padding:6px 10px}.time-inputs{flex-direction:column}.time-config-item{padding:12px}.action-buttons{padding:10px}}@media (max-width: 480px){.scheduled-title{font-size:16px}.time-config-title{font-size:14px}.date-label{font-size:11px}.time-config-list{max-height:260px}.btn-clear,.btn-apply{padding:8px 14px;font-size:13px}}\n"], 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: "ngmodule", type: FormsModule }, { kind: "component", type: CustomCalendarComponent, selector: "brickclay-custom-calendar", inputs: ["enableTimepicker", "autoApply", "closeOnAutoApply", "showCancel", "linkedCalendars", "singleDatePicker", "showWeekNumbers", "showISOWeekNumbers", "customRangeDirection", "lockStartDate", "position", "drop", "dualCalendar", "showRanges", "timeFormat", "enableSeconds", "customRanges", "multiDateSelection", "maxDate", "minDate", "placeholder", "opens", "inline", "isDisplayCrossIcon", "selectedValue", "displayFormat"], outputs: ["selected", "opened", "closed"] }, { kind: "component", type: TimePickerComponent, selector: "brickclay-time-picker", inputs: ["value", "label", "placeholder", "position", "pickerId", "closePicker", "timeFormat", "showSeconds"], outputs: ["timeChange", "pickerOpened", "pickerClosed"] }] });
2201
+ }
2202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ScheduledDatePickerComponent, decorators: [{
2203
+ type: Component,
2204
+ args: [{ selector: 'brickclay-scheduled-date-picker', standalone: true, imports: [CommonModule, FormsModule, CustomCalendarComponent, TimePickerComponent], template: "<div class=\"scheduled-date-picker-container\">\r\n <!-- Header with Tabs -->\r\n\r\n\r\n <!-- Main Content Area -->\r\n\r\n <div class=\"scheduled-content\">\r\n <!-- Left Side: Calendar -->\r\n <div class=\"calendar-section\">\r\n <h2 class=\"scheduled-title\">Scheduled Dates</h2>\r\n <div class=\"tabs\">\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'single'\"\r\n (click)=\"onTabChange('single')\">\r\n Single Date\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'multiple'\"\r\n (click)=\"onTabChange('multiple')\">\r\n Multiple Dates\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'range'\"\r\n (click)=\"onTabChange('range')\">\r\n Date Range\r\n </button>\r\n </div>\r\n <!-- Single Date Calendar -->\r\n <div *ngIf=\"activeTab === 'single'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"true\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select a date\"\r\n (selected)=\"onSingleDateSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n\r\n <!-- Multiple Dates Calendar -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [multiDateSelection]=\"true\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select multiple dates\"\r\n (selected)=\"onMultipleDatesSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n\r\n <!-- Date Range Calendar -->\r\n <div *ngIf=\"activeTab === 'range'\" class=\"calendar-wrapper-inline\">\r\n <brickclay-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select date range\"\r\n (selected)=\"onRangeSelected($event)\">\r\n </brickclay-custom-calendar>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Time Configuration -->\r\n <div class=\"time-config-section\">\r\n <h3 class=\"time-config-title\">Time Configuration</h3>\r\n\r\n <!-- Single Date Time Configuration -->\r\n <div *ngIf=\"activeTab === 'single'\">\r\n <div *ngIf=\"singleDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(singleDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"singleAllDay\"\r\n (change)=\"onSingleAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!singleAllDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n pickerId=\"single-start\"\r\n label=\"Start Time\"\r\n [value]=\"singleStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('single-start')\"\r\n (timeChange)=\"onSingleStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n pickerId=\"single-end\"\r\n label=\"End Time\"\r\n [value]=\"singleEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('single-end')\"\r\n (timeChange)=\"onSingleEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!singleDate\" class=\"no-selection\">\r\n <p>No date selected. Select a date from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Multiple Dates Time Configuration -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"time-config-list\">\r\n <div\r\n *ngFor=\"let dateConfig of multipleDates; let i = index\"\r\n class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(dateConfig.date) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"dateConfig.allDay\"\r\n (change)=\"onMultipleDateAllDayChange(i)\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!dateConfig.allDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n [pickerId]=\"'multiple-' + i + '-start'\"\r\n label=\"Start Time\"\r\n [value]=\"dateConfig.startTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-start')\"\r\n (timeChange)=\"onMultipleDateStartTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n [pickerId]=\"'multiple-' + i + '-end'\"\r\n label=\"End Time\"\r\n [value]=\"dateConfig.endTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-end')\"\r\n (timeChange)=\"onMultipleDateEndTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"multipleDates.length === 0\" class=\"no-selection\">\r\n <p>No dates selected. Select dates from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Date Range Time Configuration -->\r\n <div *ngIf=\"activeTab === 'range' && rangeStartDate && rangeEndDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(rangeStartDate) }} - {{ formatDate(rangeEndDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"rangeAllDay\"\r\n (change)=\"onRangeAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!rangeAllDay\" class=\"time-inputs\">\r\n <brickclay-time-picker\r\n pickerId=\"range-start\"\r\n label=\"Start Time\"\r\n [value]=\"rangeStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('range-start')\"\r\n (timeChange)=\"onRangeStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n <brickclay-time-picker\r\n pickerId=\"range-end\"\r\n label=\"End Time\"\r\n [value]=\"rangeEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('range-end')\"\r\n (timeChange)=\"onRangeEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </brickclay-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"activeTab === 'range' && (!rangeStartDate || !rangeEndDate)\" class=\"no-selection\">\r\n <p>No date range selected. Select a date range from the calendar.</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n <div class=\"action-buttons\">\r\n <button class=\"btn-clear\" (click)=\"clear()\">Clear</button>\r\n <button class=\"btn-apply\" (click)=\"apply()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n", styles: [".scheduled-date-picker-container{font-family:Inter,sans-serif;background:#fff;border-radius:12px;padding:0;box-shadow:0 2px 8px #0000001a;overflow:hidden;width:100%;max-width:100%;box-sizing:border-box}.scheduled-header{padding:24px 24px 16px;border-bottom:1px solid #e5e7eb;background:#fff}.scheduled-title{font-size:18px;font-weight:500;line-height:26px;color:#111827;letter-spacing:-.28px;margin:0 0 16px}.tabs{display:flex;margin-bottom:16px;border-radius:6px;padding:3px;background-color:#54578e12}.tab-button{padding:5px 11px;border:none;background:transparent;color:#6b7080;font-size:11px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:all .2s;font-family:Inter,sans-serif;flex:1;border-radius:4px}.tab-button.active{color:#15191e;border-color:#42578a26;background:#fff}.scheduled-content{display:flex;gap:0;align-items:stretch}.calendar-section{flex:0 0 55%;max-width:55%;padding:12px;border-right:1px solid #e5e7eb;background:#fff;box-sizing:border-box}.calendar-wrapper-inline{width:100%}.calendar-wrapper-inline app-custom-calendar{width:100%}.time-config-section{flex:0 0 45%;max-width:45%;padding:12px;background:#fff;overflow-y:auto;max-height:600px;box-sizing:border-box}.time-config-title{font-size:16px;font-weight:600;color:#111827;margin:17px 0 14px}.time-config-item{padding:14px;border:1px solid #e5e7eb;border-radius:8px;background:#fff}.time-config-header{display:flex;justify-content:space-between;align-items:center}.date-label{font-size:12px;font-weight:500;color:#15191e;letter-spacing:-.28px}.all-day-toggle{display:flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.all-day-toggle input[type=checkbox]{width:28px;height:16px;appearance:none;background:#bbbdc5;border-radius:10px;position:relative;cursor:pointer;transition:background .2s;margin:0}.all-day-toggle input[type=checkbox]:checked{background:#22973f}.all-day-toggle input[type=checkbox]:before{content:\"\";position:absolute;width:12px;height:12px;border-radius:50%;background:#fff;top:1.5px;left:2.5px;transition:transform .2s;box-shadow:0 1px 3px #0003}.all-day-toggle input[type=checkbox]:checked:before{transform:translate(12px)}.toggle-label{font-size:12px;font-weight:500;color:#111827}.all-day-toggle input[type=checkbox]:checked+.toggle-label{color:#111827}.time-inputs{display:flex;gap:14px;margin-top:12px}.time-config-list{display:flex;flex-direction:column;gap:14px;max-height:350px;overflow-y:auto;padding-right:4px}.time-config-list::-webkit-scrollbar{width:6px;height:6px}.time-config-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb{background:#b4b4b4;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb:hover{background:#9b9b9b}.no-selection{padding:24px;text-align:center;color:#9ca3af;font-size:14px}.action-buttons{display:flex;justify-content:flex-end;gap:12px;padding:12px;border-top:1px solid #e5e7eb;background:#fff}.btn-clear,.btn-apply{padding:10px 20px;border:none;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;font-family:Inter,sans-serif;min-width:80px}.btn-clear{background:#fff;color:#6b7280;border:1px solid #d1d5db}.btn-clear:hover{background:#f9fafb;border-color:#9ca3af}.btn-apply{background:#111827;color:#fff}.btn-apply:hover{background:#374151}@media (max-width: 1200px){.calendar-section{flex:0 0 52%;max-width:52%}.time-config-section{flex:0 0 48%;max-width:48%}}@media (max-width: 1024px){.scheduled-content{flex-direction:column}.calendar-section{flex:1 1 auto;max-width:100%;border-right:none;border-bottom:1px solid #e5e7eb}.time-config-section{flex:1 1 auto;max-width:100%;max-height:none}.time-config-list{max-height:320px}}@media (max-width: 768px){.scheduled-date-picker-container{border-radius:0}.scheduled-header{padding:16px}.calendar-section,.time-config-section{padding:12px 16px}.tabs{overflow-x:auto}.tab-button{white-space:nowrap;font-size:12px;padding:6px 10px}.time-inputs{flex-direction:column}.time-config-item{padding:12px}.action-buttons{padding:10px}}@media (max-width: 480px){.scheduled-title{font-size:16px}.time-config-title{font-size:14px}.date-label{font-size:11px}.time-config-list{max-height:260px}.btn-clear,.btn-apply{padding:8px 14px;font-size:13px}}\n"] }]
2205
+ }], propDecorators: { timeFormat: [{
2206
+ type: Input
2207
+ }], enableSeconds: [{
2208
+ type: Input
2209
+ }], scheduled: [{
2210
+ type: Output
2211
+ }], cleared: [{
2212
+ type: Output
2213
+ }] } });
2214
+
2215
+ /**
2216
+ * Optional NgModule wrapper for projects that prefer module-based usage.
2217
+ *
2218
+ * Note:
2219
+ * - The components themselves are standalone, so you can also import them
2220
+ * directly into any standalone component without using this module.
2221
+ * - This module is mainly for:
2222
+ * - Existing apps that still use feature modules
2223
+ * - Easier "plug-and-play" integration: import CalendarModule once and use
2224
+ * the three exported components anywhere in your templates.
2225
+ */
2226
+ class CalendarModule {
2227
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2228
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, imports: [CommonModule,
2229
+ CustomCalendarComponent,
2230
+ ScheduledDatePickerComponent,
2231
+ TimePickerComponent], exports: [CustomCalendarComponent,
2232
+ ScheduledDatePickerComponent,
2233
+ TimePickerComponent] });
2234
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, imports: [CommonModule,
2235
+ CustomCalendarComponent,
2236
+ ScheduledDatePickerComponent,
2237
+ TimePickerComponent] });
2238
+ }
2239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, decorators: [{
2240
+ type: NgModule,
2241
+ args: [{
2242
+ imports: [
2243
+ CommonModule,
2244
+ CustomCalendarComponent,
2245
+ ScheduledDatePickerComponent,
2246
+ TimePickerComponent
2247
+ ],
2248
+ exports: [
2249
+ CustomCalendarComponent,
2250
+ ScheduledDatePickerComponent,
2251
+ TimePickerComponent
2252
+ ]
2253
+ }]
2254
+ }] });
2255
+
2256
+ /*
2257
+ * Public API Surface of brickclay-lib
2258
+ */
2259
+
2260
+ /**
2261
+ * Generated bundle index. Do not edit.
2262
+ */
2263
+
2264
+ export { BrickclayLib, CalendarManagerService, CalendarModule, CustomCalendarComponent, ScheduledDatePickerComponent, TimePickerComponent };
2265
+ //# sourceMappingURL=brickclay-ui.mjs.map