@oneluiz/dual-datepicker 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +934 -11
- package/dual-datepicker.component.d.ts +15 -1
- package/esm2022/dual-datepicker.component.mjs +272 -46
- package/esm2022/native-date-adapter.mjs +6 -1
- package/fesm2022/oneluiz-dual-datepicker.mjs +276 -45
- package/fesm2022/oneluiz-dual-datepicker.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -27,6 +27,11 @@ class NativeDateAdapter extends DateAdapter {
|
|
|
27
27
|
return new Date(value);
|
|
28
28
|
}
|
|
29
29
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
30
|
+
// Fix timezone issues: parse YYYY-MM-DD as local date, not UTC
|
|
31
|
+
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
32
|
+
const [year, month, day] = value.split('-').map(Number);
|
|
33
|
+
return new Date(year, month - 1, day);
|
|
34
|
+
}
|
|
30
35
|
const date = new Date(value);
|
|
31
36
|
return this.isValid(date) ? date : null;
|
|
32
37
|
}
|
|
@@ -135,6 +140,7 @@ class DualDatepickerComponent {
|
|
|
135
140
|
closeOnSelection = true;
|
|
136
141
|
closeOnPresetSelection = true;
|
|
137
142
|
closeOnClickOutside = true;
|
|
143
|
+
enableKeyboardNavigation = true;
|
|
138
144
|
presets = [];
|
|
139
145
|
inputBackgroundColor = '#fff';
|
|
140
146
|
inputTextColor = '#495057';
|
|
@@ -143,6 +149,9 @@ class DualDatepickerComponent {
|
|
|
143
149
|
inputBorderColorFocus = '#80bdff';
|
|
144
150
|
inputPadding = '0.375rem 0.75rem';
|
|
145
151
|
locale = {};
|
|
152
|
+
disabledDates;
|
|
153
|
+
displayFormat = 'D MMM'; // Format for displaying dates in input
|
|
154
|
+
requireApply = false; // Require Apply button confirmation
|
|
146
155
|
dateRangeChange = new EventEmitter();
|
|
147
156
|
dateRangeSelected = new EventEmitter();
|
|
148
157
|
multiDateRangeChange = new EventEmitter();
|
|
@@ -158,6 +167,12 @@ class DualDatepickerComponent {
|
|
|
158
167
|
currentMonthDays = signal([]);
|
|
159
168
|
previousMonthDays = signal([]);
|
|
160
169
|
isDisabled = signal(false);
|
|
170
|
+
// Apply/Confirm support
|
|
171
|
+
pendingStartDate = '';
|
|
172
|
+
pendingEndDate = '';
|
|
173
|
+
hasPendingChanges = signal(false);
|
|
174
|
+
// Hover range preview
|
|
175
|
+
hoverDate = signal(null);
|
|
161
176
|
// Multi-range support
|
|
162
177
|
selectedRanges = signal([]);
|
|
163
178
|
currentRangeIndex = signal(-1);
|
|
@@ -193,6 +208,9 @@ class DualDatepickerComponent {
|
|
|
193
208
|
}
|
|
194
209
|
}
|
|
195
210
|
handleKeyboardNavigation(event) {
|
|
211
|
+
if (!this.enableKeyboardNavigation) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
196
214
|
if (!this.showDatePicker()) {
|
|
197
215
|
// When picker is closed, allow Enter/Space to open it
|
|
198
216
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
@@ -265,19 +283,63 @@ class DualDatepickerComponent {
|
|
|
265
283
|
initializeFocus() {
|
|
266
284
|
// Set initial focus to start date, end date, or first available day
|
|
267
285
|
if (this.startDate) {
|
|
268
|
-
const
|
|
269
|
-
this.
|
|
286
|
+
const inPrevMonth = this.isDateInMonth(this.startDate, this.previousMonth());
|
|
287
|
+
const inCurrMonth = this.isDateInMonth(this.startDate, this.currentMonth());
|
|
288
|
+
if (inPrevMonth || inCurrMonth) {
|
|
289
|
+
this.focusedDay.set({ date: this.startDate, monthIndex: inPrevMonth ? 0 : 1 });
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
// startDate is not visible, focus on today if visible
|
|
293
|
+
const today = this.dateAdapter.format(this.dateAdapter.today(), 'yyyy-MM-dd');
|
|
294
|
+
const inCurrMonth = this.isDateInMonth(today, this.currentMonth());
|
|
295
|
+
if (inCurrMonth) {
|
|
296
|
+
this.focusedDay.set({ date: today, monthIndex: 1 });
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
const currentMonthDays = this.currentMonthDays();
|
|
300
|
+
const firstDay = currentMonthDays.find(day => day.isCurrentMonth);
|
|
301
|
+
if (firstDay) {
|
|
302
|
+
this.focusedDay.set({ date: firstDay.date, monthIndex: 1 });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
270
306
|
}
|
|
271
307
|
else if (this.endDate) {
|
|
272
|
-
const
|
|
273
|
-
this.
|
|
308
|
+
const inPrevMonth = this.isDateInMonth(this.endDate, this.previousMonth());
|
|
309
|
+
const inCurrMonth = this.isDateInMonth(this.endDate, this.currentMonth());
|
|
310
|
+
if (inPrevMonth || inCurrMonth) {
|
|
311
|
+
this.focusedDay.set({ date: this.endDate, monthIndex: inPrevMonth ? 0 : 1 });
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
// endDate is not visible, focus on today if visible
|
|
315
|
+
const today = this.dateAdapter.format(this.dateAdapter.today(), 'yyyy-MM-dd');
|
|
316
|
+
const inCurrMonth = this.isDateInMonth(today, this.currentMonth());
|
|
317
|
+
if (inCurrMonth) {
|
|
318
|
+
this.focusedDay.set({ date: today, monthIndex: 1 });
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
const currentMonthDays = this.currentMonthDays();
|
|
322
|
+
const firstDay = currentMonthDays.find(day => day.isCurrentMonth);
|
|
323
|
+
if (firstDay) {
|
|
324
|
+
this.focusedDay.set({ date: firstDay.date, monthIndex: 1 });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
274
328
|
}
|
|
275
329
|
else {
|
|
276
|
-
// Focus first day of current month
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
280
|
-
this.focusedDay.set({ date:
|
|
330
|
+
// Focus on today if visible, otherwise first day of current month
|
|
331
|
+
const today = this.dateAdapter.format(this.dateAdapter.today(), 'yyyy-MM-dd');
|
|
332
|
+
const inCurrMonth = this.isDateInMonth(today, this.currentMonth());
|
|
333
|
+
if (inCurrMonth) {
|
|
334
|
+
this.focusedDay.set({ date: today, monthIndex: 1 });
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
// Today is not in current month, focus on first day of current month
|
|
338
|
+
const currentMonthDays = this.currentMonthDays();
|
|
339
|
+
const firstDay = currentMonthDays.find(day => day.isCurrentMonth);
|
|
340
|
+
if (firstDay) {
|
|
341
|
+
this.focusedDay.set({ date: firstDay.date, monthIndex: 1 });
|
|
342
|
+
}
|
|
281
343
|
}
|
|
282
344
|
}
|
|
283
345
|
}
|
|
@@ -303,8 +365,8 @@ class DualDatepickerComponent {
|
|
|
303
365
|
const newDate = this.dateAdapter.addDays(currentDate, direction);
|
|
304
366
|
const newDateStr = this.formatDate(newDate);
|
|
305
367
|
// Determine which month the new date belongs to
|
|
306
|
-
|
|
307
|
-
|
|
368
|
+
let inPrevMonth = this.isDateInMonth(newDateStr, this.previousMonth());
|
|
369
|
+
let inCurrMonth = this.isDateInMonth(newDateStr, this.currentMonth());
|
|
308
370
|
if (inPrevMonth || inCurrMonth) {
|
|
309
371
|
this.focusedDay.set({
|
|
310
372
|
date: newDateStr,
|
|
@@ -319,7 +381,13 @@ class DualDatepickerComponent {
|
|
|
319
381
|
else {
|
|
320
382
|
this.changeMonth(-1);
|
|
321
383
|
}
|
|
322
|
-
|
|
384
|
+
// Recalculate after month change
|
|
385
|
+
inPrevMonth = this.isDateInMonth(newDateStr, this.previousMonth());
|
|
386
|
+
inCurrMonth = this.isDateInMonth(newDateStr, this.currentMonth());
|
|
387
|
+
this.focusedDay.set({
|
|
388
|
+
date: newDateStr,
|
|
389
|
+
monthIndex: inPrevMonth ? 0 : (inCurrMonth ? 1 : 0)
|
|
390
|
+
});
|
|
323
391
|
}
|
|
324
392
|
}
|
|
325
393
|
moveFocusVertical(direction) {
|
|
@@ -333,8 +401,8 @@ class DualDatepickerComponent {
|
|
|
333
401
|
return;
|
|
334
402
|
const newDate = this.dateAdapter.addDays(currentDate, direction * 7); // Move by week
|
|
335
403
|
const newDateStr = this.formatDate(newDate);
|
|
336
|
-
|
|
337
|
-
|
|
404
|
+
let inPrevMonth = this.isDateInMonth(newDateStr, this.previousMonth());
|
|
405
|
+
let inCurrMonth = this.isDateInMonth(newDateStr, this.currentMonth());
|
|
338
406
|
if (inPrevMonth || inCurrMonth) {
|
|
339
407
|
this.focusedDay.set({
|
|
340
408
|
date: newDateStr,
|
|
@@ -349,7 +417,13 @@ class DualDatepickerComponent {
|
|
|
349
417
|
else {
|
|
350
418
|
this.changeMonth(-1);
|
|
351
419
|
}
|
|
352
|
-
|
|
420
|
+
// Recalculate after month change
|
|
421
|
+
inPrevMonth = this.isDateInMonth(newDateStr, this.previousMonth());
|
|
422
|
+
inCurrMonth = this.isDateInMonth(newDateStr, this.currentMonth());
|
|
423
|
+
this.focusedDay.set({
|
|
424
|
+
date: newDateStr,
|
|
425
|
+
monthIndex: inPrevMonth ? 0 : (inCurrMonth ? 1 : 0)
|
|
426
|
+
});
|
|
353
427
|
}
|
|
354
428
|
}
|
|
355
429
|
moveFocusToFirstDay() {
|
|
@@ -452,8 +526,25 @@ class DualDatepickerComponent {
|
|
|
452
526
|
const date = this.dateAdapter.parse(dateStr);
|
|
453
527
|
if (!date)
|
|
454
528
|
return '';
|
|
455
|
-
const
|
|
456
|
-
|
|
529
|
+
const year = this.dateAdapter.getYear(date);
|
|
530
|
+
const month = this.dateAdapter.getMonth(date);
|
|
531
|
+
const day = this.dateAdapter.getDate(date);
|
|
532
|
+
const monthNames = this.locale.monthNames || this.defaultMonthNames;
|
|
533
|
+
const monthNamesShort = this.locale.monthNamesShort || this.defaultMonthNamesShort;
|
|
534
|
+
// Replace format tokens with values
|
|
535
|
+
let formatted = this.displayFormat;
|
|
536
|
+
// Year tokens
|
|
537
|
+
formatted = formatted.replace(/YYYY/g, String(year));
|
|
538
|
+
formatted = formatted.replace(/YY/g, String(year).slice(-2));
|
|
539
|
+
// Month tokens (order matters: MMMM before MMM before MM before M)
|
|
540
|
+
formatted = formatted.replace(/MMMM/g, monthNames[month]);
|
|
541
|
+
formatted = formatted.replace(/MMM/g, monthNamesShort[month]);
|
|
542
|
+
formatted = formatted.replace(/MM/g, String(month + 1).padStart(2, '0'));
|
|
543
|
+
formatted = formatted.replace(/M/g, String(month + 1));
|
|
544
|
+
// Day tokens (order matters: DD before D)
|
|
545
|
+
formatted = formatted.replace(/DD/g, String(day).padStart(2, '0'));
|
|
546
|
+
formatted = formatted.replace(/D/g, String(day));
|
|
547
|
+
return formatted;
|
|
457
548
|
}
|
|
458
549
|
updateDateRangeText() {
|
|
459
550
|
if (this.startDate && this.endDate) {
|
|
@@ -475,18 +566,24 @@ class DualDatepickerComponent {
|
|
|
475
566
|
const previousMonthDate = this.dateAdapter.createDate(year, month - 1, 1);
|
|
476
567
|
this.previousMonth.set(previousMonthDate);
|
|
477
568
|
this.generateCalendars();
|
|
478
|
-
// Initialize keyboard focus
|
|
479
|
-
this.
|
|
569
|
+
// Initialize keyboard focus only if keyboard navigation is enabled
|
|
570
|
+
if (this.enableKeyboardNavigation) {
|
|
571
|
+
this.initializeFocus();
|
|
572
|
+
}
|
|
480
573
|
}
|
|
481
574
|
else {
|
|
482
575
|
// Clear focus when closing
|
|
483
|
-
this.
|
|
576
|
+
if (this.enableKeyboardNavigation) {
|
|
577
|
+
this.focusedDay.set(null);
|
|
578
|
+
}
|
|
484
579
|
}
|
|
485
580
|
this.onTouched();
|
|
486
581
|
}
|
|
487
582
|
closeDatePicker() {
|
|
488
583
|
this.showDatePicker.set(false);
|
|
489
|
-
this.
|
|
584
|
+
if (this.enableKeyboardNavigation) {
|
|
585
|
+
this.focusedDay.set(null);
|
|
586
|
+
}
|
|
490
587
|
this.onTouched();
|
|
491
588
|
}
|
|
492
589
|
generateCalendars() {
|
|
@@ -507,13 +604,22 @@ class DualDatepickerComponent {
|
|
|
507
604
|
for (let day = 1; day <= daysInMonth; day++) {
|
|
508
605
|
const dayDate = this.dateAdapter.createDate(year, month, day);
|
|
509
606
|
const dateStr = this.formatDate(dayDate);
|
|
607
|
+
// Check if date is in pending range (for requireApply mode)
|
|
608
|
+
const isPendingStart = this.requireApply && this.pendingStartDate === dateStr;
|
|
609
|
+
const isPendingEnd = this.requireApply && this.pendingEndDate === dateStr;
|
|
610
|
+
const inPendingRange = this.requireApply && this.pendingStartDate && this.pendingEndDate &&
|
|
611
|
+
dateStr >= this.pendingStartDate && dateStr <= this.pendingEndDate;
|
|
612
|
+
// Check if date is in hover preview range
|
|
613
|
+
const inHoverRange = this.isInHoverRange(dateStr);
|
|
510
614
|
monthDays.push({
|
|
511
615
|
day: day,
|
|
512
616
|
date: dateStr,
|
|
513
617
|
isCurrentMonth: true,
|
|
514
|
-
isStart: this.startDate === dateStr,
|
|
515
|
-
isEnd: this.endDate === dateStr,
|
|
516
|
-
inRange: this.isInRange(dateStr)
|
|
618
|
+
isStart: this.startDate === dateStr || isPendingStart,
|
|
619
|
+
isEnd: this.endDate === dateStr || isPendingEnd,
|
|
620
|
+
inRange: this.isInRange(dateStr) || inPendingRange,
|
|
621
|
+
inHoverRange: inHoverRange,
|
|
622
|
+
isDisabled: this.isDateDisabled(dayDate)
|
|
517
623
|
});
|
|
518
624
|
}
|
|
519
625
|
return monthDays;
|
|
@@ -531,8 +637,74 @@ class DualDatepickerComponent {
|
|
|
531
637
|
return dateStr >= this.startDate && dateStr <= this.endDate;
|
|
532
638
|
}
|
|
533
639
|
}
|
|
640
|
+
isDateDisabled(date) {
|
|
641
|
+
if (!this.disabledDates)
|
|
642
|
+
return false;
|
|
643
|
+
if (typeof this.disabledDates === 'function') {
|
|
644
|
+
// If it's a function, call it with the date
|
|
645
|
+
return this.disabledDates(date);
|
|
646
|
+
}
|
|
647
|
+
else if (Array.isArray(this.disabledDates)) {
|
|
648
|
+
// If it's an array, check if the date matches any disabled date
|
|
649
|
+
return this.disabledDates.some(disabledDate => {
|
|
650
|
+
return this.dateAdapter.getYear(date) === this.dateAdapter.getYear(disabledDate) &&
|
|
651
|
+
this.dateAdapter.getMonth(date) === this.dateAdapter.getMonth(disabledDate) &&
|
|
652
|
+
this.dateAdapter.getDate(date) === this.dateAdapter.getDate(disabledDate);
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
isInHoverRange(dateStr) {
|
|
658
|
+
const hover = this.hoverDate();
|
|
659
|
+
if (!hover)
|
|
660
|
+
return false;
|
|
661
|
+
// In multiRange mode, only show hover preview when selecting end date
|
|
662
|
+
if (this.multiRange) {
|
|
663
|
+
if (this.selectingStartDate())
|
|
664
|
+
return false;
|
|
665
|
+
if (!this.startDate)
|
|
666
|
+
return false;
|
|
667
|
+
const minDate = this.startDate < hover ? this.startDate : hover;
|
|
668
|
+
const maxDate = this.startDate > hover ? this.startDate : hover;
|
|
669
|
+
return dateStr >= minDate && dateStr <= maxDate;
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
// In single range mode with requireApply
|
|
673
|
+
if (this.requireApply) {
|
|
674
|
+
if (this.selectingStartDate())
|
|
675
|
+
return false;
|
|
676
|
+
if (!this.pendingStartDate)
|
|
677
|
+
return false;
|
|
678
|
+
const minDate = this.pendingStartDate < hover ? this.pendingStartDate : hover;
|
|
679
|
+
const maxDate = this.pendingStartDate > hover ? this.pendingStartDate : hover;
|
|
680
|
+
return dateStr >= minDate && dateStr <= maxDate;
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
// In single range mode without requireApply
|
|
684
|
+
if (this.selectingStartDate())
|
|
685
|
+
return false;
|
|
686
|
+
if (!this.startDate)
|
|
687
|
+
return false;
|
|
688
|
+
const minDate = this.startDate < hover ? this.startDate : hover;
|
|
689
|
+
const maxDate = this.startDate > hover ? this.startDate : hover;
|
|
690
|
+
return dateStr >= minDate && dateStr <= maxDate;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
onDayHover(dayObj) {
|
|
695
|
+
if (!dayObj.isCurrentMonth || this.isDisabled() || dayObj.isDisabled) {
|
|
696
|
+
this.hoverDate.set(null);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
this.hoverDate.set(dayObj.date);
|
|
700
|
+
this.generateCalendars();
|
|
701
|
+
}
|
|
702
|
+
clearDayHover() {
|
|
703
|
+
this.hoverDate.set(null);
|
|
704
|
+
this.generateCalendars();
|
|
705
|
+
}
|
|
534
706
|
selectDay(dayObj) {
|
|
535
|
-
if (!dayObj.isCurrentMonth || this.isDisabled())
|
|
707
|
+
if (!dayObj.isCurrentMonth || this.isDisabled() || dayObj.isDisabled)
|
|
536
708
|
return;
|
|
537
709
|
if (this.multiRange) {
|
|
538
710
|
// Multi-range mode: add ranges to array
|
|
@@ -576,32 +748,83 @@ class DualDatepickerComponent {
|
|
|
576
748
|
}
|
|
577
749
|
else {
|
|
578
750
|
// Single range mode (original behavior)
|
|
579
|
-
if (this.
|
|
580
|
-
|
|
581
|
-
this.
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
751
|
+
if (this.requireApply) {
|
|
752
|
+
// Apply mode: use pending dates, don't emit until Apply is clicked
|
|
753
|
+
if (this.selectingStartDate()) {
|
|
754
|
+
this.pendingStartDate = dayObj.date;
|
|
755
|
+
this.pendingEndDate = '';
|
|
756
|
+
this.selectingStartDate.set(false);
|
|
757
|
+
this.hasPendingChanges.set(true);
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
if (dayObj.date < this.pendingStartDate) {
|
|
761
|
+
this.pendingEndDate = this.pendingStartDate;
|
|
762
|
+
this.pendingStartDate = dayObj.date;
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
this.pendingEndDate = dayObj.date;
|
|
766
|
+
}
|
|
767
|
+
this.selectingStartDate.set(true);
|
|
768
|
+
this.hasPendingChanges.set(true);
|
|
769
|
+
}
|
|
770
|
+
this.generateCalendars();
|
|
585
771
|
}
|
|
586
772
|
else {
|
|
587
|
-
|
|
588
|
-
|
|
773
|
+
// Immediate mode: emit changes immediately
|
|
774
|
+
if (this.selectingStartDate()) {
|
|
589
775
|
this.startDate = dayObj.date;
|
|
776
|
+
this.endDate = '';
|
|
777
|
+
this.dateRangeText.set('');
|
|
778
|
+
this.selectingStartDate.set(false);
|
|
779
|
+
this.emitChange();
|
|
590
780
|
}
|
|
591
781
|
else {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
782
|
+
if (dayObj.date < this.startDate) {
|
|
783
|
+
this.endDate = this.startDate;
|
|
784
|
+
this.startDate = dayObj.date;
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
this.endDate = dayObj.date;
|
|
788
|
+
}
|
|
789
|
+
this.updateDateRangeText();
|
|
790
|
+
if (this.closeOnSelection) {
|
|
791
|
+
this.showDatePicker.set(false);
|
|
792
|
+
}
|
|
793
|
+
this.selectingStartDate.set(true);
|
|
794
|
+
this.emitChange();
|
|
795
|
+
this.emitSelection();
|
|
597
796
|
}
|
|
598
|
-
this.
|
|
599
|
-
this.emitChange();
|
|
600
|
-
this.emitSelection();
|
|
797
|
+
this.generateCalendars();
|
|
601
798
|
}
|
|
602
|
-
this.generateCalendars();
|
|
603
799
|
}
|
|
604
800
|
}
|
|
801
|
+
applySelection() {
|
|
802
|
+
if (!this.hasPendingChanges())
|
|
803
|
+
return;
|
|
804
|
+
// Apply pending dates
|
|
805
|
+
this.startDate = this.pendingStartDate;
|
|
806
|
+
this.endDate = this.pendingEndDate;
|
|
807
|
+
this.updateDateRangeText();
|
|
808
|
+
// Clear pending state
|
|
809
|
+
this.pendingStartDate = '';
|
|
810
|
+
this.pendingEndDate = '';
|
|
811
|
+
this.hasPendingChanges.set(false);
|
|
812
|
+
// Emit changes
|
|
813
|
+
this.emitChange();
|
|
814
|
+
this.emitSelection();
|
|
815
|
+
// Close picker
|
|
816
|
+
this.showDatePicker.set(false);
|
|
817
|
+
this.selectingStartDate.set(true);
|
|
818
|
+
}
|
|
819
|
+
cancelSelection() {
|
|
820
|
+
// Discard pending changes
|
|
821
|
+
this.pendingStartDate = '';
|
|
822
|
+
this.pendingEndDate = '';
|
|
823
|
+
this.hasPendingChanges.set(false);
|
|
824
|
+
this.selectingStartDate.set(true);
|
|
825
|
+
// Regenerate calendars to clear pending visual state
|
|
826
|
+
this.generateCalendars();
|
|
827
|
+
}
|
|
605
828
|
changeMonth(direction) {
|
|
606
829
|
const currentMonthValue = this.currentMonth();
|
|
607
830
|
const year = this.dateAdapter.getYear(currentMonthValue);
|
|
@@ -733,7 +956,7 @@ class DualDatepickerComponent {
|
|
|
733
956
|
this.isDisabled.set(isDisabled);
|
|
734
957
|
}
|
|
735
958
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DualDatepickerComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
736
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: DualDatepickerComponent, isStandalone: true, selector: "ngx-dual-datepicker", inputs: { placeholder: "placeholder", startDate: "startDate", endDate: "endDate", showPresets: "showPresets", showClearButton: "showClearButton", multiRange: "multiRange", closeOnSelection: "closeOnSelection", closeOnPresetSelection: "closeOnPresetSelection", closeOnClickOutside: "closeOnClickOutside", presets: "presets", inputBackgroundColor: "inputBackgroundColor", inputTextColor: "inputTextColor", inputBorderColor: "inputBorderColor", inputBorderColorHover: "inputBorderColorHover", inputBorderColorFocus: "inputBorderColorFocus", inputPadding: "inputPadding", locale: "locale" }, outputs: { dateRangeChange: "dateRangeChange", dateRangeSelected: "dateRangeSelected", multiDateRangeChange: "multiDateRangeChange", multiDateRangeSelected: "multiDateRangeSelected" }, host: { listeners: { "document:click": "onClickOutside($event)", "keydown": "handleKeyboardNavigation($event)" } }, providers: [
|
|
959
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: DualDatepickerComponent, isStandalone: true, selector: "ngx-dual-datepicker", inputs: { placeholder: "placeholder", startDate: "startDate", endDate: "endDate", showPresets: "showPresets", showClearButton: "showClearButton", multiRange: "multiRange", closeOnSelection: "closeOnSelection", closeOnPresetSelection: "closeOnPresetSelection", closeOnClickOutside: "closeOnClickOutside", enableKeyboardNavigation: "enableKeyboardNavigation", presets: "presets", inputBackgroundColor: "inputBackgroundColor", inputTextColor: "inputTextColor", inputBorderColor: "inputBorderColor", inputBorderColorHover: "inputBorderColorHover", inputBorderColorFocus: "inputBorderColorFocus", inputPadding: "inputPadding", locale: "locale", disabledDates: "disabledDates", displayFormat: "displayFormat", requireApply: "requireApply" }, outputs: { dateRangeChange: "dateRangeChange", dateRangeSelected: "dateRangeSelected", multiDateRangeChange: "multiDateRangeChange", multiDateRangeSelected: "multiDateRangeSelected" }, host: { listeners: { "document:click": "onClickOutside($event)", "keydown": "handleKeyboardNavigation($event)" } }, providers: [
|
|
737
960
|
{
|
|
738
961
|
provide: NG_VALUE_ACCESSOR,
|
|
739
962
|
useExisting: forwardRef(() => DualDatepickerComponent),
|
|
@@ -743,7 +966,7 @@ class DualDatepickerComponent {
|
|
|
743
966
|
provide: DATE_ADAPTER,
|
|
744
967
|
useClass: NativeDateAdapter
|
|
745
968
|
}
|
|
746
|
-
], usesOnChanges: true, ngImport: i0, template: "<div class=\"datepicker-wrapper\" \n [style.--input-border-hover]=\"inputBorderColorHover\"\n [style.--input-border-focus]=\"inputBorderColorFocus\">\n <input \n type=\"text\" \n class=\"datepicker-input\" \n [value]=\"dateRangeText()\" \n (click)=\"toggleDatePicker()\" \n [placeholder]=\"placeholder\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"placeholder\"\n [attr.aria-expanded]=\"showDatePicker()\"\n [attr.aria-haspopup]=\"'dialog'\"\n role=\"combobox\"\n [ngStyle]=\"{\n 'background-color': inputBackgroundColor,\n 'color': inputTextColor,\n 'border-color': inputBorderColor,\n 'padding': inputPadding\n }\"\n readonly>\n\n @if (showDatePicker()) {\n <div class=\"date-picker-dropdown\">\n @if (showPresets) {\n <div class=\"date-picker-presets\">\n @for (preset of presets; track preset.label) {\n <button type=\"button\" (click)=\"selectPresetRange(preset)\">{{ preset.label }}</button>\n }\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n @if (!showPresets) {\n <div class=\"date-picker-header-only-close\">\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n <!-- Calendars -->\n <div class=\"date-picker-calendars\">\n <!-- Previous month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" (click)=\"changeMonth(-1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ previousMonthName() }}</span>\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of previousMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.keyboard-focused]=\"hasKeyboardFocus(dayObj.date, 0)\"\n [attr.tabindex]=\"dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 0) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n (click)=\"selectDay(dayObj)\"\n [disabled]=\"!dayObj.isCurrentMonth\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n\n <!-- Current month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ currentMonthName() }}</span>\n <button type=\"button\" (click)=\"changeMonth(1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of currentMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.keyboard-focused]=\"hasKeyboardFocus(dayObj.date, 1)\"\n [attr.tabindex]=\"dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 1) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n (click)=\"selectDay(dayObj)\"\n [disabled]=\"!dayObj.isCurrentMonth\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Multi-Range List -->\n @if (multiRange && selectedRanges().length > 0) {\n <div class=\"multi-range-list\">\n <div class=\"multi-range-header\">\n <span class=\"multi-range-title\">Selected Ranges ({{ selectedRanges().length }})</span>\n </div>\n <div class=\"multi-range-items\">\n @for (range of selectedRanges(); track $index) {\n <div class=\"multi-range-item\">\n <span class=\"multi-range-text\">{{ range.rangeText }}</span>\n <button \n type=\"button\" \n class=\"btn-remove-range\" \n (click)=\"removeRange($index)\"\n title=\"Remove this range\">\n <svg width=\"14\" height=\"14\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path d=\"M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer with clear button -->\n @if (showClearButton || multiRange) {\n <div class=\"date-picker-footer\">\n @if (multiRange) {\n <div class=\"multi-range-footer-actions\">\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear all ranges\">\n Clear All\n </button>\n <button type=\"button\" class=\"btn-done\" (click)=\"closeDatePicker()\" title=\"Done selecting\">\n Done\n </button>\n </div>\n }\n @if (!multiRange && showClearButton) {\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear selection\">\n Clear\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".datepicker-wrapper{position:relative;width:100%}.datepicker-wrapper .datepicker-input{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;cursor:pointer}.datepicker-wrapper .datepicker-input:hover{border-color:var(--input-border-hover, #ced4da)}.datepicker-wrapper .datepicker-input:focus{border-color:var(--input-border-focus, #80bdff);box-shadow:0 0 0 .2rem #007bff40;outline:0}.datepicker-wrapper .datepicker-input::placeholder{color:#6c757d;opacity:1}.datepicker-wrapper .datepicker-input:disabled,.datepicker-wrapper .datepicker-input[readonly]{background-color:#e9ecef;opacity:1}.date-picker-dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #e1e4e8;border-radius:8px;box-shadow:0 4px 12px #00000014,0 0 1px #00000014;padding:16px;z-index:1060;min-width:680px}@media (max-width: 768px){.date-picker-dropdown{min-width:100%;left:0;right:0}}.date-picker-header-only-close{display:flex;justify-content:flex-end;margin-bottom:12px}.date-picker-header-only-close .btn-close-calendar{background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;border-radius:6px;cursor:pointer;transition:all .15s ease;font-size:1.5rem;line-height:1}.date-picker-header-only-close .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-header-only-close .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-presets{display:flex;gap:6px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid #e5e7eb;align-items:center}@media (max-width: 768px){.date-picker-presets{flex-wrap:wrap}}.date-picker-presets button{font-size:.75rem;padding:6px 14px;border:none;background-color:#f9fafb;color:#374151;border-radius:6px;transition:all .15s ease;font-weight:500;cursor:pointer;border:1px solid #e5e7eb}.date-picker-presets button:hover{background-color:#f3f4f6;border-color:#d1d5db;transform:translateY(-1px);box-shadow:0 2px 4px #0000000f}.date-picker-presets button:active{transform:translateY(0);box-shadow:none}.date-picker-presets .btn-close-calendar{margin-left:auto;background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;font-size:1.5rem;line-height:1}.date-picker-presets .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-presets .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-calendars{display:flex;gap:32px}@media (max-width: 768px){.date-picker-calendars{flex-direction:column;gap:16px}}.date-picker-calendar{flex:1}.date-picker-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding:0 4px}.date-picker-header span{font-size:.813rem;font-weight:600;color:#111827}.date-picker-header button{padding:4px;color:#6b7280;text-decoration:none;border-radius:6px;transition:all .15s ease;border:none;background:transparent;cursor:pointer}.date-picker-header button:hover{background-color:#f3f4f6;color:#111827}.date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:4px}.date-picker-weekdays span{text-align:center;font-size:.625rem;font-weight:600;color:#6b7280;padding:6px}.date-picker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.date-picker-day{aspect-ratio:1;border:none;background:transparent;border-radius:50%;font-size:.75rem;cursor:pointer;transition:all .15s ease;color:#374151;font-weight:400;position:relative}.date-picker-day:hover:not(:disabled):not(.selected){background-color:#f3f4f6;color:#111827}.date-picker-day.empty{visibility:hidden}.date-picker-day.selected{background-color:#222;color:#fff;font-weight:600}.date-picker-day.in-range{background-color:#f9fafb;border-radius:0}.date-picker-day:disabled{cursor:not-allowed;opacity:.3}.date-picker-day.keyboard-focused{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-day.keyboard-focused:not(.selected){background-color:#eff6ff}.date-picker-day:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-footer{padding:12px;border-top:1px solid #e1e4e8;display:flex;justify-content:center;gap:8px}.date-picker-footer .btn-clear{padding:8px 16px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-clear:hover{background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-clear:active{transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-done{padding:8px 16px;background-color:#222;border:1px solid #222;border-radius:6px;font-size:.875rem;font-weight:500;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-done:hover{background-color:#000;border-color:#000;transform:translateY(-1px);box-shadow:0 2px 4px #00000026}.date-picker-footer .btn-done:active{transform:translateY(0);box-shadow:none}.date-picker-footer .multi-range-footer-actions{display:flex;gap:8px;width:100%;justify-content:space-between}.multi-range-list{border-top:1px solid #e1e4e8;border-bottom:1px solid #e1e4e8;padding:12px;margin-top:12px}.multi-range-list .multi-range-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.multi-range-list .multi-range-header .multi-range-title{font-size:.8125rem;font-weight:600;color:#24292f;text-transform:uppercase;letter-spacing:.025em}.multi-range-list .multi-range-items{display:flex;flex-direction:column;gap:6px;max-height:150px;overflow-y:auto}.multi-range-list .multi-range-items::-webkit-scrollbar{width:6px}.multi-range-list .multi-range-items::-webkit-scrollbar-track{background:#f1f3f4;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb{background:#cbd5e0;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb:hover{background:#a0aec0}.multi-range-list .multi-range-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;transition:all .15s ease}.multi-range-list .multi-range-item:hover{background-color:#f3f4f6;border-color:#8c959f}.multi-range-list .multi-range-item .multi-range-text{font-size:.875rem;color:#24292f;font-weight:500}.multi-range-list .multi-range-item .btn-remove-range{padding:4px;background-color:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#6b7280;transition:all .15s ease}.multi-range-list .multi-range-item .btn-remove-range:hover{background-color:#fee;border-color:#fcc;color:#dc2626}.multi-range-list .multi-range-item .btn-remove-range:hover svg{transform:scale(1.1)}.multi-range-list .multi-range-item .btn-remove-range:active{transform:scale(.95)}.multi-range-list .multi-range-item .btn-remove-range svg{transition:transform .15s ease}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
969
|
+
], usesOnChanges: true, ngImport: i0, template: "<div class=\"datepicker-wrapper\" \n [style.--input-border-hover]=\"inputBorderColorHover\"\n [style.--input-border-focus]=\"inputBorderColorFocus\">\n <input \n type=\"text\" \n class=\"datepicker-input\" \n [value]=\"dateRangeText()\" \n (click)=\"toggleDatePicker()\" \n [placeholder]=\"placeholder\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"placeholder\"\n [attr.aria-expanded]=\"showDatePicker()\"\n [attr.aria-haspopup]=\"'dialog'\"\n role=\"combobox\"\n [ngStyle]=\"{\n 'background-color': inputBackgroundColor,\n 'color': inputTextColor,\n 'border-color': inputBorderColor,\n 'padding': inputPadding\n }\"\n readonly>\n\n @if (showDatePicker()) {\n <div class=\"date-picker-dropdown\">\n @if (showPresets) {\n <div class=\"date-picker-presets\">\n @for (preset of presets; track preset.label) {\n <button type=\"button\" (click)=\"selectPresetRange(preset)\">{{ preset.label }}</button>\n }\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n @if (!showPresets) {\n <div class=\"date-picker-header-only-close\">\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n <!-- Calendars -->\n <div class=\"date-picker-calendars\">\n <!-- Previous month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" (click)=\"changeMonth(-1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ previousMonthName() }}</span>\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of previousMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.in-hover-range]=\"dayObj.inHoverRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.disabled]=\"dayObj.isDisabled\"\n [class.keyboard-focused]=\"enableKeyboardNavigation && hasKeyboardFocus(dayObj.date, 0)\"\n [attr.tabindex]=\"enableKeyboardNavigation && dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 0) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n [attr.aria-disabled]=\"dayObj.isDisabled\"\n (click)=\"selectDay(dayObj)\"\n (mouseenter)=\"onDayHover(dayObj)\"\n (mouseleave)=\"clearDayHover()\"\n [disabled]=\"!dayObj.isCurrentMonth || dayObj.isDisabled\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n\n <!-- Current month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ currentMonthName() }}</span>\n <button type=\"button\" (click)=\"changeMonth(1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of currentMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.in-hover-range]=\"dayObj.inHoverRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.disabled]=\"dayObj.isDisabled\"\n [class.keyboard-focused]=\"enableKeyboardNavigation && hasKeyboardFocus(dayObj.date, 1)\"\n [attr.tabindex]=\"enableKeyboardNavigation && dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 1) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n [attr.aria-disabled]=\"dayObj.isDisabled\"\n (click)=\"selectDay(dayObj)\"\n (mouseenter)=\"onDayHover(dayObj)\"\n (mouseleave)=\"clearDayHover()\"\n [disabled]=\"!dayObj.isCurrentMonth || dayObj.isDisabled\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Multi-Range List -->\n @if (multiRange && selectedRanges().length > 0) {\n <div class=\"multi-range-list\">\n <div class=\"multi-range-header\">\n <span class=\"multi-range-title\">Selected Ranges ({{ selectedRanges().length }})</span>\n </div>\n <div class=\"multi-range-items\">\n @for (range of selectedRanges(); track $index) {\n <div class=\"multi-range-item\">\n <span class=\"multi-range-text\">{{ range.rangeText }}</span>\n <button \n type=\"button\" \n class=\"btn-remove-range\" \n (click)=\"removeRange($index)\"\n title=\"Remove this range\">\n <svg width=\"14\" height=\"14\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path d=\"M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer with buttons -->\n @if (showClearButton || multiRange || requireApply) {\n <div class=\"date-picker-footer\">\n @if (requireApply && !multiRange) {\n <div class=\"apply-footer-actions\">\n <button \n type=\"button\" \n class=\"btn-cancel\" \n (click)=\"cancelSelection()\" \n [disabled]=\"!hasPendingChanges()\"\n title=\"Cancel selection\">\n Cancel\n </button>\n <button \n type=\"button\" \n class=\"btn-apply\" \n (click)=\"applySelection()\" \n [disabled]=\"!hasPendingChanges() || !pendingStartDate || !pendingEndDate\"\n title=\"Apply selection\">\n Apply\n </button>\n </div>\n }\n @if (multiRange) {\n <div class=\"multi-range-footer-actions\">\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear all ranges\">\n Clear All\n </button>\n <button type=\"button\" class=\"btn-done\" (click)=\"closeDatePicker()\" title=\"Done selecting\">\n Done\n </button>\n </div>\n }\n @if (!multiRange && !requireApply && showClearButton) {\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear selection\">\n Clear\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".datepicker-wrapper{position:relative;width:100%}.datepicker-wrapper .datepicker-input{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;cursor:pointer}.datepicker-wrapper .datepicker-input:hover{border-color:var(--input-border-hover, #ced4da)}.datepicker-wrapper .datepicker-input:focus{border-color:var(--input-border-focus, #80bdff);box-shadow:0 0 0 .2rem #007bff40;outline:0}.datepicker-wrapper .datepicker-input::placeholder{color:#6c757d;opacity:1}.datepicker-wrapper .datepicker-input:disabled,.datepicker-wrapper .datepicker-input[readonly]{background-color:#e9ecef;opacity:1}.date-picker-dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #e1e4e8;border-radius:8px;box-shadow:0 4px 12px #00000014,0 0 1px #00000014;padding:16px;z-index:1060;min-width:680px}@media (max-width: 768px){.date-picker-dropdown{min-width:100%;left:0;right:0}}.date-picker-header-only-close{display:flex;justify-content:flex-end;margin-bottom:12px}.date-picker-header-only-close .btn-close-calendar{background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;border-radius:6px;cursor:pointer;transition:all .15s ease;font-size:1.5rem;line-height:1}.date-picker-header-only-close .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-header-only-close .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-presets{display:flex;gap:6px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid #e5e7eb;align-items:center}@media (max-width: 768px){.date-picker-presets{flex-wrap:wrap}}.date-picker-presets button{font-size:.75rem;padding:6px 14px;border:none;background-color:#f9fafb;color:#374151;border-radius:6px;transition:all .15s ease;font-weight:500;cursor:pointer;border:1px solid #e5e7eb}.date-picker-presets button:hover{background-color:#f3f4f6;border-color:#d1d5db;transform:translateY(-1px);box-shadow:0 2px 4px #0000000f}.date-picker-presets button:active{transform:translateY(0);box-shadow:none}.date-picker-presets .btn-close-calendar{margin-left:auto;background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;font-size:1.5rem;line-height:1}.date-picker-presets .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-presets .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-calendars{display:flex;gap:32px}@media (max-width: 768px){.date-picker-calendars{flex-direction:column;gap:16px}}.date-picker-calendar{flex:1}.date-picker-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding:0 4px}.date-picker-header span{font-size:.813rem;font-weight:600;color:#111827}.date-picker-header button{padding:4px;color:#6b7280;text-decoration:none;border-radius:6px;transition:all .15s ease;border:none;background:transparent;cursor:pointer}.date-picker-header button:hover{background-color:#f3f4f6;color:#111827}.date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:4px}.date-picker-weekdays span{text-align:center;font-size:.625rem;font-weight:600;color:#6b7280;padding:6px}.date-picker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.date-picker-day{aspect-ratio:1;border:none;background:transparent;border-radius:50%;font-size:.75rem;cursor:pointer;transition:all .15s ease;color:#374151;font-weight:400;position:relative}.date-picker-day:hover:not(:disabled):not(.selected){background-color:#f3f4f6;color:#111827}.date-picker-day.empty{visibility:hidden}.date-picker-day.selected{background-color:#222;color:#fff;font-weight:600}.date-picker-day.in-range{background-color:#f9fafb;border-radius:0}.date-picker-day.in-hover-range{background-color:#e0e7ff;border-radius:0;opacity:.7;position:relative}.date-picker-day.in-hover-range:after{content:\"\";position:absolute;inset:0;border:1px dashed #6366f1;pointer-events:none}.date-picker-day:disabled{cursor:not-allowed;opacity:.3}.date-picker-day.disabled{cursor:not-allowed;opacity:.4;color:#9ca3af;background-color:#f9fafb;text-decoration:line-through}.date-picker-day.disabled:hover{background-color:#f9fafb;color:#9ca3af}.date-picker-day.keyboard-focused{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-day.keyboard-focused:not(.selected){background-color:#eff6ff}.date-picker-day:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-footer{padding:12px;border-top:1px solid #e1e4e8;display:flex;justify-content:center;gap:8px}.date-picker-footer .btn-clear{padding:8px 16px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-clear:hover{background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-clear:active{transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-done{padding:8px 16px;background-color:#222;border:1px solid #222;border-radius:6px;font-size:.875rem;font-weight:500;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-done:hover{background-color:#000;border-color:#000;transform:translateY(-1px);box-shadow:0 2px 4px #00000026}.date-picker-footer .btn-done:active{transform:translateY(0);box-shadow:none}.date-picker-footer .btn-apply{padding:8px 24px;background-color:#2563eb;border:1px solid #2563eb;border-radius:6px;font-size:.875rem;font-weight:600;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-apply:hover:not(:disabled){background-color:#1d4ed8;border-color:#1d4ed8;transform:translateY(-1px);box-shadow:0 2px 8px #2563eb40}.date-picker-footer .btn-apply:active:not(:disabled){transform:translateY(0);box-shadow:none}.date-picker-footer .btn-apply:disabled{opacity:.5;cursor:not-allowed}.date-picker-footer .btn-cancel{padding:8px 24px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-cancel:hover:not(:disabled){background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-cancel:active:not(:disabled){transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-cancel:disabled{opacity:.5;cursor:not-allowed}.date-picker-footer .apply-footer-actions{display:flex;gap:8px;width:100%;justify-content:flex-end}.date-picker-footer .multi-range-footer-actions{display:flex;gap:8px;width:100%;justify-content:space-between}.multi-range-list{border-top:1px solid #e1e4e8;border-bottom:1px solid #e1e4e8;padding:12px;margin-top:12px}.multi-range-list .multi-range-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.multi-range-list .multi-range-header .multi-range-title{font-size:.8125rem;font-weight:600;color:#24292f;text-transform:uppercase;letter-spacing:.025em}.multi-range-list .multi-range-items{display:flex;flex-direction:column;gap:6px;max-height:150px;overflow-y:auto}.multi-range-list .multi-range-items::-webkit-scrollbar{width:6px}.multi-range-list .multi-range-items::-webkit-scrollbar-track{background:#f1f3f4;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb{background:#cbd5e0;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb:hover{background:#a0aec0}.multi-range-list .multi-range-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;transition:all .15s ease}.multi-range-list .multi-range-item:hover{background-color:#f3f4f6;border-color:#8c959f}.multi-range-list .multi-range-item .multi-range-text{font-size:.875rem;color:#24292f;font-weight:500}.multi-range-list .multi-range-item .btn-remove-range{padding:4px;background-color:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#6b7280;transition:all .15s ease}.multi-range-list .multi-range-item .btn-remove-range:hover{background-color:#fee;border-color:#fcc;color:#dc2626}.multi-range-list .multi-range-item .btn-remove-range:hover svg{transform:scale(1.1)}.multi-range-list .multi-range-item .btn-remove-range:active{transform:scale(.95)}.multi-range-list .multi-range-item .btn-remove-range svg{transition:transform .15s ease}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
747
970
|
}
|
|
748
971
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DualDatepickerComponent, decorators: [{
|
|
749
972
|
type: Component,
|
|
@@ -757,7 +980,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
757
980
|
provide: DATE_ADAPTER,
|
|
758
981
|
useClass: NativeDateAdapter
|
|
759
982
|
}
|
|
760
|
-
], template: "<div class=\"datepicker-wrapper\" \n [style.--input-border-hover]=\"inputBorderColorHover\"\n [style.--input-border-focus]=\"inputBorderColorFocus\">\n <input \n type=\"text\" \n class=\"datepicker-input\" \n [value]=\"dateRangeText()\" \n (click)=\"toggleDatePicker()\" \n [placeholder]=\"placeholder\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"placeholder\"\n [attr.aria-expanded]=\"showDatePicker()\"\n [attr.aria-haspopup]=\"'dialog'\"\n role=\"combobox\"\n [ngStyle]=\"{\n 'background-color': inputBackgroundColor,\n 'color': inputTextColor,\n 'border-color': inputBorderColor,\n 'padding': inputPadding\n }\"\n readonly>\n\n @if (showDatePicker()) {\n <div class=\"date-picker-dropdown\">\n @if (showPresets) {\n <div class=\"date-picker-presets\">\n @for (preset of presets; track preset.label) {\n <button type=\"button\" (click)=\"selectPresetRange(preset)\">{{ preset.label }}</button>\n }\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n @if (!showPresets) {\n <div class=\"date-picker-header-only-close\">\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n <!-- Calendars -->\n <div class=\"date-picker-calendars\">\n <!-- Previous month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" (click)=\"changeMonth(-1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ previousMonthName() }}</span>\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of previousMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.keyboard-focused]=\"hasKeyboardFocus(dayObj.date, 0)\"\n [attr.tabindex]=\"dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 0) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n (click)=\"selectDay(dayObj)\"\n [disabled]=\"!dayObj.isCurrentMonth\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n\n <!-- Current month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ currentMonthName() }}</span>\n <button type=\"button\" (click)=\"changeMonth(1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of currentMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.keyboard-focused]=\"hasKeyboardFocus(dayObj.date, 1)\"\n [attr.tabindex]=\"dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 1) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n (click)=\"selectDay(dayObj)\"\n [disabled]=\"!dayObj.isCurrentMonth\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Multi-Range List -->\n @if (multiRange && selectedRanges().length > 0) {\n <div class=\"multi-range-list\">\n <div class=\"multi-range-header\">\n <span class=\"multi-range-title\">Selected Ranges ({{ selectedRanges().length }})</span>\n </div>\n <div class=\"multi-range-items\">\n @for (range of selectedRanges(); track $index) {\n <div class=\"multi-range-item\">\n <span class=\"multi-range-text\">{{ range.rangeText }}</span>\n <button \n type=\"button\" \n class=\"btn-remove-range\" \n (click)=\"removeRange($index)\"\n title=\"Remove this range\">\n <svg width=\"14\" height=\"14\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path d=\"M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer with clear button -->\n @if (showClearButton || multiRange) {\n <div class=\"date-picker-footer\">\n @if (multiRange) {\n <div class=\"multi-range-footer-actions\">\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear all ranges\">\n Clear All\n </button>\n <button type=\"button\" class=\"btn-done\" (click)=\"closeDatePicker()\" title=\"Done selecting\">\n Done\n </button>\n </div>\n }\n @if (!multiRange && showClearButton) {\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear selection\">\n Clear\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".datepicker-wrapper{position:relative;width:100%}.datepicker-wrapper .datepicker-input{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;cursor:pointer}.datepicker-wrapper .datepicker-input:hover{border-color:var(--input-border-hover, #ced4da)}.datepicker-wrapper .datepicker-input:focus{border-color:var(--input-border-focus, #80bdff);box-shadow:0 0 0 .2rem #007bff40;outline:0}.datepicker-wrapper .datepicker-input::placeholder{color:#6c757d;opacity:1}.datepicker-wrapper .datepicker-input:disabled,.datepicker-wrapper .datepicker-input[readonly]{background-color:#e9ecef;opacity:1}.date-picker-dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #e1e4e8;border-radius:8px;box-shadow:0 4px 12px #00000014,0 0 1px #00000014;padding:16px;z-index:1060;min-width:680px}@media (max-width: 768px){.date-picker-dropdown{min-width:100%;left:0;right:0}}.date-picker-header-only-close{display:flex;justify-content:flex-end;margin-bottom:12px}.date-picker-header-only-close .btn-close-calendar{background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;border-radius:6px;cursor:pointer;transition:all .15s ease;font-size:1.5rem;line-height:1}.date-picker-header-only-close .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-header-only-close .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-presets{display:flex;gap:6px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid #e5e7eb;align-items:center}@media (max-width: 768px){.date-picker-presets{flex-wrap:wrap}}.date-picker-presets button{font-size:.75rem;padding:6px 14px;border:none;background-color:#f9fafb;color:#374151;border-radius:6px;transition:all .15s ease;font-weight:500;cursor:pointer;border:1px solid #e5e7eb}.date-picker-presets button:hover{background-color:#f3f4f6;border-color:#d1d5db;transform:translateY(-1px);box-shadow:0 2px 4px #0000000f}.date-picker-presets button:active{transform:translateY(0);box-shadow:none}.date-picker-presets .btn-close-calendar{margin-left:auto;background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;font-size:1.5rem;line-height:1}.date-picker-presets .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-presets .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-calendars{display:flex;gap:32px}@media (max-width: 768px){.date-picker-calendars{flex-direction:column;gap:16px}}.date-picker-calendar{flex:1}.date-picker-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding:0 4px}.date-picker-header span{font-size:.813rem;font-weight:600;color:#111827}.date-picker-header button{padding:4px;color:#6b7280;text-decoration:none;border-radius:6px;transition:all .15s ease;border:none;background:transparent;cursor:pointer}.date-picker-header button:hover{background-color:#f3f4f6;color:#111827}.date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:4px}.date-picker-weekdays span{text-align:center;font-size:.625rem;font-weight:600;color:#6b7280;padding:6px}.date-picker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.date-picker-day{aspect-ratio:1;border:none;background:transparent;border-radius:50%;font-size:.75rem;cursor:pointer;transition:all .15s ease;color:#374151;font-weight:400;position:relative}.date-picker-day:hover:not(:disabled):not(.selected){background-color:#f3f4f6;color:#111827}.date-picker-day.empty{visibility:hidden}.date-picker-day.selected{background-color:#222;color:#fff;font-weight:600}.date-picker-day.in-range{background-color:#f9fafb;border-radius:0}.date-picker-day:disabled{cursor:not-allowed;opacity:.3}.date-picker-day.keyboard-focused{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-day.keyboard-focused:not(.selected){background-color:#eff6ff}.date-picker-day:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-footer{padding:12px;border-top:1px solid #e1e4e8;display:flex;justify-content:center;gap:8px}.date-picker-footer .btn-clear{padding:8px 16px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-clear:hover{background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-clear:active{transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-done{padding:8px 16px;background-color:#222;border:1px solid #222;border-radius:6px;font-size:.875rem;font-weight:500;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-done:hover{background-color:#000;border-color:#000;transform:translateY(-1px);box-shadow:0 2px 4px #00000026}.date-picker-footer .btn-done:active{transform:translateY(0);box-shadow:none}.date-picker-footer .multi-range-footer-actions{display:flex;gap:8px;width:100%;justify-content:space-between}.multi-range-list{border-top:1px solid #e1e4e8;border-bottom:1px solid #e1e4e8;padding:12px;margin-top:12px}.multi-range-list .multi-range-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.multi-range-list .multi-range-header .multi-range-title{font-size:.8125rem;font-weight:600;color:#24292f;text-transform:uppercase;letter-spacing:.025em}.multi-range-list .multi-range-items{display:flex;flex-direction:column;gap:6px;max-height:150px;overflow-y:auto}.multi-range-list .multi-range-items::-webkit-scrollbar{width:6px}.multi-range-list .multi-range-items::-webkit-scrollbar-track{background:#f1f3f4;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb{background:#cbd5e0;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb:hover{background:#a0aec0}.multi-range-list .multi-range-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;transition:all .15s ease}.multi-range-list .multi-range-item:hover{background-color:#f3f4f6;border-color:#8c959f}.multi-range-list .multi-range-item .multi-range-text{font-size:.875rem;color:#24292f;font-weight:500}.multi-range-list .multi-range-item .btn-remove-range{padding:4px;background-color:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#6b7280;transition:all .15s ease}.multi-range-list .multi-range-item .btn-remove-range:hover{background-color:#fee;border-color:#fcc;color:#dc2626}.multi-range-list .multi-range-item .btn-remove-range:hover svg{transform:scale(1.1)}.multi-range-list .multi-range-item .btn-remove-range:active{transform:scale(.95)}.multi-range-list .multi-range-item .btn-remove-range svg{transition:transform .15s ease}\n"] }]
|
|
983
|
+
], template: "<div class=\"datepicker-wrapper\" \n [style.--input-border-hover]=\"inputBorderColorHover\"\n [style.--input-border-focus]=\"inputBorderColorFocus\">\n <input \n type=\"text\" \n class=\"datepicker-input\" \n [value]=\"dateRangeText()\" \n (click)=\"toggleDatePicker()\" \n [placeholder]=\"placeholder\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"placeholder\"\n [attr.aria-expanded]=\"showDatePicker()\"\n [attr.aria-haspopup]=\"'dialog'\"\n role=\"combobox\"\n [ngStyle]=\"{\n 'background-color': inputBackgroundColor,\n 'color': inputTextColor,\n 'border-color': inputBorderColor,\n 'padding': inputPadding\n }\"\n readonly>\n\n @if (showDatePicker()) {\n <div class=\"date-picker-dropdown\">\n @if (showPresets) {\n <div class=\"date-picker-presets\">\n @for (preset of presets; track preset.label) {\n <button type=\"button\" (click)=\"selectPresetRange(preset)\">{{ preset.label }}</button>\n }\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n @if (!showPresets) {\n <div class=\"date-picker-header-only-close\">\n <button type=\"button\" class=\"btn-close-calendar\" (click)=\"closeDatePicker()\" title=\"Close\">\n \u00D7\n </button>\n </div>\n }\n\n <!-- Calendars -->\n <div class=\"date-picker-calendars\">\n <!-- Previous month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" (click)=\"changeMonth(-1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ previousMonthName() }}</span>\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of previousMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.in-hover-range]=\"dayObj.inHoverRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.disabled]=\"dayObj.isDisabled\"\n [class.keyboard-focused]=\"enableKeyboardNavigation && hasKeyboardFocus(dayObj.date, 0)\"\n [attr.tabindex]=\"enableKeyboardNavigation && dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 0) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n [attr.aria-disabled]=\"dayObj.isDisabled\"\n (click)=\"selectDay(dayObj)\"\n (mouseenter)=\"onDayHover(dayObj)\"\n (mouseleave)=\"clearDayHover()\"\n [disabled]=\"!dayObj.isCurrentMonth || dayObj.isDisabled\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n\n <!-- Current month calendar -->\n <div class=\"date-picker-calendar\">\n <div class=\"date-picker-header\">\n <button type=\"button\" style=\"visibility: hidden;\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>\n </svg>\n </button>\n <span>{{ currentMonthName() }}</span>\n <button type=\"button\" (click)=\"changeMonth(1)\">\n <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z\"/>\n </svg>\n </button>\n </div>\n <div class=\"date-picker-weekdays\">\n @for (dayName of weekDayNames(); track $index) {\n <span>{{ dayName }}</span>\n }\n </div>\n <div class=\"date-picker-days\">\n @for (dayObj of currentMonthDays(); track dayObj.date || $index) {\n <button \n type=\"button\"\n class=\"date-picker-day\" \n [class.empty]=\"!dayObj.isCurrentMonth\"\n [class.selected]=\"dayObj.isStart || dayObj.isEnd\"\n [class.in-range]=\"dayObj.inRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.in-hover-range]=\"dayObj.inHoverRange && !dayObj.isStart && !dayObj.isEnd\"\n [class.disabled]=\"dayObj.isDisabled\"\n [class.keyboard-focused]=\"enableKeyboardNavigation && hasKeyboardFocus(dayObj.date, 1)\"\n [attr.tabindex]=\"enableKeyboardNavigation && dayObj.isCurrentMonth && hasKeyboardFocus(dayObj.date, 1) ? 0 : -1\"\n [attr.aria-label]=\"formatDateDisplay(dayObj.date)\"\n [attr.aria-selected]=\"dayObj.isStart || dayObj.isEnd\"\n [attr.aria-current]=\"dayObj.isStart ? 'date' : null\"\n [attr.aria-disabled]=\"dayObj.isDisabled\"\n (click)=\"selectDay(dayObj)\"\n (mouseenter)=\"onDayHover(dayObj)\"\n (mouseleave)=\"clearDayHover()\"\n [disabled]=\"!dayObj.isCurrentMonth || dayObj.isDisabled\">\n {{ dayObj.day }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Multi-Range List -->\n @if (multiRange && selectedRanges().length > 0) {\n <div class=\"multi-range-list\">\n <div class=\"multi-range-header\">\n <span class=\"multi-range-title\">Selected Ranges ({{ selectedRanges().length }})</span>\n </div>\n <div class=\"multi-range-items\">\n @for (range of selectedRanges(); track $index) {\n <div class=\"multi-range-item\">\n <span class=\"multi-range-text\">{{ range.rangeText }}</span>\n <button \n type=\"button\" \n class=\"btn-remove-range\" \n (click)=\"removeRange($index)\"\n title=\"Remove this range\">\n <svg width=\"14\" height=\"14\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n <path d=\"M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer with buttons -->\n @if (showClearButton || multiRange || requireApply) {\n <div class=\"date-picker-footer\">\n @if (requireApply && !multiRange) {\n <div class=\"apply-footer-actions\">\n <button \n type=\"button\" \n class=\"btn-cancel\" \n (click)=\"cancelSelection()\" \n [disabled]=\"!hasPendingChanges()\"\n title=\"Cancel selection\">\n Cancel\n </button>\n <button \n type=\"button\" \n class=\"btn-apply\" \n (click)=\"applySelection()\" \n [disabled]=\"!hasPendingChanges() || !pendingStartDate || !pendingEndDate\"\n title=\"Apply selection\">\n Apply\n </button>\n </div>\n }\n @if (multiRange) {\n <div class=\"multi-range-footer-actions\">\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear all ranges\">\n Clear All\n </button>\n <button type=\"button\" class=\"btn-done\" (click)=\"closeDatePicker()\" title=\"Done selecting\">\n Done\n </button>\n </div>\n }\n @if (!multiRange && !requireApply && showClearButton) {\n <button type=\"button\" class=\"btn-clear\" (click)=\"clear()\" title=\"Clear selection\">\n Clear\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".datepicker-wrapper{position:relative;width:100%}.datepicker-wrapper .datepicker-input{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;cursor:pointer}.datepicker-wrapper .datepicker-input:hover{border-color:var(--input-border-hover, #ced4da)}.datepicker-wrapper .datepicker-input:focus{border-color:var(--input-border-focus, #80bdff);box-shadow:0 0 0 .2rem #007bff40;outline:0}.datepicker-wrapper .datepicker-input::placeholder{color:#6c757d;opacity:1}.datepicker-wrapper .datepicker-input:disabled,.datepicker-wrapper .datepicker-input[readonly]{background-color:#e9ecef;opacity:1}.date-picker-dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #e1e4e8;border-radius:8px;box-shadow:0 4px 12px #00000014,0 0 1px #00000014;padding:16px;z-index:1060;min-width:680px}@media (max-width: 768px){.date-picker-dropdown{min-width:100%;left:0;right:0}}.date-picker-header-only-close{display:flex;justify-content:flex-end;margin-bottom:12px}.date-picker-header-only-close .btn-close-calendar{background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;border-radius:6px;cursor:pointer;transition:all .15s ease;font-size:1.5rem;line-height:1}.date-picker-header-only-close .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-header-only-close .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-presets{display:flex;gap:6px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid #e5e7eb;align-items:center}@media (max-width: 768px){.date-picker-presets{flex-wrap:wrap}}.date-picker-presets button{font-size:.75rem;padding:6px 14px;border:none;background-color:#f9fafb;color:#374151;border-radius:6px;transition:all .15s ease;font-weight:500;cursor:pointer;border:1px solid #e5e7eb}.date-picker-presets button:hover{background-color:#f3f4f6;border-color:#d1d5db;transform:translateY(-1px);box-shadow:0 2px 4px #0000000f}.date-picker-presets button:active{transform:translateY(0);box-shadow:none}.date-picker-presets .btn-close-calendar{margin-left:auto;background-color:transparent;border:1px solid transparent;color:#6b7280;padding:6px 10px;font-size:1.5rem;line-height:1}.date-picker-presets .btn-close-calendar:hover{background-color:#fee;border-color:#fcc;color:#dc2626;transform:translateY(-1px);box-shadow:0 2px 4px #dc26261a}.date-picker-presets .btn-close-calendar:active{transform:translateY(0);box-shadow:none}.date-picker-calendars{display:flex;gap:32px}@media (max-width: 768px){.date-picker-calendars{flex-direction:column;gap:16px}}.date-picker-calendar{flex:1}.date-picker-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding:0 4px}.date-picker-header span{font-size:.813rem;font-weight:600;color:#111827}.date-picker-header button{padding:4px;color:#6b7280;text-decoration:none;border-radius:6px;transition:all .15s ease;border:none;background:transparent;cursor:pointer}.date-picker-header button:hover{background-color:#f3f4f6;color:#111827}.date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:4px}.date-picker-weekdays span{text-align:center;font-size:.625rem;font-weight:600;color:#6b7280;padding:6px}.date-picker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.date-picker-day{aspect-ratio:1;border:none;background:transparent;border-radius:50%;font-size:.75rem;cursor:pointer;transition:all .15s ease;color:#374151;font-weight:400;position:relative}.date-picker-day:hover:not(:disabled):not(.selected){background-color:#f3f4f6;color:#111827}.date-picker-day.empty{visibility:hidden}.date-picker-day.selected{background-color:#222;color:#fff;font-weight:600}.date-picker-day.in-range{background-color:#f9fafb;border-radius:0}.date-picker-day.in-hover-range{background-color:#e0e7ff;border-radius:0;opacity:.7;position:relative}.date-picker-day.in-hover-range:after{content:\"\";position:absolute;inset:0;border:1px dashed #6366f1;pointer-events:none}.date-picker-day:disabled{cursor:not-allowed;opacity:.3}.date-picker-day.disabled{cursor:not-allowed;opacity:.4;color:#9ca3af;background-color:#f9fafb;text-decoration:line-through}.date-picker-day.disabled:hover{background-color:#f9fafb;color:#9ca3af}.date-picker-day.keyboard-focused{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-day.keyboard-focused:not(.selected){background-color:#eff6ff}.date-picker-day:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;z-index:1}.date-picker-footer{padding:12px;border-top:1px solid #e1e4e8;display:flex;justify-content:center;gap:8px}.date-picker-footer .btn-clear{padding:8px 16px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-clear:hover{background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-clear:active{transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-done{padding:8px 16px;background-color:#222;border:1px solid #222;border-radius:6px;font-size:.875rem;font-weight:500;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-done:hover{background-color:#000;border-color:#000;transform:translateY(-1px);box-shadow:0 2px 4px #00000026}.date-picker-footer .btn-done:active{transform:translateY(0);box-shadow:none}.date-picker-footer .btn-apply{padding:8px 24px;background-color:#2563eb;border:1px solid #2563eb;border-radius:6px;font-size:.875rem;font-weight:600;color:#fff;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-apply:hover:not(:disabled){background-color:#1d4ed8;border-color:#1d4ed8;transform:translateY(-1px);box-shadow:0 2px 8px #2563eb40}.date-picker-footer .btn-apply:active:not(:disabled){transform:translateY(0);box-shadow:none}.date-picker-footer .btn-apply:disabled{opacity:.5;cursor:not-allowed}.date-picker-footer .btn-cancel{padding:8px 24px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;font-size:.875rem;font-weight:500;color:#24292f;cursor:pointer;transition:all .15s ease}.date-picker-footer .btn-cancel:hover:not(:disabled){background-color:#f3f4f6;border-color:#8c959f;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.date-picker-footer .btn-cancel:active:not(:disabled){transform:translateY(0);box-shadow:none;background-color:#e9ecef}.date-picker-footer .btn-cancel:disabled{opacity:.5;cursor:not-allowed}.date-picker-footer .apply-footer-actions{display:flex;gap:8px;width:100%;justify-content:flex-end}.date-picker-footer .multi-range-footer-actions{display:flex;gap:8px;width:100%;justify-content:space-between}.multi-range-list{border-top:1px solid #e1e4e8;border-bottom:1px solid #e1e4e8;padding:12px;margin-top:12px}.multi-range-list .multi-range-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.multi-range-list .multi-range-header .multi-range-title{font-size:.8125rem;font-weight:600;color:#24292f;text-transform:uppercase;letter-spacing:.025em}.multi-range-list .multi-range-items{display:flex;flex-direction:column;gap:6px;max-height:150px;overflow-y:auto}.multi-range-list .multi-range-items::-webkit-scrollbar{width:6px}.multi-range-list .multi-range-items::-webkit-scrollbar-track{background:#f1f3f4;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb{background:#cbd5e0;border-radius:4px}.multi-range-list .multi-range-items::-webkit-scrollbar-thumb:hover{background:#a0aec0}.multi-range-list .multi-range-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background-color:#f6f8fa;border:1px solid #d0d7de;border-radius:6px;transition:all .15s ease}.multi-range-list .multi-range-item:hover{background-color:#f3f4f6;border-color:#8c959f}.multi-range-list .multi-range-item .multi-range-text{font-size:.875rem;color:#24292f;font-weight:500}.multi-range-list .multi-range-item .btn-remove-range{padding:4px;background-color:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#6b7280;transition:all .15s ease}.multi-range-list .multi-range-item .btn-remove-range:hover{background-color:#fee;border-color:#fcc;color:#dc2626}.multi-range-list .multi-range-item .btn-remove-range:hover svg{transform:scale(1.1)}.multi-range-list .multi-range-item .btn-remove-range:active{transform:scale(.95)}.multi-range-list .multi-range-item .btn-remove-range svg{transition:transform .15s ease}\n"] }]
|
|
761
984
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { placeholder: [{
|
|
762
985
|
type: Input
|
|
763
986
|
}], startDate: [{
|
|
@@ -776,6 +999,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
776
999
|
type: Input
|
|
777
1000
|
}], closeOnClickOutside: [{
|
|
778
1001
|
type: Input
|
|
1002
|
+
}], enableKeyboardNavigation: [{
|
|
1003
|
+
type: Input
|
|
779
1004
|
}], presets: [{
|
|
780
1005
|
type: Input
|
|
781
1006
|
}], inputBackgroundColor: [{
|
|
@@ -792,6 +1017,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
792
1017
|
type: Input
|
|
793
1018
|
}], locale: [{
|
|
794
1019
|
type: Input
|
|
1020
|
+
}], disabledDates: [{
|
|
1021
|
+
type: Input
|
|
1022
|
+
}], displayFormat: [{
|
|
1023
|
+
type: Input
|
|
1024
|
+
}], requireApply: [{
|
|
1025
|
+
type: Input
|
|
795
1026
|
}], dateRangeChange: [{
|
|
796
1027
|
type: Output
|
|
797
1028
|
}], dateRangeSelected: [{
|